Use Behavior::CanTrade instead of Agent::trade_for_site + addressed comments

This commit is contained in:
Vincent Foulon 2021-03-30 12:55:50 +02:00 committed by Marcel Märtens
parent 51ef3547a1
commit 211ab02897
10 changed files with 64 additions and 47 deletions

View File

@ -2,7 +2,7 @@ use crate::{
comp::{humanoid, quadruped_low, quadruped_medium, quadruped_small, Body},
path::Chaser,
rtsim::RtSimController,
trade::{PendingTrade, ReducedInventory, SiteId, SitePrices, TradeId, TradeResult},
trade::{PendingTrade, ReducedInventory, SitePrices, TradeId, TradeResult},
uid::Uid,
};
use specs::{Component, Entity as EcsEntity};
@ -212,7 +212,6 @@ pub struct Agent {
pub chaser: Chaser,
/// Does the agent talk when e.g. hit by the player
// TODO move speech patterns into a Behavior component
pub trade_for_site: Option<SiteId>,
pub psyche: Psyche,
pub inbox: VecDeque<AgentEvent>,
pub action_timer: f32,
@ -233,15 +232,9 @@ impl Agent {
}
}
pub fn new(
patrol_origin: Option<Vec3<f32>>,
trade_for_site: Option<SiteId>,
body: &Body,
no_flee: bool,
) -> Self {
pub fn new(patrol_origin: Option<Vec3<f32>>, body: &Body, no_flee: bool) -> Self {
Agent {
patrol_origin,
trade_for_site,
psyche: if no_flee {
Psyche { aggro: 1.0 }
} else {

View File

@ -2,7 +2,13 @@ use specs::Component;
use specs_idvs::IdvStorage;
use std::mem;
/// Behavior Component
use crate::trade::SiteId;
/// # Behavior Component
/// This component allow an Entity to register one or more behavior tags.
/// These tags act as flags of what an Entity can do, or what it is doing.
/// Behaviors Tags can be added and removed as the Entity lives, to update its
/// state when needed
#[derive(Default, Clone, Debug)]
pub struct Behavior {
tags: Vec<BehaviorTag>,
@ -14,7 +20,7 @@ pub enum BehaviorTag {
/// The entity is allowed to speak
CanSpeak,
/// The entity is able to trade
CanTrade,
CanTrade(Option<SiteId>),
/// The entity is currently trading
IsTrading,
@ -23,13 +29,10 @@ pub enum BehaviorTag {
}
impl Behavior {
pub fn new(can_speak: bool, can_trade: bool) -> Self {
pub fn new(behavior_tags: &[BehaviorTag]) -> Self {
let mut behavior = Self::default();
if can_speak {
behavior.add_tag(BehaviorTag::CanSpeak);
}
if can_trade {
behavior.add_tag(BehaviorTag::CanTrade);
for tag in behavior_tags.iter() {
behavior.add_tag(tag.clone())
}
behavior
}
@ -56,7 +59,9 @@ impl Behavior {
/// Check if the Behavior possess a specific tag
pub fn has_tag(&self, tag: &BehaviorTag) -> bool {
self.tags.iter().any(|behavior_tag| behavior_tag == tag)
self.tags
.iter()
.any(|behavior_tag| mem::discriminant(behavior_tag) == mem::discriminant(tag))
}
/// Get a specific tag by variant

View File

@ -2,7 +2,7 @@ use crate::{
comp::{
self,
inventory::loadout_builder::{LoadoutBuilder, LoadoutConfig},
Behavior, CharacterState, StateUpdate,
Behavior, BehaviorTag, CharacterState, StateUpdate,
},
event::{LocalEvent, ServerEvent},
outcome::Outcome,
@ -104,8 +104,8 @@ impl CharacterBehavior for Data {
poise: comp::Poise::new(body),
loadout,
body,
agent: Some(comp::Agent::new(None, None, &body, true)),
behavior: Some(Behavior::new(true, false)),
agent: Some(comp::Agent::new(None, &body, true)),
behavior: Some(Behavior::new(&[BehaviorTag::CanSpeak])),
alignment: comp::Alignment::Owned(*data.uid),
scale: self
.static_data

View File

@ -15,7 +15,7 @@ use common::{
buff::{BuffCategory, BuffData, BuffKind, BuffSource},
inventory::item::MaterialStatManifest,
invite::InviteKind,
ChatType, Inventory, Item, LightEmitter, WaypointArea,
BehaviorTag, ChatType, Inventory, Item, LightEmitter, WaypointArea,
},
effect::Effect,
event::{EventBus, ServerEvent},
@ -1075,7 +1075,7 @@ fn handle_spawn_airship(
});
if let Some(pos) = destination {
builder = builder.with(comp::Agent::with_destination(pos));
builder = builder.with(comp::Behavior::new(true, false))
builder = builder.with(comp::Behavior::new(&[BehaviorTag::CanSpeak]))
}
builder.build();

View File

@ -6,7 +6,7 @@ use common::{
agent::{Agent, AgentEvent},
group::GroupManager,
invite::{Invite, InviteKind, InviteResponse, PendingInvites},
ChatType,
Behavior, ChatType,
},
trade::Trades,
uid::Uid,
@ -167,6 +167,7 @@ pub fn handle_invite_accept(server: &mut Server, entity: specs::Entity) {
let clients = state.ecs().read_storage::<Client>();
let uids = state.ecs().read_storage::<Uid>();
let mut agents = state.ecs().write_storage::<Agent>();
let behaviors = state.ecs().read_storage::<Behavior>();
let mut invites = state.ecs().write_storage::<Invite>();
if let Some((inviter, kind)) = invites.remove(entity).and_then(|invite| {
let Invite { inviter, kind } = invite;
@ -223,10 +224,10 @@ pub fn handle_invite_accept(server: &mut Server, entity: specs::Entity) {
.inbox
.push_front(AgentEvent::TradeAccepted(invitee_uid));
}
let pricing = agents
let pricing = behaviors
.get(inviter)
.and_then(|a| index.get_site_prices(a))
.or_else(|| agents.get(entity).and_then(|a| index.get_site_prices(a)));
.and_then(|b| index.get_site_prices(b))
.or_else(|| behaviors.get(entity).and_then(|b| index.get_site_prices(b)));
clients.get(inviter).map(|c| {
c.send(ServerGeneral::UpdatePendingTrade(
id,

View File

@ -3,6 +3,7 @@ use common::{
comp::{
agent::{Agent, AgentEvent},
inventory::{item::MaterialStatManifest, Inventory},
Behavior,
},
trade::{PendingTrade, ReducedInventory, TradeAction, TradeId, TradeResult, Trades},
};
@ -28,12 +29,13 @@ fn notify_agent_simple(
fn notify_agent_prices(
mut agents: specs::WriteStorage<Agent>,
behaviors: specs::ReadStorage<Behavior>,
index: &IndexOwned,
entity: EcsEntity,
event: AgentEvent,
) {
if let Some(agent) = agents.get_mut(entity) {
let prices = index.get_site_prices(agent);
if let (Some(agent), Some(behavior)) = (agents.get_mut(entity), behaviors.get(entity)) {
let prices = index.get_site_prices(behavior);
if let AgentEvent::UpdatePendingTrade(boxval) = event {
// Box<(tid, pend, _, inventories)>) = event {
agent
@ -104,6 +106,7 @@ pub fn handle_process_trade_action(
let mut inventories: [Option<ReducedInventory>; 2] = [None, None];
let mut prices = None;
let agents = server.state.ecs().read_storage::<Agent>();
let behaviors = server.state.ecs().read_storage::<Behavior>();
// sadly there is no map and collect on arrays
for i in 0..2 {
// parties.len()) {
@ -118,7 +121,9 @@ pub fn handle_process_trade_action(
// Get price info from the first Agent in the trade (currently, an
// Agent will never initiate a trade with another agent though)
prices = prices.or_else(|| {
agents.get(e).and_then(|a| server.index.get_site_prices(a))
behaviors
.get(e)
.and_then(|b| server.index.get_site_prices(b))
});
}
}
@ -135,6 +140,7 @@ pub fn handle_process_trade_action(
);
notify_agent_prices(
server.state.ecs().write_storage::<Agent>(),
server.state.ecs().read_storage::<Behavior>(),
&server.index,
e,
AgentEvent::UpdatePendingTrade(Box::new((

View File

@ -2,7 +2,7 @@
use super::*;
use common::{
comp::{self, inventory::loadout_builder::LoadoutBuilder, Behavior},
comp::{self, inventory::loadout_builder::LoadoutBuilder, Behavior, BehaviorTag},
event::{EventBus, ServerEvent},
resources::{DeltaTime, Time},
terrain::TerrainGrid,
@ -103,9 +103,9 @@ impl<'a> System<'a> for Sys {
.map(|e| e as f32)
+ Vec3::new(0.5, 0.5, body.flying_height());
let pos = comp::Pos(spawn_pos);
let agent = Some(comp::Agent::new(None, None, &body, false));
let agent = Some(comp::Agent::new(None, &body, false));
let behavior = if matches!(body, comp::Body::Humanoid(_)) {
Some(Behavior::new(true, false))
Some(Behavior::new(&[BehaviorTag::CanSpeak]))
} else {
None
};

View File

@ -935,7 +935,7 @@ impl<'a> AgentData<'a> {
event_emitter.emit(ServerEvent::Chat(
UnresolvedChatMsg::npc(*self.uid, msg),
));
} else if self.behavior.has_tag(&BehaviorTag::CanTrade) {
} else if self.behavior.has_tag(&BehaviorTag::CanTrade(None)) {
let msg = "npc.speech.merchant_advertisement".to_string();
event_emitter.emit(ServerEvent::Chat(
UnresolvedChatMsg::npc(*self.uid, msg),
@ -948,7 +948,7 @@ impl<'a> AgentData<'a> {
}
},
Subject::Trade => {
if self.behavior.has_tag(&BehaviorTag::CanTrade) {
if self.behavior.has_tag(&BehaviorTag::CanTrade(None)) {
if !self.behavior.has_tag(&BehaviorTag::IsTrading) {
controller.events.push(ControlEvent::InitiateInvite(
by,
@ -1097,7 +1097,7 @@ impl<'a> AgentData<'a> {
}
},
Some(AgentEvent::TradeInvite(with)) => {
if self.behavior.has_tag(&BehaviorTag::CanTrade) {
if self.behavior.has_tag(&BehaviorTag::CanTrade(None)) {
if !self.behavior.has_tag(&BehaviorTag::IsTrading) {
// stand still and looking towards the trading player
controller.actions.push(ControlAction::Stand);

View File

@ -2,7 +2,9 @@ use crate::{
chunk_generator::ChunkGenerator, client::Client, presence::Presence, rtsim::RtSim, Tick,
};
use common::{
comp::{self, bird_medium, inventory::loadout_builder::LoadoutConfig, Alignment, Pos},
comp::{
self, bird_medium, inventory::loadout_builder::LoadoutConfig, Alignment, BehaviorTag, Pos,
},
event::{EventBus, ServerEvent},
generation::get_npc_name,
npc::NPC_NAMES,
@ -191,7 +193,6 @@ impl<'a> System<'a> for Sys {
agent: if entity.has_agency {
Some(comp::Agent::new(
Some(entity.pos),
trade_for_site,
&body,
matches!(
loadout_config,
@ -202,7 +203,14 @@ impl<'a> System<'a> for Sys {
None
},
behavior: if entity.has_agency {
Some(comp::Behavior::new(can_speak, trade_for_site.is_some()))
let mut behavior_tags = vec![];
if can_speak {
behavior_tags.push(BehaviorTag::CanSpeak);
}
if trade_for_site.is_some() {
behavior_tags.push(BehaviorTag::CanTrade(trade_for_site));
}
Some(comp::Behavior::new(&behavior_tags))
} else {
None
},

View File

@ -4,7 +4,7 @@ use crate::{
};
use common::{
assets::{AssetExt, AssetHandle},
comp::Agent,
comp::{Behavior, BehaviorTag},
store::Store,
trade::SitePrices,
};
@ -72,13 +72,17 @@ impl Index {
pub fn colors(&self) -> AssetHandle<Arc<Colors>> { self.colors }
pub fn get_site_prices(&self, agent: &Agent) -> Option<SitePrices> {
agent
.trade_for_site
.map(|i| self.sites.recreate_id(i))
.flatten()
.map(|i| self.sites.get(i))
.map(|s| s.economy.get_site_prices())
pub fn get_site_prices(&self, behavior: &Behavior) -> Option<SitePrices> {
if let Some(BehaviorTag::CanTrade(site_id)) = behavior.get_tag(BehaviorTag::CanTrade(None))
{
site_id
.map(|i| self.sites.recreate_id(i))
.flatten()
.map(|i| self.sites.get(i))
.map(|s| s.economy.get_site_prices())
} else {
None
}
}
}