mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'james/fix-merchant-wander' into 'master'
Fix merchant wandering See merge request veloren/veloren!2035
This commit is contained in:
commit
895de16dd6
@ -285,31 +285,31 @@ impl<'a> System<'a> for Sys {
|
|||||||
///////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////
|
||||||
// Behavior tree
|
// Behavior tree
|
||||||
///////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////
|
||||||
|
// The behavior tree is meant to make decisions for agents
|
||||||
|
// *but should not* mutate any data (only action nodes
|
||||||
|
// should do that). Each path should lead to one (and only
|
||||||
|
// one) action node. This makes bugfinding much easier and
|
||||||
|
// debugging way easier. If you don't think so, try
|
||||||
|
// debugging the agent code before this MR
|
||||||
|
// (https://gitlab.com/veloren/veloren/-/merge_requests/1801).
|
||||||
|
// Each tick should arrive at one (1) action node which
|
||||||
|
// then determines what the agent does. If this makes you
|
||||||
|
// uncomfortable, consider dt the response time of the
|
||||||
|
// NPC. To make the tree easier to read, subtrees can be
|
||||||
|
// created as methods on `AgentData`. Action nodes are
|
||||||
|
// also methods on the `AgentData` struct. Action nodes
|
||||||
|
// are the only parts of this tree that should provide
|
||||||
|
// inputs.
|
||||||
|
|
||||||
// If falling fast and can glide, save yourself!
|
// If falling fast and can glide, save yourself!
|
||||||
if data.fall_glide() {
|
if data.glider_equipped && !data.physics_state.on_ground {
|
||||||
// toggle glider when vertical velocity is above some threshold (here ~
|
// toggle glider when vertical velocity is above some threshold (here ~
|
||||||
// glider fall vertical speed)
|
// glider fall vertical speed)
|
||||||
if vel.0.z < -26.0 {
|
data.glider_fall(agent, controller, &read_data);
|
||||||
controller.actions.push(ControlAction::GlideWield);
|
|
||||||
if let Some(Target { target, .. }) = 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if let Some(Target {
|
} else if let Some(Target {
|
||||||
target,
|
target, hostile, ..
|
||||||
hostile,
|
|
||||||
selected_at,
|
|
||||||
}) = agent.target
|
}) = agent.target
|
||||||
{
|
{
|
||||||
if read_data.time.0 - selected_at > RETARGETING_THRESHOLD_SECONDS {
|
|
||||||
data.choose_target(agent, controller, &read_data, &mut event_emitter);
|
|
||||||
}
|
|
||||||
if let Some(tgt_health) = read_data.healths.get(target) {
|
if let Some(tgt_health) = read_data.healths.get(target) {
|
||||||
// If the target is hostile (either based on alignment or if
|
// If the target is hostile (either based on alignment or if
|
||||||
// the target just attacked
|
// the target just attacked
|
||||||
@ -523,8 +523,9 @@ impl<'a> System<'a> for Sys {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> AgentData<'a> {
|
impl<'a> AgentData<'a> {
|
||||||
fn fall_glide(&self) -> bool { self.glider_equipped && !self.physics_state.on_ground }
|
////////////////////////////////////////
|
||||||
|
// Subtrees
|
||||||
|
////////////////////////////////////////
|
||||||
fn idle_tree(
|
fn idle_tree(
|
||||||
&self,
|
&self,
|
||||||
agent: &mut Agent,
|
agent: &mut Agent,
|
||||||
@ -577,7 +578,12 @@ impl<'a> AgentData<'a> {
|
|||||||
read_data: &ReadData,
|
read_data: &ReadData,
|
||||||
event_emitter: &mut Emitter<'_, ServerEvent>,
|
event_emitter: &mut Emitter<'_, ServerEvent>,
|
||||||
) {
|
) {
|
||||||
if let Some(Target { target, .. }) = agent.target {
|
if let Some(Target {
|
||||||
|
target,
|
||||||
|
selected_at,
|
||||||
|
..
|
||||||
|
}) = agent.target
|
||||||
|
{
|
||||||
if let Some(tgt_pos) = read_data.positions.get(target) {
|
if let Some(tgt_pos) = read_data.positions.get(target) {
|
||||||
let dist_sqrd = self.pos.0.distance_squared(tgt_pos.0);
|
let dist_sqrd = self.pos.0.distance_squared(tgt_pos.0);
|
||||||
// Should the agent flee?
|
// Should the agent flee?
|
||||||
@ -615,6 +621,13 @@ impl<'a> AgentData<'a> {
|
|||||||
event_emitter
|
event_emitter
|
||||||
.emit(ServerEvent::Chat(UnresolvedChatMsg::npc(*self.uid, msg)));
|
.emit(ServerEvent::Chat(UnresolvedChatMsg::npc(*self.uid, msg)));
|
||||||
}
|
}
|
||||||
|
// Choose a new target every 10 seconds
|
||||||
|
// TODO: This should be more principled. Consider factoring
|
||||||
|
// health, combat rating, wielded
|
||||||
|
// weapon, etc, into the decision to change
|
||||||
|
// target.
|
||||||
|
} else if read_data.time.0 - selected_at > RETARGETING_THRESHOLD_SECONDS {
|
||||||
|
self.choose_target(agent, controller, &read_data, event_emitter);
|
||||||
} else if dist_sqrd < SIGHT_DIST.powi(2) {
|
} else if dist_sqrd < SIGHT_DIST.powi(2) {
|
||||||
self.attack(
|
self.attack(
|
||||||
agent,
|
agent,
|
||||||
@ -634,6 +647,24 @@ impl<'a> AgentData<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////
|
||||||
|
// Action Nodes
|
||||||
|
////////////////////////////////////////
|
||||||
|
|
||||||
|
fn glider_fall(&self, agent: &mut Agent, controller: &mut Controller, read_data: &ReadData) {
|
||||||
|
if self.vel.0.z < -26.0 {
|
||||||
|
controller.actions.push(ControlAction::GlideWield);
|
||||||
|
if let Some(Target { target, .. }) = agent.target {
|
||||||
|
if let Some(tgt_pos) = read_data.positions.get(target) {
|
||||||
|
controller.inputs.move_dir = (self.pos.0 - tgt_pos.0)
|
||||||
|
.xy()
|
||||||
|
.try_normalized()
|
||||||
|
.unwrap_or_else(Vec2::zero);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn idle(&self, agent: &mut Agent, controller: &mut Controller, read_data: &ReadData) {
|
fn idle(&self, agent: &mut Agent, controller: &mut Controller, read_data: &ReadData) {
|
||||||
// Light lanterns at night
|
// Light lanterns at night
|
||||||
// TODO Add a method to turn on NPC lanterns underground
|
// TODO Add a method to turn on NPC lanterns underground
|
||||||
|
Loading…
x
Reference in New Issue
Block a user