aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client.rs12
-rw-r--r--src/server.rs19
-rw-r--r--src/shared/ability.rs42
-rw-r--r--src/shared/buffs.rs1
-rw-r--r--src/shared/champion.rs4
-rw-r--r--src/shared/health.rs18
-rw-r--r--src/shared/player.rs5
7 files changed, 85 insertions, 16 deletions
diff --git a/src/client.rs b/src/client.rs
index 5084eaa..8da77dc 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -522,11 +522,13 @@ fn render_health(players: Query<(&Health, &PlayerPosition, &EffectiveStats)>, mu
for (health, position, effective_stats) in players.iter() {
let start = position.0 + Vec2::new(-PLAYER_RADIUS, PLAYER_RADIUS + HEALTH_OFFSET);
let end = position.0 + Vec2::new(PLAYER_RADIUS, PLAYER_RADIUS + HEALTH_OFFSET);
- gizmos.line_2d(
- start,
- start.lerp(end, health.0 / effective_stats.0.max_health),
- Color::RED,
- );
+ let health_start = start;
+ let health_end = start.lerp(end, health.health / effective_stats.0.max_health);
+ let px_per_health = (end.x - start.x) / effective_stats.0.max_health;
+ let shield_start = health_end;
+ let shield_end = health_end + Vec2::new(health.shield * px_per_health, 0.);
+ gizmos.line_2d(health_start, health_end, Color::RED);
+ gizmos.line_2d(shield_start, shield_end, Color::GRAY);
}
}
diff --git a/src/server.rs b/src/server.rs
index 483314d..fc44120 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -55,7 +55,7 @@ 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, effective_stats.after(buffs_despawn))
.add_systems(FixedUpdate, health_regen.after(timers_tick))
.add_systems(
FixedUpdate,
@@ -466,7 +466,7 @@ fn projectile_despawn(
if let Some(target_player) = maybe_target_player {
if let Some(target_entity) = entity_map.0.get(&target_player.0) {
if let Ok(mut health) = healths.get_mut(*target_entity) {
- health.0 = (health.0 - projectile.damage).max(0.);
+ health.apply_damage(projectile.damage);
let _ = connection_manager
.send_message_to_target::<Channel1, HealthChanged>(
HealthChanged(HealthEvent {
@@ -504,7 +504,7 @@ fn health_regen(
) {
if health_regen_timer.0.just_finished() {
for (target_player, mut health, effective_stats) in healths.iter_mut() {
- health.0 = (health.0 + HEALTH_REGEN).min(effective_stats.0.max_health);
+ health.heal(HEALTH_REGEN, effective_stats.0.max_health);
let _ = connection_manager.send_message_to_target::<Channel1, HealthChanged>(
HealthChanged(HealthEvent {
target_player: *target_player,
@@ -531,7 +531,10 @@ fn effective_stats(
stats.attack_speed *= 0.5;
}
effective_stats.0 = stats;
- health.0 = health.0.min(effective_stats.0.max_health);
+ health.health = health.health.min(effective_stats.0.max_health);
+ if buffs.shield.is_none() {
+ health.shield = 0.;
+ }
}
}
@@ -541,6 +544,9 @@ fn buffs_tick(mut buffses: Query<&mut Buffs>, time: Res<Time>) {
if let Some(ref mut timer) = &mut buffs.haste {
timer.tick(dt);
}
+ if let Some(ref mut timer) = &mut buffs.shield {
+ timer.tick(dt);
+ }
if let Some(ref mut timer) = &mut buffs.slow {
timer.tick(dt);
}
@@ -557,6 +563,11 @@ fn buffs_despawn(mut buffses: Query<&mut Buffs>) {
buffs.haste = None;
}
}
+ if let Some(timer) = &buffs.shield {
+ if timer.finished() {
+ buffs.shield = None;
+ }
+ }
if let Some(timer) = &buffs.slow {
if timer.finished() {
buffs.slow = None;
diff --git a/src/shared/ability.rs b/src/shared/ability.rs
index b841661..80c74b2 100644
--- a/src/shared/ability.rs
+++ b/src/shared/ability.rs
@@ -59,6 +59,7 @@ impl TargetedAbility {
pub enum ActivatedAbility {
Focus(Focus),
Haste(Haste),
+ Shield(Shield),
Speed(Speed),
}
@@ -73,6 +74,12 @@ pub struct Haste {
}
#[derive(Copy, Clone, PartialEq, Debug, Deserialize, Serialize)]
+pub struct Shield {
+ pub duration: f32,
+ pub blocked_damage: f32,
+}
+
+#[derive(Copy, Clone, PartialEq, Debug, Deserialize, Serialize)]
pub struct Speed {
pub duration: f32,
}
@@ -84,12 +91,13 @@ impl ActivatedAbility {
match self {
ActivatedAbility::Focus(focus) => focus_activation(focus),
ActivatedAbility::Haste(haste) => haste_activation(haste),
+ ActivatedAbility::Shield(shield) => shield_activation(shield),
ActivatedAbility::Speed(speed) => speed_activation(speed),
}
}
}
-fn speed_activation(speed: Speed) -> ActivatedAbilityActivation {
+fn focus_activation(focus: Focus) -> ActivatedAbilityActivation {
Box::new(move |commands: &mut Commands, source_id: PlayerId| {
commands.add(move |world: &mut World| {
world.run_system_once(
@@ -100,7 +108,8 @@ fn speed_activation(speed: Speed) -> ActivatedAbilityActivation {
let Ok(mut buffs) = buffses.get_mut(*entity_id) else {
return;
};
- buffs.speed = Some(Timer::from_seconds(speed.duration, TimerMode::Once));
+ buffs.haste = Some(Timer::from_seconds(focus.duration, TimerMode::Once));
+ buffs.speed = Some(Timer::from_seconds(focus.duration, TimerMode::Once));
},
)
});
@@ -125,7 +134,31 @@ fn haste_activation(haste: Haste) -> ActivatedAbilityActivation {
})
}
-fn focus_activation(focus: Focus) -> ActivatedAbilityActivation {
+fn shield_activation(shield: Shield) -> ActivatedAbilityActivation {
+ Box::new(move |commands: &mut Commands, source_id: PlayerId| {
+ commands.add(move |world: &mut World| {
+ world.run_system_once(
+ move |entity_map: Res<EntityMap>,
+ mut healths: Query<&mut Health>,
+ mut buffses: Query<&mut Buffs>| {
+ let Some(entity_id) = entity_map.0.get(&source_id.0) else {
+ return;
+ };
+ let Ok(mut health) = healths.get_mut(*entity_id) else {
+ return;
+ };
+ let Ok(mut buffs) = buffses.get_mut(*entity_id) else {
+ return;
+ };
+ health.shield = health.shield + shield.blocked_damage;
+ buffs.shield = Some(Timer::from_seconds(shield.duration, TimerMode::Once));
+ },
+ )
+ });
+ })
+}
+
+fn speed_activation(speed: Speed) -> ActivatedAbilityActivation {
Box::new(move |commands: &mut Commands, source_id: PlayerId| {
commands.add(move |world: &mut World| {
world.run_system_once(
@@ -136,8 +169,7 @@ fn focus_activation(focus: Focus) -> ActivatedAbilityActivation {
let Ok(mut buffs) = buffses.get_mut(*entity_id) else {
return;
};
- buffs.haste = Some(Timer::from_seconds(focus.duration, TimerMode::Once));
- buffs.speed = Some(Timer::from_seconds(focus.duration, TimerMode::Once));
+ buffs.speed = Some(Timer::from_seconds(speed.duration, TimerMode::Once));
},
)
});
diff --git a/src/shared/buffs.rs b/src/shared/buffs.rs
index e8992d5..6b518a5 100644
--- a/src/shared/buffs.rs
+++ b/src/shared/buffs.rs
@@ -3,6 +3,7 @@ use crate::shared::*;
#[derive(Clone, Component, Default, Debug)]
pub struct Buffs {
pub haste: Option<Timer>,
+ pub shield: Option<Timer>,
pub slow: Option<Timer>,
pub speed: Option<Timer>,
}
diff --git a/src/shared/champion.rs b/src/shared/champion.rs
index da63664..86bd41e 100644
--- a/src/shared/champion.rs
+++ b/src/shared/champion.rs
@@ -55,6 +55,10 @@ impl Champion {
AbilitySlot::W => {
Ability::Directional(DirectionalAbility::Pull(Pull { max_distance: 60. }))
}
+ AbilitySlot::E => Ability::Activated(ActivatedAbility::Shield(Shield {
+ blocked_damage: 35.,
+ duration: 2.,
+ })),
AbilitySlot::R => {
Ability::Targeted(TargetedAbility::MeeleAttack(MeeleAttack { damage: 45. }))
}
diff --git a/src/shared/health.rs b/src/shared/health.rs
index b88f19c..f9cc300 100644
--- a/src/shared/health.rs
+++ b/src/shared/health.rs
@@ -1,4 +1,20 @@
use crate::shared::*;
#[derive(Component, Message, Serialize, Deserialize, Clone, Copy, Debug, PartialEq)]
-pub struct Health(pub f32);
+pub struct Health {
+ pub health: f32,
+ pub shield: f32,
+}
+
+impl Health {
+ pub fn apply_damage(&mut self, damage: f32) {
+ let shield_damage = damage.min(self.shield);
+ let health_damage = damage - shield_damage;
+ self.shield = self.shield - shield_damage;
+ self.health = (self.health - health_damage).max(0.);
+ }
+
+ pub fn heal(&mut self, health: f32, max_health: f32) {
+ self.health = (self.health + health).min(max_health);
+ }
+}
diff --git a/src/shared/player.rs b/src/shared/player.rs
index d1df3af..3805969 100644
--- a/src/shared/player.rs
+++ b/src/shared/player.rs
@@ -37,7 +37,10 @@ impl PlayerBundle {
color: PlayerColor(color),
imperative: Imperative::Idle,
cooldown: Cooldown::default(),
- health: Health(effective_stats.0.max_health),
+ health: Health {
+ health: effective_stats.0.max_health,
+ shield: 0.,
+ },
champion,
effective_stats,
buffs: Buffs::default(),