mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Get SitePricing information to clients, and use it to display coin-denominated prices in voxygen on tooltips during a trade. Also boost merchant spawn rate slightly.
This commit is contained in:
parent
28952f6d7b
commit
8d90548331
@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Pickaxes (can be used to collect gems and mine weak rock)
|
- Pickaxes (can be used to collect gems and mine weak rock)
|
||||||
- You can now jump out of rolls for a slight jump boost
|
- You can now jump out of rolls for a slight jump boost
|
||||||
- Dungeons now have multiple kinds of stairs.
|
- Dungeons now have multiple kinds of stairs.
|
||||||
|
- Trades now display item prices in tooltips.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ use common::{
|
|||||||
recipe::RecipeBook,
|
recipe::RecipeBook,
|
||||||
resources::PlayerEntity,
|
resources::PlayerEntity,
|
||||||
terrain::{block::Block, neighbors, BiomeKind, SitesKind, TerrainChunk, TerrainChunkSize},
|
terrain::{block::Block, neighbors, BiomeKind, SitesKind, TerrainChunk, TerrainChunkSize},
|
||||||
trade::{PendingTrade, TradeAction, TradeId, TradeResult},
|
trade::{PendingTrade, SitePrices, TradeAction, TradeId, TradeResult},
|
||||||
uid::{Uid, UidAllocator},
|
uid::{Uid, UidAllocator},
|
||||||
vol::RectVolSize,
|
vol::RectVolSize,
|
||||||
};
|
};
|
||||||
@ -156,7 +156,7 @@ pub struct Client {
|
|||||||
// Pending invites that this client has sent out
|
// Pending invites that this client has sent out
|
||||||
pending_invites: HashSet<Uid>,
|
pending_invites: HashSet<Uid>,
|
||||||
// The pending trade the client is involved in, and it's id
|
// The pending trade the client is involved in, and it's id
|
||||||
pending_trade: Option<(TradeId, PendingTrade)>,
|
pending_trade: Option<(TradeId, PendingTrade, Option<SitePrices>)>,
|
||||||
|
|
||||||
_network: Network,
|
_network: Network,
|
||||||
participant: Option<Participant>,
|
participant: Option<Participant>,
|
||||||
@ -694,7 +694,7 @@ impl Client {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn perform_trade_action(&mut self, action: TradeAction) {
|
pub fn perform_trade_action(&mut self, action: TradeAction) {
|
||||||
if let Some((id, _)) = self.pending_trade {
|
if let Some((id, _, _)) = self.pending_trade {
|
||||||
if let TradeAction::Decline = action {
|
if let TradeAction::Decline = action {
|
||||||
self.pending_trade.take();
|
self.pending_trade.take();
|
||||||
}
|
}
|
||||||
@ -833,7 +833,9 @@ impl Client {
|
|||||||
|
|
||||||
pub fn pending_invites(&self) -> &HashSet<Uid> { &self.pending_invites }
|
pub fn pending_invites(&self) -> &HashSet<Uid> { &self.pending_invites }
|
||||||
|
|
||||||
pub fn pending_trade(&self) -> &Option<(TradeId, PendingTrade)> { &self.pending_trade }
|
pub fn pending_trade(&self) -> &Option<(TradeId, PendingTrade, Option<SitePrices>)> {
|
||||||
|
&self.pending_trade
|
||||||
|
}
|
||||||
|
|
||||||
pub fn send_invite(&mut self, invitee: Uid, kind: InviteKind) {
|
pub fn send_invite(&mut self, invitee: Uid, kind: InviteKind) {
|
||||||
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::InitiateInvite(
|
self.send_msg(ClientGeneral::ControlEvent(ControlEvent::InitiateInvite(
|
||||||
@ -1637,12 +1639,12 @@ impl Client {
|
|||||||
impulse,
|
impulse,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
ServerGeneral::UpdatePendingTrade(id, trade) => {
|
ServerGeneral::UpdatePendingTrade(id, trade, pricing) => {
|
||||||
tracing::trace!("UpdatePendingTrade {:?} {:?}", id, trade);
|
tracing::trace!("UpdatePendingTrade {:?} {:?}", id, trade);
|
||||||
self.pending_trade = Some((id, trade));
|
self.pending_trade = Some((id, trade, pricing));
|
||||||
},
|
},
|
||||||
ServerGeneral::FinishedTrade(result) => {
|
ServerGeneral::FinishedTrade(result) => {
|
||||||
if let Some((_, trade)) = self.pending_trade.take() {
|
if let Some((_, trade, _)) = self.pending_trade.take() {
|
||||||
self.update_available_recipes();
|
self.update_available_recipes();
|
||||||
frontend_events.push(Event::TradeComplete { result, trade })
|
frontend_events.push(Event::TradeComplete { result, trade })
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ use common::{
|
|||||||
recipe::RecipeBook,
|
recipe::RecipeBook,
|
||||||
resources::TimeOfDay,
|
resources::TimeOfDay,
|
||||||
terrain::{Block, TerrainChunk},
|
terrain::{Block, TerrainChunk},
|
||||||
trade::{PendingTrade, TradeId, TradeResult},
|
trade::{PendingTrade, SitePrices, TradeId, TradeResult},
|
||||||
uid::Uid,
|
uid::Uid,
|
||||||
uuid::Uuid,
|
uuid::Uuid,
|
||||||
};
|
};
|
||||||
@ -126,7 +126,7 @@ pub enum ServerGeneral {
|
|||||||
Disconnect(DisconnectReason),
|
Disconnect(DisconnectReason),
|
||||||
/// Send a popup notification such as "Waypoint Saved"
|
/// Send a popup notification such as "Waypoint Saved"
|
||||||
Notification(Notification),
|
Notification(Notification),
|
||||||
UpdatePendingTrade(TradeId, PendingTrade),
|
UpdatePendingTrade(TradeId, PendingTrade, Option<SitePrices>),
|
||||||
FinishedTrade(TradeResult),
|
FinishedTrade(TradeResult),
|
||||||
/// Economic information about sites
|
/// Economic information about sites
|
||||||
SiteEconomy(EconomyInfo),
|
SiteEconomy(EconomyInfo),
|
||||||
@ -237,7 +237,7 @@ impl ServerMsg {
|
|||||||
| ServerGeneral::SetViewDistance(_)
|
| ServerGeneral::SetViewDistance(_)
|
||||||
| ServerGeneral::Outcomes(_)
|
| ServerGeneral::Outcomes(_)
|
||||||
| ServerGeneral::Knockback(_)
|
| ServerGeneral::Knockback(_)
|
||||||
| ServerGeneral::UpdatePendingTrade(_, _)
|
| ServerGeneral::UpdatePendingTrade(_, _, _)
|
||||||
| ServerGeneral::FinishedTrade(_)
|
| ServerGeneral::FinishedTrade(_)
|
||||||
| ServerGeneral::SiteEconomy(_) => {
|
| ServerGeneral::SiteEconomy(_) => {
|
||||||
c_type == ClientType::Game && presence.is_some()
|
c_type == ClientType::Game && presence.is_some()
|
||||||
|
@ -320,6 +320,21 @@ impl Default for Good {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Good {
|
||||||
|
/// The discounting factor applied when selling goods back to a merchant
|
||||||
|
pub fn trade_margin(&self) -> f32 {
|
||||||
|
match self {
|
||||||
|
Good::Tools | Good::Armor => 0.5,
|
||||||
|
Good::Food | Good::Potions | Good::Ingredients => 0.75,
|
||||||
|
Good::Coin => 1.0,
|
||||||
|
// Certain abstract goods (like Territory) shouldn't be attached to concrete items;
|
||||||
|
// give a sale price of 0 if the player is trying to sell a concrete item that somehow
|
||||||
|
// has one of these categories
|
||||||
|
_ => 0.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ideally this would be a real Id<Site> but that is from the world crate
|
// ideally this would be a real Id<Site> but that is from the world crate
|
||||||
pub type SiteId = u64;
|
pub type SiteId = u64;
|
||||||
|
|
||||||
@ -329,7 +344,7 @@ pub struct SiteInformation {
|
|||||||
pub unconsumed_stock: HashMap<Good, f32>,
|
pub unconsumed_stock: HashMap<Good, f32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||||
pub struct SitePrices {
|
pub struct SitePrices {
|
||||||
pub values: HashMap<Good, f32>,
|
pub values: HashMap<Good, f32>,
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,7 @@ impl Client {
|
|||||||
| ServerGeneral::SiteEconomy(_)
|
| ServerGeneral::SiteEconomy(_)
|
||||||
| ServerGeneral::Outcomes(_)
|
| ServerGeneral::Outcomes(_)
|
||||||
| ServerGeneral::Knockback(_)
|
| ServerGeneral::Knockback(_)
|
||||||
| ServerGeneral::UpdatePendingTrade(_, _)
|
| ServerGeneral::UpdatePendingTrade(_, _, _)
|
||||||
| ServerGeneral::FinishedTrade(_) => {
|
| ServerGeneral::FinishedTrade(_) => {
|
||||||
self.in_game_stream.lock().unwrap().send(g)
|
self.in_game_stream.lock().unwrap().send(g)
|
||||||
},
|
},
|
||||||
@ -162,7 +162,7 @@ impl Client {
|
|||||||
| ServerGeneral::Outcomes(_)
|
| ServerGeneral::Outcomes(_)
|
||||||
| ServerGeneral::Knockback(_)
|
| ServerGeneral::Knockback(_)
|
||||||
| ServerGeneral::SiteEconomy(_)
|
| ServerGeneral::SiteEconomy(_)
|
||||||
| ServerGeneral::UpdatePendingTrade(_, _)
|
| ServerGeneral::UpdatePendingTrade(_, _, _)
|
||||||
| ServerGeneral::FinishedTrade(_) => {
|
| ServerGeneral::FinishedTrade(_) => {
|
||||||
PreparedMsg::new(2, &g, &self.in_game_stream)
|
PreparedMsg::new(2, &g, &self.in_game_stream)
|
||||||
},
|
},
|
||||||
|
@ -3,7 +3,7 @@ use crate::{client::Client, Server};
|
|||||||
use common::{
|
use common::{
|
||||||
comp::{
|
comp::{
|
||||||
self,
|
self,
|
||||||
agent::AgentEvent,
|
agent::{Agent, AgentEvent},
|
||||||
group::GroupManager,
|
group::GroupManager,
|
||||||
invite::{Invite, InviteKind, InviteResponse, PendingInvites},
|
invite::{Invite, InviteKind, InviteResponse, PendingInvites},
|
||||||
ChatType,
|
ChatType,
|
||||||
@ -162,9 +162,11 @@ pub fn handle_invite_response(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_invite_accept(server: &mut Server, entity: specs::Entity) {
|
pub fn handle_invite_accept(server: &mut Server, entity: specs::Entity) {
|
||||||
|
let index = server.index.clone();
|
||||||
let state = server.state_mut();
|
let state = server.state_mut();
|
||||||
let clients = state.ecs().read_storage::<Client>();
|
let clients = state.ecs().read_storage::<Client>();
|
||||||
let uids = state.ecs().read_storage::<Uid>();
|
let uids = state.ecs().read_storage::<Uid>();
|
||||||
|
let agents = state.ecs().read_storage::<Agent>();
|
||||||
let mut invites = state.ecs().write_storage::<Invite>();
|
let mut invites = state.ecs().write_storage::<Invite>();
|
||||||
if let Some((inviter, kind)) = invites.remove(entity).and_then(|invite| {
|
if let Some((inviter, kind)) = invites.remove(entity).and_then(|invite| {
|
||||||
let Invite { inviter, kind } = invite;
|
let Invite { inviter, kind } = invite;
|
||||||
@ -216,12 +218,20 @@ pub fn handle_invite_accept(server: &mut Server, entity: specs::Entity) {
|
|||||||
let mut trades = state.ecs().write_resource::<Trades>();
|
let mut trades = state.ecs().write_resource::<Trades>();
|
||||||
let id = trades.begin_trade(inviter_uid, invitee_uid);
|
let id = trades.begin_trade(inviter_uid, invitee_uid);
|
||||||
let trade = trades.trades[&id].clone();
|
let trade = trades.trades[&id].clone();
|
||||||
clients
|
let pricing = agents
|
||||||
.get(inviter)
|
.get(inviter)
|
||||||
.map(|c| c.send(ServerGeneral::UpdatePendingTrade(id, trade.clone())));
|
.and_then(|a| index.get_site_prices(a))
|
||||||
|
.or_else(|| agents.get(entity).and_then(|a| index.get_site_prices(a)));
|
||||||
|
clients.get(inviter).map(|c| {
|
||||||
|
c.send(ServerGeneral::UpdatePendingTrade(
|
||||||
|
id,
|
||||||
|
trade.clone(),
|
||||||
|
pricing.clone(),
|
||||||
|
))
|
||||||
|
});
|
||||||
clients
|
clients
|
||||||
.get(entity)
|
.get(entity)
|
||||||
.map(|c| c.send(ServerGeneral::UpdatePendingTrade(id, trade)));
|
.map(|c| c.send(ServerGeneral::UpdatePendingTrade(id, trade, pricing)));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -33,19 +33,18 @@ fn notify_agent_prices(
|
|||||||
event: AgentEvent,
|
event: AgentEvent,
|
||||||
) {
|
) {
|
||||||
if let Some(agent) = agents.get_mut(entity) {
|
if let Some(agent) = agents.get_mut(entity) {
|
||||||
|
let prices = index.get_site_prices(agent);
|
||||||
if let AgentEvent::UpdatePendingTrade(boxval) = event {
|
if let AgentEvent::UpdatePendingTrade(boxval) = event {
|
||||||
// Box<(tid, pend, _, inventories)>) = event {
|
// Box<(tid, pend, _, inventories)>) = event {
|
||||||
let prices = agent
|
|
||||||
.trade_for_site
|
|
||||||
.map(|i| index.sites.recreate_id(i))
|
|
||||||
.flatten()
|
|
||||||
.map(|i| index.sites.get(i))
|
|
||||||
.map(|s| s.economy.get_site_prices())
|
|
||||||
.unwrap_or_default();
|
|
||||||
agent
|
agent
|
||||||
.inbox
|
.inbox
|
||||||
.push_front(AgentEvent::UpdatePendingTrade(Box::new((
|
.push_front(AgentEvent::UpdatePendingTrade(Box::new((
|
||||||
boxval.0, boxval.1, prices, boxval.3,
|
// 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,
|
||||||
))));
|
))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,6 +102,8 @@ pub fn handle_process_trade_action(
|
|||||||
} else {
|
} else {
|
||||||
let mut entities: [Option<specs::Entity>; 2] = [None, None];
|
let mut entities: [Option<specs::Entity>; 2] = [None, None];
|
||||||
let mut inventories: [Option<ReducedInventory>; 2] = [None, None];
|
let mut inventories: [Option<ReducedInventory>; 2] = [None, None];
|
||||||
|
let mut prices = None;
|
||||||
|
let agents = server.state.ecs().read_storage::<Agent>();
|
||||||
// sadly there is no map and collect on arrays
|
// sadly there is no map and collect on arrays
|
||||||
for i in 0..2 {
|
for i in 0..2 {
|
||||||
// parties.len()) {
|
// parties.len()) {
|
||||||
@ -114,13 +115,23 @@ pub fn handle_process_trade_action(
|
|||||||
.read_component::<Inventory>()
|
.read_component::<Inventory>()
|
||||||
.get(e)
|
.get(e)
|
||||||
.map(|i| ReducedInventory::from(i));
|
.map(|i| ReducedInventory::from(i));
|
||||||
|
// 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))
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
drop(agents);
|
||||||
for party in entities.iter() {
|
for party in entities.iter() {
|
||||||
if let Some(e) = *party {
|
if let Some(e) = *party {
|
||||||
server.notify_client(
|
server.notify_client(
|
||||||
e,
|
e,
|
||||||
ServerGeneral::UpdatePendingTrade(trade_id, entry.get().clone()),
|
ServerGeneral::UpdatePendingTrade(
|
||||||
|
trade_id,
|
||||||
|
entry.get().clone(),
|
||||||
|
prices.clone(),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
notify_agent_prices(
|
notify_agent_prices(
|
||||||
server.state.ecs().write_storage::<Agent>(),
|
server.state.ecs().write_storage::<Agent>(),
|
||||||
@ -129,7 +140,7 @@ pub fn handle_process_trade_action(
|
|||||||
AgentEvent::UpdatePendingTrade(Box::new((
|
AgentEvent::UpdatePendingTrade(Box::new((
|
||||||
trade_id,
|
trade_id,
|
||||||
entry.get().clone(),
|
entry.get().clone(),
|
||||||
Default::default(),
|
prices.clone().unwrap_or_default(),
|
||||||
inventories.clone(),
|
inventories.clone(),
|
||||||
))),
|
))),
|
||||||
);
|
);
|
||||||
|
@ -22,7 +22,7 @@ use common::{
|
|||||||
rtsim::{Memory, MemoryItem, RtSimEntity, RtSimEvent},
|
rtsim::{Memory, MemoryItem, RtSimEntity, RtSimEvent},
|
||||||
terrain::{Block, TerrainGrid},
|
terrain::{Block, TerrainGrid},
|
||||||
time::DayPeriod,
|
time::DayPeriod,
|
||||||
trade::{Good, TradeAction, TradePhase, TradeResult},
|
trade::{TradeAction, TradePhase, TradeResult},
|
||||||
uid::{Uid, UidAllocator},
|
uid::{Uid, UidAllocator},
|
||||||
util::Dir,
|
util::Dir,
|
||||||
vol::ReadVol,
|
vol::ReadVol,
|
||||||
@ -947,14 +947,6 @@ impl<'a> AgentData<'a> {
|
|||||||
// This needs revisiting when agents can initiate trades (e.g. to offer
|
// This needs revisiting when agents can initiate trades (e.g. to offer
|
||||||
// mercenary contracts as quests)
|
// mercenary contracts as quests)
|
||||||
const WHO: usize = 1;
|
const WHO: usize = 1;
|
||||||
fn trade_margin(g: Good) -> f32 {
|
|
||||||
match g {
|
|
||||||
Good::Tools | Good::Armor => 0.5,
|
|
||||||
Good::Food | Good::Potions | Good::Ingredients => 0.75,
|
|
||||||
Good::Coin => 1.0,
|
|
||||||
_ => 0.0, // what is this?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let balance = |who: usize, reduce: bool| {
|
let balance = |who: usize, reduce: bool| {
|
||||||
pending.offers[who]
|
pending.offers[who]
|
||||||
.iter()
|
.iter()
|
||||||
@ -972,7 +964,7 @@ impl<'a> AgentData<'a> {
|
|||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
* factor
|
* factor
|
||||||
* (*amount as f32)
|
* (*amount as f32)
|
||||||
* if reduce { trade_margin(material) } else { 1.0 }
|
* if reduce { material.trade_margin() } else { 1.0 }
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.flatten()
|
.flatten()
|
||||||
|
@ -64,6 +64,7 @@ pub struct InventoryScrollerState {
|
|||||||
|
|
||||||
#[derive(WidgetCommon)]
|
#[derive(WidgetCommon)]
|
||||||
pub struct InventoryScroller<'a> {
|
pub struct InventoryScroller<'a> {
|
||||||
|
client: &'a Client,
|
||||||
imgs: &'a Imgs,
|
imgs: &'a Imgs,
|
||||||
item_imgs: &'a ItemImgs,
|
item_imgs: &'a ItemImgs,
|
||||||
fonts: &'a Fonts,
|
fonts: &'a Fonts,
|
||||||
@ -87,6 +88,7 @@ pub struct InventoryScroller<'a> {
|
|||||||
impl<'a> InventoryScroller<'a> {
|
impl<'a> InventoryScroller<'a> {
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
|
client: &'a Client,
|
||||||
imgs: &'a Imgs,
|
imgs: &'a Imgs,
|
||||||
item_imgs: &'a ItemImgs,
|
item_imgs: &'a ItemImgs,
|
||||||
fonts: &'a Fonts,
|
fonts: &'a Fonts,
|
||||||
@ -105,6 +107,7 @@ impl<'a> InventoryScroller<'a> {
|
|||||||
bg_ids: &'a BackgroundIds,
|
bg_ids: &'a BackgroundIds,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
InventoryScroller {
|
InventoryScroller {
|
||||||
|
client,
|
||||||
imgs,
|
imgs,
|
||||||
item_imgs,
|
item_imgs,
|
||||||
fonts,
|
fonts,
|
||||||
@ -302,6 +305,11 @@ impl<'a> InventoryScroller<'a> {
|
|||||||
Quality::Artifact => self.imgs.inv_slot_orange,
|
Quality::Artifact => self.imgs.inv_slot_orange,
|
||||||
_ => self.imgs.inv_slot_red,
|
_ => self.imgs.inv_slot_red,
|
||||||
};
|
};
|
||||||
|
let mut desc = desc.to_string();
|
||||||
|
if let Some((_, _, prices)) = self.client.pending_trade() {
|
||||||
|
super::util::append_price_desc(&mut desc, prices, item.item_definition_id());
|
||||||
|
}
|
||||||
|
|
||||||
slot_widget
|
slot_widget
|
||||||
.filled_slot(quality_col_img)
|
.filled_slot(quality_col_img)
|
||||||
.with_tooltip(
|
.with_tooltip(
|
||||||
@ -571,6 +579,7 @@ impl<'a> Widget for Bag<'a> {
|
|||||||
.desc_text_color(TEXT_COLOR);
|
.desc_text_color(TEXT_COLOR);
|
||||||
|
|
||||||
InventoryScroller::new(
|
InventoryScroller::new(
|
||||||
|
self.client,
|
||||||
self.imgs,
|
self.imgs,
|
||||||
self.item_imgs,
|
self.item_imgs,
|
||||||
self.fonts,
|
self.fonts,
|
||||||
|
@ -20,7 +20,7 @@ use common::{
|
|||||||
inventory::item::{MaterialStatManifest, Quality},
|
inventory::item::{MaterialStatManifest, Quality},
|
||||||
Inventory,
|
Inventory,
|
||||||
},
|
},
|
||||||
trade::{PendingTrade, TradeAction, TradePhase},
|
trade::{PendingTrade, SitePrices, TradeAction, TradePhase},
|
||||||
};
|
};
|
||||||
use common_net::sync::WorldSyncExt;
|
use common_net::sync::WorldSyncExt;
|
||||||
use conrod_core::{
|
use conrod_core::{
|
||||||
@ -156,6 +156,7 @@ impl<'a> Trade<'a> {
|
|||||||
state: &mut ConrodState<'_, State>,
|
state: &mut ConrodState<'_, State>,
|
||||||
ui: &mut UiCell<'_>,
|
ui: &mut UiCell<'_>,
|
||||||
trade: &'a PendingTrade,
|
trade: &'a PendingTrade,
|
||||||
|
prices: &'a Option<SitePrices>,
|
||||||
ours: bool,
|
ours: bool,
|
||||||
) -> <Self as Widget>::Event {
|
) -> <Self as Widget>::Event {
|
||||||
let inventories = self.client.inventories();
|
let inventories = self.client.inventories();
|
||||||
@ -233,7 +234,17 @@ impl<'a> Trade<'a> {
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if matches!(trade.phase(), TradePhase::Mutate) {
|
if matches!(trade.phase(), TradePhase::Mutate) {
|
||||||
self.phase1_itemwidget(state, ui, inventory, who, ours, entity, name, &tradeslots);
|
self.phase1_itemwidget(
|
||||||
|
state,
|
||||||
|
ui,
|
||||||
|
inventory,
|
||||||
|
who,
|
||||||
|
ours,
|
||||||
|
entity,
|
||||||
|
name,
|
||||||
|
prices,
|
||||||
|
&tradeslots,
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
self.phase2_itemwidget(state, ui, inventory, who, ours, entity, &tradeslots);
|
self.phase2_itemwidget(state, ui, inventory, who, ours, entity, &tradeslots);
|
||||||
}
|
}
|
||||||
@ -250,6 +261,7 @@ impl<'a> Trade<'a> {
|
|||||||
ours: bool,
|
ours: bool,
|
||||||
entity: EcsEntity,
|
entity: EcsEntity,
|
||||||
name: String,
|
name: String,
|
||||||
|
prices: &'a Option<SitePrices>,
|
||||||
tradeslots: &[TradeSlot],
|
tradeslots: &[TradeSlot],
|
||||||
) {
|
) {
|
||||||
let item_tooltip = Tooltip::new({
|
let item_tooltip = Tooltip::new({
|
||||||
@ -272,6 +284,7 @@ impl<'a> Trade<'a> {
|
|||||||
|
|
||||||
if !ours {
|
if !ours {
|
||||||
InventoryScroller::new(
|
InventoryScroller::new(
|
||||||
|
self.client,
|
||||||
self.imgs,
|
self.imgs,
|
||||||
self.item_imgs,
|
self.item_imgs,
|
||||||
self.fonts,
|
self.fonts,
|
||||||
@ -353,6 +366,8 @@ impl<'a> Trade<'a> {
|
|||||||
Quality::Artifact => self.imgs.inv_slot_orange,
|
Quality::Artifact => self.imgs.inv_slot_orange,
|
||||||
_ => self.imgs.inv_slot_red,
|
_ => self.imgs.inv_slot_red,
|
||||||
};
|
};
|
||||||
|
let mut desc = desc.to_string();
|
||||||
|
super::util::append_price_desc(&mut desc, prices, item.item_definition_id());
|
||||||
slot_widget
|
slot_widget
|
||||||
.filled_slot(quality_col_img)
|
.filled_slot(quality_col_img)
|
||||||
.with_tooltip(
|
.with_tooltip(
|
||||||
@ -496,8 +511,8 @@ impl<'a> Widget for Trade<'a> {
|
|||||||
let widget::UpdateArgs { mut state, ui, .. } = args;
|
let widget::UpdateArgs { mut state, ui, .. } = args;
|
||||||
|
|
||||||
let mut event = None;
|
let mut event = None;
|
||||||
let trade = match self.client.pending_trade() {
|
let (trade, prices) = match self.client.pending_trade() {
|
||||||
Some((_, trade)) => trade,
|
Some((_, trade, prices)) => (trade, prices),
|
||||||
None => return Some(TradeAction::Decline),
|
None => return Some(TradeAction::Decline),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -523,8 +538,12 @@ impl<'a> Widget for Trade<'a> {
|
|||||||
self.title(&mut state, ui);
|
self.title(&mut state, ui);
|
||||||
self.phase_indicator(&mut state, ui, &trade);
|
self.phase_indicator(&mut state, ui, &trade);
|
||||||
|
|
||||||
event = self.item_pane(&mut state, ui, &trade, false).or(event);
|
event = self
|
||||||
event = self.item_pane(&mut state, ui, &trade, true).or(event);
|
.item_pane(&mut state, ui, &trade, &prices, false)
|
||||||
|
.or(event);
|
||||||
|
event = self
|
||||||
|
.item_pane(&mut state, ui, &trade, &prices, true)
|
||||||
|
.or(event);
|
||||||
event = self
|
event = self
|
||||||
.accept_decline_buttons(&mut state, ui, &trade)
|
.accept_decline_buttons(&mut state, ui, &trade)
|
||||||
.or(event);
|
.or(event);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use common::{
|
use common::{
|
||||||
comp::{
|
comp::{
|
||||||
|
inventory::trade_pricing::TradePricing,
|
||||||
item::{
|
item::{
|
||||||
armor::{Armor, ArmorKind, Protection},
|
armor::{Armor, ArmorKind, Protection},
|
||||||
tool::{Hands, StatKind, Stats, Tool, ToolKind},
|
tool::{Hands, StatKind, Stats, Tool, ToolKind},
|
||||||
@ -8,6 +9,7 @@ use common::{
|
|||||||
BuffKind,
|
BuffKind,
|
||||||
},
|
},
|
||||||
effect::Effect,
|
effect::Effect,
|
||||||
|
trade::{Good, SitePrices},
|
||||||
};
|
};
|
||||||
use std::{borrow::Cow, fmt::Write};
|
use std::{borrow::Cow, fmt::Write};
|
||||||
|
|
||||||
@ -64,6 +66,20 @@ pub fn item_text<'a>(
|
|||||||
(item.name(), desc)
|
(item.name(), desc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn append_price_desc(desc: &mut String, prices: &Option<SitePrices>, item_definition_id: &str) {
|
||||||
|
if let Some(prices) = prices {
|
||||||
|
let (material, factor) = TradePricing::get_material(item_definition_id);
|
||||||
|
let coinprice = prices.values.get(&Good::Coin).cloned().unwrap_or(1.0);
|
||||||
|
let buyprice = prices.values.get(&material).cloned().unwrap_or_default() * factor;
|
||||||
|
let sellprice = buyprice * material.trade_margin();
|
||||||
|
*desc += &format!(
|
||||||
|
"\n\nBuy price: {:0.1} coins\nSell price: {:0.1} coins",
|
||||||
|
buyprice / coinprice,
|
||||||
|
sellprice / coinprice
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: localization
|
// TODO: localization
|
||||||
fn modular_component_desc(
|
fn modular_component_desc(
|
||||||
mc: &ModularComponent,
|
mc: &ModularComponent,
|
||||||
|
@ -4,7 +4,9 @@ use crate::{
|
|||||||
};
|
};
|
||||||
use common::{
|
use common::{
|
||||||
assets::{AssetExt, AssetHandle},
|
assets::{AssetExt, AssetHandle},
|
||||||
|
comp::Agent,
|
||||||
store::Store,
|
store::Store,
|
||||||
|
trade::SitePrices,
|
||||||
};
|
};
|
||||||
use core::ops::Deref;
|
use core::ops::Deref;
|
||||||
use noise::{Seedable, SuperSimplex};
|
use noise::{Seedable, SuperSimplex};
|
||||||
@ -69,6 +71,15 @@ 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, 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())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IndexOwned {
|
impl IndexOwned {
|
||||||
|
@ -944,7 +944,7 @@ impl Settlement {
|
|||||||
.do_if(!is_dummy, |e| e.with_automatic_name())
|
.do_if(!is_dummy, |e| e.with_automatic_name())
|
||||||
.do_if(is_dummy, |e| e.with_name("Training Dummy"))
|
.do_if(is_dummy, |e| e.with_name("Training Dummy"))
|
||||||
.do_if(is_human && dynamic_rng.gen(), |entity| {
|
.do_if(is_human && dynamic_rng.gen(), |entity| {
|
||||||
match dynamic_rng.gen_range(0..5) {
|
match dynamic_rng.gen_range(0..6) {
|
||||||
0 => entity
|
0 => entity
|
||||||
.with_main_tool(Item::new_from_asset_expect(
|
.with_main_tool(Item::new_from_asset_expect(
|
||||||
"common.items.weapons.sword.iron-4",
|
"common.items.weapons.sword.iron-4",
|
||||||
@ -955,7 +955,7 @@ impl Settlement {
|
|||||||
.with_skillset_config(
|
.with_skillset_config(
|
||||||
common::skillset_builder::SkillSetConfig::Guard,
|
common::skillset_builder::SkillSetConfig::Guard,
|
||||||
),
|
),
|
||||||
1 => entity
|
1 | 2 => entity
|
||||||
.with_main_tool(Item::new_from_asset_expect(
|
.with_main_tool(Item::new_from_asset_expect(
|
||||||
"common.items.weapons.bow.eldwood-0",
|
"common.items.weapons.bow.eldwood-0",
|
||||||
))
|
))
|
||||||
|
Loading…
Reference in New Issue
Block a user