diff --git a/CHANGELOG.md b/CHANGELOG.md index 34948ffa28..d0b2e082d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -103,6 +103,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Animal Trainers now spawn in tier-5 dungeon and not in tier-3 - Reworked clay golem to have unique attacks. - Merchants now use `/tell` instead of `/say` to communicate prices +- Entities catch on fire if they stand too close to campfires +- Water extinguishes entities on fire ### Removed diff --git a/common/systems/src/buff.rs b/common/systems/src/buff.rs index 33595ab6b5..af1347d037 100644 --- a/common/systems/src/buff.rs +++ b/common/systems/src/buff.rs @@ -1,7 +1,8 @@ use common::{ comp::{ - Buff, BuffCategory, BuffChange, BuffEffect, BuffId, BuffSource, Buffs, Energy, Health, - HealthChange, HealthSource, Inventory, ModifierKind, Stats, + fluid_dynamics::Fluid, Buff, BuffCategory, BuffChange, BuffEffect, BuffId, BuffKind, + BuffSource, Buffs, Energy, Health, HealthChange, HealthSource, Inventory, ModifierKind, + PhysicsState, Stats, }, event::{EventBus, ServerEvent}, resources::DeltaTime, @@ -20,6 +21,7 @@ pub struct ReadData<'a> { server_bus: Read<'a, EventBus>, inventories: ReadStorage<'a, Inventory>, healths: ReadStorage<'a, Health>, + physics_states: ReadStorage<'a, PhysicsState>, } #[derive(Default)] @@ -61,18 +63,28 @@ impl<'a> System<'a> for Sys { // duration of strongest buff of that kind, else it ticks durations of all buffs // of that kind. Any buffs whose durations expire are marked expired. for (kind, ids) in buff_comp_kinds.iter() { + // Only get the physics state component if the entity has the burning buff, as + // we don't need it for any other conditions yet + let in_fluid = if matches!(kind, BuffKind::Burning) { + read_data + .physics_states + .get(entity) + .and_then(|p| p.in_fluid) + } else { + None + }; if kind.queues() { if let Some((Some(buff), id)) = ids.get(0).map(|id| (buff_comp_buffs.get_mut(id), id)) { - tick_buff(*id, buff, dt, |id| expired_buffs.push(id)); + tick_buff(*id, buff, dt, in_fluid, |id| expired_buffs.push(id)); } } else { for (id, buff) in buff_comp_buffs .iter_mut() .filter(|(i, _)| ids.iter().any(|id| id == *i)) { - tick_buff(*id, buff, dt, |id| expired_buffs.push(id)); + tick_buff(*id, buff, dt, in_fluid, |id| expired_buffs.push(id)); } } } @@ -227,7 +239,13 @@ impl<'a> System<'a> for Sys { } } -fn tick_buff(id: u64, buff: &mut Buff, dt: f32, mut expire_buff: impl FnMut(u64)) { +fn tick_buff( + id: u64, + buff: &mut Buff, + dt: f32, + in_fluid: Option, + mut expire_buff: impl FnMut(u64), +) { // If a buff is recently applied from an aura, do not tick duration if buff .cat_ids @@ -237,6 +255,11 @@ fn tick_buff(id: u64, buff: &mut Buff, dt: f32, mut expire_buff: impl FnMut(u64) return; } if let Some(remaining_time) = &mut buff.time { + // Extinguish Burning buff when in water + if matches!(buff.kind, BuffKind::Burning) && matches!(in_fluid, Some(Fluid::Water { .. })) { + *remaining_time = Duration::default(); + } + if let Some(new_duration) = remaining_time.checked_sub(Duration::from_secs_f32(dt)) { // The buff still continues. *remaining_time = new_duration; diff --git a/server/src/cmd.rs b/server/src/cmd.rs index c615dfdcf7..c5bf6f059f 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -1191,17 +1191,30 @@ fn handle_spawn_campfire( animated: true, }) .with(WaypointArea::default()) - .with(comp::Auras::new(vec![Aura::new( - AuraKind::Buff { - kind: BuffKind::CampfireHeal, - data: BuffData::new(0.02, Some(Duration::from_secs(1))), - category: BuffCategory::Natural, - source: BuffSource::World, - }, - 5.0, - None, - AuraTarget::All, - )])) + .with(comp::Auras::new(vec![ + Aura::new( + AuraKind::Buff { + kind: BuffKind::CampfireHeal, + data: BuffData::new(0.02, Some(Duration::from_secs(1))), + category: BuffCategory::Natural, + source: BuffSource::World, + }, + 5.0, + None, + AuraTarget::All, + ), + Aura::new( + AuraKind::Buff { + kind: BuffKind::Burning, + data: BuffData::new(20.0, Some(Duration::from_secs(10))), + category: BuffCategory::Natural, + source: BuffSource::World, + }, + 0.7, + None, + AuraTarget::All, + ), + ])) .build(); server.notify_client( diff --git a/server/src/events/entity_creation.rs b/server/src/events/entity_creation.rs index a1f284049a..1a59e6096c 100644 --- a/server/src/events/entity_creation.rs +++ b/server/src/events/entity_creation.rs @@ -242,16 +242,29 @@ pub fn handle_create_waypoint(server: &mut Server, pos: Vec3) { }) .with(WaypointArea::default()) .with(comp::Mass(10_f32.powi(10))) - .with(comp::Auras::new(vec![Aura::new( - AuraKind::Buff { - kind: BuffKind::CampfireHeal, - data: BuffData::new(0.02, Some(Duration::from_secs(1))), - category: BuffCategory::Natural, - source: BuffSource::World, - }, - 5.0, - None, - AuraTarget::All, - )])) + .with(comp::Auras::new(vec![ + Aura::new( + AuraKind::Buff { + kind: BuffKind::CampfireHeal, + data: BuffData::new(0.02, Some(Duration::from_secs(1))), + category: BuffCategory::Natural, + source: BuffSource::World, + }, + 5.0, + None, + AuraTarget::All, + ), + Aura::new( + AuraKind::Buff { + kind: BuffKind::Burning, + data: BuffData::new(20.0, Some(Duration::from_secs(10))), + category: BuffCategory::Natural, + source: BuffSource::World, + }, + 0.7, + None, + AuraTarget::All, + ), + ])) .build(); }