use bitflags instead of HashSet

This commit is contained in:
Vincent Foulon
2021-04-06 19:18:40 +02:00
committed by Marcel Märtens
parent 738f074f89
commit c33e73bbed
14 changed files with 85 additions and 115 deletions

1
Cargo.lock generated
View File

@ -5377,6 +5377,7 @@ dependencies = [
"approx 0.4.0", "approx 0.4.0",
"arraygen", "arraygen",
"assets_manager", "assets_manager",
"bitflags",
"criterion", "criterion",
"crossbeam-channel", "crossbeam-channel",
"crossbeam-utils 0.8.3", "crossbeam-utils 0.8.3",

View File

@ -24,6 +24,7 @@ serde = { version = "1.0.110", features = ["derive", "rc"] }
approx = "0.4.0" approx = "0.4.0"
arraygen = "0.1.13" arraygen = "0.1.13"
crossbeam-utils = "0.8.1" crossbeam-utils = "0.8.1"
bitflags = "1.2"
crossbeam-channel = "0.5" crossbeam-channel = "0.5"
enum-iterator = "0.6" enum-iterator = "0.6"
lazy_static = "1.4.0" lazy_static = "1.4.0"

View File

@ -1,72 +1,44 @@
use specs::Component; use specs::Component;
use specs_idvs::IdvStorage; use specs_idvs::IdvStorage;
use std::{collections::HashSet, mem};
use crate::trade::SiteId; use crate::trade::SiteId;
bitflags! {
#[derive(Default)]
pub struct BehaviorFlag: u8 {
const CAN_SPEAK = 0b00000001;
const CAN_TRADE = 0b00000010;
const IS_TRADING = 0b00000100;
const IS_TRADING_ISSUER = 0b00001000;
}
}
/// # Behavior Component /// # Behavior Component
/// This component allow an Entity to register one or more behavior tags. /// 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. /// 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 /// Behaviors Tags can be added and removed as the Entity lives, to update its
/// state when needed /// state when needed
#[derive(Default, Clone, Debug)] #[derive(Default, Copy, Clone, Debug)]
pub struct Behavior { pub struct Behavior {
tags: HashSet<BehaviorTag>, pub flags: BehaviorFlag,
pub trade_site: Option<SiteId>,
} }
/// Versatile tags attached to behaviors impl From<BehaviorFlag> for Behavior {
#[derive(Hash, Eq, PartialEq, Clone, Debug)] fn from(flags: BehaviorFlag) -> Self {
pub enum BehaviorTag { Behavior {
/// The entity is allowed to speak flags,
CanSpeak, trade_site: None,
/// The entity is able to trade }
CanTrade(Option<SiteId>), }
/// The entity is currently trading
IsTrading,
/// The entity has issued a trade
IsTradingIssuer,
} }
impl Behavior { impl Behavior {
pub fn new(behavior_tags: &[BehaviorTag]) -> Self { pub fn set(&mut self, flags: BehaviorFlag) { self.flags.set(flags, true) }
let mut behavior = Self::default();
for tag in behavior_tags.iter() {
behavior.add_tag(tag.clone())
}
behavior
}
/// Apply a tag to the Behavior pub fn unset(&mut self, flags: BehaviorFlag) { self.flags.set(flags, false) }
pub fn add_tag(&mut self, tag: BehaviorTag) {
if !self.has_tag(&tag) {
self.tags.insert(tag);
}
}
/// Revoke a tag to the Behavior pub fn has(&self, flags: BehaviorFlag) -> bool { self.flags.contains(flags) }
pub fn remove_tag(&mut self, tag: BehaviorTag) {
if self.has_tag(&tag) {
let tag = self.get_tag(&tag).cloned();
if let Some(tag) = tag {
self.tags.remove(&tag);
}
}
}
/// Check if the Behavior possess a specific tag
pub fn has_tag(&self, tag: &BehaviorTag) -> bool {
self.tags
.iter()
.any(|behavior_tag| mem::discriminant(behavior_tag) == mem::discriminant(tag))
}
/// Get a specific tag by variant
pub fn get_tag(&self, tag: &BehaviorTag) -> Option<&BehaviorTag> {
self.tags
.iter()
.find(|behavior_tag| mem::discriminant(*behavior_tag) == mem::discriminant(tag))
}
} }
impl Component for Behavior { impl Component for Behavior {

View File

@ -49,7 +49,7 @@ pub use self::{
agent::{Agent, Alignment}, agent::{Agent, Alignment},
aura::{Aura, AuraChange, AuraKind, Auras}, aura::{Aura, AuraChange, AuraKind, Auras},
beam::{Beam, BeamSegment}, beam::{Beam, BeamSegment},
behavior::{Behavior, BehaviorTag}, behavior::{Behavior, BehaviorFlag},
body::{ body::{
biped_large, biped_small, bird_medium, bird_small, dragon, fish_medium, fish_small, golem, biped_large, biped_small, bird_medium, bird_small, dragon, fish_medium, fish_small, golem,
humanoid, object, quadruped_low, quadruped_medium, quadruped_small, ship, theropod, humanoid, object, quadruped_low, quadruped_medium, quadruped_small, ship, theropod,

View File

@ -18,6 +18,8 @@
type_alias_impl_trait type_alias_impl_trait
)] )]
#[macro_use] extern crate bitflags;
/// Re-exported crates /// Re-exported crates
pub use uuid; pub use uuid;

View File

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

View File

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

View File

@ -75,11 +75,8 @@ pub fn handle_create_npc(
} else { } else {
entity entity
}; };
let entity = if let Some(behavior) = behavior {
entity.with(behavior) let entity = entity.with(behavior.unwrap_or_default());
} else {
entity.with(Behavior::default())
};
let entity = if let Some(drop_item) = drop_item { let entity = if let Some(drop_item) = drop_item {
entity.with(ItemDrop(drop_item)) entity.with(ItemDrop(drop_item))

View File

@ -226,8 +226,12 @@ pub fn handle_invite_accept(server: &mut Server, entity: specs::Entity) {
} }
let pricing = behaviors let pricing = behaviors
.get(inviter) .get(inviter)
.and_then(|b| index.get_site_prices(b)) .and_then(|b| index.get_site_prices(b.trade_site))
.or_else(|| behaviors.get(entity).and_then(|b| index.get_site_prices(b))); .or_else(|| {
behaviors
.get(entity)
.and_then(|b| index.get_site_prices(b.trade_site))
});
clients.get(inviter).map(|c| { clients.get(inviter).map(|c| {
c.send(ServerGeneral::UpdatePendingTrade( c.send(ServerGeneral::UpdatePendingTrade(
id, id,

View File

@ -35,7 +35,7 @@ fn notify_agent_prices(
event: AgentEvent, event: AgentEvent,
) { ) {
if let (Some(agent), Some(behavior)) = (agents.get_mut(entity), behaviors.get(entity)) { if let (Some(agent), Some(behavior)) = (agents.get_mut(entity), behaviors.get(entity)) {
let prices = index.get_site_prices(behavior); let prices = index.get_site_prices(behavior.trade_site);
if let AgentEvent::UpdatePendingTrade(boxval) = event { if let AgentEvent::UpdatePendingTrade(boxval) = event {
// Box<(tid, pend, _, inventories)>) = event { // Box<(tid, pend, _, inventories)>) = event {
agent agent
@ -123,7 +123,7 @@ pub fn handle_process_trade_action(
prices = prices.or_else(|| { prices = prices.or_else(|| {
behaviors behaviors
.get(e) .get(e)
.and_then(|b| server.index.get_site_prices(b)) .and_then(|b| server.index.get_site_prices(b.trade_site))
}); });
} }
} }

View File

@ -2,7 +2,7 @@
use super::*; use super::*;
use common::{ use common::{
comp::{self, inventory::loadout_builder::LoadoutBuilder, Behavior, BehaviorTag}, comp::{self, inventory::loadout_builder::LoadoutBuilder, Behavior, BehaviorFlag},
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
resources::{DeltaTime, Time}, resources::{DeltaTime, Time},
terrain::TerrainGrid, terrain::TerrainGrid,
@ -104,11 +104,8 @@ impl<'a> System<'a> for Sys {
+ Vec3::new(0.5, 0.5, body.flying_height()); + Vec3::new(0.5, 0.5, body.flying_height());
let pos = comp::Pos(spawn_pos); let pos = comp::Pos(spawn_pos);
let agent = Some(comp::Agent::new(None, &body, false)); let agent = Some(comp::Agent::new(None, &body, false));
let behavior = if matches!(body, comp::Body::Humanoid(_)) { let behavior = matches!(body, comp::Body::Humanoid(_))
Some(Behavior::new(&[BehaviorTag::CanSpeak])) .then(|| Behavior::from(BehaviorFlag::CAN_SPEAK));
} else {
None
};
let rtsim_entity = Some(RtSimEntity(id)); let rtsim_entity = Some(RtSimEntity(id));
let event = match body { let event = match body {
comp::Body::Ship(ship) => ServerEvent::CreateShip { comp::Body::Ship(ship) => ServerEvent::CreateShip {

View File

@ -14,9 +14,9 @@ use common::{
ItemDesc, ItemKind, ItemDesc, ItemKind,
}, },
skills::{AxeSkill, BowSkill, HammerSkill, Skill, StaffSkill, SwordSkill}, skills::{AxeSkill, BowSkill, HammerSkill, Skill, StaffSkill, SwordSkill},
Agent, Alignment, Behavior, BehaviorTag, Body, CharacterState, ControlAction, ControlEvent, Agent, Alignment, Behavior, BehaviorFlag, Body, CharacterState, ControlAction,
Controller, Energy, Health, InputKind, Inventory, LightEmitter, MountState, Ori, ControlEvent, Controller, Energy, Health, InputKind, Inventory, LightEmitter, MountState,
PhysicsState, Pos, Scale, Stats, UnresolvedChatMsg, Vel, Ori, PhysicsState, Pos, Scale, Stats, UnresolvedChatMsg, Vel,
}, },
event::{Emitter, EventBus, ServerEvent}, event::{Emitter, EventBus, ServerEvent},
path::TraversalConfig, path::TraversalConfig,
@ -554,7 +554,7 @@ impl<'a> AgentData<'a> {
} }
if agent.action_timer > 0.0 { if agent.action_timer > 0.0 {
if agent.action_timer if agent.action_timer
< (if self.behavior.has_tag(&BehaviorTag::IsTrading) { < (if self.behavior.has(BehaviorFlag::IS_TRADING) {
TRADE_INTERACTION_TIME TRADE_INTERACTION_TIME
} else { } else {
DEFAULT_INTERACTION_TIME DEFAULT_INTERACTION_TIME
@ -591,7 +591,7 @@ impl<'a> AgentData<'a> {
let dist_sqrd = self.pos.0.distance_squared(tgt_pos.0); let dist_sqrd = self.pos.0.distance_squared(tgt_pos.0);
// Should the agent flee? // Should the agent flee?
if 1.0 - agent.psyche.aggro > self.damage && self.flees { if 1.0 - agent.psyche.aggro > self.damage && self.flees {
if agent.action_timer == 0.0 && self.behavior.has_tag(&BehaviorTag::CanSpeak) { if agent.action_timer == 0.0 && self.behavior.has(BehaviorFlag::CAN_SPEAK) {
let msg = "npc.speech.villager_under_attack".to_string(); let msg = "npc.speech.villager_under_attack".to_string();
event_emitter event_emitter
.emit(ServerEvent::Chat(UnresolvedChatMsg::npc(*self.uid, msg))); .emit(ServerEvent::Chat(UnresolvedChatMsg::npc(*self.uid, msg)));
@ -619,7 +619,7 @@ impl<'a> AgentData<'a> {
read_data.buffs.get(target), read_data.buffs.get(target),
) { ) {
agent.target = None; agent.target = None;
if self.behavior.has_tag(&BehaviorTag::CanSpeak) { if self.behavior.has(BehaviorFlag::CAN_SPEAK) {
let msg = "npc.speech.villager_enemy_killed".to_string(); let msg = "npc.speech.villager_enemy_killed".to_string();
event_emitter event_emitter
.emit(ServerEvent::Chat(UnresolvedChatMsg::npc(*self.uid, msg))); .emit(ServerEvent::Chat(UnresolvedChatMsg::npc(*self.uid, msg)));
@ -882,7 +882,7 @@ impl<'a> AgentData<'a> {
let msg = agent.inbox.pop_back(); let msg = agent.inbox.pop_back();
match msg { match msg {
Some(AgentEvent::Talk(by, subject)) => { Some(AgentEvent::Talk(by, subject)) => {
if self.behavior.has_tag(&BehaviorTag::CanSpeak) { if self.behavior.has(BehaviorFlag::CAN_SPEAK) {
if let Some(target) = read_data.uid_allocator.retrieve_entity_internal(by.id()) if let Some(target) = read_data.uid_allocator.retrieve_entity_internal(by.id())
{ {
agent.target = Some(Target { agent.target = Some(Target {
@ -935,7 +935,7 @@ impl<'a> AgentData<'a> {
event_emitter.emit(ServerEvent::Chat( event_emitter.emit(ServerEvent::Chat(
UnresolvedChatMsg::npc(*self.uid, msg), UnresolvedChatMsg::npc(*self.uid, msg),
)); ));
} else if self.behavior.has_tag(&BehaviorTag::CanTrade(None)) { } else if self.behavior.has(BehaviorFlag::CAN_TRADE) {
let msg = "npc.speech.merchant_advertisement".to_string(); let msg = "npc.speech.merchant_advertisement".to_string();
event_emitter.emit(ServerEvent::Chat( event_emitter.emit(ServerEvent::Chat(
UnresolvedChatMsg::npc(*self.uid, msg), UnresolvedChatMsg::npc(*self.uid, msg),
@ -948,8 +948,8 @@ impl<'a> AgentData<'a> {
} }
}, },
Subject::Trade => { Subject::Trade => {
if self.behavior.has_tag(&BehaviorTag::CanTrade(None)) { if self.behavior.has(BehaviorFlag::CAN_TRADE) {
if !self.behavior.has_tag(&BehaviorTag::IsTrading) { if !self.behavior.has(BehaviorFlag::IS_TRADING) {
controller.events.push(ControlEvent::InitiateInvite( controller.events.push(ControlEvent::InitiateInvite(
by, by,
InviteKind::Trade, InviteKind::Trade,
@ -1097,8 +1097,8 @@ impl<'a> AgentData<'a> {
} }
}, },
Some(AgentEvent::TradeInvite(with)) => { Some(AgentEvent::TradeInvite(with)) => {
if self.behavior.has_tag(&BehaviorTag::CanTrade(None)) { if self.behavior.has(BehaviorFlag::CAN_TRADE) {
if !self.behavior.has_tag(&BehaviorTag::IsTrading) { if !self.behavior.has(BehaviorFlag::IS_TRADING) {
// stand still and looking towards the trading player // stand still and looking towards the trading player
controller.actions.push(ControlAction::Stand); controller.actions.push(ControlAction::Stand);
controller.actions.push(ControlAction::Talk); controller.actions.push(ControlAction::Talk);
@ -1114,13 +1114,13 @@ impl<'a> AgentData<'a> {
controller controller
.events .events
.push(ControlEvent::InviteResponse(InviteResponse::Accept)); .push(ControlEvent::InviteResponse(InviteResponse::Accept));
self.behavior.remove_tag(BehaviorTag::IsTradingIssuer); self.behavior.unset(BehaviorFlag::IS_TRADING_ISSUER);
self.behavior.add_tag(BehaviorTag::IsTrading); self.behavior.set(BehaviorFlag::IS_TRADING);
} else { } else {
controller controller
.events .events
.push(ControlEvent::InviteResponse(InviteResponse::Decline)); .push(ControlEvent::InviteResponse(InviteResponse::Decline));
if self.behavior.has_tag(&BehaviorTag::CanSpeak) { if self.behavior.has(BehaviorFlag::CAN_SPEAK) {
event_emitter.emit(ServerEvent::Chat(UnresolvedChatMsg::npc( event_emitter.emit(ServerEvent::Chat(UnresolvedChatMsg::npc(
*self.uid, *self.uid,
"npc.speech.merchant_busy".to_string(), "npc.speech.merchant_busy".to_string(),
@ -1132,7 +1132,7 @@ impl<'a> AgentData<'a> {
controller controller
.events .events
.push(ControlEvent::InviteResponse(InviteResponse::Decline)); .push(ControlEvent::InviteResponse(InviteResponse::Decline));
if self.behavior.has_tag(&BehaviorTag::CanSpeak) { if self.behavior.has(BehaviorFlag::CAN_SPEAK) {
event_emitter.emit(ServerEvent::Chat(UnresolvedChatMsg::npc( event_emitter.emit(ServerEvent::Chat(UnresolvedChatMsg::npc(
*self.uid, *self.uid,
"npc.speech.villager_decline_trade".to_string(), "npc.speech.villager_decline_trade".to_string(),
@ -1141,7 +1141,7 @@ impl<'a> AgentData<'a> {
} }
}, },
Some(AgentEvent::TradeAccepted(with)) => { Some(AgentEvent::TradeAccepted(with)) => {
if !self.behavior.has_tag(&BehaviorTag::IsTrading) { if !self.behavior.has(BehaviorFlag::IS_TRADING) {
if let Some(target) = if let Some(target) =
read_data.uid_allocator.retrieve_entity_internal(with.id()) read_data.uid_allocator.retrieve_entity_internal(with.id())
{ {
@ -1151,12 +1151,12 @@ impl<'a> AgentData<'a> {
selected_at: read_data.time.0, selected_at: read_data.time.0,
}); });
} }
self.behavior.add_tag(BehaviorTag::IsTrading); self.behavior.set(BehaviorFlag::IS_TRADING);
self.behavior.add_tag(BehaviorTag::IsTradingIssuer); self.behavior.set(BehaviorFlag::IS_TRADING_ISSUER);
} }
}, },
Some(AgentEvent::FinishedTrade(result)) => { Some(AgentEvent::FinishedTrade(result)) => {
if self.behavior.has_tag(&BehaviorTag::IsTrading) { if self.behavior.has(BehaviorFlag::IS_TRADING) {
match result { match result {
TradeResult::Completed => { TradeResult::Completed => {
event_emitter.emit(ServerEvent::Chat(UnresolvedChatMsg::npc( event_emitter.emit(ServerEvent::Chat(UnresolvedChatMsg::npc(
@ -1169,13 +1169,13 @@ impl<'a> AgentData<'a> {
"npc.speech.merchant_trade_declined".to_string(), "npc.speech.merchant_trade_declined".to_string(),
))), ))),
} }
self.behavior.remove_tag(BehaviorTag::IsTrading); self.behavior.unset(BehaviorFlag::IS_TRADING);
} }
}, },
Some(AgentEvent::UpdatePendingTrade(boxval)) => { Some(AgentEvent::UpdatePendingTrade(boxval)) => {
let (tradeid, pending, prices, inventories) = *boxval; let (tradeid, pending, prices, inventories) = *boxval;
if self.behavior.has_tag(&BehaviorTag::IsTrading) { if self.behavior.has(BehaviorFlag::IS_TRADING) {
let who: usize = if self.behavior.has_tag(&BehaviorTag::IsTradingIssuer) { let who: usize = if self.behavior.has(BehaviorFlag::IS_TRADING_ISSUER) {
0 0
} else { } else {
1 1
@ -1209,7 +1209,7 @@ impl<'a> AgentData<'a> {
} }
if pending.phase != TradePhase::Mutate { if pending.phase != TradePhase::Mutate {
// we got into the review phase but without balanced goods, decline // we got into the review phase but without balanced goods, decline
self.behavior.remove_tag(BehaviorTag::IsTrading); self.behavior.unset(BehaviorFlag::IS_TRADING);
event_emitter.emit(ServerEvent::ProcessTradeAction( event_emitter.emit(ServerEvent::ProcessTradeAction(
*self.entity, *self.entity,
tradeid, tradeid,
@ -1220,7 +1220,7 @@ impl<'a> AgentData<'a> {
} }
}, },
None => { None => {
if self.behavior.has_tag(&BehaviorTag::CanSpeak) { if self.behavior.has(BehaviorFlag::CAN_SPEAK) {
// no new events, continue looking towards the last interacting player for some // no new events, continue looking towards the last interacting player for some
// time // time
if let Some(Target { target, .. }) = &agent.target { if let Some(Target { target, .. }) = &agent.target {
@ -1343,7 +1343,7 @@ impl<'a> AgentData<'a> {
( (
self.alignment.map_or(false, |alignment| { self.alignment.map_or(false, |alignment| {
if matches!(alignment, Alignment::Npc) && e_inventory.equipped_items().filter(|item| item.tags().contains(&ItemTag::Cultist)).count() > 2 { if matches!(alignment, Alignment::Npc) && e_inventory.equipped_items().filter(|item| item.tags().contains(&ItemTag::Cultist)).count() > 2 {
if self.behavior.has_tag(&BehaviorTag::CanSpeak) { if self.behavior.has(BehaviorFlag::CAN_SPEAK) {
if self.rtsim_entity.is_some() { if self.rtsim_entity.is_some() {
agent.rtsim_controller.events.push( agent.rtsim_controller.events.push(
RtSimEvent::AddMemory(Memory { RtSimEvent::AddMemory(Memory {

View File

@ -3,7 +3,7 @@ use crate::{
}; };
use common::{ use common::{
comp::{ comp::{
self, bird_medium, inventory::loadout_builder::LoadoutConfig, Alignment, BehaviorTag, Pos, self, bird_medium, inventory::loadout_builder::LoadoutConfig, Alignment, BehaviorFlag, Pos,
}, },
event::{EventBus, ServerEvent}, event::{EventBus, ServerEvent},
generation::get_npc_name, generation::get_npc_name,
@ -14,6 +14,7 @@ use common::{
use common_ecs::{Job, Origin, Phase, System}; use common_ecs::{Job, Origin, Phase, System};
use common_net::msg::ServerGeneral; use common_net::msg::ServerGeneral;
use common_sys::state::TerrainChanges; use common_sys::state::TerrainChanges;
use comp::Behavior;
use specs::{Join, Read, ReadStorage, Write, WriteExpect}; use specs::{Join, Read, ReadStorage, Write, WriteExpect};
use std::sync::Arc; use std::sync::Arc;
use vek::*; use vek::*;
@ -203,14 +204,15 @@ impl<'a> System<'a> for Sys {
None None
}, },
behavior: if entity.has_agency { behavior: if entity.has_agency {
let mut behavior_tags = vec![]; let mut behavior = Behavior::default();
if can_speak { if can_speak {
behavior_tags.push(BehaviorTag::CanSpeak); behavior.set(BehaviorFlag::CAN_SPEAK);
} }
if trade_for_site.is_some() { if trade_for_site.is_some() {
behavior_tags.push(BehaviorTag::CanTrade(trade_for_site)); behavior.set(BehaviorFlag::CAN_TRADE);
behavior.trade_site = trade_for_site
} }
Some(comp::Behavior::new(&behavior_tags)) Some(behavior)
} else { } else {
None None
}, },

View File

@ -4,9 +4,8 @@ use crate::{
}; };
use common::{ use common::{
assets::{AssetExt, AssetHandle}, assets::{AssetExt, AssetHandle},
comp::{Behavior, BehaviorTag},
store::Store, store::Store,
trade::SitePrices, trade::{SiteId, SitePrices},
}; };
use core::ops::Deref; use core::ops::Deref;
use noise::{Seedable, SuperSimplex}; use noise::{Seedable, SuperSimplex};
@ -72,17 +71,12 @@ impl Index {
pub fn colors(&self) -> AssetHandle<Arc<Colors>> { self.colors } pub fn colors(&self) -> AssetHandle<Arc<Colors>> { self.colors }
pub fn get_site_prices(&self, behavior: &Behavior) -> Option<SitePrices> { pub fn get_site_prices(&self, site_id: Option<SiteId>) -> Option<SitePrices> {
if let Some(BehaviorTag::CanTrade(site_id)) = behavior.get_tag(&BehaviorTag::CanTrade(None)) site_id
{ .map(|i| self.sites.recreate_id(i))
site_id .flatten()
.map(|i| self.sites.recreate_id(i)) .map(|i| self.sites.get(i))
.flatten() .map(|s| s.economy.get_site_prices())
.map(|i| self.sites.get(i))
.map(|s| s.economy.get_site_prices())
} else {
None
}
} }
} }