mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Improved herbalist, hunter, farmer, added cultist factions
This commit is contained in:
parent
2aa6ced357
commit
077da13a5f
23
assets/common/entity/village/farmer.ron
Normal file
23
assets/common/entity/village/farmer.ron
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#![enable(implicit_some)]
|
||||||
|
(
|
||||||
|
name: Name("Farmer"),
|
||||||
|
body: RandomWith("humanoid"),
|
||||||
|
alignment: Alignment(Npc),
|
||||||
|
loot: LootTable("common.loot_tables.creature.humanoid"),
|
||||||
|
inventory: (
|
||||||
|
loadout: Inline((
|
||||||
|
inherit: Asset("common.loadout.village.farmer"),
|
||||||
|
active_hands: InHands((Choice([
|
||||||
|
(1, Item("common.items.weapons.tool.hoe")),
|
||||||
|
(1, Item("common.items.weapons.tool.rake")),
|
||||||
|
(1, Item("common.items.weapons.tool.shovel-0")),
|
||||||
|
(1, Item("common.items.weapons.tool.shovel-1")),
|
||||||
|
]), None)),
|
||||||
|
)),
|
||||||
|
items: [
|
||||||
|
(10, "common.items.food.cheese"),
|
||||||
|
(10, "common.items.food.plainsalad"),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
meta: [],
|
||||||
|
)
|
21
assets/common/entity/village/herbalist.ron
Normal file
21
assets/common/entity/village/herbalist.ron
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#![enable(implicit_some)]
|
||||||
|
(
|
||||||
|
name: Name("Herbalist"),
|
||||||
|
body: RandomWith("humanoid"),
|
||||||
|
alignment: Alignment(Npc),
|
||||||
|
loot: LootTable("common.loot_tables.creature.humanoid"),
|
||||||
|
inventory: (
|
||||||
|
loadout: Inline((
|
||||||
|
inherit: Asset("common.loadout.village.herbalist"),
|
||||||
|
active_hands: InHands((Choice([
|
||||||
|
(1, Item("common.items.weapons.tool.hoe")),
|
||||||
|
(1, Item("common.items.weapons.tool.rake")),
|
||||||
|
]), None)),
|
||||||
|
)),
|
||||||
|
items: [
|
||||||
|
(10, "common.items.food.cheese"),
|
||||||
|
(10, "common.items.food.plainsalad"),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
meta: [],
|
||||||
|
)
|
23
assets/common/entity/village/hunter.ron
Normal file
23
assets/common/entity/village/hunter.ron
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#![enable(implicit_some)]
|
||||||
|
(
|
||||||
|
name: Name("Hunter"),
|
||||||
|
body: RandomWith("humanoid"),
|
||||||
|
alignment: Alignment(Npc),
|
||||||
|
loot: LootTable("common.loot_tables.creature.humanoid"),
|
||||||
|
inventory: (
|
||||||
|
loadout: Inline((
|
||||||
|
inherit: Asset("common.loadout.village.hunter"),
|
||||||
|
active_hands: InHands((Choice([
|
||||||
|
(8, ModularWeapon(tool: Bow, material: Wood, hands: None)),
|
||||||
|
(4, ModularWeapon(tool: Bow, material: Bamboo, hands: None)),
|
||||||
|
(2, ModularWeapon(tool: Bow, material: Hardwood, hands: None)),
|
||||||
|
(2, ModularWeapon(tool: Bow, material: Ironwood, hands: None)),
|
||||||
|
(1, ModularWeapon(tool: Bow, material: Eldwood, hands: None)),
|
||||||
|
]), None)),
|
||||||
|
)),
|
||||||
|
items: [
|
||||||
|
(10, "common.items.consumable.potion_big"),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
meta: [],
|
||||||
|
)
|
30
assets/common/loadout/village/farmer.ron
Normal file
30
assets/common/loadout/village/farmer.ron
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
// Christmas event
|
||||||
|
//(1.0, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))),
|
||||||
|
#![enable(implicit_some)]
|
||||||
|
(
|
||||||
|
head: Choice([
|
||||||
|
(3, Item("common.items.armor.misc.head.straw")),
|
||||||
|
(3, Item("common.items.armor.misc.head.bamboo_twig")),
|
||||||
|
(2, None),
|
||||||
|
]),
|
||||||
|
chest: Choice([
|
||||||
|
(1, Item("common.items.armor.misc.chest.worker_green_0")),
|
||||||
|
(1, Item("common.items.armor.misc.chest.worker_green_1")),
|
||||||
|
(1, Item("common.items.armor.misc.chest.worker_red_0")),
|
||||||
|
(1, Item("common.items.armor.misc.chest.worker_red_1")),
|
||||||
|
(1, Item("common.items.armor.misc.chest.worker_purple_0")),
|
||||||
|
(1, Item("common.items.armor.misc.chest.worker_purple_1")),
|
||||||
|
(1, Item("common.items.armor.misc.chest.worker_yellow_0")),
|
||||||
|
(1, Item("common.items.armor.misc.chest.worker_yellow_1")),
|
||||||
|
(1, Item("common.items.armor.misc.chest.worker_orange_0")),
|
||||||
|
(1, Item("common.items.armor.misc.chest.worker_orange_1")),
|
||||||
|
]),
|
||||||
|
legs: Choice([
|
||||||
|
(1, Item("common.items.armor.misc.pants.worker_blue")),
|
||||||
|
(1, Item("common.items.armor.misc.pants.worker_brown")),
|
||||||
|
]),
|
||||||
|
feet: Choice([
|
||||||
|
(1, Item("common.items.armor.misc.foot.sandals")),
|
||||||
|
(1, Item("common.items.armor.cloth_blue.foot")),
|
||||||
|
]),
|
||||||
|
)
|
26
assets/common/loadout/village/herbalist.ron
Normal file
26
assets/common/loadout/village/herbalist.ron
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Christmas event
|
||||||
|
//(1.0, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))),
|
||||||
|
#![enable(implicit_some)]
|
||||||
|
(
|
||||||
|
head: Choice([
|
||||||
|
(3, Item("common.items.armor.misc.head.straw")),
|
||||||
|
(3, Item("common.items.armor.misc.head.hood")),
|
||||||
|
(2, None),
|
||||||
|
]),
|
||||||
|
chest: Choice([
|
||||||
|
(1, Item("common.items.armor.twigs.chest")),
|
||||||
|
(1, Item("common.items.armor.twigsflowers.chest")),
|
||||||
|
(1, Item("common.items.armor.twigsleaves.chest")),
|
||||||
|
]),
|
||||||
|
legs: Choice([
|
||||||
|
(1, Item("common.items.armor.twigs.pants")),
|
||||||
|
(1, Item("common.items.armor.twigsflowers.pants")),
|
||||||
|
(1, Item("common.items.armor.twigsleaves.pants")),
|
||||||
|
]),
|
||||||
|
feet: Choice([
|
||||||
|
(1, Item("common.items.armor.twigs.foot")),
|
||||||
|
(1, Item("common.items.armor.twigsflowers.foot")),
|
||||||
|
(1, Item("common.items.armor.twigsleaves.foot")),
|
||||||
|
(1, Item("common.items.armor.misc.foot.sandals")),
|
||||||
|
]),
|
||||||
|
)
|
28
assets/common/loadout/village/hunter.ron
Normal file
28
assets/common/loadout/village/hunter.ron
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
// Christmas event
|
||||||
|
//(1.0, Some(Item("common.items.calendar.christmas.armor.misc.head.woolly_wintercap"))),
|
||||||
|
#![enable(implicit_some)]
|
||||||
|
(
|
||||||
|
head: Choice([
|
||||||
|
(6, None),
|
||||||
|
(2, Item("common.items.armor.misc.head.straw")),
|
||||||
|
(3, Item("common.items.armor.misc.head.hood")),
|
||||||
|
(3, Item("common.items.armor.misc.head.hood_dark")),
|
||||||
|
]),
|
||||||
|
chest: Choice([
|
||||||
|
(1, Item("common.items.armor.hide.leather.chest")),
|
||||||
|
(1, Item("common.items.armor.hide.rawhide.chest")),
|
||||||
|
(1, Item("common.items.armor.hide.primal.chest")),
|
||||||
|
]),
|
||||||
|
legs: Choice([
|
||||||
|
(1, Item("common.items.armor.hide.leather.pants")),
|
||||||
|
(1, Item("common.items.armor.hide.rawhide.pants")),
|
||||||
|
(1, Item("common.items.armor.hide.primal.pants")),
|
||||||
|
]),
|
||||||
|
feet: Choice([
|
||||||
|
(1, None),
|
||||||
|
(2, Item("common.items.armor.misc.foot.sandals")),
|
||||||
|
(4, Item("common.items.armor.hide.leather.foot")),
|
||||||
|
(4, Item("common.items.armor.hide.rawhide.foot")),
|
||||||
|
(4, Item("common.items.armor.hide.primal.foot")),
|
||||||
|
]),
|
||||||
|
)
|
@ -121,6 +121,8 @@ pub enum Profession {
|
|||||||
Pirate,
|
Pirate,
|
||||||
#[serde(rename = "9")]
|
#[serde(rename = "9")]
|
||||||
Cultist,
|
Cultist,
|
||||||
|
#[serde(rename = "10")]
|
||||||
|
Herbalist,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Profession {
|
impl Profession {
|
||||||
@ -136,6 +138,7 @@ impl Profession {
|
|||||||
Self::Alchemist => "Alchemist".to_string(),
|
Self::Alchemist => "Alchemist".to_string(),
|
||||||
Self::Pirate => "Pirate".to_string(),
|
Self::Pirate => "Pirate".to_string(),
|
||||||
Self::Cultist => "Cultist".to_string(),
|
Self::Cultist => "Cultist".to_string(),
|
||||||
|
Self::Herbalist => "Herbalist".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ use vek::*;
|
|||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
pub struct Faction {
|
pub struct Faction {
|
||||||
pub leader: Option<Actor>,
|
pub leader: Option<Actor>,
|
||||||
|
pub good_or_evil: bool, // TODO: Very stupid, get rid of this
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
@ -5,6 +5,9 @@ use world::{IndexRef, World};
|
|||||||
|
|
||||||
impl Faction {
|
impl Faction {
|
||||||
pub fn generate(world: &World, index: IndexRef, rng: &mut impl Rng) -> Self {
|
pub fn generate(world: &World, index: IndexRef, rng: &mut impl Rng) -> Self {
|
||||||
Self { leader: None }
|
Self {
|
||||||
|
leader: None,
|
||||||
|
good_or_evil: rng.gen(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ impl Data {
|
|||||||
time_of_day: TimeOfDay(settings.start_time),
|
time_of_day: TimeOfDay(settings.start_time),
|
||||||
};
|
};
|
||||||
|
|
||||||
let initial_factions = (0..10)
|
let initial_factions = (0..16)
|
||||||
.map(|_| {
|
.map(|_| {
|
||||||
let faction = Faction::generate(world, index, &mut rng);
|
let faction = Faction::generate(world, index, &mut rng);
|
||||||
let wpos = world
|
let wpos = world
|
||||||
@ -56,7 +56,13 @@ impl Data {
|
|||||||
|
|
||||||
// Register sites with rtsim
|
// Register sites with rtsim
|
||||||
for (world_site_id, _) in index.sites.iter() {
|
for (world_site_id, _) in index.sites.iter() {
|
||||||
let site = Site::generate(world_site_id, world, index, &initial_factions);
|
let site = Site::generate(
|
||||||
|
world_site_id,
|
||||||
|
world,
|
||||||
|
index,
|
||||||
|
&initial_factions,
|
||||||
|
&this.factions,
|
||||||
|
);
|
||||||
this.sites.create(site);
|
this.sites.create(site);
|
||||||
}
|
}
|
||||||
info!(
|
info!(
|
||||||
@ -67,17 +73,23 @@ impl Data {
|
|||||||
// Spawn some test entities at the sites
|
// Spawn some test entities at the sites
|
||||||
for (site_id, site) in this.sites.iter()
|
for (site_id, site) in this.sites.iter()
|
||||||
// TODO: Stupid
|
// TODO: Stupid
|
||||||
.filter(|(_, site)| site.world_site.map_or(false, |ws| matches!(&index.sites.get(ws).kind, SiteKind::Refactor(_))))
|
// .filter(|(_, site)| site.world_site.map_or(false, |ws|
|
||||||
.skip(1)
|
// matches!(&index.sites.get(ws).kind, SiteKind::Refactor(_)))) .skip(1)
|
||||||
.take(1)
|
// .take(1)
|
||||||
{
|
{
|
||||||
|
let good_or_evil = site
|
||||||
|
.faction
|
||||||
|
.and_then(|f| this.factions.get(f))
|
||||||
|
.map_or(true, |f| f.good_or_evil);
|
||||||
|
|
||||||
let rand_wpos = |rng: &mut SmallRng| {
|
let rand_wpos = |rng: &mut SmallRng| {
|
||||||
let wpos2d = site.wpos.map(|e| e + rng.gen_range(-10..10));
|
let wpos2d = site.wpos.map(|e| e + rng.gen_range(-10..10));
|
||||||
wpos2d
|
wpos2d
|
||||||
.map(|e| e as f32 + 0.5)
|
.map(|e| e as f32 + 0.5)
|
||||||
.with_z(world.sim().get_alt_approx(wpos2d).unwrap_or(0.0))
|
.with_z(world.sim().get_alt_approx(wpos2d).unwrap_or(0.0))
|
||||||
};
|
};
|
||||||
for _ in 0..16 {
|
if good_or_evil {
|
||||||
|
for _ in 0..32 {
|
||||||
this.npcs.create(
|
this.npcs.create(
|
||||||
Npc::new(rng.gen(), rand_wpos(&mut rng))
|
Npc::new(rng.gen(), rand_wpos(&mut rng))
|
||||||
.with_faction(site.faction)
|
.with_faction(site.faction)
|
||||||
@ -87,12 +99,25 @@ impl Data {
|
|||||||
1 => Profession::Blacksmith,
|
1 => Profession::Blacksmith,
|
||||||
2 => Profession::Chef,
|
2 => Profession::Chef,
|
||||||
3 => Profession::Alchemist,
|
3 => Profession::Alchemist,
|
||||||
5..=10 => Profession::Farmer,
|
5..=8 => Profession::Farmer,
|
||||||
|
9..=10 => Profession::Herbalist,
|
||||||
11..=15 => Profession::Guard,
|
11..=15 => Profession::Guard,
|
||||||
_ => Profession::Adventurer(rng.gen_range(0..=3)),
|
_ => Profession::Adventurer(rng.gen_range(0..=3)),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
for _ in 0..5 {
|
||||||
|
this.npcs.create(
|
||||||
|
Npc::new(rng.gen(), rand_wpos(&mut rng))
|
||||||
|
.with_faction(site.faction)
|
||||||
|
.with_home(site_id)
|
||||||
|
.with_profession(match rng.gen_range(0..20) {
|
||||||
|
_ => Profession::Cultist,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
this.npcs.create(
|
this.npcs.create(
|
||||||
Npc::new(rng.gen(), rand_wpos(&mut rng))
|
Npc::new(rng.gen(), rand_wpos(&mut rng))
|
||||||
.with_home(site_id)
|
.with_home(site_id)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::data::{FactionId, Site};
|
use crate::data::{FactionId, Factions, Site};
|
||||||
use common::store::Id;
|
use common::store::Id;
|
||||||
use vek::*;
|
use vek::*;
|
||||||
use world::{
|
use world::{
|
||||||
@ -12,24 +12,42 @@ impl Site {
|
|||||||
world: &World,
|
world: &World,
|
||||||
index: IndexRef,
|
index: IndexRef,
|
||||||
nearby_factions: &[(Vec2<i32>, FactionId)],
|
nearby_factions: &[(Vec2<i32>, FactionId)],
|
||||||
|
factions: &Factions,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let world_site = index.sites.get(world_site_id);
|
let world_site = index.sites.get(world_site_id);
|
||||||
let wpos = world_site.get_origin();
|
let wpos = world_site.get_origin();
|
||||||
|
|
||||||
|
// TODO: This is stupid, do better
|
||||||
|
let good_or_evil = match &world_site.kind {
|
||||||
|
// Good
|
||||||
|
SiteKind::Refactor(_)
|
||||||
|
| SiteKind::CliffTown(_)
|
||||||
|
| SiteKind::DesertCity(_)
|
||||||
|
| SiteKind::SavannahPit(_) => Some(true),
|
||||||
|
// Evil
|
||||||
|
SiteKind::Dungeon(_) | SiteKind::ChapelSite(_) | SiteKind::Gnarling(_) => Some(false),
|
||||||
|
// Neutral
|
||||||
|
SiteKind::Settlement(_)
|
||||||
|
| SiteKind::Castle(_)
|
||||||
|
| SiteKind::Tree(_)
|
||||||
|
| SiteKind::GiantTree(_)
|
||||||
|
| SiteKind::Bridge(_) => None,
|
||||||
|
};
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
wpos,
|
wpos,
|
||||||
world_site: Some(world_site_id),
|
world_site: Some(world_site_id),
|
||||||
faction: if matches!(
|
faction: good_or_evil.and_then(|good_or_evil| {
|
||||||
&world_site.kind,
|
|
||||||
SiteKind::Refactor(_) | SiteKind::CliffTown(_) | SiteKind::DesertCity(_)
|
|
||||||
) {
|
|
||||||
nearby_factions
|
nearby_factions
|
||||||
.iter()
|
.iter()
|
||||||
|
.filter(|(_, faction)| {
|
||||||
|
factions
|
||||||
|
.get(*faction)
|
||||||
|
.map_or(false, |f| f.good_or_evil == good_or_evil)
|
||||||
|
})
|
||||||
.min_by_key(|(faction_wpos, _)| faction_wpos.distance_squared(wpos))
|
.min_by_key(|(faction_wpos, _)| faction_wpos.distance_squared(wpos))
|
||||||
.map(|(_, faction)| *faction)
|
.map(|(_, faction)| *faction)
|
||||||
} else {
|
}),
|
||||||
None
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -317,10 +317,9 @@ impl Rule for NpcAi {
|
|||||||
fn idle() -> impl Action { just(|ctx| *ctx.controller = Controller::idle()).debug(|| "idle") }
|
fn idle() -> impl Action { just(|ctx| *ctx.controller = Controller::idle()).debug(|| "idle") }
|
||||||
|
|
||||||
/// Try to walk toward a 3D position without caring for obstacles.
|
/// Try to walk toward a 3D position without caring for obstacles.
|
||||||
fn goto(wpos: Vec3<f32>, speed_factor: f32) -> impl Action {
|
fn goto(wpos: Vec3<f32>, speed_factor: f32, goal_dist: f32) -> impl Action {
|
||||||
const STEP_DIST: f32 = 24.0;
|
const STEP_DIST: f32 = 24.0;
|
||||||
const WAYPOINT_DIST: f32 = 12.0;
|
const WAYPOINT_DIST: f32 = 12.0;
|
||||||
const GOAL_DIST: f32 = 2.0;
|
|
||||||
|
|
||||||
let mut waypoint = None;
|
let mut waypoint = None;
|
||||||
|
|
||||||
@ -342,19 +341,19 @@ fn goto(wpos: Vec3<f32>, speed_factor: f32) -> impl Action {
|
|||||||
ctx.controller.goto = Some((*waypoint, speed_factor));
|
ctx.controller.goto = Some((*waypoint, speed_factor));
|
||||||
})
|
})
|
||||||
.repeat()
|
.repeat()
|
||||||
.stop_if(move |ctx| ctx.npc.wpos.xy().distance_squared(wpos.xy()) < GOAL_DIST.powi(2))
|
.stop_if(move |ctx| ctx.npc.wpos.xy().distance_squared(wpos.xy()) < goal_dist.powi(2))
|
||||||
.debug(move || format!("goto {}, {}, {}", wpos.x, wpos.y, wpos.z))
|
.debug(move || format!("goto {}, {}, {}", wpos.x, wpos.y, wpos.z))
|
||||||
.map(|_| {})
|
.map(|_| {})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to walk toward a 2D position on the terrain without caring for
|
/// Try to walk toward a 2D position on the terrain without caring for
|
||||||
/// obstacles.
|
/// obstacles.
|
||||||
fn goto_2d(wpos2d: Vec2<f32>, speed_factor: f32) -> impl Action {
|
fn goto_2d(wpos2d: Vec2<f32>, speed_factor: f32, goal_dist: f32) -> impl Action {
|
||||||
const MIN_DIST: f32 = 2.0;
|
const MIN_DIST: f32 = 2.0;
|
||||||
|
|
||||||
now(move |ctx| {
|
now(move |ctx| {
|
||||||
let wpos = wpos2d.with_z(ctx.world.sim().get_alt_approx(wpos2d.as_()).unwrap_or(0.0));
|
let wpos = wpos2d.with_z(ctx.world.sim().get_alt_approx(wpos2d.as_()).unwrap_or(0.0));
|
||||||
goto(wpos, speed_factor)
|
goto(wpos, speed_factor, goal_dist)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -399,7 +398,7 @@ fn travel_to_site(tgt_site: SiteId) -> impl Action {
|
|||||||
.map_or(node_chunk_wpos, |(_, wpos, _, _)| wpos.as_());
|
.map_or(node_chunk_wpos, |(_, wpos, _, _)| wpos.as_());
|
||||||
|
|
||||||
// Walk toward the node
|
// Walk toward the node
|
||||||
goto_2d(node_wpos.as_(), 1.0)
|
goto_2d(node_wpos.as_(), 1.0, 8.0)
|
||||||
.debug(move || format!("traversing track node ({}/{})", i + 1, track_len))
|
.debug(move || format!("traversing track node ({}/{})", i + 1, track_len))
|
||||||
})))
|
})))
|
||||||
})
|
})
|
||||||
@ -407,7 +406,7 @@ fn travel_to_site(tgt_site: SiteId) -> impl Action {
|
|||||||
.boxed()
|
.boxed()
|
||||||
} else if let Some(site) = sites.get(tgt_site) {
|
} else if let Some(site) = sites.get(tgt_site) {
|
||||||
// If all else fails, just walk toward the target site in a straight line
|
// If all else fails, just walk toward the target site in a straight line
|
||||||
goto_2d(site.wpos.map(|e| e as f32 + 0.5), 1.0).boxed()
|
goto_2d(site.wpos.map(|e| e as f32 + 0.5), 1.0, 8.0).boxed()
|
||||||
} else {
|
} else {
|
||||||
// If we can't find a way to get to the site at all, there's nothing more to be done
|
// If we can't find a way to get to the site at all, there's nothing more to be done
|
||||||
finish().boxed()
|
finish().boxed()
|
||||||
@ -431,10 +430,16 @@ fn adventure() -> impl Action {
|
|||||||
.sites
|
.sites
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(site_id, site)| {
|
.filter(|(site_id, site)| {
|
||||||
// TODO: faction.is_some() is used as a proxy for whether the site likely has
|
// Only path toward towns
|
||||||
// paths, don't do this
|
matches!(
|
||||||
site.faction.is_some()
|
site.world_site.map(|ws| &ctx.index.sites.get(ws).kind),
|
||||||
&& ctx.npc.current_site.map_or(true, |cs| *site_id != cs)
|
Some(
|
||||||
|
SiteKind::Refactor(_)
|
||||||
|
| SiteKind::CliffTown(_)
|
||||||
|
| SiteKind::SavannahPit(_)
|
||||||
|
| SiteKind::DesertCity(_)
|
||||||
|
),
|
||||||
|
) && ctx.npc.current_site.map_or(true, |cs| *site_id != cs)
|
||||||
&& thread_rng().gen_bool(0.25)
|
&& thread_rng().gen_bool(0.25)
|
||||||
})
|
})
|
||||||
.min_by_key(|(_, site)| site.wpos.as_().distance(ctx.npc.wpos.xy()) as i32)
|
.min_by_key(|(_, site)| site.wpos.as_().distance(ctx.npc.wpos.xy()) as i32)
|
||||||
@ -487,7 +492,7 @@ fn villager(visiting_site: SiteId) -> impl Action {
|
|||||||
Some(site2.tile_center_wpos(house.root_tile()).as_())
|
Some(site2.tile_center_wpos(house.root_tile()).as_())
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
goto_2d(house_wpos, 0.5)
|
goto_2d(house_wpos, 0.5, 1.0)
|
||||||
.debug(|| "walk to house")
|
.debug(|| "walk to house")
|
||||||
.then(idle().repeat().debug(|| "wait in house"))
|
.then(idle().repeat().debug(|| "wait in house"))
|
||||||
.stop_if(|ctx| DayPeriod::from(ctx.time_of_day.0).is_light())
|
.stop_if(|ctx| DayPeriod::from(ctx.time_of_day.0).is_light())
|
||||||
@ -514,7 +519,7 @@ fn villager(visiting_site: SiteId) -> impl Action {
|
|||||||
})
|
})
|
||||||
{
|
{
|
||||||
// Walk to the plaza...
|
// Walk to the plaza...
|
||||||
goto_2d(plaza_wpos, 0.5)
|
goto_2d(plaza_wpos, 0.5, 8.0)
|
||||||
.debug(|| "walk to plaza")
|
.debug(|| "walk to plaza")
|
||||||
// ...then wait for some time before moving on
|
// ...then wait for some time before moving on
|
||||||
.then({
|
.then({
|
||||||
|
@ -48,8 +48,13 @@ impl Rule for Setup {
|
|||||||
be generated afresh.",
|
be generated afresh.",
|
||||||
world_site_id
|
world_site_id
|
||||||
);
|
);
|
||||||
data.sites
|
data.sites.create(Site::generate(
|
||||||
.create(Site::generate(world_site_id, ctx.world, ctx.index, &[]));
|
world_site_id,
|
||||||
|
ctx.world,
|
||||||
|
ctx.index,
|
||||||
|
&[],
|
||||||
|
&data.factions,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,9 @@ use world::site::settlement::trader_loadout;
|
|||||||
|
|
||||||
fn humanoid_config(profession: &Profession) -> &'static str {
|
fn humanoid_config(profession: &Profession) -> &'static str {
|
||||||
match profession {
|
match profession {
|
||||||
Profession::Farmer | Profession::Hunter => "common.entity.village.villager",
|
Profession::Farmer => "common.entity.village.farmer",
|
||||||
|
Profession::Hunter => "common.entity.village.hunter",
|
||||||
|
Profession::Herbalist => "common.entity.village.herbalist",
|
||||||
Profession::Merchant => "common.entity.village.merchant",
|
Profession::Merchant => "common.entity.village.merchant",
|
||||||
Profession::Guard => "common.entity.village.guard",
|
Profession::Guard => "common.entity.village.guard",
|
||||||
Profession::Adventurer(rank) => match rank {
|
Profession::Adventurer(rank) => match rank {
|
||||||
@ -59,6 +61,15 @@ fn farmer_loadout(
|
|||||||
trader_loadout(loadout_builder, economy, |good| matches!(good, Good::Food))
|
trader_loadout(loadout_builder, economy, |good| matches!(good, Good::Food))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn herbalist_loadout(
|
||||||
|
loadout_builder: LoadoutBuilder,
|
||||||
|
economy: Option<&SiteInformation>,
|
||||||
|
) -> LoadoutBuilder {
|
||||||
|
trader_loadout(loadout_builder, economy, |good| {
|
||||||
|
matches!(good, Good::Ingredients)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn chef_loadout(
|
fn chef_loadout(
|
||||||
loadout_builder: LoadoutBuilder,
|
loadout_builder: LoadoutBuilder,
|
||||||
economy: Option<&SiteInformation>,
|
economy: Option<&SiteInformation>,
|
||||||
@ -90,6 +101,7 @@ fn profession_extra_loadout(
|
|||||||
match profession {
|
match profession {
|
||||||
Some(Profession::Merchant) => merchant_loadout,
|
Some(Profession::Merchant) => merchant_loadout,
|
||||||
Some(Profession::Farmer) => farmer_loadout,
|
Some(Profession::Farmer) => farmer_loadout,
|
||||||
|
Some(Profession::Herbalist) => herbalist_loadout,
|
||||||
Some(Profession::Chef) => chef_loadout,
|
Some(Profession::Chef) => chef_loadout,
|
||||||
Some(Profession::Blacksmith) => blacksmith_loadout,
|
Some(Profession::Blacksmith) => blacksmith_loadout,
|
||||||
Some(Profession::Alchemist) => alchemist_loadout,
|
Some(Profession::Alchemist) => alchemist_loadout,
|
||||||
@ -102,6 +114,7 @@ fn profession_agent_mark(profession: Option<&Profession>) -> Option<comp::agent:
|
|||||||
Some(
|
Some(
|
||||||
Profession::Merchant
|
Profession::Merchant
|
||||||
| Profession::Farmer
|
| Profession::Farmer
|
||||||
|
| Profession::Herbalist
|
||||||
| Profession::Chef
|
| Profession::Chef
|
||||||
| Profession::Blacksmith
|
| Profession::Blacksmith
|
||||||
| Profession::Alchemist,
|
| Profession::Alchemist,
|
||||||
@ -128,7 +141,11 @@ fn get_npc_entity_info(npc: &Npc, sites: &Sites, index: IndexRef) -> EntityInfo
|
|||||||
let mut rng = npc.rng(3);
|
let mut rng = npc.rng(3);
|
||||||
EntityInfo::at(pos.0)
|
EntityInfo::at(pos.0)
|
||||||
.with_entity_config(entity_config, Some(config_asset), &mut rng)
|
.with_entity_config(entity_config, Some(config_asset), &mut rng)
|
||||||
.with_alignment(comp::Alignment::Npc)
|
.with_alignment(if matches!(profession, Profession::Cultist) {
|
||||||
|
comp::Alignment::Enemy
|
||||||
|
} else {
|
||||||
|
comp::Alignment::Npc
|
||||||
|
})
|
||||||
.with_maybe_economy(economy.as_ref())
|
.with_maybe_economy(economy.as_ref())
|
||||||
.with_lazy_loadout(profession_extra_loadout(npc.profession.as_ref()))
|
.with_lazy_loadout(profession_extra_loadout(npc.profession.as_ref()))
|
||||||
.with_maybe_agent_mark(profession_agent_mark(npc.profession.as_ref()))
|
.with_maybe_agent_mark(profession_agent_mark(npc.profession.as_ref()))
|
||||||
|
Loading…
Reference in New Issue
Block a user