diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/server.rs | 104 | ||||
-rw-r--r-- | src/shared/tower.rs | 8 |
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, } |