mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Made adventurers explore sites before moving on
This commit is contained in:
parent
2b3f0737d0
commit
84eb7b0653
@ -423,7 +423,7 @@ fn timeout(time: f64) -> impl FnMut(&mut NpcCtx) -> bool + Clone + Send + Sync {
|
||||
}
|
||||
|
||||
fn adventure() -> impl Action {
|
||||
now(|ctx| {
|
||||
choose(|ctx| {
|
||||
// Choose a random site that's fairly close by
|
||||
if let Some(tgt_site) = ctx
|
||||
.state
|
||||
@ -441,33 +441,43 @@ fn adventure() -> impl Action {
|
||||
.map(|(site_id, _)| site_id)
|
||||
{
|
||||
// Travel to the site
|
||||
travel_to_site(tgt_site)
|
||||
important(
|
||||
travel_to_site(tgt_site)
|
||||
// Stop for a few minutes
|
||||
.then(villager().stop_if(timeout(60.0 * 3.0)))
|
||||
.then(villager(tgt_site).repeat().stop_if(timeout(60.0 * 3.0)))
|
||||
.map(|_| ())
|
||||
.boxed()
|
||||
.boxed(),
|
||||
)
|
||||
} else {
|
||||
finish().boxed()
|
||||
casual(finish().boxed())
|
||||
}
|
||||
})
|
||||
.debug(move || format!("adventure"))
|
||||
}
|
||||
|
||||
fn villager() -> impl Action {
|
||||
choose(|ctx| {
|
||||
if let Some(home) = ctx.npc.home {
|
||||
if ctx.npc.current_site != Some(home) {
|
||||
// Travel home if we're not there already
|
||||
urgent(travel_to_site(home).debug(move || format!("travel home")))
|
||||
} else if DayPeriod::from(ctx.time_of_day.0).is_dark() {
|
||||
important(now(move |ctx| {
|
||||
fn villager(visiting_site: SiteId) -> impl Action {
|
||||
choose(move |ctx| {
|
||||
if ctx.npc.current_site != Some(visiting_site) {
|
||||
let npc_home = ctx.npc.home;
|
||||
// Travel to the site we're supposed to be in
|
||||
urgent(travel_to_site(visiting_site).debug(move || {
|
||||
if npc_home == Some(visiting_site) {
|
||||
format!("travel home")
|
||||
} else {
|
||||
format!("travel to visiting site")
|
||||
}
|
||||
}))
|
||||
} else if DayPeriod::from(ctx.time_of_day.0).is_dark() {
|
||||
important(
|
||||
now(move |ctx| {
|
||||
if let Some(house_wpos) = ctx
|
||||
.state
|
||||
.data()
|
||||
.sites
|
||||
.get(home)
|
||||
.and_then(|home| ctx.index.sites.get(home.world_site?).site2())
|
||||
.get(visiting_site)
|
||||
.and_then(|site| ctx.index.sites.get(site.world_site?).site2())
|
||||
.and_then(|site2| {
|
||||
// Find a house
|
||||
// Find a house in the site we're visiting
|
||||
let house = site2
|
||||
.plots()
|
||||
.filter(|p| matches!(p.kind(), PlotKind::House(_)))
|
||||
@ -484,57 +494,55 @@ fn villager() -> impl Action {
|
||||
} else {
|
||||
finish().boxed()
|
||||
}
|
||||
}))
|
||||
} else if matches!(
|
||||
ctx.npc.profession,
|
||||
Some(Profession::Merchant | Profession::Blacksmith)
|
||||
) {
|
||||
// Trade professions just walk between town plazas
|
||||
casual(now(move |ctx| {
|
||||
// Choose a plaza in the NPC's home site to walk to
|
||||
if let Some(plaza_wpos) = ctx
|
||||
.state
|
||||
.data()
|
||||
.sites
|
||||
.get(home)
|
||||
.and_then(|home| ctx.index.sites.get(home.world_site?).site2())
|
||||
.and_then(|site2| {
|
||||
let plaza = &site2.plots[site2.plazas().choose(&mut thread_rng())?];
|
||||
Some(site2.tile_center_wpos(plaza.root_tile()).as_())
|
||||
})
|
||||
{
|
||||
// Walk to the plaza...
|
||||
goto_2d(plaza_wpos, 0.5)
|
||||
.debug(|| "walk to plaza")
|
||||
// ...then wait for some time before moving on
|
||||
.then({
|
||||
let wait_time = thread_rng().gen_range(10.0..30.0);
|
||||
idle().repeat().stop_if(timeout(wait_time))
|
||||
.debug(|| "wait at plaza")
|
||||
})
|
||||
.map(|_| ())
|
||||
.boxed()
|
||||
} else {
|
||||
// No plazas? :(
|
||||
finish().boxed()
|
||||
}
|
||||
}))
|
||||
} else {
|
||||
casual(idle())
|
||||
}
|
||||
})
|
||||
.debug(|| "find somewhere to sleep"),
|
||||
)
|
||||
} else {
|
||||
casual(finish()) // Nothing to do if we're homeless!
|
||||
casual(now(move |ctx| {
|
||||
// Choose a plaza in the site we're visiting to walk to
|
||||
if let Some(plaza_wpos) = ctx
|
||||
.state
|
||||
.data()
|
||||
.sites
|
||||
.get(visiting_site)
|
||||
.and_then(|site| ctx.index.sites.get(site.world_site?).site2())
|
||||
.and_then(|site2| {
|
||||
let plaza = &site2.plots[site2.plazas().choose(&mut thread_rng())?];
|
||||
Some(site2.tile_center_wpos(plaza.root_tile()).as_())
|
||||
})
|
||||
{
|
||||
// Walk to the plaza...
|
||||
goto_2d(plaza_wpos, 0.5)
|
||||
.debug(|| "walk to plaza")
|
||||
// ...then wait for some time before moving on
|
||||
.then({
|
||||
let wait_time = thread_rng().gen_range(10.0..30.0);
|
||||
idle().repeat().stop_if(timeout(wait_time))
|
||||
.debug(|| "wait at plaza")
|
||||
})
|
||||
.map(|_| ())
|
||||
.boxed()
|
||||
} else {
|
||||
// No plazas? :(
|
||||
finish().boxed()
|
||||
}
|
||||
}))
|
||||
}
|
||||
})
|
||||
.debug(move || format!("villager"))
|
||||
.debug(move || format!("villager at site {:?}", visiting_site))
|
||||
}
|
||||
|
||||
fn think() -> impl Action {
|
||||
choose(|ctx| {
|
||||
if matches!(ctx.npc.profession, Some(Profession::Adventurer(_))) {
|
||||
if matches!(
|
||||
ctx.npc.profession,
|
||||
Some(Profession::Adventurer(_) | Profession::Merchant)
|
||||
) {
|
||||
casual(adventure())
|
||||
} else if let Some(home) = ctx.npc.home {
|
||||
casual(villager(home))
|
||||
} else {
|
||||
casual(villager())
|
||||
casual(finish()) // Homeless
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -9,40 +9,39 @@ impl Rule for SimulateNpcs {
|
||||
fn start(rtstate: &mut RtState) -> Result<Self, RuleError> {
|
||||
rtstate.bind::<Self, OnTick>(|ctx| {
|
||||
let data = &mut *ctx.state.data_mut();
|
||||
for npc in data
|
||||
.npcs
|
||||
.values_mut()
|
||||
.filter(|npc| matches!(npc.mode, NpcMode::Simulated))
|
||||
{
|
||||
let body = npc.get_body();
|
||||
|
||||
// Move NPCs if they have a target destination
|
||||
if let Some((target, speed_factor)) = npc.goto {
|
||||
let diff = target.xy() - npc.wpos.xy();
|
||||
let dist2 = diff.magnitude_squared();
|
||||
|
||||
if dist2 > 0.5f32.powi(2) {
|
||||
npc.wpos += (diff
|
||||
* (body.max_speed_approx() * speed_factor * ctx.event.dt
|
||||
/ dist2.sqrt())
|
||||
.min(1.0))
|
||||
.with_z(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure NPCs remain on the surface
|
||||
npc.wpos.z = ctx
|
||||
.world
|
||||
.sim()
|
||||
.get_alt_approx(npc.wpos.xy().map(|e| e as i32))
|
||||
.unwrap_or(0.0);
|
||||
|
||||
for npc in data.npcs.values_mut() {
|
||||
// Update the NPC's current site, if any
|
||||
npc.current_site = ctx
|
||||
.world
|
||||
.sim()
|
||||
.get(npc.wpos.xy().as_::<i32>() / TerrainChunkSize::RECT_SIZE.as_())
|
||||
.and_then(|chunk| data.sites.world_site_map.get(chunk.sites.first()?).copied());
|
||||
|
||||
// Simulate the NPC's movement and interactions
|
||||
if matches!(npc.mode, NpcMode::Simulated) {
|
||||
let body = npc.get_body();
|
||||
|
||||
// Move NPCs if they have a target destination
|
||||
if let Some((target, speed_factor)) = npc.goto {
|
||||
let diff = target.xy() - npc.wpos.xy();
|
||||
let dist2 = diff.magnitude_squared();
|
||||
|
||||
if dist2 > 0.5f32.powi(2) {
|
||||
npc.wpos += (diff
|
||||
* (body.max_speed_approx() * speed_factor * ctx.event.dt
|
||||
/ dist2.sqrt())
|
||||
.min(1.0))
|
||||
.with_z(0.0);
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure NPCs remain on the surface
|
||||
npc.wpos.z = ctx
|
||||
.world
|
||||
.sim()
|
||||
.get_alt_approx(npc.wpos.xy().map(|e| e as i32))
|
||||
.unwrap_or(0.0);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1237,6 +1237,8 @@ fn handle_npc_info(
|
||||
let _ = writeln!(&mut info, "Seed: {}", npc.seed);
|
||||
let _ = writeln!(&mut info, "Profession: {:?}", npc.profession);
|
||||
let _ = writeln!(&mut info, "Home: {:?}", npc.home);
|
||||
let _ = writeln!(&mut info, "-- Status --");
|
||||
let _ = writeln!(&mut info, "Current site: {:?}", npc.current_site);
|
||||
let _ = writeln!(&mut info, "Current mode: {:?}", npc.mode);
|
||||
let _ = writeln!(&mut info, "-- Action State --");
|
||||
if let Some(brain) = &npc.brain {
|
||||
|
Loading…
Reference in New Issue
Block a user