aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/server.rs104
-rw-r--r--src/shared/tower.rs8
2 files changed, 89 insertions, 23 deletions
diff --git a/src/server.rs b/src/server.rs
index d9eccb6..6f8bce9 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -723,7 +723,14 @@ fn tower_ai(
&EffectiveStats,
&Faction,
)>,
- targets: Query<(&PlayerId, &PlayerPosition, &Shape, &Faction), Without<Tower>>,
+ non_player_targets: Query<
+ (Entity, &PlayerId, &PlayerPosition, &Shape, &Faction),
+ (Without<Tower>, Without<Player>),
+ >,
+ player_targets: Query<
+ (Entity, &PlayerId, &PlayerPosition, &Shape, &Faction),
+ (Without<Tower>, With<Player>),
+ >,
) {
for (
mut tower_tower,
@@ -733,42 +740,95 @@ fn tower_ai(
tower_faction,
) in towers.iter_mut()
{
- let mut closest_target = None;
- for (target_player_id, target_player_position, target_shape, target_faction) in
- targets.iter()
- {
+ let target_is_valid = |target_faction: &Faction,
+ target_player_position: &PlayerPosition,
+ target_shape: &Shape| {
if target_faction == tower_faction {
- continue;
+ return false;
}
let target_in_range = tower_player_position.0.distance(target_player_position.0)
< tower_effective_stats.0.attack_range + target_shape.radius;
+ target_in_range
+ };
- if !target_in_range {
- continue;
+ if let Some(last_target) = tower_tower.last_target {
+ if let Ok((_, _, target_player_position, target_shape, target_faction)) =
+ non_player_targets.get(last_target.entity)
+ {
+ if target_is_valid(target_faction, target_player_position, target_shape) {
+ return;
+ }
+ } else if let Ok((_, _, target_player_position, target_shape, target_faction)) =
+ player_targets.get(last_target.entity)
+ {
+ if target_is_valid(target_faction, target_player_position, target_shape) {
+ return;
+ }
}
+ }
- let target_distance = tower_player_position.0.distance(target_player_position.0);
- if tower_tower.last_target_player_id == Some(*target_player_id) {
- closest_target = Some((target_player_id, target_distance));
- break;
- }
+ let update_closest_target =
+ |closest_target: &mut Option<(LastTarget, f32)>,
+ target_entity: Entity,
+ target_player_id: &PlayerId,
+ target_player_position: &PlayerPosition| {
+ let target_distance = tower_player_position.0.distance(target_player_position.0);
+ let target_is_closer = closest_target
+ .map(|(_, closest_target_distance)| target_distance < closest_target_distance)
+ .unwrap_or(true);
+ if target_is_closer {
+ *closest_target = Some((
+ LastTarget {
+ entity: target_entity,
+ player_id: *target_player_id,
+ },
+ target_distance,
+ ));
+ }
+ };
- let target_is_closer = closest_target
- .map(|(_, closest_target_distance)| target_distance < closest_target_distance)
- .unwrap_or(true);
- if target_is_closer {
- closest_target = Some((target_player_id, target_distance));
+ let determine_target =
+ |closest_target: &mut Option<(LastTarget, f32)>,
+ (
+ target_entity,
+ target_player_id,
+ target_player_position,
+ target_shape,
+ target_faction,
+ ): (Entity, &PlayerId, &PlayerPosition, &Shape, &Faction)| {
+ if !target_is_valid(target_faction, target_player_position, target_shape) {
+ return;
+ }
+ update_closest_target(
+ closest_target,
+ target_entity,
+ target_player_id,
+ target_player_position,
+ );
+ };
+
+ let mut closest_non_player_target: Option<(LastTarget, f32)> = None;
+ for target in non_player_targets.iter() {
+ determine_target(&mut closest_non_player_target, target);
+ }
+
+ let mut closest_player_target: Option<(LastTarget, f32)> = None;
+ if closest_non_player_target.is_none() {
+ for target in player_targets.iter() {
+ determine_target(&mut closest_player_target, target);
}
}
- let Some((target_player_id, _)) = closest_target else {
+
+ let closest_target = closest_non_player_target.or(closest_player_target);
+ let Some((target, _)) = closest_target else {
*tower_imperative = Imperative::Idle;
- tower_tower.last_target_player_id = None;
+ tower_tower.last_target = None;
continue;
};
- *tower_imperative = Imperative::AttackTarget(AbilitySlot::A, *target_player_id);
- tower_tower.last_target_player_id = Some(*target_player_id);
+ *tower_imperative = Imperative::AttackTarget(AbilitySlot::A, target.player_id);
+ tower_tower.last_target = Some(target);
}
}
diff --git a/src/shared/tower.rs b/src/shared/tower.rs
index a21048a..4601112 100644
--- a/src/shared/tower.rs
+++ b/src/shared/tower.rs
@@ -64,5 +64,11 @@ impl TowerBundle {
#[derive(Component, Default)]
pub struct Tower {
- pub last_target_player_id: Option<PlayerId>,
+ pub last_target: Option<LastTarget>,
+}
+
+#[derive(Component, Clone, Copy)]
+pub struct LastTarget {
+ pub entity: Entity,
+ pub player_id: PlayerId,
}