From f9835e78dae668ace254436a6af0cb3dde9d3587 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 23 Mar 2021 18:41:17 -0400 Subject: [PATCH] Pets no longer drop loot on death. Code to determine targeting of pets is less hacky and now takes into account alignment of their owner. --- .../unique/mindflayer/summonminions.ron | 2 +- common/src/states/basic_summon.rs | 8 +-- server/src/events/entity_manipulation.rs | 9 ++- server/src/sys/agent.rs | 69 +++++++++++-------- 4 files changed, 52 insertions(+), 36 deletions(-) diff --git a/assets/common/abilities/unique/mindflayer/summonminions.ron b/assets/common/abilities/unique/mindflayer/summonminions.ron index d41e6cb4de..625c635acc 100644 --- a/assets/common/abilities/unique/mindflayer/summonminions.ron +++ b/assets/common/abilities/unique/mindflayer/summonminions.ron @@ -8,7 +8,7 @@ BasicSummon( species: Darkhound, body_type: Male, )), - scale: None, + scale: Some((2.0)), health_scaling: 30, loadout_config: None, skillset_config: None, diff --git a/common/src/states/basic_summon.rs b/common/src/states/basic_summon.rs index 1a2217fab6..b46555b6ab 100644 --- a/common/src/states/basic_summon.rs +++ b/common/src/states/basic_summon.rs @@ -92,12 +92,6 @@ impl CharacterBehavior for Data { ) .build(); - let alignment = if matches!(data.alignment, Some(comp::Alignment::Enemy)) { - comp::Alignment::Enemy - } else { - comp::Alignment::Owned(*data.uid) - }; - update.server_events.push_front(ServerEvent::CreateNpc { pos: *data.pos, stats, @@ -109,7 +103,7 @@ impl CharacterBehavior for Data { loadout, body, agent: Some(comp::Agent::new(None, false, None, &body, true)), - alignment, + alignment: comp::Alignment::Owned(*data.uid), scale: self .static_data .summon_info diff --git a/server/src/events/entity_manipulation.rs b/server/src/events/entity_manipulation.rs index eb5ad2225e..527e0fa914 100644 --- a/server/src/events/entity_manipulation.rs +++ b/server/src/events/entity_manipulation.rs @@ -329,7 +329,14 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc .insert(entity, comp::CharacterState::default()); false - } else if state.ecs().read_storage::().contains(entity) { + } else if state.ecs().read_storage::().contains(entity) + && !matches!( + state.ecs().read_storage::().get(entity), + Some(comp::Alignment::Owned(_)) + ) + { + // Only drop loot if entity has agency (not a player), and if it is not owned by + // another entity (not a pet) use specs::Builder; // Decide for a loot drop before turning into a lootbag diff --git a/server/src/sys/agent.rs b/server/src/sys/agent.rs index d6176071eb..44a5aa1cce 100644 --- a/server/src/sys/agent.rs +++ b/server/src/sys/agent.rs @@ -1115,7 +1115,7 @@ impl<'a> AgentData<'a> { || e_pos.0.distance_squared(self.pos.0) < listen_dist.powi(2)) // TODO implement proper sound system for agents && e != self.entity && !e_health.is_dead - && (self.alignment.and_then(|a| e_alignment.map(|b| a.hostile_towards(*b))).unwrap_or(false) || ( + && (try_owner_alignment(self.alignment, &read_data).and_then(|a| try_owner_alignment(*e_alignment, &read_data).map(|b| a.hostile_towards(*b))).unwrap_or(false) || ( if let Some(rtsim_entity) = &self.rtsim_entity { if rtsim_entity.brain.remembers_fight_with_character(&e_stats.name) { agent.rtsim_controller.events.push( @@ -1302,7 +1302,7 @@ impl<'a> AgentData<'a> { // depending on the distance from the agent to the target match tactic { Tactic::Melee => { - if dist_sqrd < (min_attack_dist * self.scale).powi(2) { + if dist_sqrd < min_attack_dist.powi(2) { controller .actions .push(ControlAction::basic_input(InputKind::Primary)); @@ -1337,7 +1337,7 @@ impl<'a> AgentData<'a> { } }, Tactic::Axe => { - if dist_sqrd < (min_attack_dist * self.scale).powi(2) { + if dist_sqrd < min_attack_dist.powi(2) { controller.inputs.move_dir = Vec2::zero(); if agent.action_timer > 6.0 { controller @@ -1395,7 +1395,7 @@ impl<'a> AgentData<'a> { } }, Tactic::Hammer => { - if dist_sqrd < (min_attack_dist * self.scale).powi(2) { + if dist_sqrd < min_attack_dist.powi(2) { controller.inputs.move_dir = Vec2::zero(); if agent.action_timer > 4.0 { controller @@ -1471,7 +1471,7 @@ impl<'a> AgentData<'a> { } }, Tactic::Sword => { - if dist_sqrd < (min_attack_dist * self.scale).powi(2) { + if dist_sqrd < min_attack_dist.powi(2) { controller.inputs.move_dir = Vec2::zero(); if self .stats @@ -1535,7 +1535,7 @@ impl<'a> AgentData<'a> { }, Tactic::Bow => { if self.body.map(|b| b.is_humanoid()).unwrap_or(false) - && dist_sqrd < (2.0 * min_attack_dist * self.scale).powi(2) + && dist_sqrd < (2.0 * min_attack_dist).powi(2) { controller .actions @@ -1628,12 +1628,12 @@ impl<'a> AgentData<'a> { }, Tactic::Staff => { if self.body.map(|b| b.is_humanoid()).unwrap_or(false) - && dist_sqrd < (min_attack_dist * self.scale).powi(2) + && dist_sqrd < min_attack_dist.powi(2) { controller .actions .push(ControlAction::basic_input(InputKind::Roll)); - } else if dist_sqrd < (5.0 * min_attack_dist * self.scale).powi(2) { + } else if dist_sqrd < (5.0 * min_attack_dist).powi(2) { if agent.action_timer < 1.5 { controller.inputs.move_dir = (tgt_pos.0 - self.pos.0) .xy() @@ -1727,7 +1727,7 @@ impl<'a> AgentData<'a> { } }, Tactic::StoneGolemBoss => { - if dist_sqrd < (min_attack_dist * self.scale).powi(2) { + if dist_sqrd < min_attack_dist.powi(2) { // 2.0 is temporary correction factor to allow them to melee with their // large hitbox controller.inputs.move_dir = Vec2::zero(); @@ -1777,19 +1777,18 @@ impl<'a> AgentData<'a> { radius, circle_time, } => { - if dist_sqrd < (min_attack_dist * self.scale).powi(2) && thread_rng().gen_bool(0.5) - { + if dist_sqrd < min_attack_dist.powi(2) && thread_rng().gen_bool(0.5) { controller.inputs.move_dir = Vec2::zero(); controller .actions .push(ControlAction::basic_input(InputKind::Primary)); - } else if dist_sqrd < (radius as f32 * min_attack_dist * self.scale).powi(2) { + } else if dist_sqrd < (radius as f32 * min_attack_dist).powi(2) { controller.inputs.move_dir = (self.pos.0 - tgt_pos.0) .xy() .try_normalized() .unwrap_or_else(Vec2::unit_y); - } else if dist_sqrd < ((radius as f32 + 1.0) * min_attack_dist * self.scale).powi(2) - && dist_sqrd > (radius as f32 * min_attack_dist * self.scale).powi(2) + } else if dist_sqrd < ((radius as f32 + 1.0) * min_attack_dist).powi(2) + && dist_sqrd > (radius as f32 * min_attack_dist).powi(2) { if agent.action_timer < circle_time as f32 { controller.inputs.move_dir = (tgt_pos.0 - self.pos.0) @@ -1839,7 +1838,7 @@ impl<'a> AgentData<'a> { } }, Tactic::QuadLowRanged => { - if dist_sqrd < (3.0 * min_attack_dist * self.scale).powi(2) { + if dist_sqrd < (3.0 * min_attack_dist).powi(2) { controller.inputs.move_dir = (tgt_pos.0 - self.pos.0) .xy() .try_normalized() @@ -1897,7 +1896,7 @@ impl<'a> AgentData<'a> { } }, Tactic::TailSlap => { - if dist_sqrd < (1.5 * min_attack_dist * self.scale).powi(2) { + if dist_sqrd < (1.5 * min_attack_dist).powi(2) { if agent.action_timer > 4.0 { controller .actions @@ -1940,13 +1939,13 @@ impl<'a> AgentData<'a> { } }, Tactic::QuadLowQuick => { - if dist_sqrd < (1.5 * min_attack_dist * self.scale).powi(2) { + if dist_sqrd < (1.5 * min_attack_dist).powi(2) { controller.inputs.move_dir = Vec2::zero(); controller .actions .push(ControlAction::basic_input(InputKind::Secondary)); - } else if dist_sqrd < (3.0 * min_attack_dist * self.scale).powi(2) - && dist_sqrd > (2.0 * min_attack_dist * self.scale).powi(2) + } else if dist_sqrd < (3.0 * min_attack_dist).powi(2) + && dist_sqrd > (2.0 * min_attack_dist).powi(2) { controller .actions @@ -1977,7 +1976,7 @@ impl<'a> AgentData<'a> { } }, Tactic::QuadLowBasic => { - if dist_sqrd < (1.5 * min_attack_dist * self.scale).powi(2) { + if dist_sqrd < (1.5 * min_attack_dist).powi(2) { controller.inputs.move_dir = Vec2::zero(); if agent.action_timer > 5.0 { agent.action_timer = 0.0; @@ -2013,12 +2012,12 @@ impl<'a> AgentData<'a> { } }, Tactic::QuadMedJump => { - if dist_sqrd < (1.5 * min_attack_dist * self.scale).powi(2) { + if dist_sqrd < (1.5 * min_attack_dist).powi(2) { controller.inputs.move_dir = Vec2::zero(); controller .actions .push(ControlAction::basic_input(InputKind::Secondary)); - } else if dist_sqrd < (5.0 * min_attack_dist * self.scale).powi(2) { + } else if dist_sqrd < (5.0 * min_attack_dist).powi(2) { controller .actions .push(ControlAction::basic_input(InputKind::Ability(0))); @@ -2051,7 +2050,7 @@ impl<'a> AgentData<'a> { } }, Tactic::QuadMedBasic => { - if dist_sqrd < (min_attack_dist * self.scale).powi(2) { + if dist_sqrd < min_attack_dist.powi(2) { controller.inputs.move_dir = Vec2::zero(); if agent.action_timer < 2.0 { controller @@ -2087,12 +2086,12 @@ impl<'a> AgentData<'a> { } }, Tactic::Lavadrake | Tactic::QuadLowBeam => { - if dist_sqrd < (2.5 * min_attack_dist * self.scale).powi(2) { + if dist_sqrd < (2.5 * min_attack_dist).powi(2) { controller.inputs.move_dir = Vec2::zero(); controller .actions .push(ControlAction::basic_input(InputKind::Secondary)); - } else if dist_sqrd < (7.0 * min_attack_dist * self.scale).powi(2) { + } else if dist_sqrd < (7.0 * min_attack_dist).powi(2) { if agent.action_timer < 2.0 { controller.inputs.move_dir = (tgt_pos.0 - self.pos.0) .xy() @@ -2142,7 +2141,7 @@ impl<'a> AgentData<'a> { } }, Tactic::Theropod => { - if dist_sqrd < (2.0 * min_attack_dist * self.scale).powi(2) { + if dist_sqrd < (2.0 * min_attack_dist).powi(2) { controller.inputs.move_dir = Vec2::zero(); controller .actions @@ -2207,7 +2206,7 @@ impl<'a> AgentData<'a> { const MINDFLAYER_ATTACK_DIST: f32 = 15.0; let mindflayer_is_far = dist_sqrd > MINDFLAYER_ATTACK_DIST.powi(2); let health_fraction = self.health.map_or(0.5, |h| h.fraction()); - if mindflayer_is_far && agent.action_timer / health_fraction > 10.0 { + if mindflayer_is_far && agent.action_timer > 5.0 / health_fraction { // Summon minions if time has passed and no one is close for other attacks. Less // often when at low health. if !self.char_state.is_attack() { @@ -2296,3 +2295,19 @@ fn should_stop_attacking(health: Option<&Health>, buffs: Option<&Buffs>) -> bool health.map_or(true, |a| a.is_dead) || buffs.map_or(false, |b| b.kinds.contains_key(&BuffKind::Invulnerability)) } + +/// Attempts to get alignment of owner if entity has Owned alignment +fn try_owner_alignment<'a>( + alignment: Option<&'a Alignment>, + read_data: &'a ReadData, +) -> Option<&'a Alignment> { + if let Some(Alignment::Owned(owner_uid)) = alignment { + if let Some(owner) = read_data + .uid_allocator + .retrieve_entity_internal(owner_uid.id()) + { + return read_data.alignments.get(owner); + } + } + alignment +}