mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Make the trading AI for pets only accept food.
This commit is contained in:
parent
ff781198d3
commit
e6576f0cf3
@ -97,6 +97,26 @@ bitflags::bitflags! {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Copy, Clone, Debug)]
|
||||
pub enum TradingBehavior {
|
||||
#[default]
|
||||
None,
|
||||
RequireBalanced {
|
||||
trade_site: SiteId,
|
||||
},
|
||||
AcceptFood,
|
||||
}
|
||||
|
||||
impl TradingBehavior {
|
||||
fn can_trade(&self, alignment: Option<Alignment>, counterparty: Uid) -> bool {
|
||||
match self {
|
||||
TradingBehavior::RequireBalanced { .. } => true,
|
||||
TradingBehavior::AcceptFood => alignment == Some(Alignment::Owned(counterparty)),
|
||||
TradingBehavior::None => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// # 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.
|
||||
@ -106,7 +126,7 @@ bitflags::bitflags! {
|
||||
pub struct Behavior {
|
||||
capabilities: BehaviorCapability,
|
||||
state: BehaviorState,
|
||||
pub trade_site: Option<SiteId>,
|
||||
pub trading_behavior: TradingBehavior,
|
||||
}
|
||||
|
||||
impl From<BehaviorCapability> for Behavior {
|
||||
@ -114,7 +134,7 @@ impl From<BehaviorCapability> for Behavior {
|
||||
Behavior {
|
||||
capabilities,
|
||||
state: BehaviorState::default(),
|
||||
trade_site: None,
|
||||
trading_behavior: TradingBehavior::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -137,7 +157,9 @@ impl Behavior {
|
||||
/// Set trade_site if Option is Some
|
||||
#[must_use]
|
||||
pub fn with_trade_site(mut self, trade_site: Option<SiteId>) -> Self {
|
||||
self.trade_site = trade_site;
|
||||
if let Some(trade_site) = trade_site {
|
||||
self.trading_behavior = TradingBehavior::RequireBalanced { trade_site };
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
@ -158,7 +180,7 @@ impl Behavior {
|
||||
|
||||
/// Check if the Behavior is able to trade
|
||||
pub fn can_trade(&self, alignment: Option<Alignment>, counterparty: Uid) -> bool {
|
||||
self.trade_site.is_some() || alignment == Some(Alignment::Owned(counterparty))
|
||||
self.trading_behavior.can_trade(alignment, counterparty)
|
||||
}
|
||||
|
||||
/// Set a state to the Behavior
|
||||
@ -169,6 +191,15 @@ impl Behavior {
|
||||
|
||||
/// Check if the Behavior has a specific state
|
||||
pub fn is(&self, state: BehaviorState) -> bool { self.state.contains(state) }
|
||||
|
||||
/// Get the trade site at which this behavior evaluates prices, if it does
|
||||
pub fn trade_site(&self) -> Option<SiteId> {
|
||||
if let TradingBehavior::RequireBalanced { trade_site } = self.trading_behavior {
|
||||
Some(trade_site)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
|
@ -55,7 +55,10 @@ pub use self::{
|
||||
MAX_ABILITIES,
|
||||
},
|
||||
admin::{Admin, AdminRole},
|
||||
agent::{Agent, Alignment, Behavior, BehaviorCapability, BehaviorState, PidController},
|
||||
agent::{
|
||||
Agent, Alignment, Behavior, BehaviorCapability, BehaviorState, PidController,
|
||||
TradingBehavior,
|
||||
},
|
||||
anchor::Anchor,
|
||||
aura::{Aura, AuraChange, AuraKind, Auras},
|
||||
beam::{Beam, BeamSegment},
|
||||
|
@ -9,7 +9,7 @@ use common::{
|
||||
buff::{BuffCategory, BuffData, BuffKind, BuffSource},
|
||||
shockwave, Agent, Alignment, Anchor, BehaviorCapability, Body, Health, Inventory, ItemDrop,
|
||||
LightEmitter, Object, Ori, PidController, Poise, Pos, Projectile, Scale, SkillSet, Stats,
|
||||
Vel, WaypointArea,
|
||||
TradingBehavior, Vel, WaypointArea,
|
||||
},
|
||||
event::{EventBus, UpdateCharacterMetadata},
|
||||
lottery::LootSpec,
|
||||
@ -104,6 +104,7 @@ pub fn handle_create_npc(
|
||||
if let Some(agent) = &mut agent {
|
||||
if let Alignment::Owned(_) = &alignment {
|
||||
agent.behavior.allow(BehaviorCapability::TRADE);
|
||||
agent.behavior.trading_behavior = TradingBehavior::AcceptFood;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -246,13 +246,13 @@ pub fn handle_invite_accept(server: &mut Server, entity: Entity) {
|
||||
.get(inviter)
|
||||
.and_then(|a| {
|
||||
a.behavior
|
||||
.trade_site
|
||||
.trade_site()
|
||||
.and_then(|id| index.get_site_prices(id))
|
||||
})
|
||||
.or_else(|| {
|
||||
agents.get(entity).and_then(|a| {
|
||||
a.behavior
|
||||
.trade_site
|
||||
.trade_site()
|
||||
.and_then(|id| index.get_site_prices(id))
|
||||
})
|
||||
});
|
||||
|
@ -35,7 +35,7 @@ fn notify_agent_prices(
|
||||
entity: EcsEntity,
|
||||
event: AgentEvent,
|
||||
) {
|
||||
if let Some((site_id, agent)) = agents.get_mut(entity).map(|a| (a.behavior.trade_site, a)) {
|
||||
if let Some((site_id, agent)) = agents.get_mut(entity).map(|a| (a.behavior.trade_site(), a)) {
|
||||
if let AgentEvent::UpdatePendingTrade(boxval) = event {
|
||||
// Prefer using this Agent's price data, but use the counterparty's price
|
||||
// data if we don't have price data
|
||||
@ -125,7 +125,7 @@ pub(super) fn handle_process_trade_action(
|
||||
prices = prices.or_else(|| {
|
||||
agents
|
||||
.get(e)
|
||||
.and_then(|a| a.behavior.trade_site)
|
||||
.and_then(|a| a.behavior.trade_site())
|
||||
.and_then(|id| server.index.get_site_prices(id))
|
||||
});
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ use crate::{client::Client, events::update_map_markers};
|
||||
use common::{
|
||||
comp::{
|
||||
self, anchor::Anchor, group::GroupManager, Agent, Alignment, Behavior, BehaviorCapability,
|
||||
Pet,
|
||||
Pet, TradingBehavior,
|
||||
},
|
||||
uid::Uid,
|
||||
};
|
||||
@ -54,9 +54,10 @@ fn tame_pet_internal(ecs: &specs::World, pet_entity: Entity, owner: Entity, pet:
|
||||
|
||||
// Create an agent for this entity using its body
|
||||
if let Some(body) = ecs.read_storage().get(pet_entity) {
|
||||
let agent = Agent::from_body(body).with_behavior(
|
||||
let mut agent = Agent::from_body(body).with_behavior(
|
||||
Behavior::default().maybe_with_capabilities(Some(BehaviorCapability::TRADE)),
|
||||
);
|
||||
agent.behavior.trading_behavior = TradingBehavior::AcceptFood;
|
||||
let _ = ecs.write_storage().insert(pet_entity, agent);
|
||||
}
|
||||
|
||||
|
@ -3,8 +3,10 @@ use common::{
|
||||
agent::{AgentEvent, Target, TimerAction},
|
||||
compass::{Direction, Distance},
|
||||
dialogue::{MoodContext, MoodState, Subject},
|
||||
inventory::item::{ItemTag, MaterialStatManifest},
|
||||
invite::{InviteKind, InviteResponse},
|
||||
BehaviorState, ControlAction, UnresolvedChatMsg, UtteranceKind,
|
||||
tool::AbilityMap,
|
||||
BehaviorState, ControlAction, Item, TradingBehavior, UnresolvedChatMsg, UtteranceKind,
|
||||
},
|
||||
event::ServerEvent,
|
||||
rtsim::{Memory, MemoryItem, RtSimEvent},
|
||||
@ -511,7 +513,10 @@ pub fn handle_inbox_update_pending_trade(bdata: &mut BehaviorData) -> bool {
|
||||
let (tradeid, pending, prices, inventories) = *boxval;
|
||||
if agent.behavior.is(BehaviorState::TRADING) {
|
||||
let who = usize::from(!agent.behavior.is(BehaviorState::TRADING_ISSUER));
|
||||
let balance0: f32 = prices.balance(&pending.offers, &inventories, 1 - who, true);
|
||||
match agent.behavior.trading_behavior {
|
||||
TradingBehavior::RequireBalanced { .. } => {
|
||||
let balance0: f32 =
|
||||
prices.balance(&pending.offers, &inventories, 1 - who, true);
|
||||
let balance1: f32 = prices.balance(&pending.offers, &inventories, who, false);
|
||||
if balance0 >= balance1 {
|
||||
// If the trade is favourable to us, only send an accept message if we're
|
||||
@ -536,16 +541,13 @@ pub fn handle_inbox_update_pending_trade(bdata: &mut BehaviorData) -> bool {
|
||||
if let Some(tgt_data) = &agent.target {
|
||||
// If talking with someone in particular, "tell" it only to them
|
||||
if let Some(with) = read_data.uids.get(tgt_data.target) {
|
||||
event_emitter.emit(ServerEvent::Chat(UnresolvedChatMsg::npc_tell(
|
||||
*agent_data.uid,
|
||||
*with,
|
||||
msg,
|
||||
)));
|
||||
event_emitter.emit(ServerEvent::Chat(
|
||||
UnresolvedChatMsg::npc_tell(*agent_data.uid, *with, msg),
|
||||
));
|
||||
} else {
|
||||
event_emitter.emit(ServerEvent::Chat(UnresolvedChatMsg::npc_say(
|
||||
*agent_data.uid,
|
||||
msg,
|
||||
)));
|
||||
event_emitter.emit(ServerEvent::Chat(
|
||||
UnresolvedChatMsg::npc_say(*agent_data.uid, msg),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
event_emitter.emit(ServerEvent::Chat(UnresolvedChatMsg::npc_say(
|
||||
@ -564,6 +566,48 @@ pub fn handle_inbox_update_pending_trade(bdata: &mut BehaviorData) -> bool {
|
||||
));
|
||||
}
|
||||
}
|
||||
},
|
||||
TradingBehavior::AcceptFood => {
|
||||
let mut only_food = true;
|
||||
let ability_map = AbilityMap::load().read();
|
||||
let msm = MaterialStatManifest::load().read();
|
||||
if let Some(ri) = &inventories[1 - who] {
|
||||
for (slot, _) in pending.offers[1 - who].iter() {
|
||||
if let Some(item) = ri.inventory.get(slot) {
|
||||
if let Ok(item) = Item::new_from_item_definition_id(
|
||||
item.name.as_ref(),
|
||||
&ability_map,
|
||||
&msm,
|
||||
) {
|
||||
if !item.tags().contains(&ItemTag::Food) {
|
||||
only_food = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !pending.accept_flags[who]
|
||||
&& pending.offers[who].is_empty()
|
||||
&& !pending.offers[1 - who].is_empty()
|
||||
&& only_food
|
||||
{
|
||||
event_emitter.emit(ServerEvent::ProcessTradeAction(
|
||||
*agent_data.entity,
|
||||
tradeid,
|
||||
TradeAction::Accept(pending.phase),
|
||||
));
|
||||
}
|
||||
},
|
||||
TradingBehavior::None => {
|
||||
agent.behavior.unset(BehaviorState::TRADING);
|
||||
event_emitter.emit(ServerEvent::ProcessTradeAction(
|
||||
*agent_data.entity,
|
||||
tradeid,
|
||||
TradeAction::Decline,
|
||||
));
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
|
Loading…
Reference in New Issue
Block a user