Prevented pet damage

This commit is contained in:
Joshua Barretto 2020-07-07 01:01:39 +01:00
parent f77d2f06c6
commit e626f6255f
14 changed files with 111 additions and 50 deletions

View File

@ -1,9 +1,9 @@
use crate::path::Chaser;
use specs::{Component, Entity as EcsEntity};
use crate::{path::Chaser, sync::Uid};
use specs::{Component, Entity as EcsEntity, FlaggedStorage};
use specs_idvs::IdvStorage;
use vek::*;
#[derive(Copy, Clone, Debug, PartialEq)]
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
pub enum Alignment {
/// Wild animals and gentle giants
Wild,
@ -14,7 +14,7 @@ pub enum Alignment {
/// Farm animals and pets of villagers
Tame,
/// Pets you've tamed with a collar
Owned(EcsEntity),
Owned(Uid),
}
impl Alignment {
@ -51,7 +51,7 @@ impl Alignment {
}
impl Component for Alignment {
type Storage = IdvStorage<Self>;
type Storage = FlaggedStorage<Self, IdvStorage<Self>>;
}
#[derive(Clone, Debug, Default)]

View File

@ -7,7 +7,8 @@
bool_to_option,
label_break_value,
trait_alias,
type_alias_impl_trait
type_alias_impl_trait,
option_zip,
)]
#[macro_use] extern crate serde_derive;

View File

@ -17,6 +17,7 @@ sum_type! {
LightEmitter(comp::LightEmitter),
Item(comp::Item),
Scale(comp::Scale),
Alignment(comp::Alignment),
MountState(comp::MountState),
Mounting(comp::Mounting),
Mass(comp::Mass),
@ -43,6 +44,7 @@ sum_type! {
LightEmitter(PhantomData<comp::LightEmitter>),
Item(PhantomData<comp::Item>),
Scale(PhantomData<comp::Scale>),
Alignment(PhantomData<comp::Alignment>),
MountState(PhantomData<comp::MountState>),
Mounting(PhantomData<comp::Mounting>),
Mass(PhantomData<comp::Mass>),
@ -69,6 +71,7 @@ impl sync::CompPacket for EcsCompPacket {
EcsCompPacket::LightEmitter(comp) => sync::handle_insert(comp, entity, world),
EcsCompPacket::Item(comp) => sync::handle_insert(comp, entity, world),
EcsCompPacket::Scale(comp) => sync::handle_insert(comp, entity, world),
EcsCompPacket::Alignment(comp) => sync::handle_insert(comp, entity, world),
EcsCompPacket::MountState(comp) => sync::handle_insert(comp, entity, world),
EcsCompPacket::Mounting(comp) => sync::handle_insert(comp, entity, world),
EcsCompPacket::Mass(comp) => sync::handle_insert(comp, entity, world),
@ -93,6 +96,7 @@ impl sync::CompPacket for EcsCompPacket {
EcsCompPacket::LightEmitter(comp) => sync::handle_modify(comp, entity, world),
EcsCompPacket::Item(comp) => sync::handle_modify(comp, entity, world),
EcsCompPacket::Scale(comp) => sync::handle_modify(comp, entity, world),
EcsCompPacket::Alignment(comp) => sync::handle_modify(comp, entity, world),
EcsCompPacket::MountState(comp) => sync::handle_modify(comp, entity, world),
EcsCompPacket::Mounting(comp) => sync::handle_modify(comp, entity, world),
EcsCompPacket::Mass(comp) => sync::handle_modify(comp, entity, world),
@ -119,6 +123,7 @@ impl sync::CompPacket for EcsCompPacket {
},
EcsCompPhantom::Item(_) => sync::handle_remove::<comp::Item>(entity, world),
EcsCompPhantom::Scale(_) => sync::handle_remove::<comp::Scale>(entity, world),
EcsCompPhantom::Alignment(_) => sync::handle_remove::<comp::Alignment>(entity, world),
EcsCompPhantom::MountState(_) => sync::handle_remove::<comp::MountState>(entity, world),
EcsCompPhantom::Mounting(_) => sync::handle_remove::<comp::Mounting>(entity, world),
EcsCompPhantom::Mass(_) => sync::handle_remove::<comp::Mass>(entity, world),

View File

@ -123,6 +123,7 @@ impl State {
ecs.register::<comp::Gravity>();
ecs.register::<comp::CharacterState>();
ecs.register::<comp::Object>();
ecs.register::<comp::Alignment>();
// Register components send from clients -> server
ecs.register::<comp::Controller>();
@ -146,7 +147,6 @@ impl State {
ecs.register::<comp::Last<comp::Vel>>();
ecs.register::<comp::Last<comp::Ori>>();
ecs.register::<comp::Agent>();
ecs.register::<comp::Alignment>();
ecs.register::<comp::WaypointArea>();
ecs.register::<comp::ForceUpdate>();
ecs.register::<comp::InventoryUpdate>();

View File

@ -31,11 +31,13 @@ impl CharacterBehavior for Data {
handle_move(data, &mut update, 0.3);
handle_jump(data, &mut update);
if !self.exhausted && if self.holdable {
data.inputs.holding_ability_key() || self.prepare_timer < self.prepare_duration
} else {
self.prepare_timer < self.prepare_duration
} {
if !self.exhausted
&& if self.holdable {
data.inputs.holding_ability_key() || self.prepare_timer < self.prepare_duration
} else {
self.prepare_timer < self.prepare_duration
}
{
// Prepare (draw the bow)
update.character = CharacterState::BasicRanged(Data {
prepare_timer: self.prepare_timer + Duration::from_secs_f32(data.dt.0),

View File

@ -45,6 +45,24 @@ impl Body {
Body::QuadrupedLow(_) => 120.0,
}
}
pub fn base_ori_rate(&self) -> f32 {
match self {
Body::Humanoid(_) => 20.0,
Body::QuadrupedSmall(_) => 15.0,
Body::QuadrupedMedium(_) => 10.0,
Body::BirdMedium(_) => 30.0,
Body::FishMedium(_) => 5.0,
Body::Dragon(_) => 5.0,
Body::BirdSmall(_) => 35.0,
Body::FishSmall(_) => 10.0,
Body::BipedLarge(_) => 12.0,
Body::Object(_) => 5.0,
Body::Golem(_) => 8.0,
Body::Critter(_) => 35.0,
Body::QuadrupedLow(_) => 12.0,
}
}
}
/// Handles updating `Components` to move player based on state of `JoinData`
@ -68,10 +86,10 @@ fn basic_move(data: &JoinData, update: &mut StateUpdate, efficiency: f32) {
update.vel.0 =
update.vel.0 + Vec2::broadcast(data.dt.0) * data.inputs.move_dir * accel * efficiency;
handle_orientation(data, update, 20.0);
handle_orientation(data, update, data.body.base_ori_rate());
}
pub fn handle_orientation(data: &JoinData, update: &mut StateUpdate, strength: f32) {
pub fn handle_orientation(data: &JoinData, update: &mut StateUpdate, rate: f32) {
// Set direction based on move direction
let ori_dir = if update.character.is_attack() || update.character.is_block() {
data.inputs.look_dir.xy()
@ -82,7 +100,7 @@ pub fn handle_orientation(data: &JoinData, update: &mut StateUpdate, strength: f
};
// Smooth orientation
update.ori.0 = Dir::slerp_to_vec3(update.ori.0, ori_dir.into(), strength * data.dt.0);
update.ori.0 = Dir::slerp_to_vec3(update.ori.0, ori_dir.into(), rate * data.dt.0);
}
/// Updates components to move player as if theyre swimming

View File

@ -245,7 +245,11 @@ impl<'a> System<'a> for Sys {
alignments
.get(*target)
.copied()
.unwrap_or(Alignment::Owned(*target)),
.unwrap_or(uids
.get(*target)
.copied()
.map(Alignment::Owned)
.unwrap_or(Alignment::Wild)),
) {
if let Some(dir) = Dir::from_unnormalized(tgt_pos.0 - pos.0) {
inputs.look_dir = dir;
@ -419,7 +423,10 @@ impl<'a> System<'a> for Sys {
// Follow owner if we're too far, or if they're under attack
if let Some(Alignment::Owned(owner)) = alignment.copied() {
if let Some(owner_pos) = positions.get(owner) {
(|| {
let owner = uid_allocator.retrieve_entity_internal(owner.id())?;
let owner_pos = positions.get(owner)?;
let dist_sqrd = pos.0.distance_squared(owner_pos.0);
if dist_sqrd > MAX_FOLLOW_DIST.powf(2.0) && !agent.activity.is_follow() {
agent.activity = Activity::Follow {
@ -429,28 +436,27 @@ impl<'a> System<'a> for Sys {
}
// Attack owner's attacker
if let Some(owner_stats) = stats.get(owner) {
if owner_stats.health.last_change.0 < 5.0 {
if let comp::HealthSource::Attack { by } =
owner_stats.health.last_change.1.cause
{
if !agent.activity.is_attack() {
if let Some(attacker) =
uid_allocator.retrieve_entity_internal(by.id())
{
agent.activity = Activity::Attack {
target: attacker,
chaser: Chaser::default(),
time: time.0,
been_close: false,
powerup: 0.0,
};
}
}
let owner_stats = stats.get(owner)?;
if owner_stats.health.last_change.0 < 5.0 {
if let comp::HealthSource::Attack { by } =
owner_stats.health.last_change.1.cause
{
if !agent.activity.is_attack() {
let attacker = uid_allocator.retrieve_entity_internal(by.id())?;
agent.activity = Activity::Attack {
target: attacker,
chaser: Chaser::default(),
time: time.0,
been_close: false,
powerup: 0.0,
};
}
}
}
}
Some(())
})();
}
debug_assert!(inputs.move_dir.map(|e| !e.is_nan()).reduce_and());

View File

@ -119,12 +119,15 @@ impl<'a> System<'a> for Sys {
// healthchange = (healthchange / 1.5).min(-1.0);
//}
// TODO: remove this when there is a better way to target healing
// Don't heal npc's hp
if alignment_b_maybe
// TODO: remove this when there is a better way to deal with alignment
// Don't heal NPCs
if (healthchange > 0.0 && alignment_b_maybe
.map(|a| !a.is_friendly_to_players())
.unwrap_or(true)
&& healthchange > 0.0
.unwrap_or(true))
// Don't hurt pets
|| (healthchange < 0.0 && alignment_b_maybe
.map(|b| Alignment::Owned(*uid).passive_towards(*b))
.unwrap_or(false))
{
healthchange = 0.0;
}

View File

@ -1,6 +1,7 @@
use crate::{
comp::{
projectile, Energy, EnergySource, HealthSource, Ori, PhysicsState, Pos, Projectile, Vel,
Alignment,
},
event::{EventBus, LocalEvent, ServerEvent},
state::DeltaTime,
@ -27,6 +28,7 @@ impl<'a> System<'a> for Sys {
WriteStorage<'a, Ori>,
WriteStorage<'a, Projectile>,
WriteStorage<'a, Energy>,
ReadStorage<'a, Alignment>,
);
fn run(
@ -43,6 +45,7 @@ impl<'a> System<'a> for Sys {
mut orientations,
mut projectiles,
mut energies,
alignments,
): Self::SystemData,
) {
let mut local_emitter = local_bus.emitter();
@ -82,7 +85,17 @@ impl<'a> System<'a> for Sys {
for effect in projectile.hit_entity.drain(..) {
match effect {
projectile::Effect::Damage(change) => {
if other != projectile.owner.unwrap() {
let owner_uid = projectile.owner.unwrap();
// Hacky: remove this when groups get implemented
let passive = uid_allocator
.retrieve_entity_internal(other.into())
.and_then(|other|
alignments
.get(other)
.map(|a| Alignment::Owned(owner_uid)
.passive_towards(*a)))
.unwrap_or(false);
if other != projectile.owner.unwrap() && !passive {
server_emitter.emit(ServerEvent::Damage { uid: other, change });
}
},

View File

@ -507,7 +507,8 @@ fn handle_spawn(
String
) {
(Some(opt_align), Some(npc::NpcBody(id, mut body)), opt_amount, opt_ai) => {
if let Some(alignment) = parse_alignment(target, &opt_align) {
let uid = server.state.read_component_cloned(target).expect("Expected player to have a UID");
if let Some(alignment) = parse_alignment(uid, &opt_align) {
let amount = opt_amount
.and_then(|a| a.parse().ok())
.filter(|x| *x > 0)
@ -715,7 +716,7 @@ fn handle_help(
}
}
fn parse_alignment(owner: EcsEntity, alignment: &str) -> Option<comp::Alignment> {
fn parse_alignment(owner: Uid, alignment: &str) -> Option<comp::Alignment> {
match alignment {
"wild" => Some(comp::Alignment::Wild),
"enemy" => Some(comp::Alignment::Enemy),

View File

@ -188,13 +188,15 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
let reinsert = if let Some(pos) =
state.read_storage::<comp::Pos>().get(entity)
{
let uid = state.read_component_cloned(entity)
.expect("Expected player to have a UID");
if (
&state.read_storage::<comp::Alignment>(),
&state.read_storage::<comp::Agent>(),
)
.join()
.filter(|(alignment, _)| {
alignment == &&comp::Alignment::Owned(entity)
alignment == &&comp::Alignment::Owned(uid)
})
.count()
>= 3
@ -222,7 +224,7 @@ pub fn handle_inventory(server: &mut Server, entity: EcsEntity, manip: comp::Inv
} {
let _ = state.ecs().write_storage().insert(
tameable_entity,
comp::Alignment::Owned(entity),
comp::Alignment::Owned(uid),
);
let _ = state
.ecs()

View File

@ -171,7 +171,7 @@ impl StateExt for State {
});
self.write_component(entity, comp::Gravity(1.0));
self.write_component(entity, comp::CharacterState::default());
self.write_component(entity, comp::Alignment::Owned(entity));
self.write_component(entity, comp::Alignment::Owned(self.read_component_cloned(entity).unwrap()));
// Set the character id for the player
// TODO this results in a warning in the console: "Error modifying synced

View File

@ -2,7 +2,7 @@ use super::SysTimer;
use common::{
comp::{
Body, CanBuild, CharacterState, Collider, Energy, Gravity, Item, LightEmitter, Loadout,
Mass, MountState, Mounting, Ori, Player, Pos, Scale, Stats, Sticky, Vel,
Mass, MountState, Mounting, Ori, Player, Pos, Scale, Stats, Sticky, Vel, Alignment,
},
msg::EcsCompPacket,
sync::{CompSyncPackage, EntityPackage, EntitySyncPackage, Uid, UpdateTracker, WorldSyncExt},
@ -48,6 +48,7 @@ pub struct TrackedComps<'a> {
pub scale: ReadStorage<'a, Scale>,
pub mounting: ReadStorage<'a, Mounting>,
pub mount_state: ReadStorage<'a, MountState>,
pub alignment: ReadStorage<'a, Alignment>,
pub mass: ReadStorage<'a, Mass>,
pub collider: ReadStorage<'a, Collider>,
pub sticky: ReadStorage<'a, Sticky>,
@ -104,6 +105,10 @@ impl<'a> TrackedComps<'a> {
.get(entity)
.cloned()
.map(|c| comps.push(c.into()));
self.alignment
.get(entity)
.cloned()
.map(|c| comps.push(c.into()));
self.mass.get(entity).copied().map(|c| comps.push(c.into()));
self.collider
.get(entity)
@ -146,6 +151,7 @@ pub struct ReadTrackers<'a> {
pub scale: ReadExpect<'a, UpdateTracker<Scale>>,
pub mounting: ReadExpect<'a, UpdateTracker<Mounting>>,
pub mount_state: ReadExpect<'a, UpdateTracker<MountState>>,
pub alignment: ReadExpect<'a, UpdateTracker<Alignment>>,
pub mass: ReadExpect<'a, UpdateTracker<Mass>>,
pub collider: ReadExpect<'a, UpdateTracker<Collider>>,
pub sticky: ReadExpect<'a, UpdateTracker<Sticky>>,
@ -178,6 +184,7 @@ impl<'a> ReadTrackers<'a> {
.with_component(&comps.uid, &*self.scale, &comps.scale, filter)
.with_component(&comps.uid, &*self.mounting, &comps.mounting, filter)
.with_component(&comps.uid, &*self.mount_state, &comps.mount_state, filter)
.with_component(&comps.uid, &*self.alignment, &comps.alignment, filter)
.with_component(&comps.uid, &*self.mass, &comps.mass, filter)
.with_component(&comps.uid, &*self.collider, &comps.collider, filter)
.with_component(&comps.uid, &*self.sticky, &comps.sticky, filter)
@ -207,6 +214,7 @@ pub struct WriteTrackers<'a> {
scale: WriteExpect<'a, UpdateTracker<Scale>>,
mounting: WriteExpect<'a, UpdateTracker<Mounting>>,
mount_state: WriteExpect<'a, UpdateTracker<MountState>>,
alignment: WriteExpect<'a, UpdateTracker<Alignment>>,
mass: WriteExpect<'a, UpdateTracker<Mass>>,
collider: WriteExpect<'a, UpdateTracker<Collider>>,
sticky: WriteExpect<'a, UpdateTracker<Sticky>>,
@ -228,6 +236,7 @@ fn record_changes(comps: &TrackedComps, trackers: &mut WriteTrackers) {
trackers.scale.record_changes(&comps.scale);
trackers.mounting.record_changes(&comps.mounting);
trackers.mount_state.record_changes(&comps.mount_state);
trackers.alignment.record_changes(&comps.alignment);
trackers.mass.record_changes(&comps.mass);
trackers.collider.record_changes(&comps.collider);
trackers.sticky.record_changes(&comps.sticky);
@ -282,6 +291,7 @@ pub fn register_trackers(world: &mut World) {
world.register_tracker::<Scale>();
world.register_tracker::<Mounting>();
world.register_tracker::<MountState>();
world.register_tracker::<Alignment>();
world.register_tracker::<Mass>();
world.register_tracker::<Collider>();
world.register_tracker::<Sticky>();

View File

@ -57,9 +57,9 @@ impl SessionState {
.set_fov_deg(global_state.settings.graphics.fov);
let hud = Hud::new(global_state, &client.borrow());
{
let my_entity = client.borrow().entity();
let mut client = client.borrow_mut();
let my_entity = client.entity();
client
.borrow_mut()
.state_mut()
.ecs_mut()
.insert(MyEntity(my_entity));