diff --git a/rtsim/src/gen/mod.rs b/rtsim/src/gen/mod.rs index c3977eb851..757cc68ef0 100644 --- a/rtsim/src/gen/mod.rs +++ b/rtsim/src/gen/mod.rs @@ -18,7 +18,7 @@ use common::{ use rand::prelude::*; use tracing::info; use vek::*; -use world::{site::SiteKind, IndexRef, World}; +use world::{site::SiteKind, site2::PlotKind, IndexRef, World}; impl Data { pub fn generate(settings: &WorldSettings, world: &World, index: IndexRef) -> Self { @@ -77,10 +77,16 @@ impl Data { this.sites.len() ); // Spawn some test entities at the sites - for (site_id, site) in this.sites.iter() - // TODO: Stupid - .filter(|(_, site)| site.world_site.map_or(false, |ws| - matches!(&index.sites.get(ws).kind, SiteKind::Refactor(_)))) + for (site_id, site, site2) in this.sites.iter() + // TODO: Stupid. Only find site2 towns + .filter_map(|(site_id, site)| Some((site_id, site, site.world_site + .and_then(|ws| match &index.sites.get(ws).kind { + SiteKind::Refactor(site2) + | SiteKind::CliffTown(site2) + | SiteKind::SavannahPit(site2) + | SiteKind::DesertCity(site2) => Some(site2), + _ => None, + })?))) { let Some(good_or_evil) = site .faction @@ -88,8 +94,13 @@ impl Data { .map(|f| f.good_or_evil) else { continue }; - let rand_wpos = |rng: &mut SmallRng| { - let wpos2d = site.wpos.map(|e| e + rng.gen_range(-10..10)); + let rand_wpos = |rng: &mut SmallRng, matches_plot: fn(&PlotKind) -> bool| { + let wpos2d = site2 + .plots() + .filter(|plot| matches_plot(plot.kind())) + .choose(&mut thread_rng()) + .map(|plot| site2.tile_center_wpos(plot.root_tile())) + .unwrap_or_else(|| site.wpos.map(|e| e + rng.gen_range(-10..10))); wpos2d .map(|e| e as f32 + 0.5) .with_z(world.sim().get_alt_approx(wpos2d).unwrap_or(0.0)) @@ -98,47 +109,71 @@ impl Data { let species = comp::humanoid::ALL_SPECIES.choose(&mut *rng).unwrap(); Body::Humanoid(comp::humanoid::Body::random_with(rng, species)) }; + let matches_buildings = (|kind: &PlotKind| { + matches!( + kind, + PlotKind::House(_) | PlotKind::Workshop(_) | PlotKind::Plaza + ) + }) as _; + let matches_plazas = (|kind: &PlotKind| matches!(kind, PlotKind::Plaza)) as _; if good_or_evil { - for _ in 0..32 { + for _ in 0..site2.plots().len() { this.npcs.create_npc( - Npc::new(rng.gen(), rand_wpos(&mut rng), random_humanoid(&mut rng)) - .with_faction(site.faction) - .with_home(site_id) - .with_personality(Personality::random(&mut rng)) - .with_profession(match rng.gen_range(0..20) { - 0 => Profession::Hunter, - 1 => Profession::Blacksmith, - 2 => Profession::Chef, - 3 => Profession::Alchemist, - 5..=8 => Profession::Farmer, - 9..=10 => Profession::Herbalist, - 11..=15 => Profession::Guard, - _ => Profession::Adventurer(rng.gen_range(0..=3)), - }), + Npc::new( + rng.gen(), + rand_wpos(&mut rng, matches_buildings), + random_humanoid(&mut rng), + ) + .with_faction(site.faction) + .with_home(site_id) + .with_personality(Personality::random(&mut rng)) + .with_profession(match rng.gen_range(0..20) { + 0 => Profession::Hunter, + 1 => Profession::Blacksmith, + 2 => Profession::Chef, + 3 => Profession::Alchemist, + 5..=8 => Profession::Farmer, + 9..=10 => Profession::Herbalist, + 11..=16 => Profession::Guard, + _ => Profession::Adventurer(rng.gen_range(0..=3)), + }), ); } } else { for _ in 0..15 { this.npcs.create_npc( - Npc::new(rng.gen(), rand_wpos(&mut rng), random_humanoid(&mut rng)) - .with_personality(Personality::random_evil(&mut rng)) - .with_faction(site.faction) - .with_home(site_id) - .with_profession(match rng.gen_range(0..20) { - _ => Profession::Cultist, - }), + Npc::new( + rng.gen(), + rand_wpos(&mut rng, matches_buildings), + random_humanoid(&mut rng), + ) + .with_personality(Personality::random_evil(&mut rng)) + .with_faction(site.faction) + .with_home(site_id) + .with_profession(match rng.gen_range(0..20) { + _ => Profession::Cultist, + }), + ); + } + } + // Merchants + if good_or_evil { + for _ in 0..(site2.plots().len() / 6) + 1 { + this.npcs.create_npc( + Npc::new( + rng.gen(), + rand_wpos(&mut rng, matches_plazas), + random_humanoid(&mut rng), + ) + .with_home(site_id) + .with_personality(Personality::random_good(&mut rng)) + .with_profession(Profession::Merchant), ); } } - this.npcs.create_npc( - Npc::new(rng.gen(), rand_wpos(&mut rng), random_humanoid(&mut rng)) - .with_home(site_id) - .with_personality(Personality::random_good(&mut rng)) - .with_profession(Profession::Merchant), - ); if rng.gen_bool(0.4) { - let wpos = rand_wpos(&mut rng) + Vec3::unit_z() * 50.0; + let wpos = rand_wpos(&mut rng, matches_plazas) + Vec3::unit_z() * 50.0; let vehicle_id = this .npcs .create_vehicle(Vehicle::new(wpos, comp::body::ship::Body::DefaultAirship)); diff --git a/rtsim/src/rule/npc_ai.rs b/rtsim/src/rule/npc_ai.rs index 1e0977b681..5e5df3c3a8 100644 --- a/rtsim/src/rule/npc_ai.rs +++ b/rtsim/src/rule/npc_ai.rs @@ -395,13 +395,13 @@ fn travel_to_point(wpos: Vec2) -> impl Action { const WAYPOINT: f32 = 24.0; let start = ctx.npc.wpos.xy(); let diff = wpos - start; + // if diff.magnitude() > 1.0 { let n = (diff.magnitude() / WAYPOINT).max(1.0); let mut points = (1..n as usize + 1).map(move |i| start + diff * (i as f32 / n)); - if diff.magnitude() > 1.0 { - traverse_points(move |_| points.next()).boxed() - } else { - finish().boxed() - } + traverse_points(move |_| points.next()).boxed() + // } else { + // finish().boxed() + // } }) .debug(|| "travel to point") } @@ -525,11 +525,16 @@ fn adventure() -> impl Action { .min_by_key(|(_, site)| site.wpos.as_().distance(ctx.npc.wpos.xy()) as i32) .map(|(site_id, _)| site_id) { + let wait_time = if matches!(ctx.npc.profession, Some(Profession::Merchant)) { + 60.0 * 15.0 + } else { + 60.0 * 3.0 + }; // Travel to the site important( travel_to_site(tgt_site) // Stop for a few minutes - .then(villager(tgt_site).repeat().stop_if(timeout(60.0 * 3.0))) + .then(villager(tgt_site).repeat().stop_if(timeout(wait_time))) .map(|_| ()) .boxed(), ) diff --git a/server/src/rtsim2/mod.rs b/server/src/rtsim2/mod.rs index a4bffb6164..bb9ffb763b 100644 --- a/server/src/rtsim2/mod.rs +++ b/server/src/rtsim2/mod.rs @@ -212,7 +212,7 @@ impl RtSim { }); if wait_until_finished { - handle.join(); + handle.join().expect("Save thread failed to join"); } self.last_saved = Some(Instant::now());