aboutsummaryrefslogtreecommitdiffstats
path: root/src/server.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/server.rs')
-rw-r--r--src/server.rs153
1 files changed, 121 insertions, 32 deletions
diff --git a/src/server.rs b/src/server.rs
index 038f854..0b15c5f 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -1,6 +1,8 @@
use crate::protocol::*;
use crate::server::network::*;
use crate::shared::ability::*;
+use crate::shared::activation::*;
+use crate::shared::buffs::*;
use crate::shared::champion::*;
use crate::shared::cooldown::*;
use crate::shared::health::*;
@@ -8,6 +10,7 @@ use crate::shared::health_event::*;
use crate::shared::imperative::*;
use crate::shared::player::*;
use crate::shared::projectile::*;
+use crate::shared::stats::*;
use crate::shared::*;
use bevy::prelude::*;
use bevy::utils::HashMap;
@@ -53,13 +56,15 @@ impl Plugin for ServerPlugin {
.add_systems(Update, (connects, disconnects))
.add_systems(Update, receive_message)
.add_systems(FixedUpdate, timers_tick)
+ .add_systems(FixedUpdate, effective_stats)
.add_systems(FixedUpdate, health_regen.after(timers_tick))
.add_systems(
FixedUpdate,
(
(imperative_attack_approach, imperative_attack_attack)
.chain()
- .after(cooldown_decrement),
+ .after(activation),
+ activation.after(cooldown_decrement),
imperative_walk_to,
)
.after(player_input),
@@ -73,6 +78,7 @@ impl Plugin for ServerPlugin {
.chain(),
)
.add_systems(FixedUpdate, cooldown_decrement)
+ .add_systems(FixedUpdate, (buffs_despawn, buffs_tick).chain())
.add_systems(FixedUpdate, player_input);
}
}
@@ -110,7 +116,7 @@ fn receive_message(
let client_id = event.context();
let SelectChampion(champion) = event.message();
let Some(entity) = entity_map.0.get(client_id) else {
- return;
+ continue;
};
commands.entity(*entity).insert(*champion);
}
@@ -133,6 +139,7 @@ fn player_input(
entity_map: Res<EntityMap>,
mut input_reader: EventReader<server::InputEvent<Inputs>>,
mut imperatives: Query<&mut Imperative>,
+ mut activations: Query<&mut Activation>,
) {
for input in input_reader.read() {
let client_id = input.context();
@@ -144,28 +151,31 @@ fn player_input(
*imperative = *new_imperative;
}
}
- _ => {}
+ Inputs::Activation(new_activation) => {
+ if let Ok(mut activation) = activations.get_mut(*entity_id) {
+ *activation = *new_activation;
+ }
+ }
+ Inputs::None => {}
}
}
}
}
}
-const MOVEMENT_SPEED: f32 = 80.;
-
fn imperative_walk_to(
- mut players: Query<(Entity, &mut Imperative)>,
+ mut players: Query<(Entity, &mut Imperative, &EffectiveStats)>,
mut positions: Query<&mut PlayerPosition>,
time: Res<Time>,
) {
- for (entity, mut imperative) in players.iter_mut() {
+ for (entity, mut imperative, effective_stats) in players.iter_mut() {
match *imperative {
Imperative::WalkTo(target_position) => {
if let Ok(mut position) = positions.get_mut(entity) {
let (new_position, target_reached) = move_to_target(
position.0,
target_position,
- MOVEMENT_SPEED * time.delta().as_secs_f32(),
+ effective_stats.0.movement_speed * time.delta().as_secs_f32(),
);
position.0 = new_position;
if target_reached {
@@ -197,38 +207,33 @@ 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)>,
+ mut players: Query<(&PlayerId, &mut Imperative, &EffectiveStats)>,
mut positions: Query<&mut PlayerPosition>,
- champions: Query<&Champion>,
time: Res<Time>,
) {
- for (id, mut imperative) in players.iter_mut() {
+ for (id, mut imperative, effective_stats) in players.iter_mut() {
match *imperative {
Imperative::AttackTarget(_, target_player) => {
let Some(entity) = entity_map.0.get(&id.0) else {
*imperative = Imperative::Idle;
- return;
- };
- let Ok(champion) = champions.get(*entity) else {
- *imperative = Imperative::Idle;
- return;
+ continue;
};
let Some(target_entity) = entity_map.0.get(&target_player.0) else {
*imperative = Imperative::Idle;
- return;
+ continue;
};
let Ok([mut position, target_position]) =
positions.get_many_mut([*entity, *target_entity])
else {
*imperative = Imperative::Idle;
- return;
+ continue;
};
let distance = target_position.0.distance(position.0);
- if distance > Stats::from_champion(*champion).attack_range {
+ if distance > effective_stats.0.attack_range {
let (new_position, _) = move_to_target(
position.0,
target_position.0,
- MOVEMENT_SPEED * time.delta().as_secs_f32(),
+ effective_stats.0.movement_speed * time.delta().as_secs_f32(),
);
position.0 = new_position;
}
@@ -242,40 +247,40 @@ fn imperative_attack_attack(
entity_map: Res<EntityMap>,
mut commands: Commands,
mut cooldowns: Query<&mut Cooldown>,
- mut players: Query<(&PlayerId, &mut Imperative)>,
+ mut players: Query<(&PlayerId, &mut Imperative, &EffectiveStats)>,
mut positions: Query<&mut PlayerPosition>,
champions: Query<&Champion>,
) {
- for (id, mut imperative) in players.iter_mut() {
+ for (id, mut imperative, effective_stats) in players.iter_mut() {
let Some(entity) = entity_map.0.get(&id.0) else {
*imperative = Imperative::Idle;
- return;
+ continue;
};
let Ok(champion) = champions.get(*entity) else {
*imperative = Imperative::Idle;
- return;
+ continue;
};
match *imperative {
Imperative::AttackTarget(ability_slot, target_player) => {
let Ability::Targeted(ability) = champion.to_ability(ability_slot) else {
*imperative = Imperative::Idle;
- return;
+ continue;
};
let Some(target_entity) = entity_map.0.get(&target_player.0) else {
*imperative = Imperative::Idle;
- return;
+ continue;
};
let Ok([position, target_position]) =
positions.get_many_mut([*entity, *target_entity])
else {
*imperative = Imperative::Idle;
- return;
+ continue;
};
let distance = target_position.0.distance(position.0);
- if distance <= Stats::from_champion(*champion).attack_range {
+ if distance <= effective_stats.0.attack_range {
let Ok(mut cooldown) = cooldowns.get_mut(*entity) else {
*imperative = Imperative::Idle;
- return;
+ continue;
};
let base_cooldown = BaseCooldown::from_champion(*champion);
if cooldown.0[ability_slot].is_zero() {
@@ -285,21 +290,24 @@ fn imperative_attack_attack(
position.0,
target_player,
)));
+ if ability_slot != AbilitySlot::A {
+ *imperative = Imperative::Idle;
+ }
}
}
}
Imperative::AttackDirection(ability_slot, direction) => {
let Ability::Directional(ability) = champion.to_ability(ability_slot) else {
*imperative = Imperative::Idle;
- return;
+ continue;
};
let Ok(position) = positions.get_mut(*entity) else {
*imperative = Imperative::Idle;
- return;
+ continue;
};
let Ok(mut cooldown) = cooldowns.get_mut(*entity) else {
*imperative = Imperative::Idle;
- return;
+ continue;
};
let base_cooldown = BaseCooldown::from_champion(*champion);
if cooldown.0[ability_slot].is_zero() {
@@ -307,6 +315,7 @@ fn imperative_attack_attack(
commands.spawn(ProjectileBundle::new(
ability.to_projectile(*id, position.0, direction),
));
+ *imperative = Imperative::Idle;
}
}
_ => {}
@@ -314,6 +323,46 @@ fn imperative_attack_attack(
}
}
+fn activation(
+ entity_map: Res<EntityMap>,
+ mut cooldowns: Query<&mut Cooldown>,
+ mut players: Query<(&PlayerId, &mut Activation, &mut Buffs)>,
+ champions: Query<&Champion>,
+) {
+ for (id, mut activation, mut buffs) in players.iter_mut() {
+ let Some(entity) = entity_map.0.get(&id.0) else {
+ *activation = Activation::None;
+ continue;
+ };
+ let Ok(champion) = champions.get(*entity) else {
+ *activation = Activation::None;
+ continue;
+ };
+ let Activation::Activate(ability_slot) = *activation else {
+ *activation = Activation::None;
+ continue;
+ };
+ let Ability::Activated(ability) = champion.to_ability(ability_slot) else {
+ *activation = Activation::None;
+ continue;
+ };
+ let Ok(mut cooldown) = cooldowns.get_mut(*entity) else {
+ *activation = Activation::None;
+ continue;
+ };
+ match ability {
+ ActivatedAbility::Speed => {
+ let base_cooldown = BaseCooldown::from_champion(*champion);
+ if cooldown.0[ability_slot].is_zero() {
+ cooldown.0[ability_slot] = base_cooldown.0[ability_slot];
+ buffs.speed = Some(Timer::from_seconds(2., TimerMode::Once));
+ *activation = Activation::None;
+ }
+ }
+ }
+ }
+}
+
const PROJECTILE_SPEED: f32 = 150.;
fn projectile_move(
@@ -460,3 +509,43 @@ fn health_regen(health_regen_timer: Res<HealthRegenTimer>, mut healths: Query<&m
}
}
}
+
+fn effective_stats(mut effective_statses: Query<(&Champion, &mut EffectiveStats, &Buffs)>) {
+ for (champion, mut effective_stats, buffs) in effective_statses.iter_mut() {
+ let mut stats = BaseStats::from_champion(*champion).0;
+ if buffs.slow.is_some() {
+ stats.movement_speed *= 0.85;
+ }
+ if buffs.speed.is_some() {
+ stats.movement_speed *= 1.25;
+ }
+ effective_stats.0 = stats;
+ }
+}
+
+fn buffs_tick(mut buffses: Query<&mut Buffs>, time: Res<Time>) {
+ let dt = time.delta();
+ for mut buffs in buffses.iter_mut() {
+ if let Some(ref mut timer) = &mut buffs.slow {
+ timer.tick(dt);
+ }
+ if let Some(ref mut timer) = &mut buffs.speed {
+ timer.tick(dt);
+ }
+ }
+}
+
+fn buffs_despawn(mut buffses: Query<&mut Buffs>) {
+ for mut buffs in buffses.iter_mut() {
+ if let Some(timer) = &buffs.slow {
+ if timer.finished() {
+ buffs.slow = None;
+ }
+ }
+ if let Some(timer) = &buffs.speed {
+ if timer.finished() {
+ buffs.speed = None;
+ }
+ }
+ }
+}