Client-side trade improvements.

- Add item tooltips in trade.
- More localization support.
- Fix bindings (R for trade, B for bag).
This commit is contained in:
Avi Weinstock 2021-02-19 15:20:27 -05:00
parent b4adc5369a
commit 559ad7b7f5
7 changed files with 87 additions and 39 deletions

View File

@ -47,6 +47,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Adjusted Stonework Defender loot table to remove mindflayer drops (bag, staff, glider).
- Changed default controller key bindings
- Improved network efficiency by ≈ factor 10 by using tokio.
- Added item tooltips to trade window.
### Removed

View File

@ -12,6 +12,10 @@
"hud.trade.has_accepted": "{playername}\nhas accepted",
"hud.trade.accept": "Accept",
"hud.trade.decline": "Decline",
"hud.trade.invite_sent": "Trade request sent to {playername}.",
"hud.trade.result.completed": "Trade completed successfully.",
"hud.trade.result.declined": "Trade declined.",
"hud.trade.result.nospace": "Not enough space to complete the trade.",
},

View File

@ -343,7 +343,7 @@ impl Inventory {
}
}
fn slot(&self, inv_slot_id: InvSlotId) -> Option<&InvSlot> {
pub fn slot(&self, inv_slot_id: InvSlotId) -> Option<&InvSlot> {
match SlotId::from(inv_slot_id) {
SlotId::Inventory(slot_idx) => self.slots.get(slot_idx),
SlotId::Loadout(loadout_slot_id) => self.loadout.inv_slot(loadout_slot_id),

View File

@ -2131,6 +2131,7 @@ impl Hud {
&self.imgs,
&self.item_imgs,
&self.fonts,
&self.rot_imgs,
tooltip_manager,
&mut self.slot_manager,
i18n,

View File

@ -1,5 +1,6 @@
use super::{
img_ids::Imgs,
get_quality_col,
img_ids::{Imgs, ImgsRot},
item_imgs::ItemImgs,
slots::{SlotManager, TradeSlot},
TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
@ -9,12 +10,12 @@ use crate::{
ui::{
fonts::Fonts,
slot::{ContentSize, SlotMaker},
TooltipManager,
ImageFrame, Tooltip, TooltipManager, Tooltipable,
},
};
use client::Client;
use common::{
comp::Inventory,
comp::{inventory::item::Quality, Inventory},
trade::{PendingTrade, TradeAction, TradePhase},
};
use common_net::sync::WorldSyncExt;
@ -54,9 +55,10 @@ pub struct Trade<'a> {
imgs: &'a Imgs,
item_imgs: &'a ItemImgs,
fonts: &'a Fonts,
rot_imgs: &'a ImgsRot,
tooltip_manager: &'a mut TooltipManager,
#[conrod(common_builder)]
common: widget::CommonBuilder,
//tooltip_manager: &'a mut TooltipManager,
slot_manager: &'a mut SlotManager,
localized_strings: &'a Localization,
pulse: f32,
@ -68,7 +70,8 @@ impl<'a> Trade<'a> {
imgs: &'a Imgs,
item_imgs: &'a ItemImgs,
fonts: &'a Fonts,
_tooltip_manager: &'a mut TooltipManager,
rot_imgs: &'a ImgsRot,
tooltip_manager: &'a mut TooltipManager,
slot_manager: &'a mut SlotManager,
localized_strings: &'a Localization,
pulse: f32,
@ -78,6 +81,8 @@ impl<'a> Trade<'a> {
imgs,
item_imgs,
fonts,
rot_imgs,
tooltip_manager,
common: widget::CommonBuilder::default(),
//tooltip_manager,
slot_manager,
@ -225,6 +230,24 @@ impl<'a> Trade<'a> {
who: usize,
tradeslots: &[TradeSlot],
) {
let item_tooltip = Tooltip::new({
// Edge images [t, b, r, l]
// Corner images [tr, tl, br, bl]
let edge = &self.rot_imgs.tt_side;
let corner = &self.rot_imgs.tt_corner;
ImageFrame::new(
[edge.cw180, edge.none, edge.cw270, edge.cw90],
[corner.none, corner.cw270, corner.cw90, corner.cw180],
Color::Rgba(0.08, 0.07, 0.04, 1.0),
5.0,
)
})
.title_font_size(self.fonts.cyri.scale(15))
.parent(ui.window)
.desc_font_size(self.fonts.cyri.scale(12))
.font_id(self.fonts.cyri.conrod_id)
.desc_text_color(TEXT_COLOR);
let mut slot_maker = SlotMaker {
empty_slot: self.imgs.inv_slot,
filled_slot: self.imgs.inv_slot,
@ -270,7 +293,33 @@ impl<'a> Trade<'a> {
0.0 + y as f64 * (40.0),
0.0 + x as f64 * (40.0),
);
slot_widget.set(state.ids.inv_slots[i + who * MAX_TRADE_SLOTS], ui);
let slot_id = state.ids.inv_slots[i + who * MAX_TRADE_SLOTS];
if let Some(Some(item)) = slot.invslot.and_then(|slotid| inventory.slot(slotid)) {
let (title, desc) = super::util::item_text(item);
let quality_col = get_quality_col(item);
let quality_col_img = match item.quality() {
Quality::Low => self.imgs.inv_slot_grey,
Quality::Common => self.imgs.inv_slot,
Quality::Moderate => self.imgs.inv_slot_green,
Quality::High => self.imgs.inv_slot_blue,
Quality::Epic => self.imgs.inv_slot_purple,
Quality::Legendary => self.imgs.inv_slot_gold,
Quality::Artifact => self.imgs.inv_slot_orange,
_ => self.imgs.inv_slot_red,
};
slot_widget
.filled_slot(quality_col_img)
.with_tooltip(
self.tooltip_manager,
title,
&*desc,
&item_tooltip,
quality_col,
)
.set(slot_id, ui);
} else {
slot_widget.set(slot_id, ui);
}
}
}
@ -416,25 +465,6 @@ impl<'a> Widget for Trade<'a> {
});
}
// TODO: item tooltips in trade preview
/*let trade_tooltip = Tooltip::new({
// Edge images [t, b, r, l]
// Corner images [tr, tl, br, bl]
let edge = &self.rot_imgs.tt_side;
let corner = &self.rot_imgs.tt_corner;
ImageFrame::new(
[edge.cw180, edge.none, edge.cw270, edge.cw90],
[corner.none, corner.cw270, corner.cw90, corner.cw180],
Color::Rgba(0.08, 0.07, 0.04, 1.0),
5.0,
)
})
.title_font_size(self.fonts.cyri.scale(15))
.parent(ui.window)
.desc_font_size(self.fonts.cyri.scale(12))
.font_id(self.fonts.cyri.conrod_id)
.desc_text_color(TEXT_COLOR);*/
self.background(&mut state, ui);
self.title(&mut state, ui);
self.phase_indicator(&mut state, ui, &trade);

View File

@ -133,14 +133,15 @@ impl SessionState {
answer,
kind,
} => {
// TODO: i18n
// TODO: i18n (complicated since substituting phrases at this granularity may
// not be grammatical in some languages)
let kind_str = match kind {
InviteKind::Group => "Group",
InviteKind::Trade => "Trade",
};
let target_name = match client.player_list().get(&target) {
Some(info) => info.player_alias.clone(),
None => "<unknown>".to_string(),
None => format!("<entity {}>", target),
};
let answer_str = match answer {
InviteAnswer::Accepted => "accepted",
@ -151,11 +152,11 @@ impl SessionState {
self.hud.new_message(ChatType::Meta.chat_msg(msg));
},
client::Event::TradeComplete { result, trade: _ } => {
// TODO: i18n, entity names
let i18n = global_state.i18n.read();
let msg = match result {
TradeResult::Completed => "Trade completed successfully.",
TradeResult::Declined => "Trade declined.",
TradeResult::NotEnoughSpace => "Not enough space to complete the trade.",
TradeResult::Completed => i18n.get("hud.trade.result.completed"),
TradeResult::Declined => i18n.get("hud.trade.result.declined"),
TradeResult::NotEnoughSpace => i18n.get("hud.trade.result.nospace"),
};
self.hud.new_message(ChatType::Meta.chat_msg(msg));
},
@ -573,11 +574,22 @@ impl PlayState for SessionState {
match interactable {
Interactable::Block(_, _) => {},
Interactable::Entity(entity) => {
client
.state()
.ecs()
.uid_from_entity(entity)
.map(|uid| client.send_invite(uid, InviteKind::Trade));
if let Some(uid) =
client.state().ecs().uid_from_entity(entity)
{
let name = client
.player_list()
.get(&uid)
.map(|info| info.player_alias.clone())
.unwrap_or_else(|| format!("<entity {:?}>", uid));
let msg = global_state
.i18n
.read()
.get("hud.trade.invite_sent")
.replace("{playername}", &name);
self.hud.new_message(ChatType::Meta.chat_msg(msg));
client.send_invite(uid, InviteKind::Trade)
};
},
}
}

View File

@ -142,8 +142,8 @@ impl ControlSettings {
GameInput::ToggleLantern => KeyMouse::Key(VirtualKeyCode::G),
GameInput::Mount => KeyMouse::Key(VirtualKeyCode::F),
GameInput::Map => KeyMouse::Key(VirtualKeyCode::M),
GameInput::Bag => KeyMouse::Key(VirtualKeyCode::R),
GameInput::Trade => KeyMouse::Key(VirtualKeyCode::B),
GameInput::Bag => KeyMouse::Key(VirtualKeyCode::B),
GameInput::Trade => KeyMouse::Key(VirtualKeyCode::R),
GameInput::Social => KeyMouse::Key(VirtualKeyCode::O),
GameInput::Crafting => KeyMouse::Key(VirtualKeyCode::C),
GameInput::Spellbook => KeyMouse::Key(VirtualKeyCode::P),