mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
1292 lines
46 KiB
Rust
1292 lines
46 KiB
Rust
use super::{
|
|
cr_color,
|
|
img_ids::{Imgs, ImgsRot},
|
|
item_imgs::ItemImgs,
|
|
slots::{ArmorSlot, EquipSlot, InventorySlot, SlotManager},
|
|
Show, CRITICAL_HP_COLOR, LOW_HP_COLOR, TEXT_COLOR, UI_HIGHLIGHT_0, UI_MAIN,
|
|
};
|
|
use crate::{
|
|
game_input::GameInput,
|
|
ui::{
|
|
fonts::Fonts,
|
|
slot::{ContentSize, SlotMaker},
|
|
ImageFrame, ItemTooltip, ItemTooltipManager, ItemTooltipable, Tooltip, TooltipManager,
|
|
Tooltipable,
|
|
},
|
|
GlobalState,
|
|
};
|
|
use client::Client;
|
|
use common::{
|
|
assets::AssetExt,
|
|
combat::{combat_rating, perception_dist_multiplier_from_stealth, Damage},
|
|
comp::{
|
|
inventory::InventorySortOrder,
|
|
item::{ItemDef, ItemDesc, MaterialStatManifest, Quality},
|
|
Body, Energy, Health, Inventory, Poise, SkillSet, Stats,
|
|
},
|
|
};
|
|
use conrod_core::{
|
|
color,
|
|
widget::{self, Button, Image, Rectangle, Scrollbar, State as ConrodState, Text},
|
|
widget_ids, Color, Colorable, Positionable, Scalar, Sizeable, UiCell, Widget, WidgetCommon,
|
|
};
|
|
use i18n::Localization;
|
|
|
|
use crate::hud::slots::SlotKind;
|
|
use specs::Entity as EcsEntity;
|
|
use std::{borrow::Borrow, sync::Arc};
|
|
use vek::Vec2;
|
|
|
|
widget_ids! {
|
|
pub struct InventoryScrollerIds {
|
|
test,
|
|
bag_close,
|
|
inv_alignment,
|
|
inv_grid_1,
|
|
inv_grid_2,
|
|
inv_scrollbar,
|
|
inv_slots_0,
|
|
inv_slots[],
|
|
bg,
|
|
bg_frame,
|
|
char_ico,
|
|
coin_ico,
|
|
space_txt,
|
|
coin_txt,
|
|
inventory_title,
|
|
inventory_title_bg,
|
|
scrollbar_bg,
|
|
second_phase_scrollbar_bg,
|
|
scrollbar_slots,
|
|
left_scrollbar_slots,
|
|
}
|
|
}
|
|
|
|
pub struct InventoryScrollerState {
|
|
ids: InventoryScrollerIds,
|
|
}
|
|
|
|
#[derive(WidgetCommon)]
|
|
pub struct InventoryScroller<'a> {
|
|
client: &'a Client,
|
|
imgs: &'a Imgs,
|
|
item_imgs: &'a ItemImgs,
|
|
fonts: &'a Fonts,
|
|
#[conrod(common_builder)]
|
|
common: widget::CommonBuilder,
|
|
item_tooltip_manager: &'a mut ItemTooltipManager,
|
|
slot_manager: &'a mut SlotManager,
|
|
pulse: f32,
|
|
localized_strings: &'a Localization,
|
|
show_stats: bool,
|
|
show_bag_inv: bool,
|
|
on_right: bool,
|
|
item_tooltip: &'a ItemTooltip<'a>,
|
|
playername: String,
|
|
entity: EcsEntity,
|
|
is_us: bool,
|
|
inventory: &'a Inventory,
|
|
bg_ids: &'a BackgroundIds,
|
|
show_salvage: bool,
|
|
}
|
|
|
|
impl<'a> InventoryScroller<'a> {
|
|
#[allow(clippy::too_many_arguments)]
|
|
pub fn new(
|
|
client: &'a Client,
|
|
imgs: &'a Imgs,
|
|
item_imgs: &'a ItemImgs,
|
|
fonts: &'a Fonts,
|
|
item_tooltip_manager: &'a mut ItemTooltipManager,
|
|
slot_manager: &'a mut SlotManager,
|
|
pulse: f32,
|
|
localized_strings: &'a Localization,
|
|
show_stats: bool,
|
|
show_bag_inv: bool,
|
|
on_right: bool,
|
|
item_tooltip: &'a ItemTooltip<'a>,
|
|
playername: String,
|
|
entity: EcsEntity,
|
|
is_us: bool,
|
|
inventory: &'a Inventory,
|
|
bg_ids: &'a BackgroundIds,
|
|
show_salvage: bool,
|
|
) -> Self {
|
|
InventoryScroller {
|
|
client,
|
|
imgs,
|
|
item_imgs,
|
|
fonts,
|
|
common: widget::CommonBuilder::default(),
|
|
item_tooltip_manager,
|
|
slot_manager,
|
|
pulse,
|
|
localized_strings,
|
|
show_stats,
|
|
show_bag_inv,
|
|
on_right,
|
|
item_tooltip,
|
|
playername,
|
|
entity,
|
|
is_us,
|
|
inventory,
|
|
bg_ids,
|
|
show_salvage,
|
|
}
|
|
}
|
|
|
|
fn background(&mut self, ui: &mut UiCell<'_>) {
|
|
let bg_id = if !self.on_right {
|
|
self.imgs.inv_bg_bag
|
|
} else {
|
|
self.imgs.player_inv_bg_bag
|
|
};
|
|
|
|
let img_id = if !self.on_right {
|
|
self.imgs.inv_frame_bag
|
|
} else {
|
|
self.imgs.player_inv_frame_bag
|
|
};
|
|
|
|
let mut bg = Image::new(if self.show_stats {
|
|
self.imgs.inv_bg_stats
|
|
} else if self.show_bag_inv {
|
|
bg_id
|
|
} else {
|
|
self.imgs.inv_bg_armor
|
|
})
|
|
.w_h(
|
|
424.0,
|
|
if self.show_bag_inv && !self.on_right {
|
|
548.0
|
|
} else {
|
|
708.0
|
|
},
|
|
);
|
|
|
|
if self.on_right {
|
|
bg = bg.bottom_right_with_margins_on(ui.window, 70.0, 5.0);
|
|
} else {
|
|
bg = bg.bottom_left_with_margins_on(ui.window, 230.0, 5.0);
|
|
}
|
|
|
|
bg.color(Some(UI_MAIN)).set(self.bg_ids.bg, ui);
|
|
|
|
Image::new(if self.show_bag_inv {
|
|
img_id
|
|
} else {
|
|
self.imgs.inv_frame
|
|
})
|
|
.w_h(
|
|
424.0,
|
|
if self.show_bag_inv && !self.on_right {
|
|
548.0
|
|
} else {
|
|
708.0
|
|
},
|
|
)
|
|
.middle_of(self.bg_ids.bg)
|
|
.color(Some(UI_HIGHLIGHT_0))
|
|
.set(self.bg_ids.bg_frame, ui);
|
|
}
|
|
|
|
fn title(&mut self, state: &mut ConrodState<'_, InventoryScrollerState>, ui: &mut UiCell<'_>) {
|
|
Text::new(
|
|
&self
|
|
.localized_strings
|
|
.get("hud.bag.inventory")
|
|
.replace("{playername}", &*self.playername),
|
|
)
|
|
.mid_top_with_margin_on(self.bg_ids.bg_frame, 9.0)
|
|
.font_id(self.fonts.cyri.conrod_id)
|
|
.font_size(self.fonts.cyri.scale(22))
|
|
.color(Color::Rgba(0.0, 0.0, 0.0, 1.0))
|
|
.set(state.ids.inventory_title_bg, ui);
|
|
Text::new(
|
|
&self
|
|
.localized_strings
|
|
.get("hud.bag.inventory")
|
|
.replace("{playername}", &*self.playername),
|
|
)
|
|
.top_left_with_margins_on(state.ids.inventory_title_bg, 2.0, 2.0)
|
|
.font_id(self.fonts.cyri.conrod_id)
|
|
.font_size(self.fonts.cyri.scale(22))
|
|
.color(TEXT_COLOR)
|
|
.set(state.ids.inventory_title, ui);
|
|
}
|
|
|
|
fn scrollbar_and_slots(
|
|
&mut self,
|
|
state: &mut ConrodState<'_, InventoryScrollerState>,
|
|
ui: &mut UiCell<'_>,
|
|
) {
|
|
let space_max = self.inventory.slots().count();
|
|
|
|
// Slots Scrollbar
|
|
if space_max > 45 && !self.show_bag_inv {
|
|
// Scrollbar-BG
|
|
Image::new(self.imgs.scrollbar_bg)
|
|
.w_h(9.0, 173.0)
|
|
.bottom_right_with_margins_on(self.bg_ids.bg_frame, 42.0, 3.0)
|
|
.color(Some(UI_HIGHLIGHT_0))
|
|
.set(state.ids.scrollbar_bg, ui);
|
|
// Scrollbar
|
|
Scrollbar::y_axis(state.ids.inv_alignment)
|
|
.thickness(5.0)
|
|
.h(123.0)
|
|
.color(UI_MAIN)
|
|
.middle_of(state.ids.scrollbar_bg)
|
|
.set(state.ids.scrollbar_slots, ui);
|
|
} else if space_max > 135 && self.on_right {
|
|
// Scrollbar-BG
|
|
Image::new(self.imgs.scrollbar_bg_big)
|
|
.w_h(9.0, 592.0)
|
|
.bottom_right_with_margins_on(self.bg_ids.bg_frame, 42.0, 3.0)
|
|
.color(Some(UI_HIGHLIGHT_0))
|
|
.set(state.ids.scrollbar_bg, ui);
|
|
// Scrollbar
|
|
Scrollbar::y_axis(state.ids.inv_alignment)
|
|
.thickness(5.0)
|
|
.h(542.0)
|
|
.color(UI_MAIN)
|
|
.middle_of(state.ids.scrollbar_bg)
|
|
.set(state.ids.scrollbar_slots, ui);
|
|
};
|
|
|
|
// This is just for the offeror inventory scrollbar
|
|
if space_max >= 108 && !self.on_right && self.show_bag_inv {
|
|
// Left bag scrollbar background
|
|
Image::new(self.imgs.second_phase_scrollbar_bg)
|
|
.w_h(9.0, 434.0)
|
|
.bottom_right_with_margins_on(self.bg_ids.bg_frame, 42.0, 3.0)
|
|
.color(Some(UI_HIGHLIGHT_0))
|
|
.set(state.ids.second_phase_scrollbar_bg, ui);
|
|
// Left bag scrollbar
|
|
Scrollbar::y_axis(state.ids.inv_alignment)
|
|
.thickness(5.0)
|
|
.h(384.0)
|
|
.color(UI_MAIN)
|
|
.middle_of(state.ids.second_phase_scrollbar_bg)
|
|
.set(state.ids.left_scrollbar_slots, ui);
|
|
}
|
|
|
|
let grid_width = if self.show_bag_inv && !self.on_right {
|
|
440.0 // This for the left bag
|
|
} else if self.show_bag_inv && self.on_right {
|
|
600.0 // This for the expanded right bag
|
|
} else {
|
|
200.0
|
|
};
|
|
|
|
// Alignment for Grid
|
|
Rectangle::fill_with([362.0, grid_width], color::TRANSPARENT)
|
|
.bottom_left_with_margins_on(
|
|
self.bg_ids.bg_frame,
|
|
29.0,
|
|
if self.show_bag_inv && !self.on_right {
|
|
28.0
|
|
} else {
|
|
46.5
|
|
},
|
|
)
|
|
.scroll_kids_vertically()
|
|
.set(state.ids.inv_alignment, ui);
|
|
|
|
// Bag Slots
|
|
// Create available inventory slot widgets
|
|
if state.ids.inv_slots.len() < self.inventory.capacity() {
|
|
state.update(|s| {
|
|
s.ids
|
|
.inv_slots
|
|
.resize(self.inventory.capacity(), &mut ui.widget_id_generator());
|
|
});
|
|
}
|
|
// Determine the range of inventory slots that are provided by the loadout item
|
|
// that the mouse is over
|
|
let mouseover_loadout_slots = self
|
|
.slot_manager
|
|
.mouse_over_slot
|
|
.and_then(|x| {
|
|
if let SlotKind::Equip(e) = x {
|
|
self.inventory.get_slot_range_for_equip_slot(e)
|
|
} else {
|
|
None
|
|
}
|
|
})
|
|
.unwrap_or(0usize..0usize);
|
|
|
|
// Display inventory contents
|
|
let mut slot_maker = SlotMaker {
|
|
empty_slot: self.imgs.inv_slot,
|
|
filled_slot: self.imgs.inv_slot,
|
|
selected_slot: self.imgs.inv_slot_sel,
|
|
background_color: Some(UI_MAIN),
|
|
content_size: ContentSize {
|
|
width_height_ratio: 1.0,
|
|
max_fraction: 0.75,
|
|
},
|
|
selected_content_scale: 1.067,
|
|
amount_font: self.fonts.cyri.conrod_id,
|
|
amount_margins: Vec2::new(-4.0, 0.0),
|
|
amount_font_size: self.fonts.cyri.scale(12),
|
|
amount_text_color: TEXT_COLOR,
|
|
content_source: self.inventory,
|
|
image_source: self.item_imgs,
|
|
slot_manager: Some(self.slot_manager),
|
|
pulse: self.pulse,
|
|
};
|
|
|
|
for (i, (pos, item)) in self.inventory.slots_with_id().enumerate() {
|
|
let x = i % 9;
|
|
let y = i / 9;
|
|
|
|
// Slot
|
|
let mut slot_widget = slot_maker
|
|
.fabricate(
|
|
InventorySlot {
|
|
slot: pos,
|
|
ours: self.is_us,
|
|
entity: self.entity,
|
|
},
|
|
[40.0; 2],
|
|
)
|
|
.top_left_with_margins_on(
|
|
state.ids.inv_alignment,
|
|
0.0 + y as f64 * (40.0),
|
|
0.0 + x as f64 * (40.0),
|
|
);
|
|
|
|
// Highlight slots are provided by the loadout item that the mouse is over
|
|
if mouseover_loadout_slots.contains(&i) {
|
|
slot_widget = slot_widget.with_background_color(Color::Rgba(1.0, 1.0, 1.0, 1.0));
|
|
}
|
|
|
|
if self.show_salvage && item.as_ref().map_or(false, |item| item.is_salvageable()) {
|
|
slot_widget = slot_widget.with_background_color(Color::Rgba(1.0, 1.0, 1.0, 1.0));
|
|
}
|
|
|
|
if let Some(item) = item {
|
|
let quality_col_img = match item.quality() {
|
|
Quality::Low => self.imgs.inv_slot_grey,
|
|
Quality::Common => self.imgs.inv_slot_common,
|
|
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,
|
|
};
|
|
|
|
let prices_info = self
|
|
.client
|
|
.pending_trade()
|
|
.as_ref()
|
|
.and_then(|(_, _, prices)| prices.clone());
|
|
|
|
if self.show_salvage && item.is_salvageable() {
|
|
let salvage_result: Vec<_> = item
|
|
.salvage_output()
|
|
.map(Arc::<ItemDef>::load_expect_cloned)
|
|
.map(|item| item as Arc<dyn ItemDesc>)
|
|
.collect();
|
|
|
|
// let items = core::iter::once(item as &dyn ItemDesc)
|
|
// .chain(salvage_result.iter().map(|item| item.borrow()));
|
|
let items = salvage_result
|
|
.iter()
|
|
.map(|item| item.borrow())
|
|
.chain(core::iter::once(item as &dyn ItemDesc));
|
|
|
|
slot_widget
|
|
.filled_slot(quality_col_img)
|
|
.with_item_tooltip(
|
|
self.item_tooltip_manager,
|
|
items,
|
|
&prices_info,
|
|
self.item_tooltip,
|
|
)
|
|
.set(state.ids.inv_slots[i], ui);
|
|
} else {
|
|
slot_widget
|
|
.filled_slot(quality_col_img)
|
|
.with_item_tooltip(
|
|
self.item_tooltip_manager,
|
|
core::iter::once(item as &dyn ItemDesc),
|
|
&prices_info,
|
|
self.item_tooltip,
|
|
)
|
|
.set(state.ids.inv_slots[i], ui);
|
|
}
|
|
} else {
|
|
slot_widget.set(state.ids.inv_slots[i], ui);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn footer_metrics(
|
|
&mut self,
|
|
state: &mut ConrodState<'_, InventoryScrollerState>,
|
|
ui: &mut UiCell<'_>,
|
|
) {
|
|
let space_used = self.inventory.populated_slots();
|
|
let space_max = self.inventory.slots().count();
|
|
let bag_space = format!("{}/{}", space_used, space_max);
|
|
let bag_space_percentage = space_used as f32 / space_max as f32;
|
|
let coin_itemdef = Arc::<ItemDef>::load_expect_cloned("common.items.utility.coins");
|
|
let coin_count = self.inventory.item_count(&coin_itemdef);
|
|
// TODO: Reuse this to generally count a stackable item the player selected
|
|
//let cheese_itemdef =
|
|
// Arc::<ItemDef>::load_expect_cloned("common.items.food.cheese");
|
|
// let cheese_count = self.inventory.item_count(&cheese_itemdef);
|
|
|
|
// Coin Icon and Coin Text
|
|
Image::new(self.imgs.coin_ico)
|
|
.w_h(16.0, 17.0)
|
|
.bottom_left_with_margins_on(self.bg_ids.bg_frame, 2.0, 43.0)
|
|
.set(state.ids.coin_ico, ui);
|
|
Text::new(&format!("{}", coin_count))
|
|
.bottom_left_with_margins_on(self.bg_ids.bg_frame, 6.0, 64.0)
|
|
.font_id(self.fonts.cyri.conrod_id)
|
|
.font_size(self.fonts.cyri.scale(14))
|
|
.color(Color::Rgba(0.871, 0.863, 0.05, 1.0))
|
|
.set(state.ids.coin_txt, ui);
|
|
// TODO: Add a customizable counter for stackable items here
|
|
// TODO: Cheese is funny until it's real
|
|
/*Image::new(self.imgs.cheese_ico)
|
|
.w_h(16.0, 17.0)
|
|
.bottom_left_with_margins_on(self.bg_ids.bg_frame, 2.0, 110.0)
|
|
.set(state.ids.cheese_ico, ui);
|
|
Text::new(&format!("{}", cheese_count))
|
|
.bottom_left_with_margins_on(self.bg_ids.bg_frame, 6.0, 144.0)
|
|
.font_id(self.fonts.cyri.conrod_id)
|
|
.font_size(self.fonts.cyri.scale(14))
|
|
.color(Color::Rgba(0.871, 0.863, 0.05, 1.0))
|
|
.set(state.ids.cheese_txt, ui);*/
|
|
//Free Bag-Space
|
|
Text::new(&bag_space)
|
|
.bottom_right_with_margins_on(self.bg_ids.bg_frame, 6.0, 43.0)
|
|
.font_id(self.fonts.cyri.conrod_id)
|
|
.font_size(self.fonts.cyri.scale(14))
|
|
.color(if bag_space_percentage < 0.8 {
|
|
TEXT_COLOR
|
|
} else if bag_space_percentage < 1.0 {
|
|
LOW_HP_COLOR
|
|
} else {
|
|
CRITICAL_HP_COLOR
|
|
})
|
|
.set(state.ids.space_txt, ui);
|
|
}
|
|
}
|
|
|
|
impl<'a> Widget for InventoryScroller<'a> {
|
|
type Event = ();
|
|
type State = InventoryScrollerState;
|
|
type Style = ();
|
|
|
|
fn init_state(&self, id_gen: widget::id::Generator) -> Self::State {
|
|
InventoryScrollerState {
|
|
ids: InventoryScrollerIds::new(id_gen),
|
|
}
|
|
}
|
|
|
|
fn style(&self) -> Self::Style {}
|
|
|
|
fn update(mut self, args: widget::UpdateArgs<Self>) -> Self::Event {
|
|
let widget::UpdateArgs { state, ui, .. } = args;
|
|
self.background(ui);
|
|
self.title(state, ui);
|
|
self.scrollbar_and_slots(state, ui);
|
|
self.footer_metrics(state, ui);
|
|
}
|
|
}
|
|
|
|
widget_ids! {
|
|
pub struct BackgroundIds {
|
|
bg,
|
|
bg_frame,
|
|
}
|
|
}
|
|
|
|
widget_ids! {
|
|
pub struct BagIds {
|
|
test,
|
|
inventory_scroller,
|
|
bag_close,
|
|
//tooltip[],
|
|
char_ico,
|
|
coin_ico,
|
|
space_txt,
|
|
inventory_title,
|
|
inventory_title_bg,
|
|
inventory_sort,
|
|
scrollbar_bg,
|
|
scrollbar_slots,
|
|
tab_1,
|
|
tab_2,
|
|
tab_3,
|
|
tab_4,
|
|
bag_expand_btn,
|
|
// Armor Slots
|
|
slots_bg,
|
|
head_slot,
|
|
neck_slot,
|
|
chest_slot,
|
|
shoulders_slot,
|
|
hands_slot,
|
|
legs_slot,
|
|
belt_slot,
|
|
lantern_slot,
|
|
ring1_slot,
|
|
ring2_slot,
|
|
feet_slot,
|
|
back_slot,
|
|
tabard_slot,
|
|
glider_slot,
|
|
active_mainhand_slot,
|
|
active_offhand_slot,
|
|
inactive_mainhand_slot,
|
|
inactive_offhand_slot,
|
|
swap_equipped_weapons_btn,
|
|
bag1_slot,
|
|
bag2_slot,
|
|
bag3_slot,
|
|
bag4_slot,
|
|
// Stats
|
|
stat_icons[],
|
|
stat_txts[],
|
|
}
|
|
}
|
|
|
|
#[derive(WidgetCommon)]
|
|
pub struct Bag<'a> {
|
|
client: &'a Client,
|
|
global_state: &'a GlobalState,
|
|
imgs: &'a Imgs,
|
|
item_imgs: &'a ItemImgs,
|
|
fonts: &'a Fonts,
|
|
#[conrod(common_builder)]
|
|
common: widget::CommonBuilder,
|
|
rot_imgs: &'a ImgsRot,
|
|
tooltip_manager: &'a mut TooltipManager,
|
|
item_tooltip_manager: &'a mut ItemTooltipManager,
|
|
slot_manager: &'a mut SlotManager,
|
|
pulse: f32,
|
|
localized_strings: &'a Localization,
|
|
stats: &'a Stats,
|
|
skill_set: &'a SkillSet,
|
|
health: &'a Health,
|
|
energy: &'a Energy,
|
|
show: &'a Show,
|
|
body: &'a Body,
|
|
msm: &'a MaterialStatManifest,
|
|
poise: &'a Poise,
|
|
}
|
|
|
|
impl<'a> Bag<'a> {
|
|
#[allow(clippy::too_many_arguments)]
|
|
pub fn new(
|
|
client: &'a Client,
|
|
global_state: &'a GlobalState,
|
|
imgs: &'a Imgs,
|
|
item_imgs: &'a ItemImgs,
|
|
fonts: &'a Fonts,
|
|
rot_imgs: &'a ImgsRot,
|
|
tooltip_manager: &'a mut TooltipManager,
|
|
item_tooltip_manager: &'a mut ItemTooltipManager,
|
|
slot_manager: &'a mut SlotManager,
|
|
pulse: f32,
|
|
localized_strings: &'a Localization,
|
|
stats: &'a Stats,
|
|
skill_set: &'a SkillSet,
|
|
health: &'a Health,
|
|
energy: &'a Energy,
|
|
show: &'a Show,
|
|
body: &'a Body,
|
|
msm: &'a MaterialStatManifest,
|
|
poise: &'a Poise,
|
|
) -> Self {
|
|
Self {
|
|
client,
|
|
global_state,
|
|
imgs,
|
|
item_imgs,
|
|
fonts,
|
|
common: widget::CommonBuilder::default(),
|
|
rot_imgs,
|
|
tooltip_manager,
|
|
item_tooltip_manager,
|
|
slot_manager,
|
|
pulse,
|
|
localized_strings,
|
|
stats,
|
|
skill_set,
|
|
energy,
|
|
health,
|
|
show,
|
|
body,
|
|
msm,
|
|
poise,
|
|
}
|
|
}
|
|
}
|
|
const STATS: [&str; 6] = [
|
|
"Health",
|
|
"Energy",
|
|
"Protection",
|
|
"Combat Rating",
|
|
"Stun Resilience",
|
|
"Stealth",
|
|
];
|
|
|
|
pub struct BagState {
|
|
ids: BagIds,
|
|
bg_ids: BackgroundIds,
|
|
}
|
|
|
|
pub enum Event {
|
|
BagExpand,
|
|
Close,
|
|
SortInventory,
|
|
SwapEquippedWeapons,
|
|
}
|
|
|
|
impl<'a> Widget for Bag<'a> {
|
|
type Event = Option<Event>;
|
|
type State = BagState;
|
|
type Style = ();
|
|
|
|
fn init_state(&self, mut id_gen: widget::id::Generator) -> Self::State {
|
|
BagState {
|
|
bg_ids: BackgroundIds {
|
|
bg: id_gen.next(),
|
|
bg_frame: id_gen.next(),
|
|
},
|
|
ids: BagIds::new(id_gen),
|
|
}
|
|
}
|
|
|
|
fn style(&self) -> Self::Style {}
|
|
|
|
fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
|
|
common_base::prof_span!("Bag::update");
|
|
let widget::UpdateArgs { state, ui, .. } = args;
|
|
let i18n = &self.localized_strings;
|
|
let key_layout = &self.global_state.window.key_layout;
|
|
|
|
let mut event = None;
|
|
let bag_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 inventories = self.client.inventories();
|
|
let inventory = match inventories.get(self.client.entity()) {
|
|
Some(l) => l,
|
|
None => return None,
|
|
};
|
|
|
|
// Tooltips
|
|
let 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 item_tooltip = ItemTooltip::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,
|
|
)
|
|
},
|
|
self.client,
|
|
self.imgs,
|
|
self.item_imgs,
|
|
self.pulse,
|
|
self.msm,
|
|
self.localized_strings,
|
|
)
|
|
.title_font_size(self.fonts.cyri.scale(20))
|
|
.parent(ui.window)
|
|
.desc_font_size(self.fonts.cyri.scale(12))
|
|
.font_id(self.fonts.cyri.conrod_id)
|
|
.desc_text_color(TEXT_COLOR);
|
|
|
|
InventoryScroller::new(
|
|
self.client,
|
|
self.imgs,
|
|
self.item_imgs,
|
|
self.fonts,
|
|
self.item_tooltip_manager,
|
|
self.slot_manager,
|
|
self.pulse,
|
|
self.localized_strings,
|
|
self.show.stats,
|
|
self.show.bag_inv,
|
|
true,
|
|
&item_tooltip,
|
|
self.stats.name.to_string(),
|
|
self.client.entity(),
|
|
true,
|
|
inventory,
|
|
&state.bg_ids,
|
|
self.show.crafting_fields.salvage,
|
|
)
|
|
.set(state.ids.inventory_scroller, ui);
|
|
|
|
// Char Pixel-Art
|
|
Image::new(self.imgs.char_art)
|
|
.w_h(40.0, 37.0)
|
|
.top_left_with_margins_on(state.bg_ids.bg, 4.0, 2.0)
|
|
.set(state.ids.char_ico, ui);
|
|
// Button to expand bag
|
|
let txt = if self.show.bag_inv {
|
|
"Show Loadout"
|
|
} else {
|
|
"Expand Bag"
|
|
};
|
|
let expand_btn = Button::image(if self.show.bag_inv {
|
|
self.imgs.collapse_btn
|
|
} else {
|
|
self.imgs.expand_btn
|
|
})
|
|
.w_h(30.0, 17.0)
|
|
.hover_image(if self.show.bag_inv {
|
|
self.imgs.collapse_btn_hover
|
|
} else {
|
|
self.imgs.expand_btn_hover
|
|
})
|
|
.press_image(if self.show.bag_inv {
|
|
self.imgs.collapse_btn_press
|
|
} else {
|
|
self.imgs.expand_btn_press
|
|
});
|
|
|
|
// Only show expand button when it's needed...
|
|
if inventory.slots().count() > 45 || self.show.bag_inv {
|
|
let expand_btn_top = if self.show.bag_inv { 53.0 } else { 460.0 };
|
|
if expand_btn
|
|
.top_right_with_margins_on(state.bg_ids.bg_frame, expand_btn_top, 37.0)
|
|
.with_tooltip(self.tooltip_manager, txt, "", &bag_tooltip, TEXT_COLOR)
|
|
.set(state.ids.bag_expand_btn, ui)
|
|
.was_clicked()
|
|
{
|
|
event = Some(Event::BagExpand);
|
|
}
|
|
}
|
|
|
|
// Sort inventory button
|
|
let inv_sort_btn_top: Scalar = if !self.show.bag_inv { 460.0 } else { 53.0 };
|
|
if Button::image(self.imgs.inv_sort_btn)
|
|
.w_h(30.0, 17.0)
|
|
.hover_image(self.imgs.inv_sort_btn_hover)
|
|
.press_image(self.imgs.inv_sort_btn_press)
|
|
.top_left_with_margins_on(state.bg_ids.bg_frame, inv_sort_btn_top, 47.0)
|
|
.with_tooltip(
|
|
self.tooltip_manager,
|
|
match inventory.next_sort_order() {
|
|
InventorySortOrder::Name => i18n.get("hud.bag.sort_by_name"),
|
|
InventorySortOrder::Quality => i18n.get("hud.bag.sort_by_quality"),
|
|
InventorySortOrder::Tag => i18n.get("hud.bag.sort_by_category"),
|
|
},
|
|
"",
|
|
&tooltip,
|
|
color::WHITE,
|
|
)
|
|
.set(state.ids.inventory_sort, ui)
|
|
.was_clicked()
|
|
{
|
|
event = Some(Event::SortInventory);
|
|
}
|
|
|
|
// Armor Slots
|
|
let mut slot_maker = SlotMaker {
|
|
empty_slot: self.imgs.armor_slot_empty,
|
|
filled_slot: self.imgs.armor_slot,
|
|
selected_slot: self.imgs.armor_slot_sel,
|
|
background_color: Some(UI_HIGHLIGHT_0),
|
|
content_size: ContentSize {
|
|
width_height_ratio: 1.0,
|
|
max_fraction: 0.75, /* Changes the item image size by setting a maximum
|
|
* fraction
|
|
* of either the width or height */
|
|
},
|
|
selected_content_scale: 1.067,
|
|
amount_font: self.fonts.cyri.conrod_id,
|
|
amount_margins: Vec2::new(-4.0, 0.0),
|
|
amount_font_size: self.fonts.cyri.scale(12),
|
|
amount_text_color: TEXT_COLOR,
|
|
content_source: inventory,
|
|
image_source: self.item_imgs,
|
|
slot_manager: Some(self.slot_manager),
|
|
pulse: self.pulse,
|
|
};
|
|
|
|
// NOTE: Yes, macros considered harmful.
|
|
// Though, this code mutably captures two different fields of `self`
|
|
// This works because it's different branches of if-let
|
|
// so in reality borrow checker allows you to do this as you
|
|
// capture only one field.
|
|
//
|
|
// The less impossible, but still tricky part is denote type of
|
|
// `$slot_maker` which has 1 lifetype parameter and 3 type parameters
|
|
// in such way that it implements all traits conrod needs.
|
|
//
|
|
// And final part is that this uses that much of arguments
|
|
// that just by passing all of them, you will get about the same
|
|
// amount of lines this macro has or even more.
|
|
//
|
|
// So considering how many times we copy-paste this code
|
|
// and how easy this macro looks it sounds like lawful evil.
|
|
//
|
|
// What this actually does is checks if we have equipped item on this slot
|
|
// and if we do, display item tooltip for it.
|
|
// If not, just show text of slot name.
|
|
macro_rules! set_tooltip {
|
|
($slot_maker:expr, $slot_id:expr, $slot:expr, $desc:expr) => {
|
|
if let Some(item) = inventory.equipped($slot) {
|
|
let manager = &mut *self.item_tooltip_manager;
|
|
$slot_maker
|
|
.with_item_tooltip(
|
|
manager,
|
|
core::iter::once(item as &dyn ItemDesc),
|
|
&None,
|
|
&item_tooltip,
|
|
)
|
|
.set($slot_id, ui)
|
|
} else {
|
|
let manager = &mut *self.tooltip_manager;
|
|
$slot_maker
|
|
.with_tooltip(manager, i18n.get($desc), "", &tooltip, color::WHITE)
|
|
.set($slot_id, ui)
|
|
}
|
|
};
|
|
}
|
|
|
|
let filled_slot = self.imgs.armor_slot;
|
|
if !self.show.bag_inv {
|
|
// Stat icons and text
|
|
state.update(|s| {
|
|
s.ids
|
|
.stat_icons
|
|
.resize(STATS.len(), &mut ui.widget_id_generator())
|
|
});
|
|
state.update(|s| {
|
|
s.ids
|
|
.stat_txts
|
|
.resize(STATS.len(), &mut ui.widget_id_generator())
|
|
});
|
|
// Stats
|
|
let combat_rating = combat_rating(
|
|
inventory,
|
|
self.health,
|
|
self.energy,
|
|
self.poise,
|
|
self.skill_set,
|
|
*self.body,
|
|
self.msm,
|
|
)
|
|
.min(999.9);
|
|
let indicator_col = cr_color(combat_rating);
|
|
for i in STATS.iter().copied().enumerate() {
|
|
let btn = Button::image(match i.1 {
|
|
"Health" => self.imgs.health_ico,
|
|
"Energy" => self.imgs.energy_ico,
|
|
"Combat Rating" => self.imgs.combat_rating_ico,
|
|
"Protection" => self.imgs.protection_ico,
|
|
"Stun Resilience" => self.imgs.stun_res_ico,
|
|
"Stealth" => self.imgs.stealth_rating_ico,
|
|
_ => self.imgs.nothing,
|
|
})
|
|
.w_h(20.0, 20.0)
|
|
.image_color(if i.1 == "Combat Rating" {
|
|
indicator_col
|
|
} else {
|
|
TEXT_COLOR
|
|
});
|
|
let protection_txt = format!(
|
|
"{}%",
|
|
(100.0
|
|
* Damage::compute_damage_reduction(None, Some(inventory), Some(self.stats)))
|
|
as i32
|
|
);
|
|
let health_txt = format!("{}", self.health.maximum().round() as usize);
|
|
let energy_txt = format!("{}", self.energy.maximum().round() as usize);
|
|
let combat_rating_txt = format!("{}", (combat_rating * 10.0) as usize);
|
|
let stun_res_txt = format!(
|
|
"{}",
|
|
(100.0 * Poise::compute_poise_damage_reduction(inventory)) as i32
|
|
);
|
|
let stealth_txt = format!(
|
|
"{:.1}%",
|
|
((1.0 - perception_dist_multiplier_from_stealth(Some(inventory), None))
|
|
* 100.0)
|
|
);
|
|
let btn = if i.0 == 0 {
|
|
btn.top_left_with_margins_on(state.bg_ids.bg_frame, 55.0, 10.0)
|
|
} else {
|
|
btn.down_from(state.ids.stat_icons[i.0 - 1], 7.0)
|
|
};
|
|
let tooltip_head = match i.1 {
|
|
"Health" => i18n.get("hud.bag.health"),
|
|
"Energy" => i18n.get("hud.bag.energy"),
|
|
"Combat Rating" => i18n.get("hud.bag.combat_rating"),
|
|
"Protection" => i18n.get("hud.bag.protection"),
|
|
"Stun Resilience" => i18n.get("hud.bag.stun_res"),
|
|
"Stealth" => i18n.get("hud.bag.stealth"),
|
|
_ => "",
|
|
};
|
|
let tooltip_txt = match i.1 {
|
|
"Combat Rating" => i18n.get("hud.bag.combat_rating_desc"),
|
|
"Protection" => i18n.get("hud.bag.protection_desc"),
|
|
"Stun Resilience" => i18n.get("hud.bag.stun_res_desc"),
|
|
_ => "",
|
|
};
|
|
btn.with_tooltip(
|
|
self.tooltip_manager,
|
|
tooltip_head,
|
|
tooltip_txt,
|
|
&bag_tooltip,
|
|
TEXT_COLOR,
|
|
)
|
|
.set(state.ids.stat_icons[i.0], ui);
|
|
Text::new(match i.1 {
|
|
"Health" => &health_txt,
|
|
"Energy" => &energy_txt,
|
|
"Combat Rating" => &combat_rating_txt,
|
|
"Protection" => &protection_txt,
|
|
"Stun Resilience" => &stun_res_txt,
|
|
"Stealth" => &stealth_txt,
|
|
_ => "",
|
|
})
|
|
.right_from(state.ids.stat_icons[i.0], 10.0)
|
|
.font_id(self.fonts.cyri.conrod_id)
|
|
.font_size(self.fonts.cyri.scale(14))
|
|
.color(TEXT_COLOR)
|
|
.graphics_for(state.ids.stat_icons[i.0])
|
|
.set(state.ids.stat_txts[i.0], ui);
|
|
}
|
|
// Loadout Slots
|
|
// Head
|
|
let item_slot = EquipSlot::Armor(ArmorSlot::Head);
|
|
let slot = slot_maker
|
|
.fabricate(item_slot, [45.0; 2])
|
|
.mid_top_with_margin_on(state.bg_ids.bg_frame, 60.0)
|
|
.with_icon(self.imgs.head_bg, Vec2::new(32.0, 40.0), Some(UI_MAIN))
|
|
.filled_slot(filled_slot);
|
|
|
|
let slot_id = state.ids.head_slot;
|
|
set_tooltip!(slot, slot_id, item_slot, "hud.bag.head");
|
|
|
|
// Necklace
|
|
let item_slot = EquipSlot::Armor(ArmorSlot::Neck);
|
|
let slot = slot_maker
|
|
.fabricate(item_slot, [45.0; 2])
|
|
.mid_bottom_with_margin_on(state.ids.head_slot, -55.0)
|
|
.with_icon(self.imgs.necklace_bg, Vec2::new(40.0, 31.0), Some(UI_MAIN))
|
|
.filled_slot(filled_slot);
|
|
|
|
let slot_id = state.ids.neck_slot;
|
|
set_tooltip!(slot, slot_id, item_slot, "hud.bag.neck");
|
|
|
|
// Chest
|
|
//Image::new(self.imgs.armor_slot) // different graphics for empty/non empty
|
|
let item_slot = EquipSlot::Armor(ArmorSlot::Chest);
|
|
let slot = slot_maker
|
|
.fabricate(item_slot, [85.0; 2])
|
|
.mid_bottom_with_margin_on(state.ids.neck_slot, -95.0)
|
|
.with_icon(self.imgs.chest_bg, Vec2::new(64.0, 42.0), Some(UI_MAIN))
|
|
.filled_slot(filled_slot);
|
|
|
|
let slot_id = state.ids.chest_slot;
|
|
set_tooltip!(slot, slot_id, item_slot, "hud.bag.chest");
|
|
|
|
// Shoulders
|
|
let item_slot = EquipSlot::Armor(ArmorSlot::Shoulders);
|
|
let slot = slot_maker
|
|
.fabricate(item_slot, [70.0; 2])
|
|
.bottom_left_with_margins_on(state.ids.chest_slot, 0.0, -80.0)
|
|
.with_icon(self.imgs.shoulders_bg, Vec2::new(60.0, 36.0), Some(UI_MAIN))
|
|
.filled_slot(filled_slot);
|
|
|
|
let slot_id = state.ids.shoulders_slot;
|
|
set_tooltip!(slot, slot_id, item_slot, "hud.bag.shoulders");
|
|
|
|
// Hands
|
|
let item_slot = EquipSlot::Armor(ArmorSlot::Hands);
|
|
let slot = slot_maker
|
|
.fabricate(item_slot, [70.0; 2])
|
|
.bottom_right_with_margins_on(state.ids.chest_slot, 0.0, -80.0)
|
|
.with_icon(self.imgs.hands_bg, Vec2::new(55.0, 60.0), Some(UI_MAIN))
|
|
.filled_slot(filled_slot);
|
|
|
|
let slot_id = state.ids.hands_slot;
|
|
set_tooltip!(slot, slot_id, item_slot, "hud.bag.hands");
|
|
|
|
// Belt
|
|
let item_slot = EquipSlot::Armor(ArmorSlot::Belt);
|
|
let slot = slot_maker
|
|
.fabricate(item_slot, [45.0; 2])
|
|
.mid_bottom_with_margin_on(state.ids.chest_slot, -55.0)
|
|
.with_icon(self.imgs.belt_bg, Vec2::new(40.0, 23.0), Some(UI_MAIN))
|
|
.filled_slot(filled_slot);
|
|
|
|
let slot_id = state.ids.belt_slot;
|
|
set_tooltip!(slot, slot_id, item_slot, "hud.bag.belt");
|
|
|
|
// Legs
|
|
let item_slot = EquipSlot::Armor(ArmorSlot::Legs);
|
|
let slot = slot_maker
|
|
.fabricate(item_slot, [85.0; 2])
|
|
.mid_bottom_with_margin_on(state.ids.belt_slot, -95.0)
|
|
.with_icon(self.imgs.legs_bg, Vec2::new(48.0, 70.0), Some(UI_MAIN))
|
|
.filled_slot(filled_slot);
|
|
|
|
let slot_id = state.ids.legs_slot;
|
|
set_tooltip!(slot, slot_id, item_slot, "hud.bag.legs");
|
|
|
|
// Ring
|
|
let item_slot = EquipSlot::Armor(ArmorSlot::Ring1);
|
|
let slot = slot_maker
|
|
.fabricate(item_slot, [45.0; 2])
|
|
.bottom_left_with_margins_on(state.ids.hands_slot, -55.0, 0.0)
|
|
.with_icon(self.imgs.ring_bg, Vec2::new(36.0, 40.0), Some(UI_MAIN))
|
|
.filled_slot(filled_slot);
|
|
|
|
let slot_id = state.ids.ring1_slot;
|
|
set_tooltip!(slot, slot_id, item_slot, "hud.bag.ring");
|
|
|
|
// Ring 2
|
|
let item_slot = EquipSlot::Armor(ArmorSlot::Ring2);
|
|
let slot = slot_maker
|
|
.fabricate(item_slot, [45.0; 2])
|
|
.bottom_right_with_margins_on(state.ids.shoulders_slot, -55.0, 0.0)
|
|
.with_icon(self.imgs.ring_bg, Vec2::new(36.0, 40.0), Some(UI_MAIN))
|
|
.filled_slot(filled_slot);
|
|
|
|
let slot_id = state.ids.ring2_slot;
|
|
set_tooltip!(slot, slot_id, item_slot, "hud.bag.ring");
|
|
|
|
// Back
|
|
let item_slot = EquipSlot::Armor(ArmorSlot::Back);
|
|
let slot = slot_maker
|
|
.fabricate(item_slot, [45.0; 2])
|
|
.down_from(state.ids.ring2_slot, 10.0)
|
|
.with_icon(self.imgs.back_bg, Vec2::new(33.0, 40.0), Some(UI_MAIN))
|
|
.filled_slot(filled_slot);
|
|
|
|
let slot_id = state.ids.back_slot;
|
|
set_tooltip!(slot, slot_id, item_slot, "hud.bag.back");
|
|
|
|
// Foot
|
|
let item_slot = EquipSlot::Armor(ArmorSlot::Feet);
|
|
let slot = slot_maker
|
|
.fabricate(item_slot, [45.0; 2])
|
|
.down_from(state.ids.ring1_slot, 10.0)
|
|
.with_icon(self.imgs.feet_bg, Vec2::new(32.0, 40.0), Some(UI_MAIN))
|
|
.filled_slot(filled_slot);
|
|
|
|
let slot_id = state.ids.feet_slot;
|
|
set_tooltip!(slot, slot_id, item_slot, "hud.bag.feet");
|
|
|
|
// Lantern
|
|
let item_slot = EquipSlot::Lantern;
|
|
let slot = slot_maker
|
|
.fabricate(item_slot, [45.0; 2])
|
|
.top_right_with_margins_on(state.bg_ids.bg_frame, 60.0, 5.0)
|
|
.with_icon(self.imgs.lantern_bg, Vec2::new(24.0, 38.0), Some(UI_MAIN))
|
|
.filled_slot(filled_slot);
|
|
|
|
let slot_id = state.ids.lantern_slot;
|
|
set_tooltip!(slot, slot_id, item_slot, "hud.bag.lantern");
|
|
|
|
// Glider
|
|
let item_slot = EquipSlot::Glider;
|
|
let slot = slot_maker
|
|
.fabricate(item_slot, [45.0; 2])
|
|
.down_from(state.ids.lantern_slot, 5.0)
|
|
.with_icon(self.imgs.glider_bg, Vec2::new(38.0, 38.0), Some(UI_MAIN))
|
|
.filled_slot(filled_slot);
|
|
|
|
let slot_id = state.ids.glider_slot;
|
|
set_tooltip!(slot, slot_id, item_slot, "hud.bag.glider");
|
|
|
|
// Tabard
|
|
let item_slot = EquipSlot::Armor(ArmorSlot::Tabard);
|
|
let slot = slot_maker
|
|
.fabricate(item_slot, [45.0; 2])
|
|
.down_from(state.ids.glider_slot, 5.0)
|
|
.with_icon(self.imgs.tabard_bg, Vec2::new(38.0, 38.0), Some(UI_MAIN))
|
|
.filled_slot(filled_slot);
|
|
|
|
let slot_id = state.ids.tabard_slot;
|
|
set_tooltip!(slot, slot_id, item_slot, "hud.bag.tabard");
|
|
|
|
// Active Mainhand/Left-Slot
|
|
let item_slot = EquipSlot::ActiveMainhand;
|
|
let slot = slot_maker
|
|
.fabricate(item_slot, [85.0; 2])
|
|
.bottom_right_with_margins_on(state.ids.back_slot, -95.0, 0.0)
|
|
.with_icon(self.imgs.mainhand_bg, Vec2::new(75.0, 75.0), Some(UI_MAIN))
|
|
.filled_slot(filled_slot);
|
|
|
|
let slot_id = state.ids.active_mainhand_slot;
|
|
set_tooltip!(slot, slot_id, item_slot, "hud.bag.mainhand");
|
|
|
|
// Active Offhand/Right-Slot
|
|
let item_slot = EquipSlot::ActiveOffhand;
|
|
let slot = slot_maker
|
|
.fabricate(item_slot, [85.0; 2])
|
|
.bottom_left_with_margins_on(state.ids.feet_slot, -95.0, 0.0)
|
|
.with_icon(self.imgs.offhand_bg, Vec2::new(75.0, 75.0), Some(UI_MAIN))
|
|
.filled_slot(filled_slot);
|
|
|
|
let slot_id = state.ids.active_offhand_slot;
|
|
set_tooltip!(slot, slot_id, item_slot, "hud.bag.offhand");
|
|
|
|
// Inactive Mainhand/Left-Slot
|
|
let item_slot = EquipSlot::InactiveMainhand;
|
|
let slot = slot_maker
|
|
.fabricate(item_slot, [40.0; 2])
|
|
.bottom_right_with_margins_on(state.ids.active_mainhand_slot, 3.0, -47.0)
|
|
.with_icon(self.imgs.mainhand_bg, Vec2::new(35.0, 35.0), Some(UI_MAIN))
|
|
.filled_slot(filled_slot);
|
|
|
|
let slot_id = state.ids.inactive_mainhand_slot;
|
|
set_tooltip!(slot, slot_id, item_slot, "hud.bag.inactive_mainhand");
|
|
|
|
// Inactive Offhand/Right-Slot
|
|
let item_slot = EquipSlot::InactiveOffhand;
|
|
let slot = slot_maker
|
|
.fabricate(item_slot, [40.0; 2])
|
|
.bottom_left_with_margins_on(state.ids.active_offhand_slot, 3.0, -47.0)
|
|
.with_icon(self.imgs.offhand_bg, Vec2::new(35.0, 35.0), Some(UI_MAIN))
|
|
.filled_slot(filled_slot);
|
|
|
|
let slot_id = state.ids.inactive_offhand_slot;
|
|
set_tooltip!(slot, slot_id, item_slot, "hud.bag.inactive_offhand");
|
|
|
|
if Button::image(self.imgs.swap_equipped_weapons_btn)
|
|
.hover_image(self.imgs.swap_equipped_weapons_btn_hover)
|
|
.press_image(self.imgs.swap_equipped_weapons_btn_press)
|
|
.w_h(32.0, 40.0)
|
|
.bottom_left_with_margins_on(state.bg_ids.bg_frame, 0.0, 23.3)
|
|
.align_middle_y_of(state.ids.active_mainhand_slot)
|
|
.with_tooltip(
|
|
self.tooltip_manager,
|
|
i18n.get("hud.bag.swap_equipped_weapons_title"),
|
|
if let Some(key) = self
|
|
.global_state
|
|
.settings
|
|
.controls
|
|
.get_binding(GameInput::SwapLoadout)
|
|
{
|
|
i18n.get("hud.bag.swap_equipped_weapons_desc")
|
|
.replace("{key}", key.display_string(key_layout).as_str())
|
|
} else {
|
|
"".to_string()
|
|
}
|
|
.as_str(),
|
|
&tooltip,
|
|
color::WHITE,
|
|
)
|
|
.set(state.ids.swap_equipped_weapons_btn, ui)
|
|
.was_clicked()
|
|
{
|
|
event = Some(Event::SwapEquippedWeapons);
|
|
}
|
|
}
|
|
|
|
// Bag 1
|
|
let item_slot = EquipSlot::Armor(ArmorSlot::Bag1);
|
|
let slot = slot_maker
|
|
.fabricate(item_slot, [35.0; 2])
|
|
.bottom_left_with_margins_on(
|
|
state.bg_ids.bg_frame,
|
|
if self.show.bag_inv { 600.0 } else { 167.0 },
|
|
3.0,
|
|
)
|
|
.with_icon(self.imgs.bag_bg, Vec2::new(28.0, 24.0), Some(UI_MAIN))
|
|
.filled_slot(filled_slot);
|
|
|
|
let slot_id = state.ids.bag1_slot;
|
|
set_tooltip!(slot, slot_id, item_slot, "hud.bag.bag");
|
|
|
|
// Bag 2
|
|
let item_slot = EquipSlot::Armor(ArmorSlot::Bag2);
|
|
let slot = slot_maker
|
|
.fabricate(item_slot, [35.0; 2])
|
|
.down_from(state.ids.bag1_slot, 2.0)
|
|
.with_icon(self.imgs.bag_bg, Vec2::new(28.0, 24.0), Some(UI_MAIN))
|
|
.filled_slot(filled_slot);
|
|
|
|
let slot_id = state.ids.bag2_slot;
|
|
set_tooltip!(slot, slot_id, item_slot, "hud.bag.bag");
|
|
|
|
// Bag 3
|
|
let item_slot = EquipSlot::Armor(ArmorSlot::Bag3);
|
|
let slot = slot_maker
|
|
.fabricate(item_slot, [35.0; 2])
|
|
.down_from(state.ids.bag2_slot, 2.0)
|
|
.with_icon(self.imgs.bag_bg, Vec2::new(28.0, 24.0), Some(UI_MAIN))
|
|
.filled_slot(filled_slot);
|
|
|
|
let slot_id = state.ids.bag3_slot;
|
|
set_tooltip!(slot, slot_id, item_slot, "hud.bag.bag");
|
|
|
|
// Bag 4
|
|
let item_slot = EquipSlot::Armor(ArmorSlot::Bag4);
|
|
let slot = slot_maker
|
|
.fabricate(item_slot, [35.0; 2])
|
|
.down_from(state.ids.bag3_slot, 2.0)
|
|
.with_icon(self.imgs.bag_bg, Vec2::new(28.0, 24.0), Some(UI_MAIN))
|
|
.filled_slot(filled_slot);
|
|
|
|
let slot_id = state.ids.bag4_slot;
|
|
set_tooltip!(slot, slot_id, item_slot, "hud.bag.bag");
|
|
|
|
// Close button
|
|
if Button::image(self.imgs.close_btn)
|
|
.w_h(24.0, 25.0)
|
|
.hover_image(self.imgs.close_btn_hover)
|
|
.press_image(self.imgs.close_btn_press)
|
|
.top_right_with_margins_on(state.bg_ids.bg, 0.0, 0.0)
|
|
.set(state.ids.bag_close, ui)
|
|
.was_clicked()
|
|
{
|
|
event = Some(Event::Close);
|
|
}
|
|
event
|
|
}
|
|
}
|