mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Allow pets to be traded with.
This commit is contained in:
parent
dd5523785c
commit
c62bc0dd0d
@ -86,6 +86,7 @@ bitflags::bitflags! {
|
||||
#[derive(Default)]
|
||||
pub struct BehaviorCapability: u8 {
|
||||
const SPEAK = 0b00000001;
|
||||
const TRADE = 0b00000010;
|
||||
}
|
||||
}
|
||||
bitflags::bitflags! {
|
||||
@ -156,7 +157,9 @@ impl Behavior {
|
||||
}
|
||||
|
||||
/// Check if the Behavior is able to trade
|
||||
pub fn can_trade(&self) -> bool { self.trade_site.is_some() }
|
||||
pub fn can_trade(&self, alignment: Option<&Alignment>, counterparty: Uid) -> bool {
|
||||
self.trade_site.is_some() || alignment == Some(&Alignment::Owned(counterparty))
|
||||
}
|
||||
|
||||
/// Set a state to the Behavior
|
||||
pub fn set(&mut self, state: BehaviorState) { self.state.set(state, true) }
|
||||
|
@ -7,9 +7,9 @@ use common::{
|
||||
aura::{Aura, AuraKind, AuraTarget},
|
||||
beam,
|
||||
buff::{BuffCategory, BuffData, BuffKind, BuffSource},
|
||||
shockwave, Agent, Alignment, Anchor, Body, Health, Inventory, ItemDrop, LightEmitter,
|
||||
Object, Ori, PidController, Poise, Pos, Projectile, Scale, SkillSet, Stats, Vel,
|
||||
WaypointArea,
|
||||
shockwave, Agent, Alignment, Anchor, BehaviorCapability, Body, Health, Inventory, ItemDrop,
|
||||
LightEmitter, Object, Ori, PidController, Poise, Pos, Projectile, Scale, SkillSet, Stats,
|
||||
Vel, WaypointArea,
|
||||
},
|
||||
event::{EventBus, UpdateCharacterMetadata},
|
||||
lottery::LootSpec,
|
||||
@ -98,10 +98,18 @@ pub fn handle_create_npc(
|
||||
let entity = server
|
||||
.state
|
||||
.create_npc(pos, stats, skill_set, health, poise, inventory, body)
|
||||
.with(scale)
|
||||
.with(alignment);
|
||||
.with(scale);
|
||||
|
||||
let entity = if let Some(agent) = agent.into() {
|
||||
let mut agent = agent.into();
|
||||
if let Some(agent) = &mut agent {
|
||||
if let Alignment::Owned(_) = &alignment {
|
||||
agent.behavior.allow(BehaviorCapability::TRADE);
|
||||
}
|
||||
}
|
||||
|
||||
let entity = entity.with(alignment);
|
||||
|
||||
let entity = if let Some(agent) = agent {
|
||||
entity.with(agent)
|
||||
} else {
|
||||
entity
|
||||
|
@ -35,20 +35,18 @@ fn notify_agent_prices(
|
||||
entity: EcsEntity,
|
||||
event: AgentEvent,
|
||||
) {
|
||||
if let Some((Some(site_id), agent)) = agents.get_mut(entity).map(|a| (a.behavior.trade_site, a))
|
||||
{
|
||||
let prices = index.get_site_prices(site_id);
|
||||
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
|
||||
let prices = site_id
|
||||
.and_then(|site_id| index.get_site_prices(site_id))
|
||||
.unwrap_or(boxval.2);
|
||||
// Box<(tid, pend, _, inventories)>) = event {
|
||||
agent
|
||||
.inbox
|
||||
.push_back(AgentEvent::UpdatePendingTrade(Box::new((
|
||||
// Prefer using this Agent's price data, but use the counterparty's price
|
||||
// data if we don't have price data
|
||||
boxval.0,
|
||||
boxval.1,
|
||||
prices.unwrap_or(boxval.2),
|
||||
boxval.3,
|
||||
boxval.0, boxval.1, prices, boxval.3,
|
||||
))));
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
use crate::{client::Client, events::update_map_markers};
|
||||
use common::{
|
||||
comp::{self, anchor::Anchor, group::GroupManager, Agent, Alignment, Pet},
|
||||
comp::{
|
||||
self, anchor::Anchor, group::GroupManager, Agent, Alignment, Behavior, BehaviorCapability,
|
||||
Pet,
|
||||
},
|
||||
uid::Uid,
|
||||
};
|
||||
use common_net::msg::ServerGeneral;
|
||||
@ -51,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 _ = ecs
|
||||
.write_storage()
|
||||
.insert(pet_entity, Agent::from_body(body));
|
||||
let agent = Agent::from_body(body).with_behavior(
|
||||
Behavior::default().maybe_with_capabilities(Some(BehaviorCapability::TRADE)),
|
||||
);
|
||||
let _ = ecs.write_storage().insert(pet_entity, agent);
|
||||
}
|
||||
|
||||
// Add to group system
|
||||
|
@ -108,17 +108,21 @@ impl BehaviorTree {
|
||||
/// events.
|
||||
pub fn interaction(agent: &Agent) -> Self {
|
||||
let is_in_combat = agent.target.map_or(false, |t| t.hostile);
|
||||
if !is_in_combat && agent.behavior.can(BehaviorCapability::SPEAK) {
|
||||
Self {
|
||||
tree: vec![
|
||||
increment_timer_deltatime,
|
||||
handle_inbox_talk,
|
||||
handle_inbox_trade_invite,
|
||||
handle_inbox_trade_accepted,
|
||||
handle_inbox_finished_trade,
|
||||
handle_inbox_update_pending_trade,
|
||||
],
|
||||
if !is_in_combat
|
||||
&& (agent.behavior.can(BehaviorCapability::SPEAK)
|
||||
|| agent.behavior.can(BehaviorCapability::TRADE))
|
||||
{
|
||||
let mut tree: Vec<BehaviorFn> = vec![increment_timer_deltatime];
|
||||
if agent.behavior.can(BehaviorCapability::SPEAK) {
|
||||
tree.push(handle_inbox_talk);
|
||||
}
|
||||
tree.extend_from_slice(&[
|
||||
handle_inbox_trade_invite,
|
||||
handle_inbox_trade_accepted,
|
||||
handle_inbox_finished_trade,
|
||||
handle_inbox_update_pending_trade,
|
||||
]);
|
||||
Self { tree }
|
||||
} else {
|
||||
Self {
|
||||
tree: vec![handle_inbox_cancel_interactions],
|
||||
|
@ -167,7 +167,7 @@ pub fn handle_inbox_talk(bdata: &mut BehaviorData) -> bool {
|
||||
standard_response_msg()
|
||||
};
|
||||
agent_data.chat_npc(msg, event_emitter);
|
||||
} else if agent.behavior.can_trade() {
|
||||
} else if agent.behavior.can_trade(agent_data.alignment, by) {
|
||||
if !agent.behavior.is(BehaviorState::TRADING) {
|
||||
controller.push_initiate_invite(by, InviteKind::Trade);
|
||||
agent_data.chat_npc(
|
||||
@ -250,21 +250,29 @@ pub fn handle_inbox_talk(bdata: &mut BehaviorData) -> bool {
|
||||
}
|
||||
},
|
||||
Subject::Trade => {
|
||||
if agent.behavior.can_trade() {
|
||||
if agent.behavior.can_trade(agent_data.alignment, by) {
|
||||
if !agent.behavior.is(BehaviorState::TRADING) {
|
||||
controller.push_initiate_invite(by, InviteKind::Trade);
|
||||
agent_data.chat_npc(
|
||||
agent_data.chat_npc_if_allowed_to_speak(
|
||||
"npc-speech-merchant_advertisement",
|
||||
agent,
|
||||
event_emitter,
|
||||
);
|
||||
} else {
|
||||
agent_data.chat_npc("npc-speech-merchant_busy", event_emitter);
|
||||
agent_data.chat_npc_if_allowed_to_speak(
|
||||
"npc-speech-merchant_busy",
|
||||
agent,
|
||||
event_emitter,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
// TODO: maybe make some travellers willing to trade with
|
||||
// simpler goods like potions
|
||||
agent_data
|
||||
.chat_npc("npc-speech-villager_decline_trade", event_emitter);
|
||||
agent_data.chat_npc_if_allowed_to_speak(
|
||||
"npc-speech-villager_decline_trade",
|
||||
agent,
|
||||
event_emitter,
|
||||
);
|
||||
}
|
||||
},
|
||||
Subject::Mood => {
|
||||
@ -387,7 +395,7 @@ pub fn handle_inbox_trade_invite(bdata: &mut BehaviorData) -> bool {
|
||||
}
|
||||
|
||||
if let Some(AgentEvent::TradeInvite(with)) = agent.inbox.pop_front() {
|
||||
if agent.behavior.can_trade() {
|
||||
if agent.behavior.can_trade(agent_data.alignment, with) {
|
||||
if !agent.behavior.is(BehaviorState::TRADING) {
|
||||
// stand still and looking towards the trading player
|
||||
controller.push_action(ControlAction::Stand);
|
||||
@ -458,10 +466,18 @@ pub fn handle_inbox_finished_trade(bdata: &mut BehaviorData) -> bool {
|
||||
if agent.behavior.is(BehaviorState::TRADING) {
|
||||
match result {
|
||||
TradeResult::Completed => {
|
||||
agent_data.chat_npc("npc-speech-merchant_trade_successful", event_emitter);
|
||||
agent_data.chat_npc_if_allowed_to_speak(
|
||||
"npc-speech-merchant_trade_successful",
|
||||
agent,
|
||||
event_emitter,
|
||||
);
|
||||
},
|
||||
_ => {
|
||||
agent_data.chat_npc("npc-speech-merchant_trade_declined", event_emitter);
|
||||
agent_data.chat_npc_if_allowed_to_speak(
|
||||
"npc-speech-merchant_trade_declined",
|
||||
agent,
|
||||
event_emitter,
|
||||
);
|
||||
},
|
||||
}
|
||||
agent.behavior.unset(BehaviorState::TRADING);
|
||||
@ -587,7 +603,7 @@ pub fn handle_inbox_cancel_interactions(bdata: &mut BehaviorData) -> bool {
|
||||
{
|
||||
// in combat, speak to players that aren't the current target
|
||||
if !target.hostile || target.target != speaker {
|
||||
if agent.behavior.can_trade() {
|
||||
if agent.behavior.can_trade(agent_data.alignment, *by) {
|
||||
agent_data.chat_npc_if_allowed_to_speak(
|
||||
"npc-speech-merchant_busy",
|
||||
agent,
|
||||
@ -610,12 +626,18 @@ pub fn handle_inbox_cancel_interactions(bdata: &mut BehaviorData) -> bool {
|
||||
if agent.behavior.is(BehaviorState::TRADING) {
|
||||
match result {
|
||||
TradeResult::Completed => {
|
||||
agent_data
|
||||
.chat_npc("npc-speech-merchant_trade_successful", event_emitter);
|
||||
agent_data.chat_npc_if_allowed_to_speak(
|
||||
"npc-speech-merchant_trade_successful",
|
||||
agent,
|
||||
event_emitter,
|
||||
);
|
||||
},
|
||||
_ => {
|
||||
agent_data
|
||||
.chat_npc("npc-speech-merchant_trade_declined", event_emitter);
|
||||
agent_data.chat_npc_if_allowed_to_speak(
|
||||
"npc-speech-merchant_trade_declined",
|
||||
agent,
|
||||
event_emitter,
|
||||
);
|
||||
},
|
||||
}
|
||||
agent.behavior.unset(BehaviorState::TRADING);
|
||||
@ -631,7 +653,11 @@ pub fn handle_inbox_cancel_interactions(bdata: &mut BehaviorData) -> bool {
|
||||
*tradeid,
|
||||
TradeAction::Decline,
|
||||
));
|
||||
agent_data.chat_npc("npc-speech-merchant_trade_cancelled_hostile", event_emitter);
|
||||
agent_data.chat_npc_if_allowed_to_speak(
|
||||
"npc-speech-merchant_trade_cancelled_hostile",
|
||||
agent,
|
||||
event_emitter,
|
||||
);
|
||||
true
|
||||
},
|
||||
AgentEvent::ServerSound(_) | AgentEvent::Hurt => false,
|
||||
|
@ -517,6 +517,7 @@ impl NpcData {
|
||||
.with_behavior(
|
||||
Behavior::default()
|
||||
.maybe_with_capabilities(can_speak.then_some(BehaviorCapability::SPEAK))
|
||||
.maybe_with_capabilities(trade_for_site.map(|_| BehaviorCapability::TRADE))
|
||||
.with_trade_site(trade_for_site),
|
||||
)
|
||||
.with_patrol_origin(pos)
|
||||
|
@ -2103,12 +2103,18 @@ impl Hud {
|
||||
},
|
||||
Some(comp::Alignment::Owned(owner))
|
||||
if Some(*owner) == client.uid()
|
||||
&& !client.is_riding()
|
||||
&& is_mount.is_none()
|
||||
&& is_mountable(body, bodies.get(client.entity()))
|
||||
&& dist_sqr < common::consts::MAX_MOUNT_RANGE.powi(2) =>
|
||||
{
|
||||
vec![(GameInput::Mount, i18n.get_msg("hud-mount").to_string())]
|
||||
let mut options =
|
||||
vec![(GameInput::Trade, i18n.get_msg("hud-trade").to_string())];
|
||||
if !client.is_riding()
|
||||
&& is_mount.is_none()
|
||||
&& is_mountable(body, bodies.get(client.entity()))
|
||||
{
|
||||
options
|
||||
.push((GameInput::Mount, i18n.get_msg("hud-mount").to_string()))
|
||||
}
|
||||
options
|
||||
},
|
||||
_ => Vec::new(),
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user