mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Refactor projectile system
This commit is contained in:
parent
497a94cd7a
commit
1efc3188ef
@ -5,7 +5,7 @@ use common::{
|
||||
projectile, Body, CharacterState, Combo, Energy, Group, Health, HealthSource, Inventory,
|
||||
Ori, PhysicsState, Player, Pos, Projectile, Stats, Vel,
|
||||
},
|
||||
event::{EventBus, ServerEvent},
|
||||
event::{Emitter, EventBus, ServerEvent},
|
||||
outcome::Outcome,
|
||||
resources::{DeltaTime, Time},
|
||||
uid::{Uid, UidAllocator},
|
||||
@ -15,8 +15,8 @@ use common::{
|
||||
use common_ecs::{Job, Origin, Phase, System};
|
||||
use rand::{thread_rng, Rng};
|
||||
use specs::{
|
||||
saveload::MarkerAllocator, shred::ResourceId, Entities, Join, Read, ReadStorage, SystemData,
|
||||
World, Write, WriteStorage,
|
||||
saveload::MarkerAllocator, shred::ResourceId, Entities, Entity as EcsEntity, Join, Read,
|
||||
ReadStorage, SystemData, World, Write, WriteStorage,
|
||||
};
|
||||
use std::time::Duration;
|
||||
use vek::*;
|
||||
@ -115,106 +115,36 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
|
||||
let projectile = &mut *projectile;
|
||||
// FIXME: this code is highway to hell, resolve this
|
||||
|
||||
let entity_of =
|
||||
|uid: Uid| read_data.uid_allocator.retrieve_entity_internal(uid.into());
|
||||
for effect in projectile.hit_entity.drain(..) {
|
||||
match effect {
|
||||
projectile::Effect::Attack(attack) => {
|
||||
if let Some(target) = read_data
|
||||
.uid_allocator
|
||||
.retrieve_entity_internal(other.into())
|
||||
{
|
||||
if let (Some(pos), Some(ori)) =
|
||||
(read_data.positions.get(target), orientations.get(entity))
|
||||
{
|
||||
let dir = ori.look_dir();
|
||||
let owner = projectile.owner.and_then(entity_of);
|
||||
let projectile_info = ProjectileInfo {
|
||||
entity,
|
||||
effect,
|
||||
owner_uid: projectile.owner,
|
||||
owner,
|
||||
ori: orientations.get(entity),
|
||||
pos,
|
||||
};
|
||||
|
||||
let owner_entity = projectile.owner.and_then(|u| {
|
||||
read_data.uid_allocator.retrieve_entity_internal(u.into())
|
||||
});
|
||||
let target = entity_of(other);
|
||||
let projectile_target_info = ProjectileTargetInfo {
|
||||
uid: other,
|
||||
entity: target,
|
||||
target_group,
|
||||
ori: target.and_then(|target| orientations.get(target)),
|
||||
};
|
||||
|
||||
let attacker_info =
|
||||
owner_entity.zip(projectile.owner).map(|(entity, uid)| {
|
||||
AttackerInfo {
|
||||
entity,
|
||||
uid,
|
||||
energy: read_data.energies.get(entity),
|
||||
combo: read_data.combos.get(entity),
|
||||
inventory: read_data.inventories.get(entity),
|
||||
}
|
||||
});
|
||||
|
||||
let target_info = TargetInfo {
|
||||
entity: target,
|
||||
uid: other,
|
||||
inventory: read_data.inventories.get(target),
|
||||
stats: read_data.stats.get(target),
|
||||
health: read_data.healths.get(target),
|
||||
pos: pos.0,
|
||||
ori: orientations.get(target),
|
||||
char_state: read_data.character_states.get(target),
|
||||
};
|
||||
|
||||
if let Some(&body) = read_data.bodies.get(entity) {
|
||||
outcomes.push(Outcome::ProjectileHit {
|
||||
pos: pos.0,
|
||||
body,
|
||||
vel: read_data
|
||||
.velocities
|
||||
.get(entity)
|
||||
.map_or(Vec3::zero(), |v| v.0),
|
||||
source: projectile.owner,
|
||||
target: read_data.uids.get(target).copied(),
|
||||
});
|
||||
}
|
||||
|
||||
let avoid_harm = combat::avoid_player_harm(
|
||||
owner_entity.and_then(|owner| read_data.players.get(owner)),
|
||||
read_data.players.get(target),
|
||||
);
|
||||
|
||||
let attack_options = AttackOptions {
|
||||
// They say witchers can dodge arrows,
|
||||
// but we don't have witchers
|
||||
target_dodging: false,
|
||||
avoid_harm,
|
||||
target_group,
|
||||
};
|
||||
attack.apply_attack(
|
||||
attacker_info,
|
||||
target_info,
|
||||
dir,
|
||||
attack_options,
|
||||
1.0,
|
||||
AttackSource::Projectile,
|
||||
|e| server_emitter.emit(e),
|
||||
|o| outcomes.push(o),
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
projectile::Effect::Explode(e) => {
|
||||
server_emitter.emit(ServerEvent::Explosion {
|
||||
pos: pos.0,
|
||||
explosion: e,
|
||||
owner: projectile.owner,
|
||||
});
|
||||
},
|
||||
projectile::Effect::Vanish => {
|
||||
server_emitter.emit(ServerEvent::Destroy {
|
||||
entity,
|
||||
cause: HealthSource::World,
|
||||
});
|
||||
projectile_vanished = true;
|
||||
},
|
||||
projectile::Effect::Possess => {
|
||||
if other != projectile.owner.unwrap() {
|
||||
if let Some(owner) = projectile.owner {
|
||||
server_emitter.emit(ServerEvent::Possess(owner, other));
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
dispatch_hit(
|
||||
projectile_info,
|
||||
projectile_target_info,
|
||||
&read_data,
|
||||
&mut projectile_vanished,
|
||||
&mut outcomes,
|
||||
&mut server_emitter,
|
||||
);
|
||||
}
|
||||
|
||||
if projectile_vanished {
|
||||
@ -266,3 +196,141 @@ impl<'a> System<'a> for Sys {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ProjectileInfo<'a> {
|
||||
entity: EcsEntity,
|
||||
effect: projectile::Effect,
|
||||
owner_uid: Option<Uid>,
|
||||
owner: Option<EcsEntity>,
|
||||
ori: Option<&'a Ori>,
|
||||
pos: &'a Pos,
|
||||
}
|
||||
|
||||
struct ProjectileTargetInfo<'a> {
|
||||
uid: Uid,
|
||||
entity: Option<EcsEntity>,
|
||||
target_group: GroupTarget,
|
||||
ori: Option<&'a Ori>,
|
||||
}
|
||||
|
||||
fn dispatch_hit(
|
||||
projectile_info: ProjectileInfo,
|
||||
projectile_target_info: ProjectileTargetInfo,
|
||||
read_data: &ReadData,
|
||||
projectile_vanished: &mut bool,
|
||||
outcomes: &mut Vec<Outcome>,
|
||||
server_emitter: &mut Emitter<ServerEvent>,
|
||||
) {
|
||||
match projectile_info.effect {
|
||||
projectile::Effect::Attack(attack) => {
|
||||
let target_uid = projectile_target_info.uid;
|
||||
let target = if let Some(entity) = projectile_target_info.entity {
|
||||
entity
|
||||
} else {
|
||||
return;
|
||||
};
|
||||
|
||||
let (target_pos, projectile_dir) = {
|
||||
let target_pos = read_data.positions.get(target);
|
||||
let projectile_ori = projectile_info.ori;
|
||||
match target_pos.zip(projectile_ori) {
|
||||
Some((tgt_pos, proj_ori)) => {
|
||||
let Pos(tgt_pos) = tgt_pos;
|
||||
(*tgt_pos, proj_ori.look_dir())
|
||||
},
|
||||
None => return,
|
||||
}
|
||||
};
|
||||
|
||||
let owner = projectile_info.owner;
|
||||
let projectile_entity = projectile_info.entity;
|
||||
|
||||
let attacker_info =
|
||||
owner
|
||||
.zip(projectile_info.owner_uid)
|
||||
.map(|(entity, uid)| AttackerInfo {
|
||||
entity,
|
||||
uid,
|
||||
energy: read_data.energies.get(entity),
|
||||
combo: read_data.combos.get(entity),
|
||||
inventory: read_data.inventories.get(entity),
|
||||
});
|
||||
|
||||
let target_info = TargetInfo {
|
||||
entity: target,
|
||||
uid: target_uid,
|
||||
inventory: read_data.inventories.get(target),
|
||||
stats: read_data.stats.get(target),
|
||||
health: read_data.healths.get(target),
|
||||
pos: target_pos,
|
||||
ori: projectile_target_info.ori,
|
||||
char_state: read_data.character_states.get(target),
|
||||
};
|
||||
|
||||
// TODO: Is it possible to have projectile without body??
|
||||
if let Some(&body) = read_data.bodies.get(projectile_entity) {
|
||||
outcomes.push(Outcome::ProjectileHit {
|
||||
pos: target_pos,
|
||||
body,
|
||||
vel: read_data
|
||||
.velocities
|
||||
.get(projectile_entity)
|
||||
.map_or(Vec3::zero(), |v| v.0),
|
||||
source: projectile_info.owner_uid,
|
||||
target: read_data.uids.get(target).copied(),
|
||||
});
|
||||
}
|
||||
|
||||
let avoid_harm = combat::avoid_player_harm(
|
||||
owner.and_then(|owner| read_data.players.get(owner)),
|
||||
read_data.players.get(target),
|
||||
);
|
||||
|
||||
let attack_options = AttackOptions {
|
||||
// They say witchers can dodge arrows,
|
||||
// but we don't have witchers
|
||||
target_dodging: false,
|
||||
avoid_harm,
|
||||
target_group: projectile_target_info.target_group,
|
||||
};
|
||||
|
||||
attack.apply_attack(
|
||||
attacker_info,
|
||||
target_info,
|
||||
projectile_dir,
|
||||
attack_options,
|
||||
1.0,
|
||||
AttackSource::Projectile,
|
||||
|e| server_emitter.emit(e),
|
||||
|o| outcomes.push(o),
|
||||
);
|
||||
},
|
||||
projectile::Effect::Explode(e) => {
|
||||
let Pos(pos) = *projectile_info.pos;
|
||||
let owner_uid = projectile_info.owner_uid;
|
||||
server_emitter.emit(ServerEvent::Explosion {
|
||||
pos,
|
||||
explosion: e,
|
||||
owner: owner_uid,
|
||||
});
|
||||
},
|
||||
projectile::Effect::Vanish => {
|
||||
let entity = projectile_info.entity;
|
||||
server_emitter.emit(ServerEvent::Destroy {
|
||||
entity,
|
||||
cause: HealthSource::World,
|
||||
});
|
||||
*projectile_vanished = true;
|
||||
},
|
||||
projectile::Effect::Possess => {
|
||||
let target_uid = projectile_target_info.uid;
|
||||
let owner_uid = projectile_info.owner_uid;
|
||||
if let Some(owner_uid) = owner_uid {
|
||||
if target_uid != owner_uid {
|
||||
server_emitter.emit(ServerEvent::Possess(owner_uid, target_uid));
|
||||
}
|
||||
}
|
||||
},
|
||||
projectile::Effect::Stick => {},
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user