From ecf6a84b2fbe6bd8335849703ff22473399c9eb1 Mon Sep 17 00:00:00 2001 From: Imbris Date: Fri, 31 Jul 2020 00:30:17 -0400 Subject: [PATCH] Don't give exp when killing self or group members --- server/src/events/entity_manipulation.rs | 110 +++++++++++++---------- 1 file changed, 63 insertions(+), 47 deletions(-) diff --git a/server/src/events/entity_manipulation.rs b/server/src/events/entity_manipulation.rs index cdb3ee8ba0..b6900b70fd 100644 --- a/server/src/events/entity_manipulation.rs +++ b/server/src/events/entity_manipulation.rs @@ -55,56 +55,72 @@ pub fn handle_destroy(server: &mut Server, entity: EcsEntity, cause: HealthSourc state.notify_registered_clients(comp::ChatType::Kill.server_msg(msg)); } - { - // Give EXP to the killer if entity had stats + // Give EXP to the killer if entity had stats + (|| { let mut stats = state.ecs().write_storage::(); - if let Some(entity_stats) = stats.get(entity).cloned() { - if let HealthSource::Attack { by } | HealthSource::Projectile { owner: Some(by) } = - cause - { - const MAX_EXP_DIST: f32 = 150.0; - // Attacker gets same as exp of everyone else - const ATTACKER_EXP_WEIGHT: f32 = 1.0; - let mut exp_reward = (entity_stats.body_type.base_exp() - + entity_stats.level.level() * entity_stats.body_type.base_exp_increase()) - as f32; - state.ecs().entity_from_uid(by.into()).map(|attacker| { - // Distribute EXP to group - let groups = state.ecs().read_storage::(); - let positions = state.ecs().read_storage::(); - // TODO: rework if change to groups makes it easier to iterate entities in a - // group - if let (Some(attacker_group), Some(pos)) = - (groups.get(attacker), positions.get(entity)) - { - let members_in_range = (&state.ecs().entities(), &groups, &positions) - .join() - .filter(|(entity, group, member_pos)| { - *group == attacker_group - && *entity != attacker - && pos.0.distance_squared(member_pos.0) < MAX_EXP_DIST.powi(2) - }) - .map(|(entity, _, _)| entity) - .collect::>(); - let exp = - exp_reward / (members_in_range.len() as f32 + ATTACKER_EXP_WEIGHT); - exp_reward = exp * ATTACKER_EXP_WEIGHT; - members_in_range.into_iter().for_each(|e| { - if let Some(stats) = stats.get_mut(e) { - stats.exp.change_by(exp.ceil() as i64); - } - }); - } + let by = if let HealthSource::Attack { by } | HealthSource::Projectile { owner: Some(by) } = + cause + { + by + } else { + return; + }; + let attacker = if let Some(attacker) = state.ecs().entity_from_uid(by.into()) { + attacker + } else { + return; + }; + let entity_stats = if let Some(entity_stats) = stats.get(entity) { + entity_stats + } else { + return; + }; - if let Some(attacker_stats) = stats.get_mut(attacker) { - // TODO: Discuss whether we should give EXP by Player - // Killing or not. - attacker_stats.exp.change_by(exp_reward.ceil() as i64); - } - }); - } + let groups = state.ecs().read_storage::(); + let attacker_group = groups.get(attacker); + let destroyed_group = groups.get(entity); + // Don't give exp if attacker destroyed themselves or one of their group members + if (attacker_group.is_some() && attacker_group == destroyed_group) || attacker == entity { + return; } - } + + // Maximum distance for other group members to receive exp + const MAX_EXP_DIST: f32 = 150.0; + // Attacker gets same as exp of everyone else + const ATTACKER_EXP_WEIGHT: f32 = 1.0; + let mut exp_reward = (entity_stats.body_type.base_exp() + + entity_stats.level.level() * entity_stats.body_type.base_exp_increase()) + as f32; + + // Distribute EXP to group + let positions = state.ecs().read_storage::(); + if let (Some(attacker_group), Some(pos)) = (attacker_group, positions.get(entity)) { + // TODO: rework if change to groups makes it easier to iterate entities in a + // group + let members_in_range = (&state.ecs().entities(), &groups, &positions) + .join() + .filter(|(entity, group, member_pos)| { + *group == attacker_group + && *entity != attacker + && pos.0.distance_squared(member_pos.0) < MAX_EXP_DIST.powi(2) + }) + .map(|(entity, _, _)| entity) + .collect::>(); + let exp = exp_reward / (members_in_range.len() as f32 + ATTACKER_EXP_WEIGHT); + exp_reward = exp * ATTACKER_EXP_WEIGHT; + members_in_range.into_iter().for_each(|e| { + if let Some(stats) = stats.get_mut(e) { + stats.exp.change_by(exp.ceil() as i64); + } + }); + } + + if let Some(attacker_stats) = stats.get_mut(attacker) { + // TODO: Discuss whether we should give EXP by Player + // Killing or not. + attacker_stats.exp.change_by(exp_reward.ceil() as i64); + } + })(); if state .ecs()