Implement killer name in chat

Former-commit-id: 5aa87529179a684d5675c33e4001806aa2040802
This commit is contained in:
timokoesters 2019-05-27 21:41:24 +02:00
parent 40eef27bcb
commit 171ca86340
9 changed files with 76 additions and 29 deletions

View File

@ -22,4 +22,5 @@ pub use inputs::Jumping;
pub use inputs::Respawning; pub use inputs::Respawning;
pub use player::Player; pub use player::Player;
pub use stats::Dying; pub use stats::Dying;
pub use stats::HealthSource;
pub use stats::Stats; pub use stats::Stats;

View File

@ -1,17 +1,33 @@
use crate::state::Time; use crate::state::{Time, Uid};
use specs::{Component, FlaggedStorage, NullStorage, VecStorage}; use specs::{Component, FlaggedStorage, NullStorage, VecStorage};
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub enum HealthSource {
Attack { by: Uid }, // TODO: Implement weapon
Suicide,
}
#[derive(Clone, Copy, Debug, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub struct Health { pub struct Health {
pub current: u32, current: u32,
pub maximum: u32, maximum: u32,
pub last_change: Option<(i32, f64)>, pub last_change: Option<(i32, f64, HealthSource)>,
} }
impl Health { impl Health {
pub fn change_by(&mut self, amount: i32) { pub fn get_current(&self) -> u32 {
self.current
}
pub fn get_maximum(&self) -> u32 {
self.maximum
}
pub fn set_to(&mut self, amount: u32, cause: HealthSource) {
self.last_change = Some((amount as i32 - self.current as i32, 0.0, cause));
self.current = amount;
}
pub fn change_by(&mut self, amount: i32, cause: HealthSource) {
self.current = (self.current as i32 + amount).max(0) as u32; self.current = (self.current as i32 + amount).max(0) as u32;
self.last_change = Some((amount, 0.0)); self.last_change = Some((amount, 0.0, cause));
} }
} }
@ -47,9 +63,11 @@ impl Component for Stats {
type Storage = FlaggedStorage<Self, VecStorage<Self>>; type Storage = FlaggedStorage<Self, VecStorage<Self>>;
} }
#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub struct Dying; pub struct Dying {
pub cause: HealthSource,
}
impl Component for Dying { impl Component for Dying {
type Storage = NullStorage<Self>; type Storage = VecStorage<Self>;
} }

View File

@ -6,9 +6,10 @@ use vek::*;
use crate::{ use crate::{
comp::{ comp::{
phys::{Dir, ForceUpdate, Pos, Vel}, phys::{Dir, ForceUpdate, Pos, Vel},
Animation, AnimationInfo, Attacking, Control, Gliding, Jumping, Respawning, Stats, Animation, AnimationInfo, Attacking, Control, Gliding, HealthSource, Jumping, Respawning,
Stats,
}, },
state::{DeltaTime, Time}, state::{DeltaTime, Time, Uid},
terrain::TerrainMap, terrain::TerrainMap,
vol::{ReadVol, Vox}, vol::{ReadVol, Vox},
}; };
@ -19,6 +20,7 @@ pub struct Sys;
impl<'a> System<'a> for Sys { impl<'a> System<'a> for Sys {
type SystemData = ( type SystemData = (
Entities<'a>, Entities<'a>,
ReadStorage<'a, Uid>,
Read<'a, Time>, Read<'a, Time>,
Read<'a, DeltaTime>, Read<'a, DeltaTime>,
ReadExpect<'a, TerrainMap>, ReadExpect<'a, TerrainMap>,
@ -39,6 +41,7 @@ impl<'a> System<'a> for Sys {
&mut self, &mut self,
( (
entities, entities,
uids,
time, time,
dt, dt,
terrain, terrain,
@ -140,8 +143,8 @@ impl<'a> System<'a> for Sys {
); );
} }
for (entity, pos, dir, attacking) in for (entity, &uid, pos, dir, attacking) in
(&entities, &positions, &directions, &mut attackings).join() (&entities, &uids, &positions, &directions, &mut attackings).join()
{ {
if !attacking.applied { if !attacking.applied {
for (b, pos_b, mut stat_b, mut vel_b) in for (b, pos_b, mut stat_b, mut vel_b) in
@ -154,7 +157,7 @@ impl<'a> System<'a> for Sys {
&& dir.0.angle_between(pos_b.0 - pos.0).to_degrees() < 70.0 && dir.0.angle_between(pos_b.0 - pos.0).to_degrees() < 70.0
{ {
// Deal damage // Deal damage
stat_b.hp.change_by(-10); // TODO: variable damage stat_b.hp.change_by(-10, HealthSource::Attack { by: uid }); // TODO: variable damage and weapon
vel_b.0 += (pos_b.0 - pos.0).normalized() * 10.0; vel_b.0 += (pos_b.0 - pos.0).normalized() * 10.0;
vel_b.0.z = 15.0; vel_b.0.z = 15.0;
force_updates.insert(b, ForceUpdate); force_updates.insert(b, ForceUpdate);

View File

@ -23,7 +23,16 @@ impl<'a> System<'a> for Sys {
for (entity, mut stat) in (&entities, &mut stats).join() { for (entity, mut stat) in (&entities, &mut stats).join() {
if stat.should_die() && !stat.is_dead { if stat.should_die() && !stat.is_dead {
// TODO: Replace is_dead with client states // TODO: Replace is_dead with client states
dyings.insert(entity, Dying); dyings.insert(
entity,
Dying {
cause: stat
.hp
.last_change
.expect("Nothing caused the entity to die")
.2, // Safe because damage is necessary for death
},
);
stat.is_dead = true; stat.is_dead = true;
} }
if let Some(change) = &mut stat.hp.last_change { if let Some(change) = &mut stat.hp.last_change {

View File

@ -150,7 +150,7 @@ fn handle_kill(server: &mut Server, entity: EcsEntity, args: String, action: &Ch
.ecs_mut() .ecs_mut()
.write_storage::<comp::Stats>() .write_storage::<comp::Stats>()
.get_mut(entity) .get_mut(entity)
.map(|s| s.hp.current = 0); .map(|s| s.hp.set_to(0, comp::HealthSource::Suicide));
} }
fn handle_alias(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) { fn handle_alias(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) {

View File

@ -211,14 +211,35 @@ impl Server {
self.world.tick(dt); self.world.tick(dt);
// Sync deaths. // Sync deaths.
let todo_kill = ( let ecs = &self.state.ecs();
&self.state.ecs().entities(), let clients = &mut self.clients;
&self.state.ecs().read_storage::<comp::Dying>(), let todo_kill = (&ecs.entities(), &ecs.read_storage::<comp::Dying>())
)
.join() .join()
.map(|(entity, _)| entity) .map(|(entity, dying)| {
// Chat message
if let Some(player) = ecs.read_storage::<comp::Player>().get(entity) {
// While waiting for if-let-chains to be implemented...
let msg = if let comp::HealthSource::Attack { by } = dying.cause {
if let Some(attacker) = ecs
.read_storage::<comp::Player>()
.get(ecs.entity_from_uid(by.into()).unwrap())
{
format!("{} was killed by {}", &player.alias, &attacker.alias)
} else {
format!("{} died", &player.alias)
}
} else {
format!("{} died", &player.alias)
};
clients.notify_registered(ServerMsg::Chat(msg));
}
entity
})
.collect::<Vec<_>>(); .collect::<Vec<_>>();
// Actually kill them
for entity in todo_kill { for entity in todo_kill {
if let Some(client) = self.clients.get_mut(&entity) { if let Some(client) = self.clients.get_mut(&entity) {
self.state self.state
@ -229,11 +250,6 @@ impl Server {
self.state.ecs_mut().delete_entity_synced(entity); self.state.ecs_mut().delete_entity_synced(entity);
continue; continue;
} }
if let Some(player) = self.state.ecs().read_storage::<comp::Player>().get(entity) {
self.clients
.notify_registered(ServerMsg::Chat(format!("{} died", &player.alias)));
}
} }
// Handle respawns // Handle respawns

View File

@ -358,7 +358,7 @@ impl Hud {
// Filling // Filling
Rectangle::fill_with( Rectangle::fill_with(
[ [
120.0 * (stats.hp.current as f64 / stats.hp.maximum as f64), 120.0 * (stats.hp.get_current() as f64 / stats.hp.get_maximum() as f64),
8.0, 8.0,
], ],
HP_COLOR, HP_COLOR,

View File

@ -78,7 +78,7 @@ impl<'a> Widget for Skillbar<'a> {
let next_level_xp = (level as f64).powi(4) - start_level_xp; let next_level_xp = (level as f64).powi(4) - start_level_xp;
// TODO: We need a max xp value // TODO: We need a max xp value
let xp_percentage = (self.stats.xp as f64 - start_level_xp) / next_level_xp; let xp_percentage = (self.stats.xp as f64 - start_level_xp) / next_level_xp;
let hp_percentage = self.stats.hp.current as f64 / self.stats.hp.maximum as f64; let hp_percentage = self.stats.hp.get_current() as f64 / self.stats.hp.get_maximum() as f64;
let mana_percentage = 1.0; let mana_percentage = 1.0;
// TODO: Only show while aiming with a bow or when casting a spell. // TODO: Only show while aiming with a bow or when casting a spell.

View File

@ -475,7 +475,7 @@ impl FigureMgr {
// Change in health as color! // Change in health as color!
let col = stats let col = stats
.and_then(|stats| stats.hp.last_change) .and_then(|stats| stats.hp.last_change)
.map(|(change_by, time)| { .map(|(change_by, time, _)| {
Rgba::broadcast(1.0) Rgba::broadcast(1.0)
+ Rgba::new(0.0, -1.0, -1.0, 0.0) + Rgba::new(0.0, -1.0, -1.0, 0.0)
.map(|c| (c / (1.0 + DAMAGE_FADE_COEFFICIENT * time)) as f32) .map(|c| (c / (1.0 + DAMAGE_FADE_COEFFICIENT * time)) as f32)