mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Address comments
This commit is contained in:
parent
018d51b1a0
commit
f9fc015680
@ -87,8 +87,8 @@ pub struct ReadData<'a> {
|
||||
}
|
||||
|
||||
// This is 3.1 to last longer than the last damage timer (3.0 seconds)
|
||||
const DAMAGE_MEMORY_DURATION: f64 = 3.0;
|
||||
const FLEE_DURATION: f32 = 3.1;
|
||||
const DAMAGE_MEMORY_DURATION: f64 = 0.1;
|
||||
const FLEE_DURATION: f32 = 3.0;
|
||||
const MAX_FOLLOW_DIST: f32 = 12.0;
|
||||
const MAX_CHASE_DIST: f32 = 20.0;
|
||||
const MAX_FLEE_DIST: f32 = 20.0;
|
||||
@ -250,71 +250,103 @@ impl<'a> System<'a> for Sys {
|
||||
// glider fall vertical speed)
|
||||
if vel.0.z < -26.0 {
|
||||
controller.actions.push(ControlAction::GlideWield);
|
||||
if let Some(Target { target, hostile: _ }) = agent.target {
|
||||
if let Some(tgt_pos) = read_data.positions.get(target) {
|
||||
controller.inputs.move_dir = (pos.0 - tgt_pos.0)
|
||||
.xy()
|
||||
.try_normalized()
|
||||
.unwrap_or_else(Vec2::zero);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pet branch
|
||||
} else if let Some(Alignment::Owned(owner)) = alignment {
|
||||
if let Some(owner) =
|
||||
read_data.uid_allocator.retrieve_entity_internal(owner.id())
|
||||
{
|
||||
if let (Some(owner_pos), Some(owner_health)) =
|
||||
(read_data.positions.get(owner), read_data.healths.get(owner))
|
||||
{
|
||||
agent.target = Some(Target {
|
||||
target: owner,
|
||||
hostile: false,
|
||||
});
|
||||
let dist_sqrd = pos.0.distance_squared(owner_pos.0);
|
||||
|
||||
// If really far away drop everything and follow
|
||||
if dist_sqrd > (2.0 * MAX_FOLLOW_DIST).powi(2) {
|
||||
data.follow(agent, controller, &read_data.terrain, owner_pos);
|
||||
// Attack owner's attacker
|
||||
} else if owner_health.last_change.0 < 5.0
|
||||
&& owner_health.last_change.1.amount < 0
|
||||
{
|
||||
if let comp::HealthSource::Damage { by: Some(by), .. } =
|
||||
owner_health.last_change.1.cause
|
||||
{
|
||||
if let Some(attacker) = read_data
|
||||
.uid_allocator
|
||||
.retrieve_entity_internal(by.id())
|
||||
} else if let Some(Target { target, hostile }) = agent.target {
|
||||
if let Some(tgt_health) = read_data.healths.get(target) {
|
||||
// If the target is hostile (either based on alignment or if
|
||||
// the target just attacked
|
||||
if !tgt_health.is_dead {
|
||||
if hostile {
|
||||
data.hostile_tree(
|
||||
agent,
|
||||
controller,
|
||||
&read_data,
|
||||
&mut event_emitter,
|
||||
);
|
||||
// Target is something worth following methinks
|
||||
} else if let Some(Alignment::Owned(_)) = data.alignment {
|
||||
if let Some(tgt_pos) = read_data.positions.get(target) {
|
||||
let dist_sqrd = pos.0.distance_squared(tgt_pos.0);
|
||||
// If really far away drop everything and follow
|
||||
if dist_sqrd > (2.0 * MAX_FOLLOW_DIST).powi(2) {
|
||||
agent.bearing = Vec2::zero();
|
||||
data.follow(
|
||||
agent,
|
||||
controller,
|
||||
&read_data.terrain,
|
||||
tgt_pos,
|
||||
);
|
||||
// Attack target's attacker
|
||||
} else if tgt_health.last_change.0 < 5.0
|
||||
&& tgt_health.last_change.1.amount < 0
|
||||
{
|
||||
agent.target = Some(Target {
|
||||
target: attacker,
|
||||
hostile: true,
|
||||
});
|
||||
if let (Some(tgt_pos), Some(tgt_health)) = (
|
||||
read_data.positions.get(attacker),
|
||||
read_data.healths.get(attacker),
|
||||
) {
|
||||
if tgt_health.is_dead
|
||||
|| dist_sqrd > MAX_CHASE_DIST.powi(2)
|
||||
if let comp::HealthSource::Damage {
|
||||
by: Some(by), ..
|
||||
} = tgt_health.last_change.1.cause
|
||||
{
|
||||
if let Some(attacker) = read_data
|
||||
.uid_allocator
|
||||
.retrieve_entity_internal(by.id())
|
||||
{
|
||||
agent.target = Some(Target {
|
||||
target: owner,
|
||||
hostile: false,
|
||||
target: attacker,
|
||||
hostile: true,
|
||||
});
|
||||
data.idle(agent, controller, &read_data);
|
||||
} else {
|
||||
data.attack(
|
||||
agent,
|
||||
controller,
|
||||
&read_data.terrain,
|
||||
tgt_pos,
|
||||
read_data.bodies.get(attacker),
|
||||
&read_data.dt,
|
||||
);
|
||||
if let (Some(tgt_pos), Some(tgt_health)) = (
|
||||
read_data.positions.get(attacker),
|
||||
read_data.healths.get(attacker),
|
||||
) {
|
||||
if tgt_health.is_dead
|
||||
|| dist_sqrd > MAX_CHASE_DIST.powi(2)
|
||||
{
|
||||
agent.target = Some(Target {
|
||||
target,
|
||||
hostile: false,
|
||||
});
|
||||
data.idle(
|
||||
agent, controller, &read_data,
|
||||
);
|
||||
} else {
|
||||
data.attack(
|
||||
agent,
|
||||
controller,
|
||||
&read_data.terrain,
|
||||
tgt_pos,
|
||||
read_data.bodies.get(attacker),
|
||||
&read_data.dt,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Follow owner if too far away and not
|
||||
// fighting
|
||||
} else if dist_sqrd > MAX_FOLLOW_DIST.powi(2) {
|
||||
data.follow(
|
||||
agent,
|
||||
controller,
|
||||
&read_data.terrain,
|
||||
tgt_pos,
|
||||
);
|
||||
|
||||
// Otherwise just idle
|
||||
} else {
|
||||
data.idle_tree(
|
||||
agent,
|
||||
controller,
|
||||
&read_data,
|
||||
&mut event_emitter,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Follow owner if too far away and not fighting
|
||||
} else if dist_sqrd > MAX_FOLLOW_DIST.powi(2) {
|
||||
data.follow(agent, controller, &read_data.terrain, owner_pos);
|
||||
|
||||
// Otherwise just idle
|
||||
} else {
|
||||
data.idle_tree(
|
||||
agent,
|
||||
@ -323,26 +355,12 @@ impl<'a> System<'a> for Sys {
|
||||
&mut event_emitter,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Non-owned agent branch
|
||||
} else if let Some(Target { target, hostile }) = agent.target {
|
||||
if let Some(tgt_health) = read_data.healths.get(target) {
|
||||
// If the target is hostile (either based on alignment or if
|
||||
// the target just attacked
|
||||
if hostile && !tgt_health.is_dead {
|
||||
data.hostile_tree(
|
||||
agent,
|
||||
controller,
|
||||
&read_data,
|
||||
&mut event_emitter,
|
||||
);
|
||||
// If the target is not hostile, just idle
|
||||
} else {
|
||||
agent.target = None;
|
||||
data.idle_tree(agent, controller, &read_data, &mut event_emitter);
|
||||
}
|
||||
} else {
|
||||
agent.target = None;
|
||||
data.idle_tree(agent, controller, &read_data, &mut event_emitter);
|
||||
}
|
||||
} else {
|
||||
@ -355,11 +373,20 @@ impl<'a> System<'a> for Sys {
|
||||
read_data.uid_allocator.retrieve_entity_internal(by.id())
|
||||
{
|
||||
if let Some(tgt_pos) = read_data.positions.get(attacker) {
|
||||
// If the target is dead, remove the target and idle.
|
||||
if read_data
|
||||
.healths
|
||||
.get(attacker)
|
||||
.map_or(false, |a| !a.is_dead)
|
||||
.map_or(true, |a| a.is_dead)
|
||||
{
|
||||
agent.target = None;
|
||||
data.idle_tree(
|
||||
agent,
|
||||
controller,
|
||||
&read_data,
|
||||
&mut event_emitter,
|
||||
);
|
||||
} else {
|
||||
agent.target = Some(Target {
|
||||
target: attacker,
|
||||
hostile: true,
|
||||
@ -372,14 +399,6 @@ impl<'a> System<'a> for Sys {
|
||||
read_data.bodies.get(attacker),
|
||||
&read_data.dt,
|
||||
);
|
||||
} else {
|
||||
agent.target = None;
|
||||
data.idle_tree(
|
||||
agent,
|
||||
controller,
|
||||
&read_data,
|
||||
&mut event_emitter,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
agent.target = None;
|
||||
@ -424,23 +443,28 @@ impl<'a> AgentData<'a> {
|
||||
read_data: &ReadData,
|
||||
event_emitter: &mut Emitter<'_, ServerEvent>,
|
||||
) {
|
||||
// Set owner if no target
|
||||
if agent.target.is_none() && thread_rng().gen_bool(0.1) {
|
||||
if let Some(Alignment::Owned(owner)) = self.alignment {
|
||||
if let Some(owner) = read_data.uid_allocator.retrieve_entity_internal(owner.id()) {
|
||||
agent.target = Some(Target {
|
||||
target: owner,
|
||||
hostile: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
// Interact if incoming messages
|
||||
if !agent.inbox.is_empty() {
|
||||
agent.action_timer = 0.1
|
||||
agent.action_timer = 0.1;
|
||||
}
|
||||
if agent.action_timer > 0.0 {
|
||||
if self.flees && agent.can_speak {
|
||||
if agent.action_timer < DEFAULT_INTERACTION_TIME {
|
||||
self.interact(agent, controller, &read_data, event_emitter);
|
||||
} else {
|
||||
agent.action_timer = 0.0;
|
||||
agent.target = None;
|
||||
controller.actions.push(ControlAction::Stand);
|
||||
self.idle(agent, controller, &read_data);
|
||||
}
|
||||
if agent.action_timer < DEFAULT_INTERACTION_TIME {
|
||||
self.interact(agent, controller, &read_data, event_emitter);
|
||||
} else {
|
||||
agent.inbox.clear();
|
||||
agent.action_timer = 0.0;
|
||||
agent.target = None;
|
||||
controller.actions.push(ControlAction::Stand);
|
||||
self.idle(agent, controller, &read_data);
|
||||
}
|
||||
} else if thread_rng().gen::<f32>() < 0.1 {
|
||||
@ -526,29 +550,20 @@ impl<'a> AgentData<'a> {
|
||||
let lantern_turned_on = self.light_emitter.is_some();
|
||||
let day_period = DayPeriod::from(read_data.time_of_day.0);
|
||||
// Only emit event for agents that have a lantern equipped
|
||||
if lantern_equipped {
|
||||
let mut rng = thread_rng();
|
||||
if lantern_equipped && thread_rng().gen_bool(0.001) {
|
||||
if day_period.is_dark() && !lantern_turned_on {
|
||||
// Agents with turned off lanterns turn them on randomly once it's
|
||||
// nighttime and keep them on
|
||||
// Only emit event for agents that sill need to
|
||||
// turn on their lantern
|
||||
if let 0 = rng.gen_range(0..1000) {
|
||||
controller.events.push(ControlEvent::EnableLantern)
|
||||
}
|
||||
controller.events.push(ControlEvent::EnableLantern)
|
||||
} else if lantern_turned_on && day_period.is_light() {
|
||||
// agents with turned on lanterns turn them off randomly once it's
|
||||
// daytime and keep them off
|
||||
if let 0 = rng.gen_range(0..2000) {
|
||||
controller.events.push(ControlEvent::DisableLantern)
|
||||
}
|
||||
controller.events.push(ControlEvent::DisableLantern)
|
||||
}
|
||||
};
|
||||
|
||||
if self.physics_state.on_ground {
|
||||
controller.actions.push(ControlAction::Unwield);
|
||||
}
|
||||
|
||||
agent.action_timer = 0.0;
|
||||
if let Some((travel_to, _destination)) = &agent.rtsim_controller.travel_to {
|
||||
// if it has an rtsim destination and can fly then it should
|
||||
@ -607,7 +622,7 @@ impl<'a> AgentData<'a> {
|
||||
};
|
||||
|
||||
// Put away weapon
|
||||
if thread_rng().gen::<f32>() < 0.05
|
||||
if thread_rng().gen_bool(0.1)
|
||||
&& matches!(
|
||||
read_data.char_states.get(*self.entity),
|
||||
Some(CharacterState::Wielding)
|
||||
@ -654,7 +669,7 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
|
||||
// Put away weapon
|
||||
if thread_rng().gen::<f32>() < 0.05
|
||||
if thread_rng().gen_bool(0.1)
|
||||
&& matches!(
|
||||
read_data.char_states.get(*self.entity),
|
||||
Some(CharacterState::Wielding)
|
||||
@ -692,54 +707,58 @@ impl<'a> AgentData<'a> {
|
||||
.push(ControlEvent::InviteResponse(InviteResponse::Decline));
|
||||
}
|
||||
agent.action_timer += read_data.dt.0;
|
||||
if let Some(AgentEvent::Talk(by)) = agent.inbox.pop_back() {
|
||||
if let Some(target) = read_data.uid_allocator.retrieve_entity_internal(by.id()) {
|
||||
agent.target = Some(Target {
|
||||
target,
|
||||
hostile: false,
|
||||
});
|
||||
if let Some(tgt_pos) = read_data.positions.get(target) {
|
||||
if agent.can_speak {
|
||||
if let Some(AgentEvent::Talk(by)) = agent.inbox.pop_back() {
|
||||
if let Some(target) = read_data.uid_allocator.retrieve_entity_internal(by.id()) {
|
||||
agent.target = Some(Target {
|
||||
target,
|
||||
hostile: false,
|
||||
});
|
||||
if let Some(tgt_pos) = read_data.positions.get(target) {
|
||||
let eye_offset = self.body.map_or(0.0, |b| b.eye_height());
|
||||
let tgt_eye_offset =
|
||||
read_data.bodies.get(target).map_or(0.0, |b| b.eye_height());
|
||||
if let Some(dir) = Dir::from_unnormalized(
|
||||
Vec3::new(tgt_pos.0.x, tgt_pos.0.y, tgt_pos.0.z + tgt_eye_offset)
|
||||
- Vec3::new(self.pos.0.x, self.pos.0.y, self.pos.0.z + eye_offset),
|
||||
) {
|
||||
controller.inputs.look_dir = dir;
|
||||
}
|
||||
controller.actions.push(ControlAction::Stand);
|
||||
controller.actions.push(ControlAction::Talk);
|
||||
if let Some((_travel_to, destination_name)) =
|
||||
&agent.rtsim_controller.travel_to
|
||||
{
|
||||
let msg =
|
||||
format!("I'm heading to {}! Want to come along?", destination_name);
|
||||
event_emitter
|
||||
.emit(ServerEvent::Chat(UnresolvedChatMsg::npc(*self.uid, msg)));
|
||||
} else {
|
||||
let msg = "npc.speech.villager".to_string();
|
||||
event_emitter
|
||||
.emit(ServerEvent::Chat(UnresolvedChatMsg::npc(*self.uid, msg)));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let Some(Target { target, .. }) = &agent.target {
|
||||
if let Some(tgt_pos) = read_data.positions.get(*target) {
|
||||
let eye_offset = self.body.map_or(0.0, |b| b.eye_height());
|
||||
let tgt_eye_offset =
|
||||
read_data.bodies.get(target).map_or(0.0, |b| b.eye_height());
|
||||
let tgt_eye_offset = read_data
|
||||
.bodies
|
||||
.get(*target)
|
||||
.map_or(0.0, |b| b.eye_height());
|
||||
if let Some(dir) = Dir::from_unnormalized(
|
||||
Vec3::new(tgt_pos.0.x, tgt_pos.0.y, tgt_pos.0.z + tgt_eye_offset)
|
||||
- Vec3::new(self.pos.0.x, self.pos.0.y, self.pos.0.z + eye_offset),
|
||||
) {
|
||||
controller.inputs.look_dir = dir;
|
||||
}
|
||||
controller.actions.push(ControlAction::Stand);
|
||||
controller.actions.push(ControlAction::Talk);
|
||||
if let Some((_travel_to, destination_name)) = &agent.rtsim_controller.travel_to
|
||||
{
|
||||
let msg =
|
||||
format!("I'm heading to {}! Want to come along?", destination_name);
|
||||
event_emitter
|
||||
.emit(ServerEvent::Chat(UnresolvedChatMsg::npc(*self.uid, msg)));
|
||||
} else {
|
||||
let msg = "npc.speech.villager".to_string();
|
||||
event_emitter
|
||||
.emit(ServerEvent::Chat(UnresolvedChatMsg::npc(*self.uid, msg)));
|
||||
}
|
||||
//}
|
||||
}
|
||||
}
|
||||
} else if let Some(Target { target, .. }) = &agent.target {
|
||||
if let Some(tgt_pos) = read_data.positions.get(*target) {
|
||||
let eye_offset = self.body.map_or(0.0, |b| b.eye_height());
|
||||
let tgt_eye_offset = read_data
|
||||
.bodies
|
||||
.get(*target)
|
||||
.map_or(0.0, |b| b.eye_height());
|
||||
if let Some(dir) = Dir::from_unnormalized(
|
||||
Vec3::new(tgt_pos.0.x, tgt_pos.0.y, tgt_pos.0.z + tgt_eye_offset)
|
||||
- Vec3::new(self.pos.0.x, self.pos.0.y, self.pos.0.z + eye_offset),
|
||||
) {
|
||||
controller.inputs.look_dir = dir;
|
||||
}
|
||||
} else {
|
||||
agent.action_timer = 0.0;
|
||||
}
|
||||
} else {
|
||||
agent.action_timer = 0.0;
|
||||
agent.inbox.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@ -842,10 +861,13 @@ impl<'a> AgentData<'a> {
|
||||
None
|
||||
}
|
||||
}) {
|
||||
Some(ToolKind::Bow) => Tactic::Bow,
|
||||
Some(ToolKind::Staff) => Tactic::Staff,
|
||||
Some(ToolKind::Bow) | Some(ToolKind::BowSimple) => Tactic::Bow,
|
||||
Some(ToolKind::Staff) | Some(ToolKind::StaffSimple) => Tactic::Staff,
|
||||
Some(ToolKind::Hammer) => Tactic::Hammer,
|
||||
Some(ToolKind::Sword) => Tactic::Sword,
|
||||
Some(ToolKind::Sword)
|
||||
| Some(ToolKind::Spear)
|
||||
| Some(ToolKind::SwordSimple)
|
||||
| Some(ToolKind::AxeSimple) => Tactic::Sword,
|
||||
Some(ToolKind::Axe) => Tactic::Axe,
|
||||
Some(ToolKind::Unique(UniqueKind::StoneGolemFist)) => Tactic::StoneGolemBoss,
|
||||
Some(ToolKind::Unique(UniqueKind::QuadMedQuick)) => Tactic::CircleCharge {
|
||||
@ -863,7 +885,8 @@ impl<'a> AgentData<'a> {
|
||||
Some(ToolKind::Unique(UniqueKind::QuadLowTail)) => Tactic::TailSlap,
|
||||
Some(ToolKind::Unique(UniqueKind::QuadLowQuick)) => Tactic::QuadLowQuick,
|
||||
Some(ToolKind::Unique(UniqueKind::QuadLowBasic)) => Tactic::QuadLowBasic,
|
||||
Some(ToolKind::Unique(UniqueKind::QuadLowBreathe)) => Tactic::Lavadrake,
|
||||
Some(ToolKind::Unique(UniqueKind::QuadLowBreathe))
|
||||
| Some(ToolKind::Unique(UniqueKind::QuadLowBeam)) => Tactic::Lavadrake,
|
||||
Some(ToolKind::Unique(UniqueKind::TheropodBasic)) => Tactic::Theropod,
|
||||
Some(ToolKind::Unique(UniqueKind::TheropodBird)) => Tactic::Theropod,
|
||||
Some(ToolKind::Unique(UniqueKind::ObjectTurret)) => Tactic::Turret,
|
||||
@ -1605,7 +1628,7 @@ impl<'a> AgentData<'a> {
|
||||
agent.target = None;
|
||||
}
|
||||
},
|
||||
Tactic::Lavadrake => {
|
||||
Tactic::Lavadrake | Tactic::QuadLowBeam => {
|
||||
if dist_sqrd < (2.5 * min_attack_dist * self.scale).powi(2) {
|
||||
controller.inputs.move_dir = Vec2::zero();
|
||||
controller.inputs.secondary.set_state(true);
|
||||
@ -1677,8 +1700,7 @@ impl<'a> AgentData<'a> {
|
||||
}
|
||||
},
|
||||
Tactic::Turret => {
|
||||
if can_see_tgt(&*terrain, self.pos, tgt_pos, dist_sqrd)
|
||||
{
|
||||
if can_see_tgt(&*terrain, self.pos, tgt_pos, dist_sqrd) {
|
||||
controller.inputs.primary.set_state(true);
|
||||
} else {
|
||||
agent.target = None;
|
||||
@ -1686,8 +1708,7 @@ impl<'a> AgentData<'a> {
|
||||
},
|
||||
Tactic::FixedTurret => {
|
||||
controller.inputs.look_dir = self.ori.look_dir();
|
||||
if can_see_tgt(&*terrain, self.pos, tgt_pos, dist_sqrd)
|
||||
{
|
||||
if can_see_tgt(&*terrain, self.pos, tgt_pos, dist_sqrd) {
|
||||
controller.inputs.primary.set_state(true);
|
||||
} else {
|
||||
agent.target = None;
|
||||
@ -1696,13 +1717,12 @@ impl<'a> AgentData<'a> {
|
||||
Tactic::RotatingTurret => {
|
||||
controller.inputs.look_dir = Dir::new(
|
||||
Quaternion::from_xyzw(self.ori.look_dir().x, self.ori.look_dir().y, 0.0, 0.0)
|
||||
.rotated_z(6.0 * dt.0 as f32)
|
||||
.into_vec3()
|
||||
.try_normalized()
|
||||
.unwrap_or_default(),
|
||||
.rotated_z(6.0 * dt.0 as f32)
|
||||
.into_vec3()
|
||||
.try_normalized()
|
||||
.unwrap_or_default(),
|
||||
);
|
||||
if can_see_tgt(&*terrain, self.pos, tgt_pos, dist_sqrd)
|
||||
{
|
||||
if can_see_tgt(&*terrain, self.pos, tgt_pos, dist_sqrd) {
|
||||
controller.inputs.primary.set_state(true);
|
||||
} else {
|
||||
agent.target = None;
|
||||
|
Loading…
Reference in New Issue
Block a user