Don't forget about pets in PvP checks

This commit is contained in:
juliancoffee 2021-08-27 15:52:52 +03:00
parent 0dcfe2721b
commit 6b0d016418
8 changed files with 123 additions and 43 deletions

View File

@ -469,11 +469,10 @@ impl Attack {
}
}
/// Checks if we should allow negative effects from one player to another
// FIXME: handle pets?
// This code works only with players.
// You still can kill someone's pet and
// you still can be killed by someone's pet
/// Says if we should allow negative effects from one player to another
///
/// NOTE: this function doesn't handle pets or friendly-fire, you will need to
/// figure it out on call-side.
pub fn may_harm(attacker: Option<&Player>, target: Option<&Player>) -> bool {
attacker
.zip(target)

View File

@ -3,10 +3,10 @@ use crate::{
path::Chaser,
rtsim::RtSimController,
trade::{PendingTrade, ReducedInventory, SiteId, SitePrices, TradeId, TradeResult},
uid::Uid,
uid::{Uid, UidAllocator},
};
use serde::Deserialize;
use specs::{Component, Entity as EcsEntity};
use specs::{saveload::MarkerAllocator, Component, Entity as EcsEntity};
use specs_idvs::IdvStorage;
use std::{collections::VecDeque, fmt};
use strum::IntoEnumIterator;
@ -34,6 +34,15 @@ pub enum Alignment {
Passive,
}
// Helper function to get owner
pub fn owner_of(alignment: Option<Alignment>, uid_allocator: &UidAllocator) -> Option<EcsEntity> {
if let Some(Alignment::Owned(uid)) = alignment {
uid_allocator.retrieve_entity_internal(uid.into())
} else {
None
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Mark {
Merchant,

View File

@ -1,10 +1,11 @@
use common::{
combat,
comp::{
agent::owner_of,
aura::{AuraChange, AuraKey, AuraKind, AuraTarget},
buff::{Buff, BuffCategory, BuffChange, BuffSource},
group::Group,
Aura, Auras, BuffKind, Buffs, CharacterState, Health, Player, Pos,
Alignment, Aura, Auras, BuffKind, Buffs, CharacterState, Health, Player, Pos,
},
event::{Emitter, EventBus, ServerEvent},
resources::DeltaTime,
@ -27,6 +28,7 @@ pub struct ReadData<'a> {
cached_spatial_grid: Read<'a, common::CachedSpatialGrid>,
positions: ReadStorage<'a, Pos>,
char_states: ReadStorage<'a, CharacterState>,
alignments: ReadStorage<'a, Alignment>,
healths: ReadStorage<'a, Health>,
groups: ReadStorage<'a, Group>,
uids: ReadStorage<'a, Uid>,
@ -174,7 +176,7 @@ fn activate_aura(
// TODO: this check will disable friendly fire with PvE switch.
//
// Which means that you can't apply debuffs on you and your group
// even if it's intented mechanics.
// even if it's intented mechanic.
//
// Not that we have this for now, but think about this
// when we will add this.
@ -185,11 +187,19 @@ fn activate_aura(
},
_ => None,
};
owner.map_or(true, |attacker| {
let attacker = read_data.players.get(attacker);
let target = read_data.players.get(target);
combat::may_harm(attacker, target)
})
let owner_if_pet = |entity| {
// Return owner entity if pet,
// or just return entity back otherwise
owner_of(
read_data.alignments.get(entity).copied(),
&read_data.uid_allocator,
)
.unwrap_or(entity)
};
combat::may_harm(
owner.and_then(|owner| read_data.players.get(owner_if_pet(owner))),
read_data.players.get(owner_if_pet(target)),
)
};
conditions_held && (kind.is_buff() || may_harm())

View File

@ -1,9 +1,9 @@
use common::{
combat::{self, AttackOptions, AttackSource, AttackerInfo, TargetInfo},
comp::{
agent::{Sound, SoundKind},
Beam, BeamSegment, Body, CharacterState, Combo, Energy, Group, Health, HealthSource,
Inventory, Ori, Player, Pos, Scale, Stats,
agent::{owner_of, Sound, SoundKind},
Alignment, Beam, BeamSegment, Body, CharacterState, Combo, Energy, Group, Health,
HealthSource, Inventory, Ori, Player, Pos, Scale, Stats,
},
event::{EventBus, ServerEvent},
outcome::Outcome,
@ -36,6 +36,7 @@ pub struct ReadData<'a> {
uids: ReadStorage<'a, Uid>,
positions: ReadStorage<'a, Pos>,
orientations: ReadStorage<'a, Ori>,
alignments: ReadStorage<'a, Alignment>,
scales: ReadStorage<'a, Scale>,
bodies: ReadStorage<'a, Body>,
healths: ReadStorage<'a, Health>,
@ -214,9 +215,19 @@ impl<'a> System<'a> for Sys {
};
// PvP check
let owner_if_pet = |entity| {
// Return owner entity if pet,
// or just return entity back otherwise
owner_of(
read_data.alignments.get(entity).copied(),
&read_data.uid_allocator,
)
.unwrap_or(entity)
};
let may_harm = combat::may_harm(
beam_owner.and_then(|owner| read_data.players.get(owner)),
read_data.players.get(target),
beam_owner.and_then(|owner| read_data.players.get(owner_if_pet(owner))),
read_data.players.get(owner_if_pet(target)),
);
let attack_options = AttackOptions {
// No luck with dodging beams

View File

@ -1,14 +1,14 @@
use common::{
combat::{self, AttackOptions, AttackSource, AttackerInfo, TargetInfo},
comp::{
agent::{Sound, SoundKind},
Body, CharacterState, Combo, Energy, Group, Health, Inventory, Melee, Ori, Player, Pos,
Scale, Stats,
agent::{owner_of, Sound, SoundKind},
Alignment, Body, CharacterState, Combo, Energy, Group, Health, Inventory, Melee, Ori,
Player, Pos, Scale, Stats,
},
event::{EventBus, ServerEvent},
outcome::Outcome,
resources::Time,
uid::Uid,
uid::{Uid, UidAllocator},
util::Dir,
GroupTarget,
};
@ -21,11 +21,13 @@ use vek::*;
#[derive(SystemData)]
pub struct ReadData<'a> {
time: Read<'a, Time>,
uid_allocator: Read<'a, UidAllocator>,
entities: Entities<'a>,
players: ReadStorage<'a, Player>,
uids: ReadStorage<'a, Uid>,
positions: ReadStorage<'a, Pos>,
orientations: ReadStorage<'a, Ori>,
alignments: ReadStorage<'a, Alignment>,
scales: ReadStorage<'a, Scale>,
bodies: ReadStorage<'a, Body>,
healths: ReadStorage<'a, Health>,
@ -162,9 +164,19 @@ impl<'a> System<'a> for Sys {
char_state: read_data.char_states.get(target),
};
// PvP check
let owner_if_pet = |entity| {
// Return owner entity if pet,
// or just return entity back otherwise
owner_of(
read_data.alignments.get(entity).copied(),
&read_data.uid_allocator,
)
.unwrap_or(entity)
};
let may_harm = combat::may_harm(
read_data.players.get(attacker),
read_data.players.get(target),
read_data.players.get(owner_if_pet(attacker)),
read_data.players.get(owner_if_pet(target)),
);
let attack_options = AttackOptions {

View File

@ -1,9 +1,9 @@
use common::{
combat::{self, AttackOptions, AttackSource, AttackerInfo, TargetInfo},
comp::{
agent::{Sound, SoundKind},
projectile, Body, CharacterState, Combo, Energy, Group, Health, HealthSource, Inventory,
Ori, PhysicsState, Player, Pos, Projectile, Stats, Vel,
agent::{owner_of, Sound, SoundKind},
projectile, Alignment, Body, CharacterState, Combo, Energy, Group, Health, HealthSource,
Inventory, Ori, PhysicsState, Player, Pos, Projectile, Stats, Vel,
},
event::{Emitter, EventBus, ServerEvent},
outcome::Outcome,
@ -31,6 +31,7 @@ pub struct ReadData<'a> {
server_bus: Read<'a, EventBus<ServerEvent>>,
uids: ReadStorage<'a, Uid>,
positions: ReadStorage<'a, Pos>,
alignments: ReadStorage<'a, Alignment>,
physics_states: ReadStorage<'a, PhysicsState>,
velocities: ReadStorage<'a, Vel>,
inventories: ReadStorage<'a, Inventory>,
@ -299,9 +300,19 @@ fn dispatch_hit(
});
}
// PvP check
let owner_if_pet = |entity| {
// Return owner entity if pet,
// or just return entity back otherwise
owner_of(
read_data.alignments.get(entity).copied(),
&read_data.uid_allocator,
)
.unwrap_or(entity)
};
let may_harm = combat::may_harm(
owner.and_then(|owner| read_data.players.get(owner)),
read_data.players.get(target),
owner.and_then(|owner| read_data.players.get(owner_if_pet(owner))),
read_data.players.get(owner_if_pet(target)),
);
let attack_options = AttackOptions {

View File

@ -1,9 +1,9 @@
use common::{
combat::{self, AttackOptions, AttackSource, AttackerInfo, TargetInfo},
comp::{
agent::{Sound, SoundKind},
Body, CharacterState, Combo, Energy, Group, Health, HealthSource, Inventory, Ori,
PhysicsState, Player, Pos, Scale, Shockwave, ShockwaveHitEntities, Stats,
agent::{owner_of, Sound, SoundKind},
Alignment, Body, CharacterState, Combo, Energy, Group, Health, HealthSource, Inventory,
Ori, PhysicsState, Player, Pos, Scale, Shockwave, ShockwaveHitEntities, Stats,
},
event::{EventBus, ServerEvent},
outcome::Outcome,
@ -31,6 +31,7 @@ pub struct ReadData<'a> {
uids: ReadStorage<'a, Uid>,
positions: ReadStorage<'a, Pos>,
orientations: ReadStorage<'a, Ori>,
alignments: ReadStorage<'a, Alignment>,
scales: ReadStorage<'a, Scale>,
bodies: ReadStorage<'a, Body>,
healths: ReadStorage<'a, Health>,
@ -209,9 +210,20 @@ impl<'a> System<'a> for Sys {
char_state: read_data.character_states.get(target),
};
// PvP check
let owner_if_pet = |entity| {
// Return owner entity if pet,
// or just return entity back otherwise
owner_of(
read_data.alignments.get(entity).copied(),
&read_data.uid_allocator,
)
.unwrap_or(entity)
};
let may_harm = combat::may_harm(
shockwave_owner.and_then(|owner| read_data.players.get(owner)),
read_data.players.get(target),
shockwave_owner
.and_then(|owner| read_data.players.get(owner_if_pet(owner))),
read_data.players.get(owner_if_pet(target)),
);
let attack_options = AttackOptions {
// Trying roll during earthquake isn't the best idea

View File

@ -1,7 +1,7 @@
use crate::{
client::Client,
comp::{
agent::{Agent, AgentEvent, Sound, SoundKind},
agent::{owner_of, Agent, AgentEvent, Sound, SoundKind},
biped_large, bird_large, quadruped_low, quadruped_medium, quadruped_small,
skills::SkillGroupKind,
theropod, BuffKind, BuffSource, PhysicsState,
@ -873,6 +873,8 @@ pub fn handle_explosion(server: &Server, pos: Vec3<f32>, explosion: Explosion, o
let energies = &ecs.read_storage::<comp::Energy>();
let combos = &ecs.read_storage::<comp::Combo>();
let inventories = &ecs.read_storage::<comp::Inventory>();
let alignments = &ecs.read_storage::<Alignment>();
let uid_allocator = &ecs.read_resource::<UidAllocator>();
let players = &ecs.read_storage::<comp::Player>();
for (
entity_b,
@ -942,9 +944,16 @@ pub fn handle_explosion(server: &Server, pos: Vec3<f32>, explosion: Explosion, o
char_state: char_state_b_maybe,
};
// PvP check
let owner_if_pet = |entity| {
// Return owner entity if pet,
// or just return entity back otherwise
owner_of(alignments.get(entity).copied(), uid_allocator)
.unwrap_or(entity)
};
let may_harm = combat::may_harm(
owner_entity.and_then(|owner| players.get(owner)),
players.get(entity_b),
owner_entity.and_then(|owner| players.get(owner_if_pet(owner))),
players.get(owner_if_pet(entity_b)),
);
let attack_options = combat::AttackOptions {
// cool guyz maybe don't look at explosions
@ -968,6 +977,8 @@ pub fn handle_explosion(server: &Server, pos: Vec3<f32>, explosion: Explosion, o
}
},
RadiusEffect::Entity(mut effect) => {
let alignments = &ecs.read_storage::<Alignment>();
let uid_allocator = &ecs.read_resource::<UidAllocator>();
let players = &ecs.read_storage::<comp::Player>();
for (entity_b, pos_b, body_b_maybe) in (
&ecs.entities(),
@ -994,12 +1005,17 @@ pub fn handle_explosion(server: &Server, pos: Vec3<f32>, explosion: Explosion, o
// you want to harm yourself.
//
// This can be changed later.
// PvP check
let owner_if_pet = |entity| {
// Return owner entity if pet,
// or just return entity back otherwise
owner_of(alignments.get(entity).copied(), uid_allocator).unwrap_or(entity)
};
let may_harm = || {
owner_entity.map_or(false, |attacker| {
let attacker_player = players.get(attacker);
let target_player = players.get(entity_b);
combat::may_harm(attacker_player, target_player) || attacker == entity_b
})
combat::may_harm(
owner_entity.and_then(|owner| players.get(owner_if_pet(owner))),
players.get(owner_if_pet(entity_b)),
) || owner_entity.map_or(true, |entity_a| entity_a == entity_b)
};
if strength > 0.0 {
let is_alive = ecs