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 .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> { pub fn view_distance(&self) -> Option<u32> {
self.view_distance self.view_distance
} }

View File

@ -37,29 +37,30 @@ pub enum Armor {
Necklace, 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)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Item { pub enum Item {
Weapon { Weapon {
kind: Weapon,
damage: i32, damage: i32,
strength: i32, strength: i32,
rarity: Rarity,
}, },
Armor { Armor {
kind: Armor,
defense: i32, defense: i32,
health_bonus: 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 { impl Component for Item {
type Storage = IDVStorage<Self>; type Storage = IDVStorage<Self>;
} }

View File

@ -17,6 +17,20 @@ impl Inventory {
&self.slots &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 // Get info about an item slot
pub fn get(&self, cell: usize) -> Option<Item> { pub fn get(&self, cell: usize) -> Option<Item> {
self.slots.get(cell).cloned().flatten() self.slots.get(cell).cloned().flatten()
@ -28,6 +42,12 @@ impl Inventory {
self.slots.get_mut(cell).and_then(|cell| cell.replace(item)) 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 // Remove an item from the slot
pub fn remove(&mut self, cell: usize) -> Option<Item> { pub fn remove(&mut self, cell: usize) -> Option<Item> {
self.slots.get_mut(cell).and_then(|item| item.take()) self.slots.get_mut(cell).and_then(|item| item.take())
@ -36,9 +56,15 @@ impl Inventory {
impl Default for Inventory { impl Default for Inventory {
fn default() -> Inventory { fn default() -> Inventory {
Inventory { let mut this = Inventory {
slots: vec![None; 8], 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, vel: comp::Vel,
ori: comp::Ori, ori: comp::Ori,
}, },
SwapInventorySlots(usize, usize),
TerrainChunkRequest { TerrainChunkRequest {
key: Vec2<i32>, key: Vec2<i32>,
}, },

View File

@ -197,7 +197,7 @@ impl<'a> System<'a> for Sys {
// ...and the vertical resolution direction is sufficiently great... // ...and the vertical resolution direction is sufficiently great...
&& -dir.z > 0.1 && -dir.z > 0.1
// ...and we're falling/standing OR there is a block *directly* beneath our current origin (note: not hitbox)... // ...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)) .get((pos.0 - Vec3::unit_z()).map(|e| e.floor() as i32))
.map(|vox| !vox.is_empty()) .map(|vox| !vox.is_empty())
.unwrap_or(false)) .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 { ClientMsg::Character { name, body } => match client.client_state {
// Become Registered first. // Become Registered first.
ClientState::Connected => { 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 client::Client;
use conrod_core::{ use conrod_core::{
color, color,
@ -17,10 +17,10 @@ widget_ids! {
inv_grid_1, inv_grid_1,
inv_grid_2, inv_grid_2,
inv_scrollbar, inv_scrollbar,
inv_slot_0, inv_slots_0,
map_title, map_title,
inv_slot[], inv_slots[],
item1, items[],
} }
} }
@ -51,6 +51,7 @@ pub struct State {
const BAG_SCALE: f64 = 4.0; const BAG_SCALE: f64 = 4.0;
pub enum Event { pub enum Event {
HudEvent(HudEvent),
Close, Close,
} }
@ -72,12 +73,13 @@ impl<'a> Widget for Bag<'a> {
fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event { fn update(self, args: widget::UpdateArgs<Self>) -> Self::Event {
let widget::UpdateArgs { state, ui, .. } = args; let widget::UpdateArgs { state, ui, .. } = args;
let inventory_slots = self let mut event = None;
.client
.inventories() let invs = self.client.inventories();
.get(self.client.entity()) let inventory = match invs.get(self.client.entity()) {
.map(|inv| inv.slots().len()) Some(inv) => inv,
.unwrap_or(0); None => return None,
};
// Bag parts // Bag parts
Image::new(self.imgs.bag_bot) 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) .bottom_right_with_margins_on(ui.window, 60.0, 5.0)
.set(state.ids.bag_bot, ui); .set(state.ids.bag_bot, ui);
Image::new(self.imgs.bag_mid) 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) .up_from(state.ids.bag_bot, 0.0)
.set(state.ids.bag_mid, ui); .set(state.ids.bag_mid, ui);
Image::new(self.imgs.bag_top) Image::new(self.imgs.bag_top)
@ -95,7 +97,7 @@ impl<'a> Widget for Bag<'a> {
// Alignment for Grid // Alignment for Grid
Rectangle::fill_with( 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, color::TRANSPARENT,
) )
.top_left_with_margins_on(state.ids.bag_top, 9.0 * BAG_SCALE, 3.0 * BAG_SCALE) .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);*/ .set(state.ids.inv_scrollbar, ui);*/
// Create available inventory slot widgets // Create available inventory slot widgets
if state.ids.inv_slot.len() < inventory_slots {
if state.ids.inv_slots.len() < inventory.len() {
state.update(|s| { state.update(|s| {
s.ids s.ids
.inv_slot .inv_slots
.resize(inventory_slots, &mut ui.widget_id_generator()); .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 x = i % 5;
let y = 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( .top_left_with_margins_on(
state.ids.inv_alignment, state.ids.inv_alignment,
4.0 + y as f64 * (40.0 + 4.0), 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... ) // conrod uses a (y,x) format for placing...
.parent(state.ids.bag_mid) // Avoids the background overlapping available slots .parent(state.ids.bag_mid) // Avoids the background overlapping available slots
.w_h(40.0, 40.0) .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)));
} }
// Test Item
if inventory_slots > 0 { // Item
if item.is_some() {
Button::image(self.imgs.potion_red) // TODO: Insert variable image depending on the item displayed in that slot 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 .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 .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("5x") // TODO: Quantity goes here...
.label_font_id(self.fonts.opensans) .label_font_id(self.fonts.opensans)
.label_font_size(12) .label_font_size(12)
.label_x(Relative::Scalar(10.0)) .label_x(Relative::Scalar(10.0))
.label_y(Relative::Scalar(-10.0)) .label_y(Relative::Scalar(-10.0))
.label_color(TEXT_COLOR) .label_color(TEXT_COLOR)
.set(state.ids.item1, ui); // TODO: Add widget_id generator for displayed items .parent(state.ids.inv_slots[i])
.set(state.ids.items[i], ui);
} }
// X-button }
// Close button
if Button::image(self.imgs.close_button) if Button::image(self.imgs.close_button)
.w_h(28.0, 28.0) .w_h(28.0, 28.0)
.hover_image(self.imgs.close_button_hover) .hover_image(self.imgs.close_button_hover)
@ -163,9 +186,9 @@ impl<'a> Widget for Bag<'a> {
.set(state.ids.bag_close, ui) .set(state.ids.bag_close, ui)
.was_clicked() .was_clicked()
{ {
Some(Event::Close) event = Some(Event::Close);
} else {
None
} }
event
} }
} }

View File

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

View File

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