diff --git a/rust/src/player.rs b/rust/src/player.rs index 9d207f1..6686ce4 100644 --- a/rust/src/player.rs +++ b/rust/src/player.rs @@ -11,7 +11,7 @@ use godot::{ use serde::{Deserialize, Serialize}; use crate::{ - game_manager::Game, + game_manager::{Game, GameOption}, net::{ network_manager::{ NetworkManager, @@ -56,14 +56,15 @@ pub trait IPlayer { fn get_ball_origin(&self) -> Option>; } -pub trait PlayerMovement { +pub trait PlayerCommon { fn player_update(&mut self, delta: f64); fn try_jump(&mut self) -> bool; fn drop_ball_common(&mut self, with_velocity: bool) -> bool; fn get_look_dir(&self) -> Vector3; + fn can_take_damage(&self, source: &DamageSource) -> bool; } -impl PlayerMovement for T { +impl PlayerCommon for T { fn player_update(&mut self, delta: f64) { self.set_y_speed(self.get_y_speed() - 9.8 * delta as f32); if self.base().is_on_floor() && self.get_y_speed() < 0. { @@ -141,6 +142,30 @@ impl PlayerMovement for T { Vector3::ZERO } } + + fn can_take_damage(&self, source: &DamageSource) -> bool { + match source { + DamageSource::Player(source_player_id) => { + if let Some(game) = Game::singleton() { + let (self_team, source_team) = if let Some(self_player) = + game.bind().find_player(self.get_player_id().unwrap_or(0)) + && let Some(source_player) = game.bind().find_player(*source_player_id) + { + (self_player.data.team, source_player.data.team) + } else { + (0, 0) + }; + if self_team == source_team + && !game.bind().opts.is_true(GameOption::FriendlyFire) + { + return false; + } + } + } + _ => {} + } + true + } } #[derive(GodotClass)] @@ -271,12 +296,16 @@ impl IPlayer for LocalPlayer { } fn take_damage(&mut self, source: DamageSource, damage: i32, kill: bool) { - let (signal, player) = source.into_signal(); - self.run_deferred(move |s| s.signals().on_take_damage().emit(signal, player, damage)); - self.health -= damage; - if kill && self.health <= 0 { - self.kill(source); - } + self.run_deferred(move |s| { + if s.can_take_damage(&source) { + let (signal, player) = source.into_signal(); + s.run_deferred(move |s| s.signals().on_take_damage().emit(signal, player, damage)); + s.health -= damage; + if kill && s.health <= 0 { + s.kill(source); + } + } + }); } fn is_dead(&self) -> bool { @@ -645,12 +674,16 @@ impl IPlayer for RemotePlayer { } fn take_damage(&mut self, source: DamageSource, damage: i32, kill: bool) { - let (signal, player) = source.into_signal(); - self.run_deferred(move |s| s.signals().on_take_damage().emit(signal, player, damage)); - self.health -= damage; - if kill && self.health <= 0 { - self.kill(source); - } + self.run_deferred(move |s| { + if s.can_take_damage(&source) { + let (signal, player) = source.into_signal(); + s.run_deferred(move |s| s.signals().on_take_damage().emit(signal, player, damage)); + s.health -= damage; + if kill && s.health <= 0 { + s.kill(source); + } + } + }); } fn is_dead(&self) -> bool {