Started work on inventory manipulation

This commit is contained in:
Joshua Barretto 2019-07-25 23:52:28 +01:00
parent 123a78552a
commit 31f8794c39
9 changed files with 119 additions and 50 deletions

View File

@ -164,6 +164,11 @@ impl Client {
.send_message(ClientMsg::SetViewDistance(self.view_distance.unwrap())); // Can't fail
}
pub fn swap_inventory_slots(&mut self, a: usize, b: usize) {
self.postbox
.send_message(ClientMsg::SwapInventorySlots(a, b))
}
pub fn view_distance(&self) -> Option<u32> {
self.view_distance
}

View File

@ -37,29 +37,30 @@ pub enum Armor {
Necklace,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Rarity {
Common,
Uncommon,
Rare,
Legendary,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Item {
Weapon {
kind: Weapon,
damage: i32,
strength: i32,
rarity: Rarity,
},
Armor {
kind: Armor,
defense: i32,
health_bonus: i32,
rarity: Rarity,
variant: Armor,
},
}
impl Default for Item {
fn default() -> Self {
Item::Weapon {
kind: Weapon::Hammer,
damage: 0,
strength: 0,
}
}
}
impl Component for Item {
type Storage = IDVStorage<Self>;
}

View File

@ -17,6 +17,20 @@ impl Inventory {
&self.slots
}
pub fn len(&self) -> usize {
self.slots.len()
}
pub fn insert(&mut self, item: Item) -> Option<Item> {
match self.slots.iter_mut().find(|slot| slot.is_none()) {
Some(slot) => {
*slot = Some(item);
None
}
None => Some(item),
}
}
// Get info about an item slot
pub fn get(&self, cell: usize) -> Option<Item> {
self.slots.get(cell).cloned().flatten()
@ -28,6 +42,12 @@ impl Inventory {
self.slots.get_mut(cell).and_then(|cell| cell.replace(item))
}
pub fn swap_slots(&mut self, a: usize, b: usize) {
if a.max(b) < self.slots.len() {
self.slots.swap(a, b);
}
}
// Remove an item from the slot
pub fn remove(&mut self, cell: usize) -> Option<Item> {
self.slots.get_mut(cell).and_then(|item| item.take())
@ -36,9 +56,15 @@ impl Inventory {
impl Default for Inventory {
fn default() -> Inventory {
Inventory {
let mut this = Inventory {
slots: vec![None; 8],
}
};
this.insert(Item::default());
this.insert(Item::default());
this.insert(Item::default());
this
}
}

View File

@ -28,6 +28,7 @@ pub enum ClientMsg {
vel: comp::Vel,
ori: comp::Ori,
},
SwapInventorySlots(usize, usize),
TerrainChunkRequest {
key: Vec2<i32>,
},

View File

@ -197,7 +197,7 @@ impl<'a> System<'a> for Sys {
// ...and the vertical resolution direction is sufficiently great...
&& -dir.z > 0.1
// ...and we're falling/standing OR there is a block *directly* beneath our current origin (note: not hitbox)...
&& (vel.0.z <= 0.0 && terrain
&& (vel.0.z > 0.0 || terrain
.get((pos.0 - Vec3::unit_z()).map(|e| e.floor() as i32))
.map(|vox| !vox.is_empty())
.unwrap_or(false))

View File

@ -490,6 +490,14 @@ impl Server {
}
_ => {}
},
ClientMsg::SwapInventorySlots(a, b) => {
state
.ecs()
.write_storage::<comp::Inventory>()
.get_mut(entity)
.map(|inv| inv.swap_slots(a, b));
state.write_component(entity, comp::InventoryUpdate);
}
ClientMsg::Character { name, body } => match client.client_state {
// Become Registered first.
ClientState::Connected => {

View File

@ -1,4 +1,4 @@
use super::{img_ids::Imgs, Fonts, TEXT_COLOR};
use super::{img_ids::Imgs, Event as HudEvent, Fonts, TEXT_COLOR};
use client::Client;
use conrod_core::{
color,
@ -17,10 +17,10 @@ widget_ids! {
inv_grid_1,
inv_grid_2,
inv_scrollbar,
inv_slot_0,
inv_slots_0,
map_title,
inv_slot[],
item1,
inv_slots[],
items[],
}
}
@ -51,6 +51,7 @@ pub struct State {
const BAG_SCALE: f64 = 4.0;
pub enum Event {
HudEvent(HudEvent),
Close,
}
@ -72,12 +73,13 @@ impl<'a> Widget for Bag<'a> {
fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
let widget::UpdateArgs { state, ui, .. } = args;
let inventory_slots = self
.client
.inventories()
.get(self.client.entity())
.map(|inv| inv.slots().len())
.unwrap_or(0);
let mut event = None;
let invs = self.client.inventories();
let inventory = match invs.get(self.client.entity()) {
Some(inv) => inv,
None => return None,
};
// Bag parts
Image::new(self.imgs.bag_bot)
@ -85,7 +87,7 @@ impl<'a> Widget for Bag<'a> {
.bottom_right_with_margins_on(ui.window, 60.0, 5.0)
.set(state.ids.bag_bot, ui);
Image::new(self.imgs.bag_mid)
.w_h(61.0 * BAG_SCALE, ((inventory_slots + 4) / 5) as f64 * 44.0)
.w_h(61.0 * BAG_SCALE, ((inventory.len() + 4) / 5) as f64 * 44.0)
.up_from(state.ids.bag_bot, 0.0)
.set(state.ids.bag_mid, ui);
Image::new(self.imgs.bag_top)
@ -95,7 +97,7 @@ impl<'a> Widget for Bag<'a> {
// Alignment for Grid
Rectangle::fill_with(
[54.0 * BAG_SCALE, ((inventory_slots + 4) / 5) as f64 * 44.0],
[54.0 * BAG_SCALE, ((inventory.len() + 4) / 5) as f64 * 44.0],
color::TRANSPARENT,
)
.top_left_with_margins_on(state.ids.bag_top, 9.0 * BAG_SCALE, 3.0 * BAG_SCALE)
@ -120,18 +122,31 @@ impl<'a> Widget for Bag<'a> {
.set(state.ids.inv_scrollbar, ui);*/
// Create available inventory slot widgets
if state.ids.inv_slot.len() < inventory_slots {
if state.ids.inv_slots.len() < inventory.len() {
state.update(|s| {
s.ids
.inv_slot
.resize(inventory_slots, &mut ui.widget_id_generator());
.inv_slots
.resize(inventory.len(), &mut ui.widget_id_generator());
});
}
// "Allowed" max. inventory space should be handled serverside and thus isn't limited in the UI
for i in 0..inventory_slots {
if state.ids.items.len() < inventory.len() {
state.update(|s| {
s.ids
.items
.resize(inventory.len(), &mut ui.widget_id_generator());
});
}
// Display inventory contents
for (i, item) in inventory.slots().iter().enumerate() {
let x = i % 5;
let y = i / 5;
Button::image(self.imgs.inv_slot)
// Slot
if Button::image(self.imgs.inv_slot)
.top_left_with_margins_on(
state.ids.inv_alignment,
4.0 + y as f64 * (40.0 + 4.0),
@ -139,22 +154,30 @@ impl<'a> Widget for Bag<'a> {
) // conrod uses a (y,x) format for placing...
.parent(state.ids.bag_mid) // Avoids the background overlapping available slots
.w_h(40.0, 40.0)
.set(state.ids.inv_slot[i], ui);
.set(state.ids.inv_slots[i], ui)
.was_clicked()
{
event = Some(Event::HudEvent(HudEvent::SwapInventorySlots(0, i)));
}
// Item
if item.is_some() {
Button::image(self.imgs.potion_red) // TODO: Insert variable image depending on the item displayed in that slot
.w_h(4.0 * 4.4, 7.0 * 4.4) // TODO: Fix height and scale width correctly to that to avoid a stretched item image
.middle_of(state.ids.inv_slots[i]) // TODO: Items need to be assigned to a certain slot and then placed like in this example
.label("5x") // TODO: Quantity goes here...
.label_font_id(self.fonts.opensans)
.label_font_size(12)
.label_x(Relative::Scalar(10.0))
.label_y(Relative::Scalar(-10.0))
.label_color(TEXT_COLOR)
.parent(state.ids.inv_slots[i])
.set(state.ids.items[i], ui);
}
}
// Test Item
if inventory_slots > 0 {
Button::image(self.imgs.potion_red) // TODO: Insert variable image depending on the item displayed in that slot
.w_h(4.0 * 4.4, 7.0 * 4.4) // TODO: Fix height and scale width correctly to that to avoid a stretched item image
.middle_of(state.ids.inv_slot[0]) // TODO: Items need to be assigned to a certain slot and then placed like in this example
.label("5x") // TODO: Quantity goes here...
.label_font_id(self.fonts.opensans)
.label_font_size(12)
.label_x(Relative::Scalar(10.0))
.label_y(Relative::Scalar(-10.0))
.label_color(TEXT_COLOR)
.set(state.ids.item1, ui); // TODO: Add widget_id generator for displayed items
}
// X-button
// Close button
if Button::image(self.imgs.close_button)
.w_h(28.0, 28.0)
.hover_image(self.imgs.close_button_hover)
@ -163,9 +186,9 @@ impl<'a> Widget for Bag<'a> {
.set(state.ids.bag_close, ui)
.was_clicked()
{
Some(Event::Close)
} else {
None
event = Some(Event::Close);
}
event
}
}

View File

@ -141,6 +141,7 @@ pub enum Event {
CrosshairType(CrosshairType),
UiScale(ScaleChange),
CharacterSelection,
SwapInventorySlots(usize, usize),
Logout,
Quit,
}
@ -589,6 +590,7 @@ impl Hud {
// Bag contents
if self.show.bag {
match Bag::new(client, &self.imgs, &self.fonts).set(self.ids.bag, ui_widgets) {
Some(bag::Event::HudEvent(event)) => events.push(event),
Some(bag::Event::Close) => {
self.show.bag(false);
self.force_ungrab = true;

View File

@ -318,6 +318,9 @@ impl PlayState for SessionState {
global_state.settings.graphics.max_fps = fps;
global_state.settings.save_to_file_warn();
}
HudEvent::SwapInventorySlots(a, b) => {
self.client.borrow_mut().swap_inventory_slots(a, b)
}
}
}