Add killbox kinds

This commit is contained in:
Sofia 2026-07-24 23:21:57 +03:00
parent 32c4367aeb
commit a00ced88d0
6 changed files with 98 additions and 29 deletions

View File

@ -57,9 +57,9 @@ impl ChatMessage {
add_player(&mut label, &player); add_player(&mut label, &player);
} }
} }
DamageSource::Killbox => { DamageSource::Killbox(kind) => {
add_player(&mut label, &player); add_player(&mut label, &player);
label.append_text(" fell into the void"); label.append_text(&kind.as_kill_text());
} }
} }
} }

View File

@ -739,30 +739,38 @@ impl Game {
if let Ok(mut local_player) = character.clone().try_cast::<LocalPlayer>() { if let Ok(mut local_player) = character.clone().try_cast::<LocalPlayer>() {
local_player.bind_mut().signals().on_die().connect_other( local_player.bind_mut().signals().on_die().connect_other(
self, self,
move |s, signal, spid| { move |s, signal, spid, kind| {
s.on_death(DamageSource::from_signal(signal, spid), id) s.on_death(DamageSource::from_signal(signal, spid, kind), id)
}, },
); );
local_player local_player
.bind_mut() .bind_mut()
.signals() .signals()
.on_take_damage() .on_take_damage()
.connect_other(self, move |s, signal, spid, damage| { .connect_other(self, move |s, signal, spid, kind, damage| {
s.on_take_damage(DamageSource::from_signal(signal, spid), id, damage) s.on_take_damage(
DamageSource::from_signal(signal, spid, kind),
id,
damage,
)
}); });
} else if let Ok(mut remote_player) = character.clone().try_cast::<RemotePlayer>() { } else if let Ok(mut remote_player) = character.clone().try_cast::<RemotePlayer>() {
remote_player.bind_mut().signals().on_die().connect_other( remote_player.bind_mut().signals().on_die().connect_other(
self, self,
move |s, signal, spid| { move |s, signal, spid, kind| {
s.on_death(DamageSource::from_signal(signal, spid), id) s.on_death(DamageSource::from_signal(signal, spid, kind), id)
}, },
); );
remote_player remote_player
.bind_mut() .bind_mut()
.signals() .signals()
.on_take_damage() .on_take_damage()
.connect_other(self, move |s, signal, spid, damage| { .connect_other(self, move |s, signal, spid, kind, damage| {
s.on_take_damage(DamageSource::from_signal(signal, spid), id, damage) s.on_take_damage(
DamageSource::from_signal(signal, spid, kind),
id,
damage,
)
}); });
} }
} }

View File

@ -2,6 +2,7 @@ use godot::{
classes::{Area3D, IArea3D}, classes::{Area3D, IArea3D},
prelude::*, prelude::*,
}; };
use serde::{Deserialize, Serialize};
use crate::{ use crate::{
game_manager::Game, game_manager::Game,
@ -9,9 +10,48 @@ use crate::{
player::{DamageSource, IPlayer, ball::Ball}, player::{DamageSource, IPlayer, ball::Ball},
}; };
#[derive(Debug, Clone, Copy, GodotConvert, Default, Var, Serialize, Deserialize)]
#[godot(via = GString)]
pub enum KillboxKind {
#[default]
Void,
Spikes,
Lava,
SeaOfBlood,
OuterSpace,
Quicksand,
LargeBoulder,
ElectricFence,
RadioactiveGoo,
}
impl KillboxKind {
pub fn as_kill_text(&self) -> String {
match self {
KillboxKind::Void => " fell into the void",
KillboxKind::Spikes => " got impailed by spikes",
KillboxKind::Lava => " burned in lava",
KillboxKind::SeaOfBlood => " went looking for the Iron Lung",
KillboxKind::OuterSpace => " suffocated in outer space",
KillboxKind::Quicksand => " drowned in a pit of sand",
KillboxKind::LargeBoulder => {
" was squished by a large boulder the size of a small boulder"
}
KillboxKind::ElectricFence => " got electrocuted by a fence",
KillboxKind::RadioactiveGoo => {
" turned into a mutant..! no, died of radiation poisoning."
}
}
.to_string()
}
}
#[derive(GodotClass)] #[derive(GodotClass)]
#[class(base=Area3D, init)] #[class(base=Area3D, init)]
pub struct Killbox { pub struct Killbox {
#[var]
pub kind: KillboxKind,
base: Base<Area3D>, base: Base<Area3D>,
} }
@ -31,7 +71,7 @@ impl Killbox {
if NetworkManager::singleton().bind().is_host() { if NetworkManager::singleton().bind().is_host() {
player player
.dyn_bind_mut() .dyn_bind_mut()
.take_damage(DamageSource::Killbox, 1000, true); .take_damage(DamageSource::Killbox(self.kind), 1000, true);
} }
} else if let Ok(_) = node.try_cast::<Ball>() { } else if let Ok(_) = node.try_cast::<Ball>() {
if let Some(game) = &mut Game::singleton() { if let Some(game) = &mut Game::singleton() {

View File

@ -12,6 +12,7 @@ use godot::{
use crate::{ use crate::{
game_manager::{Game, GameManager}, game_manager::{Game, GameManager},
game_settings::{GameSettings, GameSettingsManager}, game_settings::{GameSettings, GameSettingsManager},
killbox::KillboxKind,
net::{ net::{
network_manager::{ network_manager::{
NetworkManager, NetworkManager,
@ -184,8 +185,12 @@ impl IPlayer for LocalPlayer {
fn take_damage(&mut self, source: DamageSource, damage: i32, kill: bool) { fn take_damage(&mut self, source: DamageSource, damage: i32, kill: bool) {
self.run_deferred(move |s| { self.run_deferred(move |s| {
if s.can_take_damage(&source) { if s.can_take_damage(&source) {
let (signal, player) = source.into_signal(); let (signal, player, kind) = source.into_signal();
s.run_deferred(move |s| s.signals().on_take_damage().emit(signal, player, damage)); s.run_deferred(move |s| {
s.signals()
.on_take_damage()
.emit(signal, player, kind, damage)
});
s.health -= damage; s.health -= damage;
if kill && s.health <= 0 { if kill && s.health <= 0 {
s.kill(source); s.kill(source);
@ -208,8 +213,8 @@ impl IPlayer for LocalPlayer {
fn kill(&mut self, source: DamageSource) { fn kill(&mut self, source: DamageSource) {
self.drop_ball(false); self.drop_ball(false);
let (signal, player) = source.into_signal(); let (signal, player, kind) = source.into_signal();
self.run_deferred(move |s| s.signals().on_die().emit(signal, player)); self.run_deferred(move |s| s.signals().on_die().emit(signal, player, kind));
if let Some(mut mesh) = self.soldier_mesh.take() { if let Some(mut mesh) = self.soldier_mesh.take() {
mesh.queue_free(); mesh.queue_free();
} }
@ -567,9 +572,14 @@ impl ICharacterBody3D for LocalPlayer {
#[godot_api] #[godot_api]
impl LocalPlayer { impl LocalPlayer {
#[signal] #[signal]
pub fn on_die(source: DamageSourceSignal, player: u16); pub fn on_die(source: DamageSourceSignal, player: u16, killbox_kind: KillboxKind);
#[signal] #[signal]
pub fn on_take_damage(source: DamageSourceSignal, source_player: u16, damage: i32); pub fn on_take_damage(
source: DamageSourceSignal,
source_player: u16,
killbox_kind: KillboxKind,
damage: i32,
);
fn update_lock(&mut self) { fn update_lock(&mut self) {
self.run_deferred(|s| { self.run_deferred(|s| {

View File

@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
game_manager::{Game, GameOption}, game_manager::{Game, GameOption},
killbox::KillboxKind,
net::{network_manager::NetworkManager, util::NetVector3}, net::{network_manager::NetworkManager, util::NetVector3},
player::weapon::{BallWeapon, Weapon, WeaponType}, player::weapon::{BallWeapon, Weapon, WeaponType},
}; };
@ -162,21 +163,21 @@ impl<T: IPlayer + ICharacterBody3D + WithBaseField> PlayerCommon for T {
#[derive(Clone, Copy, Debug, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, Serialize, Deserialize)]
pub enum DamageSource { pub enum DamageSource {
Player(u16), Player(u16),
Killbox, Killbox(KillboxKind),
} }
impl DamageSource { impl DamageSource {
pub fn into_signal(&self) -> (DamageSourceSignal, u16) { pub fn into_signal(&self) -> (DamageSourceSignal, u16, KillboxKind) {
match self { match self {
DamageSource::Player(id) => (DamageSourceSignal::Player, *id), DamageSource::Player(id) => (DamageSourceSignal::Player, *id, KillboxKind::default()),
DamageSource::Killbox => (DamageSourceSignal::Killbox, 0), DamageSource::Killbox(kind) => (DamageSourceSignal::Killbox, 0, *kind),
} }
} }
pub fn from_signal(signal: DamageSourceSignal, player: u16) -> DamageSource { pub fn from_signal(signal: DamageSourceSignal, player: u16, kind: KillboxKind) -> DamageSource {
match signal { match signal {
DamageSourceSignal::Player => DamageSource::Player(player), DamageSourceSignal::Player => DamageSource::Player(player),
DamageSourceSignal::Killbox => DamageSource::Killbox, DamageSourceSignal::Killbox => DamageSource::Killbox(kind),
} }
} }
} }

View File

@ -9,6 +9,7 @@ use godot::{
use crate::{ use crate::{
game_manager::Game, game_manager::Game,
killbox::KillboxKind,
player::{ player::{
DamageSource, DamageSourceSignal, IPlayer, NetTransform, PlayerCommon, DamageSource, DamageSourceSignal, IPlayer, NetTransform, PlayerCommon,
effects::PlayerEffects, effects::PlayerEffects,
@ -144,8 +145,12 @@ impl IPlayer for RemotePlayer {
fn take_damage(&mut self, source: DamageSource, damage: i32, kill: bool) { fn take_damage(&mut self, source: DamageSource, damage: i32, kill: bool) {
self.run_deferred(move |s| { self.run_deferred(move |s| {
if s.can_take_damage(&source) { if s.can_take_damage(&source) {
let (signal, player) = source.into_signal(); let (signal, player, kind) = source.into_signal();
s.run_deferred(move |s| s.signals().on_take_damage().emit(signal, player, damage)); s.run_deferred(move |s| {
s.signals()
.on_take_damage()
.emit(signal, player, kind, damage)
});
s.health -= damage; s.health -= damage;
if kill && s.health <= 0 { if kill && s.health <= 0 {
s.kill(source); s.kill(source);
@ -169,8 +174,8 @@ impl IPlayer for RemotePlayer {
fn kill(&mut self, source: DamageSource) { fn kill(&mut self, source: DamageSource) {
self.drop_ball(false); self.drop_ball(false);
let (signal, player) = source.into_signal(); let (signal, player, kind) = source.into_signal();
self.run_deferred(move |s| s.signals().on_die().emit(signal, player)); self.run_deferred(move |s| s.signals().on_die().emit(signal, player, kind));
if let Some(mut mesh) = self.soldier_mesh.take() { if let Some(mut mesh) = self.soldier_mesh.take() {
mesh.queue_free(); mesh.queue_free();
} }
@ -272,9 +277,14 @@ impl ICharacterBody3D for RemotePlayer {
#[godot_api] #[godot_api]
impl RemotePlayer { impl RemotePlayer {
#[signal] #[signal]
pub fn on_die(source: DamageSourceSignal, player: u16); pub fn on_die(source: DamageSourceSignal, player: u16, killbox_kind: KillboxKind);
#[signal] #[signal]
pub fn on_take_damage(source: DamageSourceSignal, source_player: u16, damage: i32); pub fn on_take_damage(
source: DamageSourceSignal,
source_player: u16,
killbox_kind: KillboxKind,
damage: i32,
);
} }
#[godot_dyn] #[godot_dyn]