aboutsummaryrefslogtreecommitdiffstats
path: root/src/server.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/server.rs')
-rw-r--r--src/server.rs87
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);
+ }
+}