mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
cleaner entity creation
This commit is contained in:
parent
e7798f2a4e
commit
ca02b5e97c
@ -6,6 +6,7 @@
|
|||||||
loot: LootTable("common.loot_tables.creature.humanoid"),
|
loot: LootTable("common.loot_tables.creature.humanoid"),
|
||||||
inventory: (
|
inventory: (
|
||||||
loadout: Inline((
|
loadout: Inline((
|
||||||
|
inherit: Asset("common.loadout.village.merchant"),
|
||||||
active_hands: InHands((Choice([
|
active_hands: InHands((Choice([
|
||||||
(2, ModularWeapon(tool: Bow, material: Eldwood, hands: None)),
|
(2, ModularWeapon(tool: Bow, material: Eldwood, hands: None)),
|
||||||
(1, ModularWeapon(tool: Sword, material: Steel, hands: None)),
|
(1, ModularWeapon(tool: Sword, material: Steel, hands: None)),
|
||||||
|
@ -379,6 +379,12 @@ impl EntityInfo {
|
|||||||
self.agent_mark = Some(agent_mark);
|
self.agent_mark = Some(agent_mark);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn with_maybe_agent_mark(mut self, agent_mark: Option<agent::Mark>) -> Self {
|
||||||
|
self.agent_mark = agent_mark;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_loot_drop(mut self, loot_drop: LootSpec<String>) -> Self {
|
pub fn with_loot_drop(mut self, loot_drop: LootSpec<String>) -> Self {
|
||||||
@ -441,6 +447,13 @@ impl EntityInfo {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// map contains price+amount
|
||||||
|
#[must_use]
|
||||||
|
pub fn with_maybe_economy(mut self, e: Option<&SiteInformation>) -> Self {
|
||||||
|
self.trading_information = e.cloned();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_no_flee(mut self) -> Self {
|
pub fn with_no_flee(mut self) -> Self {
|
||||||
self.no_flee = true;
|
self.no_flee = true;
|
||||||
|
@ -108,6 +108,14 @@ pub enum Profession {
|
|||||||
Adventurer(u32),
|
Adventurer(u32),
|
||||||
#[serde(rename = "5")]
|
#[serde(rename = "5")]
|
||||||
Blacksmith,
|
Blacksmith,
|
||||||
|
#[serde(rename = "6")]
|
||||||
|
Chef,
|
||||||
|
#[serde(rename = "7")]
|
||||||
|
Alchemist,
|
||||||
|
#[serde(rename = "8")]
|
||||||
|
Pirate,
|
||||||
|
#[serde(rename = "9")]
|
||||||
|
Cultist,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Profession {
|
impl Profession {
|
||||||
@ -119,6 +127,10 @@ impl Profession {
|
|||||||
Self::Guard => "Guard".to_string(),
|
Self::Guard => "Guard".to_string(),
|
||||||
Self::Adventurer(_) => "Adventurer".to_string(),
|
Self::Adventurer(_) => "Adventurer".to_string(),
|
||||||
Self::Blacksmith => "Blacksmith".to_string(),
|
Self::Blacksmith => "Blacksmith".to_string(),
|
||||||
|
Self::Chef => "Chef".to_string(),
|
||||||
|
Self::Alchemist => "Alchemist".to_string(),
|
||||||
|
Self::Pirate => "Pirate".to_string(),
|
||||||
|
Self::Cultist => "Cultist".to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,10 +52,12 @@ impl Data {
|
|||||||
};
|
};
|
||||||
for _ in 0..20 {
|
for _ in 0..20 {
|
||||||
|
|
||||||
this.npcs.create(Npc::new(rng.gen(), rand_wpos(&mut rng)).with_home(site_id).with_profession(match rng.gen_range(0..10) {
|
this.npcs.create(Npc::new(rng.gen(), rand_wpos(&mut rng)).with_home(site_id).with_profession(match rng.gen_range(0..15) {
|
||||||
0 => Profession::Hunter,
|
0 => Profession::Hunter,
|
||||||
1 => Profession::Blacksmith,
|
1 => Profession::Blacksmith,
|
||||||
2..=4 => Profession::Farmer,
|
2 => Profession::Chef,
|
||||||
|
3 => Profession::Alchemist,
|
||||||
|
5..=10 => Profession::Farmer,
|
||||||
_ => Profession::Guard,
|
_ => Profession::Guard,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -9,15 +9,114 @@ use common::{
|
|||||||
resources::{DeltaTime, Time, TimeOfDay},
|
resources::{DeltaTime, Time, TimeOfDay},
|
||||||
rtsim::{RtSimController, RtSimEntity},
|
rtsim::{RtSimController, RtSimEntity},
|
||||||
slowjob::SlowJobPool,
|
slowjob::SlowJobPool,
|
||||||
trade::Good,
|
trade::{Good, SiteInformation},
|
||||||
LoadoutBuilder,
|
LoadoutBuilder,
|
||||||
SkillSetBuilder,
|
SkillSetBuilder,
|
||||||
};
|
};
|
||||||
use common_ecs::{Job, Origin, Phase, System};
|
use common_ecs::{Job, Origin, Phase, System};
|
||||||
use rtsim2::data::npc::{NpcMode, Profession};
|
use rtsim2::data::{npc::{NpcMode, Profession}, Npc, Sites};
|
||||||
use specs::{Join, Read, ReadExpect, ReadStorage, WriteExpect, WriteStorage};
|
use specs::{Join, Read, ReadExpect, ReadStorage, WriteExpect, WriteStorage};
|
||||||
use std::{sync::Arc, time::Duration};
|
use std::{sync::Arc, time::Duration};
|
||||||
use world::site::settlement::{merchant_loadout, trader_loadout};
|
use world::site::settlement::trader_loadout;
|
||||||
|
|
||||||
|
fn humanoid_config(profession: &Profession) -> &'static str {
|
||||||
|
match profession {
|
||||||
|
Profession::Farmer | Profession::Hunter => "common.entity.village.villager",
|
||||||
|
Profession::Merchant => "common.entity.village.merchant",
|
||||||
|
Profession::Guard => "common.entity.village.guard",
|
||||||
|
Profession::Adventurer(rank) => match rank {
|
||||||
|
0 => "common.entity.world.traveler0",
|
||||||
|
1 => "common.entity.world.traveler1",
|
||||||
|
2 => "common.entity.world.traveler2",
|
||||||
|
_ => "common.entity.world.traveler3",
|
||||||
|
},
|
||||||
|
Profession::Blacksmith => "common.entity.village.blacksmith",
|
||||||
|
Profession::Chef => "common.entity.village.chef",
|
||||||
|
Profession::Alchemist => "common.entity.village.alchemist",
|
||||||
|
Profession::Pirate => "common.entity.spot.pirate",
|
||||||
|
Profession::Cultist => "common.entity.dungeon.tier-5.cultist",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn loadout_default(loadout: LoadoutBuilder, _economy: Option<&SiteInformation>) -> LoadoutBuilder {
|
||||||
|
loadout
|
||||||
|
}
|
||||||
|
|
||||||
|
fn merchant_loadout(
|
||||||
|
loadout_builder: LoadoutBuilder,
|
||||||
|
economy: Option<&SiteInformation>,
|
||||||
|
) -> LoadoutBuilder {
|
||||||
|
trader_loadout(loadout_builder, economy, |_| true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn farmer_loadout(
|
||||||
|
loadout_builder: LoadoutBuilder,
|
||||||
|
economy: Option<&SiteInformation>,
|
||||||
|
) -> LoadoutBuilder {
|
||||||
|
trader_loadout(loadout_builder, economy, |good| matches!(good, Good::Food))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn chef_loadout(
|
||||||
|
loadout_builder: LoadoutBuilder,
|
||||||
|
economy: Option<&SiteInformation>,
|
||||||
|
) -> LoadoutBuilder {
|
||||||
|
trader_loadout(loadout_builder, economy, |good| matches!(good, Good::Food))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn blacksmith_loadout(
|
||||||
|
loadout_builder: LoadoutBuilder,
|
||||||
|
economy: Option<&SiteInformation>,
|
||||||
|
) -> LoadoutBuilder {
|
||||||
|
trader_loadout(loadout_builder, economy, |good| matches!(good, Good::Tools | Good::Armor))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn profession_extra_loadout(profession: Option<&Profession>) -> fn(LoadoutBuilder, Option<&SiteInformation>) -> LoadoutBuilder {
|
||||||
|
match profession {
|
||||||
|
Some(Profession::Merchant) => merchant_loadout,
|
||||||
|
Some(Profession::Farmer) => farmer_loadout,
|
||||||
|
Some(Profession::Chef) => chef_loadout,
|
||||||
|
Some(Profession::Blacksmith) => blacksmith_loadout,
|
||||||
|
_ => loadout_default,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn profession_agent_mark(profession: Option<&Profession>) -> Option<comp::agent::Mark> {
|
||||||
|
match profession {
|
||||||
|
Some(Profession::Merchant | Profession::Farmer | Profession::Chef | Profession::Blacksmith) => Some(comp::agent::Mark::Merchant),
|
||||||
|
Some(Profession::Guard) => Some(comp::agent::Mark::Guard),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_npc_entity_info(npc: &Npc, sites: &Sites, index: IndexRef) -> EntityInfo {
|
||||||
|
let body = npc.get_body();
|
||||||
|
let pos = comp::Pos(npc.wpos);
|
||||||
|
|
||||||
|
if let Some(ref profession) = npc.profession {
|
||||||
|
|
||||||
|
let economy = npc.home
|
||||||
|
.and_then(|home| {
|
||||||
|
let site = sites.get(home)?.world_site?;
|
||||||
|
index.sites.get(site).trade_information(site.id())
|
||||||
|
});
|
||||||
|
|
||||||
|
let config_asset = humanoid_config(profession);
|
||||||
|
|
||||||
|
let entity_config = EntityConfig::from_asset_expect_owned(config_asset).with_body(BodyBuilder::Exact(body));
|
||||||
|
let mut rng = npc.rng(3);
|
||||||
|
EntityInfo::at(pos.0)
|
||||||
|
.with_entity_config(entity_config, Some(config_asset), &mut rng)
|
||||||
|
.with_alignment(comp::Alignment::Npc)
|
||||||
|
.with_maybe_economy(economy.as_ref())
|
||||||
|
.with_lazy_loadout(profession_extra_loadout(npc.profession.as_ref()))
|
||||||
|
.with_maybe_agent_mark(profession_agent_mark(npc.profession.as_ref()))
|
||||||
|
} else {
|
||||||
|
EntityInfo::at(pos.0)
|
||||||
|
.with_body(body)
|
||||||
|
.with_alignment(comp::Alignment::Wild)
|
||||||
|
.with_name("Rtsim NPC")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Sys;
|
pub struct Sys;
|
||||||
@ -46,7 +145,7 @@ impl<'a> System<'a> for Sys {
|
|||||||
dt,
|
dt,
|
||||||
time,
|
time,
|
||||||
time_of_day,
|
time_of_day,
|
||||||
mut server_event_bus,
|
server_event_bus,
|
||||||
mut rtsim,
|
mut rtsim,
|
||||||
world,
|
world,
|
||||||
index,
|
index,
|
||||||
@ -82,81 +181,42 @@ impl<'a> System<'a> for Sys {
|
|||||||
&& chunk_states.0.get(chunk).map_or(false, |c| c.is_some())
|
&& chunk_states.0.get(chunk).map_or(false, |c| c.is_some())
|
||||||
{
|
{
|
||||||
npc.mode = NpcMode::Loaded;
|
npc.mode = NpcMode::Loaded;
|
||||||
let body = npc.get_body();
|
|
||||||
let mut loadout_builder = LoadoutBuilder::from_default(&body);
|
|
||||||
let mut rng = npc.rng(3);
|
|
||||||
|
|
||||||
let economy = npc.home
|
let entity_info = get_npc_entity_info(npc, &data.sites, index.as_index_ref());
|
||||||
.and_then(|home| {
|
|
||||||
let site = data.sites.get(home)?.world_site?;
|
|
||||||
index.sites.get(site).trade_information(site.id())
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Some(ref profession) = npc.profession {
|
emitter.emit(match NpcData::from_entity_info(entity_info) {
|
||||||
loadout_builder = match profession {
|
NpcData::Data {
|
||||||
Profession::Guard => loadout_builder
|
pos,
|
||||||
.with_asset_expect("common.loadout.village.guard", &mut rng),
|
stats,
|
||||||
|
skill_set,
|
||||||
Profession::Merchant => merchant_loadout(loadout_builder, economy.as_ref()),
|
health,
|
||||||
|
poise,
|
||||||
Profession::Farmer => trader_loadout(
|
inventory,
|
||||||
loadout_builder
|
agent,
|
||||||
.with_asset_expect("common.loadout.village.villager", &mut rng),
|
body,
|
||||||
economy.as_ref(),
|
alignment,
|
||||||
|good| matches!(good, Good::Food),
|
scale,
|
||||||
),
|
loot,
|
||||||
Profession::Blacksmith => trader_loadout(
|
} => ServerEvent::CreateNpc {
|
||||||
loadout_builder
|
pos,
|
||||||
.with_asset_expect("common.loadout.village.blacksmith", &mut rng),
|
stats,
|
||||||
economy.as_ref(),
|
skill_set,
|
||||||
|good| matches!(good, Good::Tools | Good::Armor),
|
health,
|
||||||
),
|
poise,
|
||||||
Profession::Hunter => loadout_builder
|
inventory,
|
||||||
.with_asset_expect("common.loadout.village.villager", &mut rng),
|
agent,
|
||||||
|
body,
|
||||||
Profession::Adventurer(level) => todo!(),
|
alignment,
|
||||||
};
|
scale,
|
||||||
}
|
anchor: None,
|
||||||
|
loot,
|
||||||
let can_speak = npc.profession.is_some(); // TODO: not this
|
rtsim_entity: Some(RtSimEntity(npc_id)),
|
||||||
|
projectile: None,
|
||||||
let trade_for_site = if let Some(Profession::Merchant | Profession::Farmer | Profession::Blacksmith) = npc.profession {
|
|
||||||
npc.home.and_then(|home| Some(data.sites.get(home)?.world_site?.id()))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
let skill_set = SkillSetBuilder::default().build();
|
|
||||||
let health_level = skill_set
|
|
||||||
.skill_level(skills::Skill::General(skills::GeneralSkill::HealthIncrease))
|
|
||||||
.unwrap_or(0);
|
|
||||||
emitter.emit(ServerEvent::CreateNpc {
|
|
||||||
pos: comp::Pos(npc.wpos),
|
|
||||||
stats: comp::Stats::new(npc.profession
|
|
||||||
.as_ref()
|
|
||||||
.map(|p| p.to_name())
|
|
||||||
.unwrap_or_else(|| "Rtsim NPC".to_string())),
|
|
||||||
skill_set: skill_set,
|
|
||||||
health: Some(comp::Health::new(body, health_level)),
|
|
||||||
poise: comp::Poise::new(body),
|
|
||||||
inventory: comp::Inventory::with_loadout(loadout_builder.build(), body),
|
|
||||||
body,
|
|
||||||
agent: Some(comp::Agent::from_body(&body)
|
|
||||||
.with_behavior(
|
|
||||||
comp::Behavior::default()
|
|
||||||
.maybe_with_capabilities(can_speak.then_some(comp::BehaviorCapability::SPEAK))
|
|
||||||
.with_trade_site(trade_for_site),
|
|
||||||
)),
|
|
||||||
alignment: if can_speak {
|
|
||||||
comp::Alignment::Npc
|
|
||||||
} else {
|
|
||||||
comp::Alignment::Wild
|
|
||||||
},
|
},
|
||||||
scale: comp::Scale(1.0),
|
// EntityConfig can't represent Waypoints at all
|
||||||
anchor: None,
|
// as of now, and if someone will try to spawn
|
||||||
loot: Default::default(),
|
// rtsim waypoint it is definitely error.
|
||||||
rtsim_entity: Some(RtSimEntity(npc_id)),
|
NpcData::Waypoint(_) => unimplemented!(),
|
||||||
projectile: None,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user