Fix loot protection bugs

This fixes:
- Giving loot protection to the entity to be destroyed instead of the
  one who killed it.
- Checking the destroyed entity for non-humanoid body instead of the
  entity receiving loot when deciding whether loot protection should be
  given or not.
- Incorrect assumption that NPC groups are tracked in the group
  manager when cleaning up loot protections.
This commit is contained in:
crabman 2024-04-20 09:09:28 +00:00
parent d5522b0401
commit 68c53a7d1c
No known key found for this signature in database
3 changed files with 17 additions and 7 deletions

View File

@ -532,3 +532,9 @@ impl GroupManager {
});
}
}
impl Group {
/// Returns whether this is one of the special npc or enemy groups
// FIXME: These groups are a HACK
pub fn is_special(&self) -> bool { *self == NPC || *self == ENEMY }
}

View File

@ -592,13 +592,11 @@ impl ServerEvent for DestroyEvent {
false
} else {
if let Some((_agent, uid, pos, alignment, vel, body)) = (
if let Some((_agent, pos, alignment, vel)) = (
&data.agents,
&data.uids,
&data.positions,
data.alignments.maybe(),
data.velocities.maybe(),
data.bodies.maybe(),
)
.lend_join()
.get(ev.entity, &data.entities)
@ -614,16 +612,16 @@ impl ServerEvent for DestroyEvent {
// Remove entries where zero exp was awarded - this happens because some
// entities like Object bodies don't give EXP.
let mut item_receivers = HashMap::new();
for (_entity, exp, group) in exp_awards {
for (entity, exp, group) in exp_awards {
if exp >= f32::EPSILON {
let loot_owner = if let Some(group) = group {
Some(LootOwnerKind::Group(group))
} else {
let uid = body.and_then(|body| {
let uid = data.bodies.get(entity).and_then(|body| {
// Only humanoids are awarded loot ownership - if the winner
// was a non-humanoid NPC the loot will be free-for-all
if matches!(body, Body::Humanoid(_)) {
Some(*uid)
data.uids.get(entity).copied()
} else {
None
}
@ -655,12 +653,14 @@ impl ServerEvent for DestroyEvent {
);
Some(LootOwner::new(loot_owner, false))
} else {
debug!("No loot owner");
None
},
})
};
if item_receivers.is_empty() {
debug!("No item receivers");
for item in flatten_counted_items(&items, &data.ability_map, &data.msm)
{
spawn_item(item, None)

View File

@ -35,7 +35,11 @@ impl<'a> System<'a> for Sys {
LootOwnerKind::Player(uid) => id_maps
.uid_entity(uid)
.map_or(true, |entity| !entities.is_alive(entity)),
LootOwnerKind::Group(group) => group_manager.group_info(group).is_none(),
LootOwnerKind::Group(group) => {
// Special alignment groups (NPC and ENEMY) aren't tracked by the group
// manager, check them separately here
!group.is_special() && group_manager.group_info(group).is_none()
},
}
})
.map(|(entity, _)| entity)