mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Allow NPCs to migrate away from towns with a high population density
This commit is contained in:
parent
9e17042bf6
commit
2a1ea63910
@ -225,6 +225,9 @@ npc-speech-prisoner =
|
||||
.a4 = I wish i still had my pick!
|
||||
npc-speech-moving_on =
|
||||
.a0 = I've spent enough time here, onward to { $site }!
|
||||
npc-speech-migrating =
|
||||
.a0 = I'm no longer happy living here. Time to migrate to { $site }.
|
||||
.a1 = Time to move to { $site }, I've had it with this place.
|
||||
npc-speech-night_time =
|
||||
.a0 = It's dark, time to head home.
|
||||
.a1 = I'm tired.
|
||||
|
@ -55,6 +55,7 @@ pub struct PathingMemory {
|
||||
pub struct Controller {
|
||||
pub actions: Vec<NpcAction>,
|
||||
pub activity: Option<NpcActivity>,
|
||||
pub new_home: Option<SiteId>,
|
||||
}
|
||||
|
||||
impl Controller {
|
||||
@ -79,6 +80,8 @@ impl Controller {
|
||||
pub fn attack(&mut self, target: impl Into<Actor>) {
|
||||
self.actions.push(NpcAction::Attack(target.into()));
|
||||
}
|
||||
|
||||
pub fn set_new_home(&mut self, new_home: SiteId) { self.new_home = Some(new_home); }
|
||||
}
|
||||
|
||||
pub struct Brain {
|
||||
|
@ -599,28 +599,50 @@ fn choose_plaza(ctx: &mut NpcCtx, site: SiteId) -> Option<Vec2<f32>> {
|
||||
|
||||
fn villager(visiting_site: SiteId) -> impl Action {
|
||||
choose(move |ctx| {
|
||||
/*
|
||||
if ctx
|
||||
// Consider moving home if the home site gets too full
|
||||
if ctx.rng.gen_bool(0.0001)
|
||||
&& let Some(home) = ctx.npc.home
|
||||
&& Some(home) == ctx.npc.current_site
|
||||
&& let Some(home_pop_ratio) = ctx.state.data().sites.get(home)
|
||||
.and_then(|site| Some((site, ctx.index.sites.get(site.world_site?).site2()?)))
|
||||
.map(|(site, site2)| site.population.len() as f32 / site2.plots().len() as f32)
|
||||
// Only consider moving if the population is more than 1.5x the number of homes
|
||||
.filter(|pop_ratio| *pop_ratio > 1.5)
|
||||
&& let Some(new_home) = ctx
|
||||
.state
|
||||
.data()
|
||||
.sites
|
||||
.get(visiting_site)
|
||||
.map_or(true, |s| s.world_site.is_none())
|
||||
.iter()
|
||||
// Don't try to move to the site that's currently our home
|
||||
.filter(|(site_id, _)| Some(*site_id) != ctx.npc.home)
|
||||
// Only consider towns as potential homes
|
||||
.filter_map(|(site_id, site)| {
|
||||
let site2 = match site.world_site.map(|ws| &ctx.index.sites.get(ws).kind) {
|
||||
Some(SiteKind::Refactor(site2)
|
||||
| SiteKind::CliffTown(site2)
|
||||
| SiteKind::SavannahPit(site2)
|
||||
| SiteKind::DesertCity(site2)) => site2,
|
||||
_ => return None,
|
||||
};
|
||||
Some((site_id, site, site2))
|
||||
})
|
||||
// Only select sites that are less densely populated than our own
|
||||
.filter(|(_, site, site2)| (site.population.len() as f32 / site2.plots().len() as f32) < home_pop_ratio)
|
||||
// Find the closest of the candidate sites
|
||||
.min_by_key(|(_, site, _)| site.wpos.as_().distance(ctx.npc.wpos.xy()) as i32)
|
||||
.map(|(site_id, _, _)| site_id)
|
||||
{
|
||||
return casual(idle()
|
||||
.debug(|| "idling (visiting site does not exist, perhaps it's stale data?)"));
|
||||
} else if ctx.npc.current_site != Some(visiting_site) {
|
||||
let npc_home = ctx.npc.home;
|
||||
// Travel to the site we're supposed to be in
|
||||
return urgent(travel_to_site(visiting_site, 1.0).debug(move || {
|
||||
if npc_home == Some(visiting_site) {
|
||||
"travel home".to_string()
|
||||
} else {
|
||||
"travel to visiting site".to_string()
|
||||
let site_name = ctx.state.data().sites[new_home].world_site
|
||||
.map(|ws| ctx.index.sites.get(ws).name().to_string());
|
||||
return important(just(move |ctx| {
|
||||
if let Some(site_name) = &site_name {
|
||||
ctx.controller.say(None, Content::localized_with_args("npc-speech-migrating", [("site", site_name.clone())]))
|
||||
}
|
||||
}));
|
||||
} else
|
||||
*/
|
||||
})
|
||||
.then(travel_to_site(new_home, 0.5))
|
||||
.then(just(move |ctx| ctx.controller.set_new_home(new_home))));
|
||||
}
|
||||
|
||||
if DayPeriod::from(ctx.time_of_day.0).is_dark()
|
||||
&& !matches!(ctx.npc.profession, Some(Profession::Guard))
|
||||
{
|
||||
|
@ -151,12 +151,8 @@ fn on_death(ctx: EventCtx<SimulateNpcs, OnDeath>) {
|
||||
|
||||
fn on_tick(ctx: EventCtx<SimulateNpcs, OnTick>) {
|
||||
let data = &mut *ctx.state.data_mut();
|
||||
for npc in data
|
||||
.npcs
|
||||
.npcs
|
||||
.values_mut()
|
||||
.filter(|npc| matches!(npc.mode, SimulationMode::Simulated) && !npc.is_dead)
|
||||
{
|
||||
for npc in data.npcs.npcs.values_mut().filter(|npc| !npc.is_dead) {
|
||||
if matches!(npc.mode, SimulationMode::Simulated) {
|
||||
// Simulate NPC movement when riding
|
||||
if let Some(riding) = &npc.riding {
|
||||
if let Some(vehicle) = data.npcs.vehicles.get_mut(riding.vehicle) {
|
||||
@ -248,7 +244,9 @@ fn on_tick(ctx: EventCtx<SimulateNpcs, OnTick>) {
|
||||
.with_z(0.0);
|
||||
}
|
||||
},
|
||||
Some(NpcActivity::Gather(_) | NpcActivity::HuntAnimals | NpcActivity::Dance) => {
|
||||
Some(
|
||||
NpcActivity::Gather(_) | NpcActivity::HuntAnimals | NpcActivity::Dance,
|
||||
) => {
|
||||
// TODO: Maybe they should walk around randomly
|
||||
// when gathering resources?
|
||||
},
|
||||
@ -272,4 +270,10 @@ fn on_tick(ctx: EventCtx<SimulateNpcs, OnTick>) {
|
||||
.unwrap_or(0.0)
|
||||
+ npc.body.flying_height();
|
||||
}
|
||||
|
||||
// Move home if required
|
||||
if let Some(new_home) = npc.controller.new_home.take() {
|
||||
npc.home = Some(new_home);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user