diff options
Diffstat (limited to 'src/server.rs')
-rw-r--r-- | src/server.rs | 87 |
1 files changed, 74 insertions, 13 deletions
diff --git a/src/server.rs b/src/server.rs index 5ac07c0..4da2253 100644 --- a/src/server.rs +++ b/src/server.rs @@ -9,11 +9,13 @@ use crate::shared::champion::*; use crate::shared::cooldown::*; use crate::shared::health::*; use crate::shared::health_event::*; +use crate::shared::immovable::*; use crate::shared::imperative::*; use crate::shared::player::*; use crate::shared::projectile::*; +use crate::shared::shape::*; use crate::shared::stats::*; -use crate::shared::*; +use crate::shared::tower::*; use bevy::prelude::*; use bevy::utils::*; use lightyear::prelude::*; @@ -88,14 +90,18 @@ impl Plugin for ServerPlugin { ) .add_systems(FixedUpdate, cooldown_decrement) .add_systems(FixedUpdate, (buffs_despawn, buffs_tick).chain()) - .add_systems(FixedUpdate, player_input); + .add_systems(FixedUpdate, player_input) + .add_systems(FixedUpdate, tower_ai); } } fn setup(mut commands: Commands, mut entity_map: ResMut<EntityMap>) { - let client_id = 1; let entity = commands.spawn(PlayerBundle::new(1, Vec2::ZERO, Color::GRAY)); - entity_map.0.insert(client_id, entity.id()); + entity_map.0.insert(1, entity.id()); + let entity = commands.spawn(TowerBundle::new(2, Vec2::new(0., 100.), Color::RED)); + entity_map.0.insert(2, entity.id()); + let entity = commands.spawn(TowerBundle::new(3, Vec2::new(0., -100.), Color::BLUE)); + entity_map.0.insert(3, entity.id()); } fn connects( @@ -216,8 +222,9 @@ fn move_along_direction(position: Vec2, direction: Vec2, distance: f32) -> Vec2 fn imperative_attack_approach( entity_map: Res<EntityMap>, - mut players: Query<(&PlayerId, &mut Imperative, &EffectiveStats)>, + mut players: Query<(&PlayerId, &mut Imperative, &EffectiveStats), Without<Immovable>>, mut positions: Query<&mut PlayerPosition>, + shapes: Query<&Shape>, time: Res<Time>, ) { for (id, mut imperative, effective_stats) in players.iter_mut() { @@ -237,8 +244,12 @@ fn imperative_attack_approach( *imperative = Imperative::Idle; continue; }; + let Ok(target_shape) = shapes.get(*target_entity) else { + *imperative = Imperative::Idle; + continue; + }; let distance = target_position.0.distance(position.0); - if distance > effective_stats.0.attack_range { + if distance > effective_stats.0.attack_range + target_shape.radius { let (new_position, _) = move_to_target( position.0, target_position.0, @@ -258,6 +269,7 @@ fn imperative_attack_attack( mut cooldowns: Query<&mut Cooldown>, mut players: Query<(&PlayerId, &mut Imperative, &EffectiveStats)>, mut positions: Query<&mut PlayerPosition>, + shapes: Query<&Shape>, champions: Query<&Champion>, ) { for (id, mut imperative, effective_stats) in players.iter_mut() { @@ -285,8 +297,12 @@ fn imperative_attack_attack( *imperative = Imperative::Idle; continue; }; + let Ok(target_shape) = shapes.get(*target_entity) else { + *imperative = Imperative::Idle; + continue; + }; let distance = target_position.0.distance(position.0); - if distance <= effective_stats.0.attack_range { + if distance <= effective_stats.0.attack_range + target_shape.radius { let Ok(mut cooldown) = cooldowns.get_mut(*entity) else { *imperative = Imperative::Idle; continue; @@ -413,19 +429,19 @@ fn projectile_despawn( mut healths: Query<&mut Health>, player_positions: Query<&PlayerPosition>, projectiles: Query<(Entity, &mut Projectile)>, - projectile_targets: Query<(&PlayerId, &PlayerPosition)>, + projectile_targets: Query<(&PlayerId, &PlayerPosition, &Shape)>, ) { for (entity, projectile) in projectiles.iter() { let (despawn, maybe_target_player): (bool, Option<PlayerId>) = (|| match &projectile.type_ { ProjectileType::Free(free_projectile) => { let mut maybe_target_player = None; let mut maybe_target_distance = None; - for (player, position) in projectile_targets.iter() { + for (player, position, player_shape) in projectile_targets.iter() { if *player == projectile.source_player { continue; } let distance = free_projectile.position.distance(position.0); - if distance > PLAYER_RADIUS { + if distance > player_shape.radius { continue; } match maybe_target_distance { @@ -629,20 +645,65 @@ fn area_of_effect_despawn(area_of_effects: Query<(Entity, &AreaOfEffect)>, mut c } fn area_of_effect_activate( - players: Query<(&PlayerId, &PlayerPosition)>, + players: Query<(&PlayerId, &PlayerPosition, &Shape)>, area_of_effects: Query<&AreaOfEffect>, mut commands: Commands, ) { for area_of_effect in area_of_effects.iter() { - for (player_id, player_position) in players.iter() { + for (player_id, player_position, player_shape) in players.iter() { if *player_id == area_of_effect.source_player { continue; } if area_of_effect.position.distance(player_position.0) - < area_of_effect.radius + PLAYER_RADIUS + < area_of_effect.radius + player_shape.radius { area_of_effect.activate()(&mut commands, area_of_effect.source_player, *player_id); } } } } + +fn tower_ai( + mut towers: Query<( + &mut Tower, + &mut Imperative, + &PlayerPosition, + &EffectiveStats, + )>, + targets: Query<(&PlayerId, &PlayerPosition, &Shape), Without<Tower>>, +) { + for (mut tower_tower, mut tower_imperative, tower_player_position, tower_effective_stats) in + towers.iter_mut() + { + let mut closest_target = None; + for (target_player_id, target_player_position, target_shape) in targets.iter() { + let target_in_range = tower_player_position.0.distance(target_player_position.0) + < tower_effective_stats.0.attack_range + target_shape.radius; + + if !target_in_range { + continue; + } + + 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 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 Some((target_player_id, _)) = closest_target else { + *tower_imperative = Imperative::Idle; + tower_tower.last_target_player_id = None; + continue; + }; + + *tower_imperative = Imperative::AttackTarget(AbilitySlot::A, *target_player_id); + tower_tower.last_target_player_id = Some(*target_player_id); + } +} |