From 20248a4818d81ad5c1d4d4efd20eeb9686a1fdc7 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Tue, 22 Oct 2019 20:18:40 +0200 Subject: [PATCH 1/6] feat: store items as RON files When a new item is created, a ron file will be used as a template --- Cargo.lock | 1 + assets/common/items/apple.ron | 11 + assets/common/items/debug/boost.ron | 5 + assets/common/items/debug/possess.ron | 5 + assets/common/items/flowers/blue.ron | 5 + assets/common/items/flowers/pink.ron | 5 + assets/common/items/flowers/red.ron | 5 + assets/common/items/flowers/sun.ron | 5 + assets/common/items/flowers/white.ron | 5 + assets/common/items/flowers/yellow.ron | 5 + assets/common/items/grasses/long.ron | 5 + assets/common/items/grasses/medium.ron | 5 + assets/common/items/grasses/short.ron | 5 + assets/common/items/mushroom.ron | 11 + assets/common/items/velorite.ron | 8 + assets/common/items/veloritefrag.ron | 8 + assets/common/items/weapons/starter_axe.ron | 8 + assets/common/items/weapons/starter_bow.ron | 8 + .../common/items/weapons/starter_dagger.ron | 8 + .../common/items/weapons/starter_hammer.ron | 8 + assets/common/items/weapons/starter_staff.ron | 8 + assets/common/items/weapons/starter_sword.ron | 8 + client/src/lib.rs | 7 +- common/Cargo.toml | 1 + common/src/assets/mod.rs | 12 + common/src/comp/inventory/item.rs | 327 ++++-------------- common/src/comp/inventory/mod.rs | 7 +- common/src/comp/mod.rs | 2 +- common/src/event.rs | 2 +- common/src/msg/client.rs | 2 +- common/src/sys/combat.rs | 17 +- common/src/sys/controller.rs | 19 +- server/src/lib.rs | 74 ++-- server/src/sys/message.rs | 12 +- server/src/sys/terrain.rs | 23 +- voxygen/src/hud/bag.rs | 10 +- voxygen/src/hud/item_imgs.rs | 26 +- voxygen/src/hud/skillbar.rs | 29 +- voxygen/src/menu/char_selection/mod.rs | 22 +- voxygen/src/menu/char_selection/ui.rs | 37 +- voxygen/src/scene/figure/load.rs | 8 +- 41 files changed, 364 insertions(+), 415 deletions(-) create mode 100644 assets/common/items/apple.ron create mode 100644 assets/common/items/debug/boost.ron create mode 100644 assets/common/items/debug/possess.ron create mode 100644 assets/common/items/flowers/blue.ron create mode 100644 assets/common/items/flowers/pink.ron create mode 100644 assets/common/items/flowers/red.ron create mode 100644 assets/common/items/flowers/sun.ron create mode 100644 assets/common/items/flowers/white.ron create mode 100644 assets/common/items/flowers/yellow.ron create mode 100644 assets/common/items/grasses/long.ron create mode 100644 assets/common/items/grasses/medium.ron create mode 100644 assets/common/items/grasses/short.ron create mode 100644 assets/common/items/mushroom.ron create mode 100644 assets/common/items/velorite.ron create mode 100644 assets/common/items/veloritefrag.ron create mode 100644 assets/common/items/weapons/starter_axe.ron create mode 100644 assets/common/items/weapons/starter_bow.ron create mode 100644 assets/common/items/weapons/starter_dagger.ron create mode 100644 assets/common/items/weapons/starter_hammer.ron create mode 100644 assets/common/items/weapons/starter_staff.ron create mode 100644 assets/common/items/weapons/starter_sword.ron diff --git a/Cargo.lock b/Cargo.lock index 391abb1593..ab677350bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3609,6 +3609,7 @@ dependencies = [ "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/assets/common/items/apple.ron b/assets/common/items/apple.ron new file mode 100644 index 0000000000..83237e354b --- /dev/null +++ b/assets/common/items/apple.ron @@ -0,0 +1,11 @@ +Item( + name: "An apple", + description: "Looks refreshing", + kind: Consumable( + kind: Apple, + effect: Health(( + amount: 10, + cause: Item, + )), + ), +) diff --git a/assets/common/items/debug/boost.ron b/assets/common/items/debug/boost.ron new file mode 100644 index 0000000000..d9b350c5f2 --- /dev/null +++ b/assets/common/items/debug/boost.ron @@ -0,0 +1,5 @@ +Item( + name: "Boost rod", + description: "Your legs feel full of energy while holding this", + kind: Debug(Boost), +) diff --git a/assets/common/items/debug/possess.ron b/assets/common/items/debug/possess.ron new file mode 100644 index 0000000000..79e3b10d7e --- /dev/null +++ b/assets/common/items/debug/possess.ron @@ -0,0 +1,5 @@ +Item( + name: "Possession rod", + description: "Your body seems loose while holding this", + kind: Debug(Possess), +) diff --git a/assets/common/items/flowers/blue.ron b/assets/common/items/flowers/blue.ron new file mode 100644 index 0000000000..582dd02513 --- /dev/null +++ b/assets/common/items/flowers/blue.ron @@ -0,0 +1,5 @@ +Item( + name: "A blue flower", + description: "Look beautiful", + kind: Ingredient(Flower), +) diff --git a/assets/common/items/flowers/pink.ron b/assets/common/items/flowers/pink.ron new file mode 100644 index 0000000000..fed902b2a0 --- /dev/null +++ b/assets/common/items/flowers/pink.ron @@ -0,0 +1,5 @@ +Item( + name: "A pink flower", + description: "Look beautiful", + kind: Ingredient(Flower), +) diff --git a/assets/common/items/flowers/red.ron b/assets/common/items/flowers/red.ron new file mode 100644 index 0000000000..0e4148317e --- /dev/null +++ b/assets/common/items/flowers/red.ron @@ -0,0 +1,5 @@ +Item( + name: "A red flower", + description: "Look beautiful", + kind: Ingredient(Flower), +) diff --git a/assets/common/items/flowers/sun.ron b/assets/common/items/flowers/sun.ron new file mode 100644 index 0000000000..219cd19ee1 --- /dev/null +++ b/assets/common/items/flowers/sun.ron @@ -0,0 +1,5 @@ +Item( + name: "A sunflower", + description: "Look beautiful", + kind: Ingredient(Flower), +) diff --git a/assets/common/items/flowers/white.ron b/assets/common/items/flowers/white.ron new file mode 100644 index 0000000000..02f65ac369 --- /dev/null +++ b/assets/common/items/flowers/white.ron @@ -0,0 +1,5 @@ +Item( + name: "A white flower", + description: "Look beautiful", + kind: Ingredient(Flower), +) diff --git a/assets/common/items/flowers/yellow.ron b/assets/common/items/flowers/yellow.ron new file mode 100644 index 0000000000..dfd0aea52f --- /dev/null +++ b/assets/common/items/flowers/yellow.ron @@ -0,0 +1,5 @@ +Item( + name: "A yellow flower", + description: "Look beautiful", + kind: Ingredient(Flower), +) diff --git a/assets/common/items/grasses/long.ron b/assets/common/items/grasses/long.ron new file mode 100644 index 0000000000..720e3aa962 --- /dev/null +++ b/assets/common/items/grasses/long.ron @@ -0,0 +1,5 @@ +Item( + name: "Long grass", + description: "Just some grass", + kind: Ingredient(Grass), +) diff --git a/assets/common/items/grasses/medium.ron b/assets/common/items/grasses/medium.ron new file mode 100644 index 0000000000..65419a1f33 --- /dev/null +++ b/assets/common/items/grasses/medium.ron @@ -0,0 +1,5 @@ +Item( + name: "Medium grass", + description: "Just some grass", + kind: Ingredient(Grass), +) diff --git a/assets/common/items/grasses/short.ron b/assets/common/items/grasses/short.ron new file mode 100644 index 0000000000..19a6216718 --- /dev/null +++ b/assets/common/items/grasses/short.ron @@ -0,0 +1,5 @@ +Item( + name: "Short grass", + description: "Just some grass", + kind: Ingredient(Grass), +) diff --git a/assets/common/items/mushroom.ron b/assets/common/items/mushroom.ron new file mode 100644 index 0000000000..336d4b2ce4 --- /dev/null +++ b/assets/common/items/mushroom.ron @@ -0,0 +1,11 @@ +Item( + name: "A mushroom", + description: "It's dirty, but looks edible", + kind: Consumable( + kind: Mushroom, + effect: Health(( + amount: 10, + cause: Item, + )), + ), +) diff --git a/assets/common/items/velorite.ron b/assets/common/items/velorite.ron new file mode 100644 index 0000000000..da756e3116 --- /dev/null +++ b/assets/common/items/velorite.ron @@ -0,0 +1,8 @@ +Item( + name: "Velorite", + description: "It's smooth and looks edible", + kind: Consumable( + kind: Velorite, + effect: Xp(50), + ), +) diff --git a/assets/common/items/veloritefrag.ron b/assets/common/items/veloritefrag.ron new file mode 100644 index 0000000000..44bda9dd21 --- /dev/null +++ b/assets/common/items/veloritefrag.ron @@ -0,0 +1,8 @@ +Item( + name: "Velorite Fragment", + description: "It's dirty, but looks edible", + kind: Consumable( + kind: VeloriteFrag, + effect: Xp(20), + ), +) diff --git a/assets/common/items/weapons/starter_axe.ron b/assets/common/items/weapons/starter_axe.ron new file mode 100644 index 0000000000..51fa9a5fb4 --- /dev/null +++ b/assets/common/items/weapons/starter_axe.ron @@ -0,0 +1,8 @@ +Item( + name: "Your first axe", + description: "A dusty axe that looks surprisingly weak", + kind: Tool( + kind: Axe, + power: 10, + ), +) diff --git a/assets/common/items/weapons/starter_bow.ron b/assets/common/items/weapons/starter_bow.ron new file mode 100644 index 0000000000..f1cdbadffe --- /dev/null +++ b/assets/common/items/weapons/starter_bow.ron @@ -0,0 +1,8 @@ +Item( + name: "Your first bow", + description: "A dusty bow that looks surprisingly weak", + kind: Tool( + kind: Bow, + power: 10, + ), +) diff --git a/assets/common/items/weapons/starter_dagger.ron b/assets/common/items/weapons/starter_dagger.ron new file mode 100644 index 0000000000..6e1e42afb8 --- /dev/null +++ b/assets/common/items/weapons/starter_dagger.ron @@ -0,0 +1,8 @@ +Item( + name: "Your first dagger", + description: "A dusty dagger that looks surprisingly weak", + kind: Tool( + kind: Dagger, + power: 10, + ), +) diff --git a/assets/common/items/weapons/starter_hammer.ron b/assets/common/items/weapons/starter_hammer.ron new file mode 100644 index 0000000000..5a697d1fd3 --- /dev/null +++ b/assets/common/items/weapons/starter_hammer.ron @@ -0,0 +1,8 @@ +Item( + name: "Your first hammer", + description: "A dusty hammer that looks surprisingly weak", + kind: Tool( + kind: Hammer, + power: 10, + ), +) diff --git a/assets/common/items/weapons/starter_staff.ron b/assets/common/items/weapons/starter_staff.ron new file mode 100644 index 0000000000..9abec910ec --- /dev/null +++ b/assets/common/items/weapons/starter_staff.ron @@ -0,0 +1,8 @@ +Item( + name: "Your first staff", + description: "A dusty staff that looks surprisingly weak", + kind: Tool( + kind: Staff, + power: 10, + ), +) diff --git a/assets/common/items/weapons/starter_sword.ron b/assets/common/items/weapons/starter_sword.ron new file mode 100644 index 0000000000..0da5b8ab68 --- /dev/null +++ b/assets/common/items/weapons/starter_sword.ron @@ -0,0 +1,8 @@ +Item( + name: "Your first sword", + description: "A dusty sword that looks surprisingly weak", + kind: Tool( + kind: Sword, + power: 10, + ), +) diff --git a/client/src/lib.rs b/client/src/lib.rs index 1aeb7c7b31..3f1b611f55 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -169,12 +169,7 @@ impl Client { } /// Request a state transition to `ClientState::Character`. - pub fn request_character( - &mut self, - name: String, - body: comp::Body, - main: Option, - ) { + pub fn request_character(&mut self, name: String, body: comp::Body, main: Option) { self.postbox .send_message(ClientMsg::Character { name, body, main }); self.client_state = ClientState::Pending; diff --git a/common/Cargo.toml b/common/Cargo.toml index d1825f29fd..92683740d3 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -17,6 +17,7 @@ mio-extras = "2.0.5" serde = "1.0.98" serde_derive = "1.0.98" serde_json = "1.0.40" +ron = "0.5.1" bincode = "1.1.4" log = "0.4.8" rand = "0.7.0" diff --git a/common/src/assets/mod.rs b/common/src/assets/mod.rs index 89bea172b9..ab97fd8ce0 100644 --- a/common/src/assets/mod.rs +++ b/common/src/assets/mod.rs @@ -84,6 +84,12 @@ pub fn load(specifier: &str) -> Result, Error> { load_map(specifier, |x| x) } +/// Function used to load assets from the filesystem or the cache and return a clone. +pub fn load_cloned(specifier: &str) -> Option { + let asset: Option> = load(specifier).ok(); + asset.map(|asset| (*asset).clone()) +} + /// Function used to load essential assets from the filesystem or the cache. It will panic if the asset is not found. /// Example usage: /// ```no_run @@ -96,6 +102,12 @@ pub fn load_expect(specifier: &str) -> Arc { load(specifier).unwrap_or_else(|_| panic!("Failed loading essential asset: {}", specifier)) } +/// Function used to load essential assets from the filesystem or the cache and return a clone. It will panic if the asset is not found. +pub fn load_expect_cloned(specifier: &str) -> A { + let asset: Arc = load_expect(specifier); + (*asset).clone() +} + /// Load an asset while registering it to be watched and reloaded when it changes pub fn load_watched( specifier: &str, diff --git a/common/src/comp/inventory/item.rs b/common/src/comp/inventory/item.rs index daa2026015..c3d7882d97 100644 --- a/common/src/comp/inventory/item.rs +++ b/common/src/comp/inventory/item.rs @@ -1,11 +1,12 @@ use crate::{ - comp, + assets::{self, Asset}, effect::Effect, terrain::{Block, BlockKind}, }; -use rand::prelude::*; use specs::{Component, FlaggedStorage}; use specs_idvs::IDVStorage; +use std::fs::File; +use std::io::BufReader; #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Tool { @@ -18,52 +19,6 @@ pub enum Tool { Staff, } -impl Tool { - pub fn name(&self) -> &'static str { - match self { - Tool::Dagger => "Dagger", - Tool::Shield => "Shield", - Tool::Sword => "Sword", - Tool::Axe => "Axe", - Tool::Hammer => "Hammer", - Tool::Bow => "Bow", - Tool::Staff => "Staff", - } - } - - pub fn description(&self) -> &'static str { - match self { - Tool::Dagger => { - "A basic kitchen knife.\n\ - NOT YET AVAILABLE." - } - Tool::Shield => { - "This shield belonged to many adventurers.\n\ - Now it's yours.\n\ - NOT YET AVAILABLE." - } - Tool::Sword => "When closing one eye it's nearly like it wasn't rusty at all!", - Tool::Axe => { - "It has a name written on it.\n\ - Sounds dwarvish." - } - Tool::Hammer => "Use with caution around nails.", - Tool::Bow => "An old but sturdy hunting bow.", - Tool::Staff => "The wood smells like magic.", - } - } -} - -pub const ALL_TOOLS: [Tool; 7] = [ - Tool::Dagger, - Tool::Shield, - Tool::Sword, - Tool::Axe, - Tool::Hammer, - Tool::Bow, - Tool::Staff, -]; - #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Armor { // TODO: Don't make armor be a body part. Wearing enemy's head is funny but also a creepy thing to do. @@ -80,28 +35,6 @@ pub enum Armor { Necklace, } -impl Armor { - pub fn name(&self) -> &'static str { - match self { - Armor::Helmet => "Helmet", - Armor::Shoulders => "Shoulder Pads", - Armor::Chestplate => "Chestplate", - Armor::Belt => "Belt", - Armor::Gloves => "Gloves", - Armor::Pants => "Pants", - Armor::Boots => "Boots", - Armor::Back => "Back", - Armor::Tabard => "Tabard", - Armor::Gem => "Gem", - Armor::Necklace => "Necklace", - } - } - - pub fn description(&self) -> &'static str { - self.name() - } -} - #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Consumable { Apple, @@ -111,50 +44,12 @@ pub enum Consumable { VeloriteFrag, } -impl Consumable { - pub fn name(&self) -> &'static str { - match self { - Consumable::Apple => "Apple", - Consumable::Potion => "Potion", - Consumable::Mushroom => "Mushroom", - Consumable::Velorite => "Velorite", - Consumable::VeloriteFrag => "Glowing Fragment", - } - } - - pub fn description(&self) -> &'static str { - match self { - Consumable::Apple => "A tasty Apple.", - Consumable::Potion => "This Potion contains the essence of Life.", - Consumable::Mushroom => "A common Mushroom.", - Consumable::Velorite => "Has a subtle turqoise glow.", - Consumable::VeloriteFrag => "Seems to be the fragment of a bigger piece...", - } - } -} - #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Ingredient { Flower, Grass, } -impl Ingredient { - pub fn name(&self) -> &'static str { - match self { - Ingredient::Flower => "Flower", - Ingredient::Grass => "Grass", - } - } - - pub fn description(&self) -> &'static str { - match self { - Ingredient::Flower => "It smells great.", - Ingredient::Grass => "Greener than an orc's snout.", - } - } -} - #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Debug { Boost, @@ -162,167 +57,75 @@ pub enum Debug { } #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub enum Item { - Tool { - kind: Tool, - power: u32, - stamina: i32, - strength: i32, - dexterity: i32, - intelligence: i32, - }, - Armor { - kind: Armor, - stamina: i32, - strength: i32, - dexterity: i32, - intelligence: i32, - }, - Consumable { - kind: Consumable, - effect: Effect, - }, - Ingredient { - kind: Ingredient, - }, +pub enum ItemKind { + Tool { kind: Tool, power: u32 }, + Armor { kind: Armor, power: u32 }, + Consumable { kind: Consumable, effect: Effect }, + Ingredient(Ingredient), Debug(Debug), } -impl Item { - pub fn name(&self) -> &'static str { - match self { - Item::Tool { kind, .. } => kind.name(), - Item::Armor { kind, .. } => kind.name(), - Item::Consumable { kind, .. } => kind.name(), - Item::Ingredient { kind, .. } => kind.name(), - Item::Debug(_) => "Debugging item", - } - } +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct Item { + name: String, + description: String, + pub kind: ItemKind, +} - pub fn title(&self) -> String { - format!("{} ({})", self.name(), self.category()) - } - - pub fn info(&self) -> String { - match self { - Item::Tool { power, .. } => format!("{:+} attack", power), - Item::Armor { .. } => String::new(), - Item::Consumable { effect, .. } => format!("{}", effect.info()), - Item::Ingredient { .. } => String::new(), - Item::Debug(_) => format!("+99999 insanity"), - } - } - - pub fn category(&self) -> &'static str { - match self { - Item::Tool { .. } => "Tool", - Item::Armor { .. } => "Armor", - Item::Consumable { .. } => "Consumable", - Item::Ingredient { .. } => "Ingredient", - Item::Debug(_) => "Debug", - } - } - - pub fn description(&self) -> String { - match self { - Item::Tool { kind, .. } => format!("{}", kind.description()), - Item::Armor { kind, .. } => format!("{}", kind.description()), - Item::Consumable { kind, .. } => format!("{}", kind.description()), - Item::Ingredient { kind, .. } => format!("{}", kind.description()), - Item::Debug(_) => format!("Debugging item"), - } - } - - pub fn try_reclaim_from_block(block: Block) -> Option { - match block.kind() { - BlockKind::Apple => Some(Self::apple()), - BlockKind::Mushroom => Some(Self::mushroom()), - BlockKind::Velorite => Some(Self::velorite()), - BlockKind::BlueFlower => Some(Self::flower()), - BlockKind::PinkFlower => Some(Self::flower()), - BlockKind::PurpleFlower => Some(Self::flower()), - BlockKind::RedFlower => Some(Self::flower()), - BlockKind::WhiteFlower => Some(Self::flower()), - BlockKind::YellowFlower => Some(Self::flower()), - BlockKind::Sunflower => Some(Self::flower()), - BlockKind::LongGrass => Some(Self::grass()), - BlockKind::MediumGrass => Some(Self::grass()), - BlockKind::ShortGrass => Some(Self::grass()), - BlockKind::Chest => Some(match rand::random::() % 4 { - 0 => Self::apple(), - 1 => Self::velorite(), - 2 => Item::Tool { - kind: *(&ALL_TOOLS).choose(&mut rand::thread_rng()).unwrap(), - power: 8 + rand::random::() % (rand::random::() % 29 + 1), - stamina: 0, - strength: 0, - dexterity: 0, - intelligence: 0, - }, - 3 => Self::veloritefrag(), - _ => unreachable!(), - }), - _ => None, - } - } - - // General item constructors - - pub fn apple() -> Self { - Item::Consumable { - kind: Consumable::Apple, - effect: Effect::Health(comp::HealthChange { - amount: 50, - cause: comp::HealthSource::Item, - }), - } - } - - pub fn mushroom() -> Self { - Item::Consumable { - kind: Consumable::Mushroom, - effect: Effect::Health(comp::HealthChange { - amount: 10, - cause: comp::HealthSource::Item, - }), - } - } - - pub fn velorite() -> Self { - Item::Consumable { - kind: Consumable::Velorite, - effect: Effect::Xp(50), - } - } - pub fn veloritefrag() -> Self { - Item::Consumable { - kind: Consumable::VeloriteFrag, - effect: Effect::Xp(20), - } - } - - pub fn flower() -> Self { - Item::Ingredient { - kind: Ingredient::Flower, - } - } - - pub fn grass() -> Self { - Item::Ingredient { - kind: Ingredient::Grass, - } +impl Asset for Item { + const ENDINGS: &'static [&'static str] = &["ron"]; + fn parse(buf_reader: BufReader) -> Result { + Ok(ron::de::from_reader(buf_reader).unwrap()) } } -impl Default for Item { - fn default() -> Self { - Item::Tool { - kind: Tool::Hammer, - power: 0, - stamina: 0, - strength: 0, - dexterity: 0, - intelligence: 0, +impl Item { + pub fn name(&self) -> &str { + &self.name + } + pub fn description(&self) -> &str { + &self.description + } + pub fn try_reclaim_from_block(block: Block) -> Option { + match block.kind() { + BlockKind::Apple => Some(assets::load_expect_cloned("common.items.apple")), + BlockKind::Mushroom => Some(assets::load_expect_cloned("common.items.mushroom")), + BlockKind::Velorite => Some(assets::load_expect_cloned("common.items.velorite")), + BlockKind::BlueFlower => Some(assets::load_expect_cloned("common.items.flowers.blue")), + BlockKind::PinkFlower => Some(assets::load_expect_cloned("common.items.flowers.pink")), + BlockKind::PurpleFlower => { + Some(assets::load_expect_cloned("common.items.flowers.purple")) + } + BlockKind::RedFlower => Some(assets::load_expect_cloned("common.items.flowers.red")), + BlockKind::WhiteFlower => { + Some(assets::load_expect_cloned("common.items.flowers.white")) + } + BlockKind::YellowFlower => { + Some(assets::load_expect_cloned("common.items.flowers.yellow")) + } + BlockKind::Sunflower => Some(assets::load_expect_cloned("common.items.flowers.sun")), + BlockKind::LongGrass => Some(assets::load_expect_cloned("common.items.grasses.long")), + BlockKind::MediumGrass => { + Some(assets::load_expect_cloned("common.items.grasses.medium")) + } + BlockKind::ShortGrass => Some(assets::load_expect_cloned("common.items.grasses.short")), + BlockKind::Chest => Some(match rand::random::() % 4 { + 0 => assets::load_expect_cloned("common.items.apple"), + 1 => assets::load_expect_cloned("common.items.velorite"), + // TODO: Implement random asset loading + //2 => Item::Tool { + // kind: *(&ALL_TOOLS).choose(&mut rand::thread_rng()), + // power: 8 + rand::random::() % (rand::random::() % 29 + 1), + // stamina: 0, + // strength: 0, + // dexterity: 0, + // intelligence: 0, + //}, + 2 => assets::load_expect_cloned("common.items.apple"), + 3 => assets::load_expect_cloned("common.items.veloritefrag"), + _ => unreachable!(), + }), + _ => None, } } } diff --git a/common/src/comp/inventory/mod.rs b/common/src/comp/inventory/mod.rs index 2e2c27226e..6c5b65e2ba 100644 --- a/common/src/comp/inventory/mod.rs +++ b/common/src/comp/inventory/mod.rs @@ -1,8 +1,9 @@ pub mod item; // Reexports -pub use item::{Debug, Item, Tool}; +pub use item::{Debug, Item, ItemKind, Tool}; +use crate::assets; use specs::{Component, HashMapStorage, NullStorage}; #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] @@ -72,8 +73,8 @@ impl Default for Inventory { slots: vec![None; 25], }; - inventory.push(Item::Debug(Debug::Boost)); - inventory.push(Item::Debug(Debug::Possess)); + inventory.push(assets::load_expect_cloned("common.items.debug.boost")); + inventory.push(assets::load_expect_cloned("common.items.debug.possess")); inventory } } diff --git a/common/src/comp/mod.rs b/common/src/comp/mod.rs index 5df88295b5..d79fb41ae7 100644 --- a/common/src/comp/mod.rs +++ b/common/src/comp/mod.rs @@ -22,7 +22,7 @@ pub use controller::{ ControlEvent, Controller, ControllerInputs, InventoryManip, MountState, Mounting, }; pub use inputs::CanBuild; -pub use inventory::{item, Inventory, InventoryUpdate, Item}; +pub use inventory::{item, Inventory, InventoryUpdate, Item, ItemKind}; pub use last::Last; pub use location::Waypoint; pub use phys::{ForceUpdate, Gravity, Mass, Ori, PhysicsState, Pos, Scale, Sticky, Vel}; diff --git a/common/src/event.rs b/common/src/event.rs index c76bc59b16..70b09d9b37 100644 --- a/common/src/event.rs +++ b/common/src/event.rs @@ -51,7 +51,7 @@ pub enum ServerEvent { entity: EcsEntity, name: String, body: comp::Body, - main: Option, + main: Option, }, CreateNpc { pos: comp::Pos, diff --git a/common/src/msg/client.rs b/common/src/msg/client.rs index c699db93d1..b8e26f95cc 100644 --- a/common/src/msg/client.rs +++ b/common/src/msg/client.rs @@ -12,7 +12,7 @@ pub enum ClientMsg { Character { name: String, body: comp::Body, - main: Option, + main: Option, // Specifier for the weapon }, ControllerInputs(comp::ControllerInputs), ControlEvent(comp::ControlEvent), diff --git a/common/src/sys/combat.rs b/common/src/sys/combat.rs index de10cf5fa2..f4d1e04d8f 100644 --- a/common/src/sys/combat.rs +++ b/common/src/sys/combat.rs @@ -1,7 +1,7 @@ use crate::{ comp::{ - item::Item, ActionState::*, CharacterState, Controller, HealthChange, HealthSource, Ori, - Pos, Stats, + ActionState::*, CharacterState, Controller, HealthChange, HealthSource, ItemKind, Ori, Pos, + Stats, }, event::{EventBus, LocalEvent, ServerEvent}, state::{DeltaTime, Uid}, @@ -110,12 +110,13 @@ impl<'a> System<'a> for Sys { && ori2.angle_between(pos_b2 - pos2) < (1.0 / pos2.distance(pos_b2)).atan() { // Weapon gives base damage - let mut dmg = - if let Some(Item::Tool { power, .. }) = stat.equipment.main { - power as i32 - } else { - 1 - }; + let mut dmg = if let Some(ItemKind::Tool { power, .. }) = + stat.equipment.main.as_ref().map(|i| &i.kind) + { + *power as i32 + } else { + 1 + }; // Block if character_b.action.is_block() diff --git a/common/src/sys/controller.rs b/common/src/sys/controller.rs index a1d8c3b0aa..3a7c1bb0ed 100644 --- a/common/src/sys/controller.rs +++ b/common/src/sys/controller.rs @@ -5,7 +5,8 @@ use super::{ use crate::{ comp::{ self, item, projectile, ActionState::*, Body, CharacterState, ControlEvent, Controller, - HealthChange, HealthSource, Item, MovementState::*, PhysicsState, Projectile, Stats, Vel, + HealthChange, HealthSource, ItemKind, MovementState::*, PhysicsState, Projectile, Stats, + Vel, }, event::{EventBus, LocalEvent, ServerEvent}, }; @@ -131,8 +132,8 @@ impl<'a> System<'a> for Sys { }; } - match stats.equipment.main { - Some(Item::Tool { + match stats.equipment.main.as_ref().map(|i| &i.kind) { + Some(ItemKind::Tool { kind: item::Tool::Bow, power, .. @@ -158,7 +159,7 @@ impl<'a> System<'a> for Sys { hit_wall: vec![projectile::Effect::Stick], hit_entity: vec![ projectile::Effect::Damage(HealthChange { - amount: -(power as i32), + amount: -(*power as i32), cause: HealthSource::Attack { by: *uid }, }), projectile::Effect::Vanish, @@ -170,7 +171,7 @@ impl<'a> System<'a> for Sys { } } } - Some(Item::Tool { + Some(ItemKind::Tool { kind: item::Tool::Staff, power, .. @@ -220,7 +221,7 @@ impl<'a> System<'a> for Sys { hit_wall: vec![projectile::Effect::Vanish], hit_entity: vec![ projectile::Effect::Damage(HealthChange { - amount: -(power as i32), + amount: -(*power as i32), cause: HealthSource::Attack { by: *uid }, }), projectile::Effect::Vanish, @@ -232,7 +233,7 @@ impl<'a> System<'a> for Sys { } } } - Some(Item::Tool { .. }) => { + Some(ItemKind::Tool { .. }) => { // Melee Attack if inputs.primary && (character.movement == Stand @@ -263,7 +264,7 @@ impl<'a> System<'a> for Sys { }; } } - Some(Item::Debug(item::Debug::Boost)) => { + Some(ItemKind::Debug(item::Debug::Boost)) => { if inputs.primary { local_emitter.emit(LocalEvent::Boost { entity, @@ -278,7 +279,7 @@ impl<'a> System<'a> for Sys { }); } } - Some(Item::Debug(item::Debug::Possess)) => { + Some(ItemKind::Debug(item::Debug::Possess)) => { if inputs.primary && (character.movement == Stand || character.movement == Run diff --git a/server/src/lib.rs b/server/src/lib.rs index 1639fd323c..349f84bc34 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -21,7 +21,7 @@ use crate::{ cmd::CHAT_COMMANDS, }; use common::{ - comp, + assets, comp, effect::Effect, event::{EventBus, ServerEvent}, msg::{ClientMsg, ClientState, ServerError, ServerInfo, ServerMsg}, @@ -201,9 +201,12 @@ impl Server { entity: EcsEntity, name: String, body: comp::Body, - main: Option, + main: Option, server_settings: &ServerSettings, ) { + // Give no item when an invalid specifier is given + let main = main.and_then(|specifier| assets::load_cloned(&specifier)); + let spawn_point = state.ecs().read_resource::().0; state.write_component(entity, body); @@ -428,40 +431,44 @@ impl Server { } comp::InventoryManip::Use(slot) => { - let item = state + let item_opt = state .ecs() .write_storage::() .get_mut(entity) .and_then(|inv| inv.remove(slot)); - match item { - Some(comp::Item::Tool { .. }) | Some(comp::Item::Debug(_)) => { - if let Some(stats) = - state.ecs().write_storage::().get_mut(entity) - { - // Insert old item into inventory - if let Some(old_item) = stats.equipment.main.take() { - state - .ecs() - .write_storage::() - .get_mut(entity) - .map(|inv| inv.insert(slot, old_item)); - } + match item_opt { + Some(item) => match item.kind { + comp::ItemKind::Tool { .. } => { + if let Some(stats) = state + .ecs() + .write_storage::() + .get_mut(entity) + { + // Insert old item into inventory + if let Some(old_item) = stats.equipment.main.take() { + state + .ecs() + .write_storage::() + .get_mut(entity) + .map(|inv| inv.insert(slot, old_item)); + } - stats.equipment.main = item; + stats.equipment.main = Some(item); + } } - } - Some(comp::Item::Consumable { effect, .. }) => { - state.apply_effect(entity, effect); - } - Some(item) => { - // Re-insert it if unused - let _ = state - .ecs() - .write_storage::() - .get_mut(entity) - .map(|inv| inv.insert(slot, item)); - } + comp::ItemKind::Consumable { effect, .. } => { + state.apply_effect(entity, effect); + } + _ => { + // Re-insert it if unused + let _ = state + .ecs() + .write_storage::() + .get_mut(entity) + .map(|inv| inv.insert(slot, item)); + } + }, _ => {} } @@ -610,14 +617,15 @@ impl Server { { let mut inventories = ecs.write_storage::(); if let Some(inventory) = inventories.get_mut(possesse) { - inventory - .push(comp::Item::Debug(comp::item::Debug::Possess)); + inventory.push(assets::load_expect_cloned( + "common.items.debug.possess", + )); } else { let _ = inventories.insert( possesse, comp::Inventory { - slots: vec![Some(comp::Item::Debug( - comp::item::Debug::Possess, + slots: vec![Some(assets::load_expect_cloned( + "common.items.debug.possess", ))], }, ); diff --git a/server/src/sys/message.rs b/server/src/sys/message.rs index 363039d443..3cb71e71a6 100644 --- a/server/src/sys/message.rs +++ b/server/src/sys/message.rs @@ -1,7 +1,8 @@ use super::SysTimer; use crate::{auth_provider::AuthProvider, client::Client, CLIENT_TIMEOUT}; use common::{ - comp::{Admin, Body, CanBuild, Controller, Item, Ori, Player, Pos, Vel}, + assets, + comp::{Admin, Body, CanBuild, Controller, Ori, Player, Pos, Vel}, event::{EventBus, ServerEvent}, msg::{validate_chat_msg, ChatMsgValidationError, MAX_BYTES_CHAT_MSG}, msg::{ClientMsg, ClientState, RequestStateError, ServerMsg}, @@ -168,14 +169,7 @@ impl<'a> System<'a> for Sys { entity, name, body, - main: main.map(|t| Item::Tool { - kind: t, - power: 10, - stamina: 0, - strength: 0, - dexterity: 0, - intelligence: 0, - }), + main: main.and_then(|specifier| assets::load_cloned(&specifier)), }); } ClientState::Character => client.error_state(RequestStateError::Already), diff --git a/server/src/sys/terrain.rs b/server/src/sys/terrain.rs index a70d07d8b9..3193c84776 100644 --- a/server/src/sys/terrain.rs +++ b/server/src/sys/terrain.rs @@ -1,6 +1,7 @@ use super::SysTimer; use crate::{chunk_generator::ChunkGenerator, client::Client, Tick}; use common::{ + assets, comp::{self, Player, Pos}, event::{EventBus, ServerEvent}, msg::ServerMsg, @@ -95,14 +96,9 @@ impl<'a> System<'a> for Sys { let (mut stats, mut body) = if rand::random() { let stats = comp::Stats::new( "Humanoid".to_string(), - Some(comp::Item::Tool { - kind: comp::item::Tool::Sword, - power: 5, - stamina: 0, - strength: 0, - dexterity: 0, - intelligence: 0, - }), + Some(assets::load_expect_cloned( + "common.items.weapons.starter_sword", + )), ); let body = comp::Body::Humanoid(comp::humanoid::Body::random()); (stats, body) @@ -120,14 +116,9 @@ impl<'a> System<'a> for Sys { if rand::random::() < 0.8 { stats = comp::Stats::new( "Humanoid".to_string(), - Some(comp::Item::Tool { - kind: comp::item::Tool::Sword, - power: 10, - stamina: 0, - strength: 0, - dexterity: 0, - intelligence: 0, - }), + Some(assets::load_expect_cloned( + "common.items.weapons.starter_sword", + )), ); body = comp::Body::Humanoid(comp::humanoid::Body::random()); } diff --git a/voxygen/src/hud/bag.rs b/voxygen/src/hud/bag.rs index 39cb392d5b..7462c08388 100644 --- a/voxygen/src/hud/bag.rs +++ b/voxygen/src/hud/bag.rs @@ -1,6 +1,6 @@ use super::{ img_ids::{Imgs, ImgsRot}, - item_imgs::{ItemImgs, ItemKind}, + item_imgs::{ItemImgs, ItemKey}, Event as HudEvent, Fonts, TEXT_COLOR, }; use crate::ui::{ImageFrame, Tooltip, TooltipManager, Tooltipable}; @@ -65,7 +65,7 @@ impl<'a> Bag<'a> { pub struct State { ids: Ids, - img_id_cache: Vec>, + img_id_cache: Vec>, selected_slot: Option, } @@ -195,8 +195,8 @@ impl<'a> Widget for Bag<'a> { slot_widget .with_tooltip( self.tooltip_manager, - &item.title(), - &format!("{}\n{}", item.info(), item.description()), + &item.name(), + &format!("{}\n{}", item.name(), item.description()), &item_tooltip, ) .set(state.ids.inv_slots[i], ui) @@ -222,7 +222,7 @@ impl<'a> Widget for Bag<'a> { state.update(|s| s.selected_slot = selected_slot); } // Item - if let Some(kind) = item.as_ref().map(|i| ItemKind::from(i)) { + if let Some(kind) = item.as_ref().map(|i| ItemKey::from(i)) { Button::image(match &state.img_id_cache[i] { Some((cached_kind, id)) if cached_kind == &kind => *id, _ => { diff --git a/voxygen/src/hud/item_imgs.rs b/voxygen/src/hud/item_imgs.rs index 61d90bd59c..2c5ab5cfad 100644 --- a/voxygen/src/hud/item_imgs.rs +++ b/voxygen/src/hud/item_imgs.rs @@ -1,7 +1,7 @@ use crate::ui::{Graphic, Transform, Ui}; use common::{ assets::{self, watch::ReloadIndicator, Asset}, - comp::item::{Armor, Consumable, Debug, Ingredient, Item, Tool}, + comp::item::{Armor, Consumable, Debug, Ingredient, Item, ItemKind, Tool}, }; use conrod_core::image::Id; use dot_vox::DotVoxData; @@ -13,21 +13,21 @@ use std::{fs::File, io::BufReader, sync::Arc}; use vek::*; #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub enum ItemKind { +pub enum ItemKey { Tool(Tool), Armor(Armor), Consumable(Consumable), Ingredient(Ingredient), Debug(Debug), } -impl From<&Item> for ItemKind { +impl From<&Item> for ItemKey { fn from(item: &Item) -> Self { - match item { - Item::Tool { kind, .. } => ItemKind::Tool(kind.clone()), - Item::Armor { kind, .. } => ItemKind::Armor(kind.clone()), - Item::Consumable { kind, .. } => ItemKind::Consumable(kind.clone()), - Item::Ingredient { kind, .. } => ItemKind::Ingredient(kind.clone()), - Item::Debug(kind) => ItemKind::Debug(kind.clone()), + match &item.kind { + ItemKind::Tool { kind, .. } => ItemKey::Tool(kind.clone()), + ItemKind::Armor { kind, .. } => ItemKey::Armor(kind.clone()), + ItemKind::Consumable { kind, .. } => ItemKey::Consumable(kind.clone()), + ItemKind::Ingredient(kind) => ItemKey::Ingredient(kind.clone()), + ItemKind::Debug(kind) => ItemKey::Debug(kind.clone()), } } } @@ -68,7 +68,7 @@ impl ImageSpec { } } #[derive(Serialize, Deserialize)] -struct ItemImagesSpec(HashMap); +struct ItemImagesSpec(HashMap); impl Asset for ItemImagesSpec { const ENDINGS: &'static [&'static str] = &["ron"]; fn parse(buf_reader: BufReader) -> Result { @@ -77,7 +77,7 @@ impl Asset for ItemImagesSpec { } pub struct ItemImgs { - map: HashMap, + map: HashMap, indicator: ReloadIndicator, } impl ItemImgs { @@ -110,7 +110,7 @@ impl ItemImgs { // See if we already have an id we can use match self.map.get(&kind) { Some(id) => ui.replace_graphic(*id, graphic), - // Otherwise, generate new id and insert it into our Id -> ItemKind map + // Otherwise, generate new id and insert it into our Id -> ItemKey map None => { self.map.insert(kind.clone(), ui.add_graphic(graphic)); } @@ -118,7 +118,7 @@ impl ItemImgs { } } } - pub fn img_id(&self, item_kind: ItemKind) -> Option { + pub fn img_id(&self, item_kind: ItemKey) -> Option { match self.map.get(&item_kind) { Some(id) => Some(*id), // There was no specification in the ron diff --git a/voxygen/src/hud/skillbar.rs b/voxygen/src/hud/skillbar.rs index 8064b2ffec..cb3635f104 100644 --- a/voxygen/src/hud/skillbar.rs +++ b/voxygen/src/hud/skillbar.rs @@ -3,8 +3,7 @@ use super::{ /*FOCUS_COLOR, RAGE_COLOR,*/ HP_COLOR, LOW_HP_COLOR, MANA_COLOR, TEXT_COLOR, XP_COLOR, }; use crate::GlobalState; -use common::comp::{item::Debug, item::Tool, Item, Stats}; - +use common::comp::{item::Debug, item::Tool, Item, ItemKind, Stats}; use conrod_core::{ color, widget::{self, Button, Image, Rectangle, Text}, @@ -506,8 +505,8 @@ impl<'a> Widget for Skillbar<'a> { // M1 Slot Image::new(self.imgs.skillbar_slot_big_bg) .w_h(36.0 * scale, 36.0 * scale) - .color(match self.stats.equipment.main { - Some(Item::Tool { kind, .. }) => match kind { + .color(match self.stats.equipment.main.as_ref().map(|i| &i.kind) { + Some(ItemKind::Tool { kind, .. }) => match kind { Tool::Bow => Some(BG_COLOR_2), Tool::Staff => Some(BG_COLOR_2), _ => Some(BG_COLOR_2), @@ -516,20 +515,20 @@ impl<'a> Widget for Skillbar<'a> { }) .middle_of(state.ids.m1_slot) .set(state.ids.m1_slot_bg, ui); - Button::image(match self.stats.equipment.main { - Some(Item::Tool { kind, .. }) => match kind { + Button::image(match self.stats.equipment.main.as_ref().map(|i| &i.kind) { + Some(ItemKind::Tool { kind, .. }) => match kind { Tool::Sword => self.imgs.twohsword_m1, Tool::Hammer => self.imgs.twohhammer_m1, Tool::Axe => self.imgs.twohaxe_m1, Tool::Bow => self.imgs.bow_m1, Tool::Staff => self.imgs.staff_m1, + Tool::Debug(Debug::Boost) => self.imgs.flyingrod_m1, _ => self.imgs.twohaxe_m1, }, - Some(Item::Debug(Debug::Boost)) => self.imgs.flyingrod_m1, _ => self.imgs.twohaxe_m1, }) // Insert Icon here - .w(match self.stats.equipment.main { - Some(Item::Tool { kind, .. }) => match kind { + .w(match self.stats.equipment.main.as_ref().map(|i| &i.kind) { + Some(ItemKind::Tool { kind, .. }) => match kind { Tool::Bow => 30.0 * scale, Tool::Staff => 30.0 * scale, _ => 38.0 * scale, @@ -537,7 +536,7 @@ impl<'a> Widget for Skillbar<'a> { _ => 38.0 * scale, }) .h(match self.stats.equipment.main { - Some(Item::Tool { kind, .. }) => match kind { + Some(ItemKind::Tool { kind, .. }) => match kind { Tool::Bow => 30.0 * scale, Tool::Staff => 36.0 * scale, _ => 38.0 * scale, @@ -563,20 +562,20 @@ impl<'a> Widget for Skillbar<'a> { }) .middle_of(state.ids.m2_slot) .set(state.ids.m2_slot_bg, ui); - Button::image(match self.stats.equipment.main { - Some(Item::Tool { kind, .. }) => match kind { + Button::image(match self.stats.equipment.main.as_ref().map(|i| &i.kind) { + Some(ItemKind::Tool { kind, .. }) => match kind { Tool::Sword => self.imgs.twohsword_m2, Tool::Hammer => self.imgs.twohhammer_m2, Tool::Axe => self.imgs.twohaxe_m2, Tool::Bow => self.imgs.bow_m2, Tool::Staff => self.imgs.staff_m2, + Tool::Debug(Debug::Boost) => self.imgs.flyingrod_m2, _ => self.imgs.twohaxe_m2, }, - Some(Item::Debug(Debug::Boost)) => self.imgs.flyingrod_m2, _ => self.imgs.twohaxe_m2, }) // Insert Icon here .w(match self.stats.equipment.main { - Some(Item::Tool { kind, .. }) => match kind { + Some(ItemKind::Tool { kind, .. }) => match kind { Tool::Bow => 30.0 * scale, Tool::Staff => 30.0 * scale, _ => 38.0 * scale, @@ -584,7 +583,7 @@ impl<'a> Widget for Skillbar<'a> { _ => 38.0 * scale, }) .h(match self.stats.equipment.main { - Some(Item::Tool { kind, .. }) => match kind { + Some(ItemKind::Tool { kind, .. }) => match kind { Tool::Bow => 30.0 * scale, Tool::Staff => 30.0 * scale, _ => 38.0 * scale, diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs index acffc56b7e..c411ae5afd 100644 --- a/voxygen/src/menu/char_selection/mod.rs +++ b/voxygen/src/menu/char_selection/mod.rs @@ -6,7 +6,7 @@ use crate::{ PlayStateResult, }; use client::{self, Client}; -use common::{clock::Clock, comp, msg::ClientState}; +use common::{assets, clock::Clock, comp, msg::ClientState}; use log::error; use scene::Scene; use std::{cell::RefCell, rc::Rc, time::Duration}; @@ -67,7 +67,9 @@ impl PlayState for CharSelectionState { self.client.borrow_mut().request_character( self.char_selection_ui.character_name.clone(), comp::Body::Humanoid(self.char_selection_ui.character_body), - self.char_selection_ui.character_tool, + self.char_selection_ui + .character_tool + .map(|specifier| specifier.to_owned()), ); return PlayStateResult::Push(Box::new(SessionState::new( global_state, @@ -93,18 +95,10 @@ impl PlayState for CharSelectionState { &self.client.borrow(), self.char_selection_ui.character_body, &comp::Equipment { - main: if let Some(kind) = self.char_selection_ui.character_tool { - Some(comp::Item::Tool { - kind: kind, - power: 10, - stamina: 0, - strength: 0, - dexterity: 0, - intelligence: 0, - }) - } else { - None - }, + main: self + .char_selection_ui + .character_tool + .and_then(|specifier| assets::load_cloned(&specifier)), alt: None, }, ); diff --git a/voxygen/src/menu/char_selection/ui.rs b/voxygen/src/menu/char_selection/ui.rs index 9a805b5130..2cb169b6cf 100644 --- a/voxygen/src/menu/char_selection/ui.rs +++ b/voxygen/src/menu/char_selection/ui.rs @@ -17,6 +17,13 @@ use conrod_core::{ widget_ids, Borderable, Color, Colorable, Labelable, Positionable, Sizeable, UiCell, Widget, }; +const STARTER_HAMMER: &str = "common.items.weapons.starter_hammer"; +const STARTER_BOW: &str = "common.items.weapons.starter_bow"; +const STARTER_AXE: &str = "common.items.weapons.starter_axe"; +const STARTER_STAFF: &str = "common.items.weapons.starter_staff"; +const STARTER_SWORD: &str = "common.items.weapons.starter_sword"; +const STARTER_DAGGER: &str = "common.items.weapons.starter_dagger"; + widget_ids! { struct Ids { // Background and logo @@ -249,7 +256,7 @@ pub struct CharSelectionUi { //deletion_confirmation: bool, pub character_name: String, pub character_body: humanoid::Body, - pub character_tool: Option, + pub character_tool: Option<&'static str>, } impl CharSelectionUi { @@ -280,7 +287,7 @@ impl CharSelectionUi { character_creation: false, character_name: "Character Name".to_string(), character_body: humanoid::Body::random(), - character_tool: Some(Tool::Sword), + character_tool: Some(STARTER_SWORD), } } @@ -469,7 +476,7 @@ impl CharSelectionUi { .was_clicked() { self.character_creation = true; - self.character_tool = Some(Tool::Sword); + self.character_tool = Some(STARTER_SWORD); } // Alpha Version @@ -852,7 +859,7 @@ impl CharSelectionUi { .w_h(70.0, 70.0) .bottom_left_with_margins_on(self.ids.creation_buttons_alignment_2, 0.0, 0.0) .set(self.ids.hammer, ui_widgets); - if Button::image(if let Some(Tool::Hammer) = self.character_tool { + if Button::image(if let Some(STARTER_HAMMER) = self.character_tool { self.imgs.icon_border_pressed } else { self.imgs.icon_border @@ -864,7 +871,7 @@ impl CharSelectionUi { .set(self.ids.hammer_button, ui_widgets) .was_clicked() { - self.character_tool = Some(Tool::Hammer); + self.character_tool = Some(STARTER_HAMMER); } // REMOVE THIS AFTER IMPLEMENTATION /*Rectangle::fill_with([67.0, 67.0], color::rgba(0.0, 0.0, 0.0, 0.8)) @@ -877,7 +884,7 @@ impl CharSelectionUi { .w_h(70.0, 70.0) .right_from(self.ids.hammer, 2.0) .set(self.ids.bow, ui_widgets); - if Button::image(if let Some(Tool::Bow) = self.character_tool { + if Button::image(if let Some(STARTER_BOW) = self.character_tool { self.imgs.icon_border_pressed } else { self.imgs.icon_border @@ -889,7 +896,7 @@ impl CharSelectionUi { .set(self.ids.bow_button, ui_widgets) .was_clicked() { - self.character_tool = Some(Tool::Bow); + self.character_tool = Some(STARTER_BOW); } // REMOVE THIS AFTER IMPLEMENTATION /*Rectangle::fill_with([67.0, 67.0], color::rgba(0.0, 0.0, 0.0, 0.8)) @@ -900,7 +907,7 @@ impl CharSelectionUi { .w_h(70.0, 70.0) .right_from(self.ids.bow, 2.0) .set(self.ids.staff, ui_widgets); - if Button::image(if let Some(Tool::Staff) = self.character_tool { + if Button::image(if let Some(STARTER_STAFF) = self.character_tool { self.imgs.icon_border_pressed } else { self.imgs.icon_border @@ -912,7 +919,7 @@ impl CharSelectionUi { .set(self.ids.staff_button, ui_widgets) .was_clicked() { - self.character_tool = Some(Tool::Staff); + self.character_tool = Some(STARTER_STAFF); } // REMOVE THIS AFTER IMPLEMENTATION /*Rectangle::fill_with([67.0, 67.0], color::rgba(0.0, 0.0, 0.0, 0.8)) @@ -923,7 +930,7 @@ impl CharSelectionUi { .w_h(70.0, 70.0) .up_from(self.ids.hammer, 2.0) .set(self.ids.sword, ui_widgets); - if Button::image(if let Some(Tool::Sword) = self.character_tool { + if Button::image(if let Some(STARTER_SWORD) = self.character_tool { self.imgs.icon_border_pressed } else { self.imgs.icon_border @@ -935,7 +942,7 @@ impl CharSelectionUi { .set(self.ids.sword_button, ui_widgets) .was_clicked() { - self.character_tool = Some(Tool::Sword); + self.character_tool = Some(STARTER_SWORD); } // Daggers @@ -943,7 +950,7 @@ impl CharSelectionUi { .w_h(70.0, 70.0) .right_from(self.ids.sword, 2.0) .set(self.ids.daggers, ui_widgets); - if Button::image(if let Some(Tool::Dagger) = self.character_tool { + if Button::image(if let Some(STARTER_DAGGER) = self.character_tool { self.imgs.icon_border_pressed } else { self.imgs.icon_border @@ -955,7 +962,7 @@ impl CharSelectionUi { .set(self.ids.daggers_button, ui_widgets) .was_clicked() { - // self.character_tool = Some(Tool::Daggers); + // self.character_tool = Some(STARTER_DAGGER); } // REMOVE THIS AFTER IMPLEMENTATION Rectangle::fill_with([67.0, 67.0], color::rgba(0.0, 0.0, 0.0, 0.8)) .middle_of(self.ids.daggers) @@ -966,7 +973,7 @@ impl CharSelectionUi { .w_h(70.0, 70.0) .right_from(self.ids.daggers, 2.0) .set(self.ids.axe, ui_widgets); - if Button::image(if let Some(Tool::Axe) = self.character_tool { + if Button::image(if let Some(STARTER_AXE) = self.character_tool { self.imgs.icon_border_pressed } else { self.imgs.icon_border @@ -978,7 +985,7 @@ impl CharSelectionUi { .set(self.ids.axe_button, ui_widgets) .was_clicked() { - self.character_tool = Some(Tool::Axe); + self.character_tool = Some(STARTER_AXE); } // REMOVE THIS AFTER IMPLEMENTATION /*Rectangle::fill_with([67.0, 67.0], color::rgba(0.0, 0.0, 0.0, 0.8)) diff --git a/voxygen/src/scene/figure/load.rs b/voxygen/src/scene/figure/load.rs index ec84ac025f..040555594f 100644 --- a/voxygen/src/scene/figure/load.rs +++ b/voxygen/src/scene/figure/load.rs @@ -10,7 +10,7 @@ use common::{ Belt, BodyType, Chest, EyeColor, Eyebrows, Foot, Hand, Pants, Race, Shoulder, Skin, }, item::Tool, - object, quadruped, quadruped_medium, Item, + object, quadruped, quadruped_medium, Item, ItemKind, }, figure::{DynaUnionizer, MatSegment, Material, Segment}, }; @@ -511,8 +511,8 @@ impl HumArmorFootSpec { pub fn mesh_main(item: Option<&Item>) -> Mesh { if let Some(item) = item { - let (name, offset) = match item { - Item::Tool { kind, .. } => match kind { + let (name, offset) = match item.kind { + ItemKind::Tool { kind, .. } => match kind { Tool::Sword => ("weapon.sword.rusty_2h", Vec3::new(-1.5, -6.5, -4.0)), Tool::Axe => ("weapon.axe.rusty_2h", Vec3::new(-1.5, -5.0, -4.0)), Tool::Hammer => ("weapon.hammer.rusty_2h", Vec3::new(-2.5, -5.5, -4.0)), @@ -521,7 +521,7 @@ pub fn mesh_main(item: Option<&Item>) -> Mesh { Tool::Bow => ("weapon.bow.simple-bow", Vec3::new(-1.0, -6.0, -2.0)), Tool::Staff => ("weapon.staff.wood-fire", Vec3::new(-1.0, -6.0, -3.0)), }, - Item::Debug(_) => ("weapon.debug_wand", Vec3::new(-1.5, -9.5, -4.0)), + ItemKind::Debug(_) => ("weapon.debug_wand", Vec3::new(-1.5, -9.5, -4.0)), _ => return Mesh::new(), }; load_mesh(name, offset) From 0a1e12c9adfeacb7cb66a8858de0d11d04793cc4 Mon Sep 17 00:00:00 2001 From: timokoesters Date: Tue, 22 Oct 2019 22:58:27 +0200 Subject: [PATCH 2/6] improvement: make debug items of type ItemKind::Tool This way all items that can be held in a hand are tools --- assets/common/items/debug/boost.ron | 5 +- assets/common/items/debug/possess.ron | 5 +- assets/voxygen/item_image_manifest.ron | 19 ++++--- common/src/comp/inventory/item.rs | 14 ++--- common/src/sys/controller.rs | 73 ++++++++++++++----------- voxygen/src/anim/character/block.rs | 21 +++++++ voxygen/src/anim/character/blockidle.rs | 21 +++++++ voxygen/src/anim/character/cidle.rs | 21 +++++++ voxygen/src/anim/character/wield.rs | 21 +++++++ voxygen/src/anim/mod.rs | 2 + voxygen/src/hud/item_imgs.rs | 4 +- voxygen/src/hud/skillbar.rs | 12 ++-- voxygen/src/menu/char_selection/ui.rs | 2 +- voxygen/src/scene/figure/load.rs | 2 +- 14 files changed, 160 insertions(+), 62 deletions(-) diff --git a/assets/common/items/debug/boost.ron b/assets/common/items/debug/boost.ron index d9b350c5f2..7f78c5e05b 100644 --- a/assets/common/items/debug/boost.ron +++ b/assets/common/items/debug/boost.ron @@ -1,5 +1,8 @@ Item( name: "Boost rod", description: "Your legs feel full of energy while holding this", - kind: Debug(Boost), + kind: Tool( + kind: Debug(Boost), + power: 0, + ), ) diff --git a/assets/common/items/debug/possess.ron b/assets/common/items/debug/possess.ron index 79e3b10d7e..721459ad0a 100644 --- a/assets/common/items/debug/possess.ron +++ b/assets/common/items/debug/possess.ron @@ -1,5 +1,8 @@ Item( name: "Possession rod", description: "Your body seems loose while holding this", - kind: Debug(Possess), + kind: Tool( + kind: Debug(Possess), + power: 0, + ), ) diff --git a/assets/voxygen/item_image_manifest.ron b/assets/voxygen/item_image_manifest.ron index 23ad4299ef..68f11d1ea0 100644 --- a/assets/voxygen/item_image_manifest.ron +++ b/assets/voxygen/item_image_manifest.ron @@ -1,15 +1,7 @@ // Png(specifier), // Vox(specier), // VoxTrans(specifier, offset, (x_rot, y_rot, z_rot), zoom) -({ // Debug Items - Debug(Boost): VoxTrans( - "voxel.weapon.debug_wand-0", - (0.0, -7.0, 0.0), (90.0, 90.0, 0.0), 1.6, - ), - Debug(Possess): VoxTrans( - "voxel.weapon.debug_wand-1", - (0.0, -7.0, 0.0), (90.0, 90.0, 0.0), 1.6, - ), +({ // Weapons Tool(Bow): VoxTrans( "voxel.weapon.bow.simple-bow", @@ -69,4 +61,13 @@ "voxel.sprite.grass.grass_long_5", (0.0, 0.0, 0.0), (-90.0, 50.0, 0.0), 1.0, ), + // Debug Items + Tool(Debug(Boost)): VoxTrans( + "voxel.weapon.debug_wand-0", + (0.0, -7.0, 0.0), (90.0, 90.0, 0.0), 1.6, + ), + Tool(Debug(Possess)): VoxTrans( + "voxel.weapon.debug_wand-1", + (0.0, -7.0, 0.0), (90.0, 90.0, 0.0), 1.6, + ), }) diff --git a/common/src/comp/inventory/item.rs b/common/src/comp/inventory/item.rs index c3d7882d97..385877881e 100644 --- a/common/src/comp/inventory/item.rs +++ b/common/src/comp/inventory/item.rs @@ -17,6 +17,13 @@ pub enum Tool { Hammer, Bow, Staff, + Debug(Debug), +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum Debug { + Boost, + Possess, } #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] @@ -50,19 +57,12 @@ pub enum Ingredient { Grass, } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub enum Debug { - Boost, - Possess, -} - #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum ItemKind { Tool { kind: Tool, power: u32 }, Armor { kind: Armor, power: u32 }, Consumable { kind: Consumable, effect: Effect }, Ingredient(Ingredient), - Debug(Debug), } #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] diff --git a/common/src/sys/controller.rs b/common/src/sys/controller.rs index 3a7c1bb0ed..a9fd1a1e00 100644 --- a/common/src/sys/controller.rs +++ b/common/src/sys/controller.rs @@ -233,38 +233,10 @@ impl<'a> System<'a> for Sys { } } } - Some(ItemKind::Tool { .. }) => { - // Melee Attack - if inputs.primary - && (character.movement == Stand - || character.movement == Run - || character.movement == Jump) - { - if let Wield { time_left } = character.action { - if time_left == Duration::default() { - character.action = Attack { - time_left: ATTACK_DURATION, - applied: false, - }; - } - } - } - - // Block - if inputs.secondary - && (character.movement == Stand || character.movement == Run) - && character.action.is_wield() - { - character.action = Block { - time_left: Duration::from_secs(5), - }; - } else if !inputs.secondary && character.action.is_block() { - character.action = Wield { - time_left: Duration::default(), - }; - } - } - Some(ItemKind::Debug(item::Debug::Boost)) => { + Some(ItemKind::Tool { + kind: item::Tool::Debug(item::Debug::Boost), + .. + }) => { if inputs.primary { local_emitter.emit(LocalEvent::Boost { entity, @@ -279,7 +251,10 @@ impl<'a> System<'a> for Sys { }); } } - Some(ItemKind::Debug(item::Debug::Possess)) => { + Some(ItemKind::Tool { + kind: item::Tool::Debug(item::Debug::Possess), + .. + }) => { if inputs.primary && (character.movement == Stand || character.movement == Run @@ -326,6 +301,38 @@ impl<'a> System<'a> for Sys { }; } } + // All other tools + Some(ItemKind::Tool { .. }) => { + // Attack + if inputs.primary + && (character.movement == Stand + || character.movement == Run + || character.movement == Jump) + { + if let Wield { time_left } = character.action { + if time_left == Duration::default() { + character.action = Attack { + time_left: ATTACK_DURATION, + applied: false, + }; + } + } + } + + // Block + if inputs.secondary + && (character.movement == Stand || character.movement == Run) + && character.action.is_wield() + { + character.action = Block { + time_left: Duration::from_secs(5), + }; + } else if !inputs.secondary && character.action.is_block() { + character.action = Wield { + time_left: Duration::default(), + }; + } + } None => { // Attack if inputs.primary diff --git a/voxygen/src/anim/character/block.rs b/voxygen/src/anim/character/block.rs index 3477153c74..f0fb7fd838 100644 --- a/voxygen/src/anim/character/block.rs +++ b/voxygen/src/anim/character/block.rs @@ -224,6 +224,27 @@ impl Animation for BlockAnimation { * Quaternion::rotation_z(0.0); next.weapon.scale = Vec3::one(); } + Tool::Debug(_) => { + next.l_hand.offset = Vec3::new(-7.0, 3.5, 6.5); + next.l_hand.ori = Quaternion::rotation_x(2.07) + * Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(-0.2); + next.l_hand.scale = Vec3::one() * 1.01; + next.r_hand.offset = Vec3::new(7.0, 2.5, 3.75); + next.r_hand.ori = Quaternion::rotation_x(2.07) + * Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(-0.2); + next.r_hand.scale = Vec3::one() * 1.01; + next.weapon.offset = Vec3::new( + 5.0 + skeleton_attr.weapon_x, + 8.75 + skeleton_attr.weapon_y, + 5.5, + ); + next.weapon.ori = Quaternion::rotation_x(-0.3) + * Quaternion::rotation_y(-1.35) + * Quaternion::rotation_z(-0.85); + next.weapon.scale = Vec3::one(); + } } //next.l_foot.offset = Vec3::new(-3.4, 0.3, 8.0 + wave_ultra_slow_cos * 0.1); //next.l_foot.ori = Quaternion::rotation_x(-0.3); diff --git a/voxygen/src/anim/character/blockidle.rs b/voxygen/src/anim/character/blockidle.rs index dfaedd3e75..43b88c8d51 100644 --- a/voxygen/src/anim/character/blockidle.rs +++ b/voxygen/src/anim/character/blockidle.rs @@ -223,6 +223,27 @@ impl Animation for BlockIdleAnimation { * Quaternion::rotation_z(0.0); next.weapon.scale = Vec3::one(); } + Tool::Debug(_) => { + next.l_hand.offset = Vec3::new(-7.0, 3.5 + wave_ultra_slow * 2.0, 6.5); + next.l_hand.ori = Quaternion::rotation_x(2.07) + * Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(-0.2); + next.l_hand.scale = Vec3::one() * 1.01; + next.r_hand.offset = Vec3::new(7.0, 2.5 + wave_ultra_slow * 2.0, 3.75); + next.r_hand.ori = Quaternion::rotation_x(2.07) + * Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(-0.2); + next.r_hand.scale = Vec3::one() * 1.01; + next.weapon.offset = Vec3::new( + 5.0 + skeleton_attr.weapon_x, + 8.75 + wave_ultra_slow * 2.0 + skeleton_attr.weapon_y, + 5.5, + ); + next.weapon.ori = Quaternion::rotation_x(-0.3) + * Quaternion::rotation_y(-1.35) + * Quaternion::rotation_z(-0.85); + next.weapon.scale = Vec3::one(); + } } next.l_foot.offset = Vec3::new(-3.4, 0.3, 8.0 + wave_ultra_slow_cos * 0.1); next.l_foot.ori = Quaternion::rotation_x(-0.3); diff --git a/voxygen/src/anim/character/cidle.rs b/voxygen/src/anim/character/cidle.rs index 67c5ee9011..70bfeb1eae 100644 --- a/voxygen/src/anim/character/cidle.rs +++ b/voxygen/src/anim/character/cidle.rs @@ -235,6 +235,27 @@ impl Animation for CidleAnimation { * Quaternion::rotation_z(0.0); next.weapon.scale = Vec3::one(); } + Tool::Debug(_) => { + next.l_hand.offset = Vec3::new(-7.0, 4.0, 3.0); + next.l_hand.ori = Quaternion::rotation_x(1.27 + wave_ultra_slow * -0.1) + * Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(-0.3); + next.l_hand.scale = Vec3::one() * 1.01; + next.r_hand.offset = Vec3::new(7.0, 2.5, -1.25); + next.r_hand.ori = Quaternion::rotation_x(1.27 + wave_ultra_slow * -0.1) + * Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(-0.3); + next.r_hand.scale = Vec3::one() * 1.01; + next.weapon.offset = Vec3::new( + 5.0 + skeleton_attr.weapon_x, + 8.75 + skeleton_attr.weapon_y, + -2.5, + ); + next.weapon.ori = Quaternion::rotation_x(-0.3) + * Quaternion::rotation_y(-1.27) + * Quaternion::rotation_z(wave_ultra_slow * 0.2); + next.weapon.scale = Vec3::one(); + } } next.l_foot.offset = Vec3::new(-3.4, -1.5, 8.0 + wave_slow * 0.2); next.l_foot.ori = Quaternion::rotation_x(wave_ultra_slow_cos * 0.015); diff --git a/voxygen/src/anim/character/wield.rs b/voxygen/src/anim/character/wield.rs index faeef5b6bc..591212eb62 100644 --- a/voxygen/src/anim/character/wield.rs +++ b/voxygen/src/anim/character/wield.rs @@ -151,6 +151,27 @@ impl Animation for WieldAnimation { * Quaternion::rotation_z(0.0); next.weapon.scale = Vec3::one(); } + Tool::Debug(_) => { + next.l_hand.offset = Vec3::new(-7.0, 4.0, 3.0); + next.l_hand.ori = Quaternion::rotation_x(1.27 + wave * 0.25) + * Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(0.0); + next.l_hand.scale = Vec3::one() * 1.01; + next.r_hand.offset = Vec3::new(7.0, 2.5, -1.25); + next.r_hand.ori = Quaternion::rotation_x(1.27 + wave * 0.25) + * Quaternion::rotation_y(0.0) + * Quaternion::rotation_z(-0.3); + next.r_hand.scale = Vec3::one() * 1.01; + next.weapon.offset = Vec3::new( + 5.0 + skeleton_attr.weapon_x, + 8.75 + skeleton_attr.weapon_y, + -2.0, + ); + next.weapon.ori = Quaternion::rotation_x(-0.3) + * Quaternion::rotation_y(-1.27) + * Quaternion::rotation_z(wave * -0.25); + next.weapon.scale = Vec3::one(); + } } next diff --git a/voxygen/src/anim/mod.rs b/voxygen/src/anim/mod.rs index 5f92c1c6a4..a527d759ce 100644 --- a/voxygen/src/anim/mod.rs +++ b/voxygen/src/anim/mod.rs @@ -154,6 +154,7 @@ impl<'a> From<&'a comp::humanoid::Body> for SkeletonAttr { Tool::Staff => 3.0, Tool::Bow => 0.0, Tool::Dagger => 0.0, + Tool::Debug(_) => 0.0, }, weapon_y: match Tool::Hammer { // TODO: Inventory @@ -164,6 +165,7 @@ impl<'a> From<&'a comp::humanoid::Body> for SkeletonAttr { Tool::Staff => 0.0, Tool::Bow => -2.0, Tool::Dagger => -2.0, + Tool::Debug(_) => 0.0, }, } } diff --git a/voxygen/src/hud/item_imgs.rs b/voxygen/src/hud/item_imgs.rs index 2c5ab5cfad..81e539d34a 100644 --- a/voxygen/src/hud/item_imgs.rs +++ b/voxygen/src/hud/item_imgs.rs @@ -1,7 +1,7 @@ use crate::ui::{Graphic, Transform, Ui}; use common::{ assets::{self, watch::ReloadIndicator, Asset}, - comp::item::{Armor, Consumable, Debug, Ingredient, Item, ItemKind, Tool}, + comp::item::{Armor, Consumable, Ingredient, Item, ItemKind, Tool}, }; use conrod_core::image::Id; use dot_vox::DotVoxData; @@ -18,7 +18,6 @@ pub enum ItemKey { Armor(Armor), Consumable(Consumable), Ingredient(Ingredient), - Debug(Debug), } impl From<&Item> for ItemKey { fn from(item: &Item) -> Self { @@ -27,7 +26,6 @@ impl From<&Item> for ItemKey { ItemKind::Armor { kind, .. } => ItemKey::Armor(kind.clone()), ItemKind::Consumable { kind, .. } => ItemKey::Consumable(kind.clone()), ItemKind::Ingredient(kind) => ItemKey::Ingredient(kind.clone()), - ItemKind::Debug(kind) => ItemKey::Debug(kind.clone()), } } } diff --git a/voxygen/src/hud/skillbar.rs b/voxygen/src/hud/skillbar.rs index cb3635f104..860ef4f57b 100644 --- a/voxygen/src/hud/skillbar.rs +++ b/voxygen/src/hud/skillbar.rs @@ -3,7 +3,7 @@ use super::{ /*FOCUS_COLOR, RAGE_COLOR,*/ HP_COLOR, LOW_HP_COLOR, MANA_COLOR, TEXT_COLOR, XP_COLOR, }; use crate::GlobalState; -use common::comp::{item::Debug, item::Tool, Item, ItemKind, Stats}; +use common::comp::{item::Debug, item::Tool, ItemKind, Stats}; use conrod_core::{ color, widget::{self, Button, Image, Rectangle, Text}, @@ -535,7 +535,7 @@ impl<'a> Widget for Skillbar<'a> { }, _ => 38.0 * scale, }) - .h(match self.stats.equipment.main { + .h(match self.stats.equipment.main.as_ref().map(|i| &i.kind) { Some(ItemKind::Tool { kind, .. }) => match kind { Tool::Bow => 30.0 * scale, Tool::Staff => 36.0 * scale, @@ -552,8 +552,8 @@ impl<'a> Widget for Skillbar<'a> { .set(state.ids.m2_slot, ui); Image::new(self.imgs.skillbar_slot_big_bg) .w_h(36.0 * scale, 36.0 * scale) - .color(match self.stats.equipment.main { - Some(Item::Tool { kind, .. }) => match kind { + .color(match self.stats.equipment.main.as_ref().map(|i| &i.kind) { + Some(ItemKind::Tool { kind, .. }) => match kind { Tool::Bow => Some(BG_COLOR_2), Tool::Staff => Some(BG_COLOR_2), _ => Some(BG_COLOR_2), @@ -574,7 +574,7 @@ impl<'a> Widget for Skillbar<'a> { }, _ => self.imgs.twohaxe_m2, }) // Insert Icon here - .w(match self.stats.equipment.main { + .w(match self.stats.equipment.main.as_ref().map(|i| &i.kind) { Some(ItemKind::Tool { kind, .. }) => match kind { Tool::Bow => 30.0 * scale, Tool::Staff => 30.0 * scale, @@ -582,7 +582,7 @@ impl<'a> Widget for Skillbar<'a> { }, _ => 38.0 * scale, }) - .h(match self.stats.equipment.main { + .h(match self.stats.equipment.main.as_ref().map(|i| &i.kind) { Some(ItemKind::Tool { kind, .. }) => match kind { Tool::Bow => 30.0 * scale, Tool::Staff => 30.0 * scale, diff --git a/voxygen/src/menu/char_selection/ui.rs b/voxygen/src/menu/char_selection/ui.rs index 2cb169b6cf..49cb38dd73 100644 --- a/voxygen/src/menu/char_selection/ui.rs +++ b/voxygen/src/menu/char_selection/ui.rs @@ -8,7 +8,7 @@ use crate::{ GlobalState, }; use client::Client; -use common::comp::{humanoid, item::Tool}; +use common::comp::humanoid; use conrod_core::{ color, color::TRANSPARENT, diff --git a/voxygen/src/scene/figure/load.rs b/voxygen/src/scene/figure/load.rs index 040555594f..b5783de10c 100644 --- a/voxygen/src/scene/figure/load.rs +++ b/voxygen/src/scene/figure/load.rs @@ -520,8 +520,8 @@ pub fn mesh_main(item: Option<&Item>) -> Mesh { Tool::Shield => ("weapon.axe.rusty_2h", Vec3::new(-2.5, -6.5, -2.0)), Tool::Bow => ("weapon.bow.simple-bow", Vec3::new(-1.0, -6.0, -2.0)), Tool::Staff => ("weapon.staff.wood-fire", Vec3::new(-1.0, -6.0, -3.0)), + Tool::Debug(_) => ("weapon.debug_wand", Vec3::new(-1.5, -9.5, -4.0)), }, - ItemKind::Debug(_) => ("weapon.debug_wand", Vec3::new(-1.5, -9.5, -4.0)), _ => return Mesh::new(), }; load_mesh(name, offset) From f1b728b89b018140bebb5c77eea39c85caf4240c Mon Sep 17 00:00:00 2001 From: timokoesters Date: Thu, 24 Oct 2019 10:13:32 +0200 Subject: [PATCH 3/6] improvement: load_cloned returns a result --- common/src/assets/mod.rs | 6 +++--- server/src/lib.rs | 2 +- voxygen/src/menu/char_selection/mod.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/common/src/assets/mod.rs b/common/src/assets/mod.rs index ab97fd8ce0..2cd5222437 100644 --- a/common/src/assets/mod.rs +++ b/common/src/assets/mod.rs @@ -85,9 +85,9 @@ pub fn load(specifier: &str) -> Result, Error> { } /// Function used to load assets from the filesystem or the cache and return a clone. -pub fn load_cloned(specifier: &str) -> Option { - let asset: Option> = load(specifier).ok(); - asset.map(|asset| (*asset).clone()) +pub fn load_cloned(specifier: &str) -> Result { + let asset = load(specifier); + asset.map(|asset: Arc| (*asset).clone()) } /// Function used to load essential assets from the filesystem or the cache. It will panic if the asset is not found. diff --git a/server/src/lib.rs b/server/src/lib.rs index 349f84bc34..65bca2ef34 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -205,7 +205,7 @@ impl Server { server_settings: &ServerSettings, ) { // Give no item when an invalid specifier is given - let main = main.and_then(|specifier| assets::load_cloned(&specifier)); + let main = main.and_then(|specifier| assets::load_cloned(&specifier).ok()); let spawn_point = state.ecs().read_resource::().0; diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs index c411ae5afd..941d94cd5f 100644 --- a/voxygen/src/menu/char_selection/mod.rs +++ b/voxygen/src/menu/char_selection/mod.rs @@ -98,7 +98,7 @@ impl PlayState for CharSelectionState { main: self .char_selection_ui .character_tool - .and_then(|specifier| assets::load_cloned(&specifier)), + .and_then(|specifier| assets::load_cloned(&specifier).ok()), alt: None, }, ); From a6faffca4e7f122829df8afed3af5a45d80f9c3c Mon Sep 17 00:00:00 2001 From: timokoesters Date: Thu, 24 Oct 2019 19:43:55 +0200 Subject: [PATCH 4/6] feat: asset glob loading, random weapons in chests --- common/src/assets/mod.rs | 58 +++++++++++++++++++++++++++++-- common/src/comp/inventory/item.rs | 17 ++++----- 2 files changed, 62 insertions(+), 13 deletions(-) diff --git a/common/src/assets/mod.rs b/common/src/assets/mod.rs index 2cd5222437..8acc12d5b6 100644 --- a/common/src/assets/mod.rs +++ b/common/src/assets/mod.rs @@ -72,6 +72,43 @@ pub fn load_map A>( } } +pub fn load_glob(specifier: &str) -> Result>>, Error> { + if let Some(assets) = ASSETS.read().unwrap().get(specifier) { + return Ok(Arc::clone(assets).downcast()?); + } + + // Get glob matches + let glob_matches = read_dir(specifier.trim_end_matches(".*")).map(|dir| { + dir.filter_map(|direntry| { + direntry.ok().and_then(|file| { + file.file_name() + .to_string_lossy() + .rsplitn(2, '.') + .last() + .map(|s| s.to_owned()) + }) + }) + .collect::>() + }); + + match glob_matches { + Ok(glob_matches) => { + let assets = Arc::new( + glob_matches + .into_iter() + .filter_map(|name| load(&specifier.replace("*", &name)).ok()) + .collect::>(), + ); + let clone = Arc::clone(&assets); + + let mut assets_write = ASSETS.write().unwrap(); + assets_write.insert(specifier.to_owned(), clone); + Ok(assets) + } + Err(error) => Err(error), + } +} + /// Function used to load assets from the filesystem or the cache. /// Example usage: /// ```no_run @@ -141,8 +178,6 @@ pub fn load_watched( Ok(asset) } -/// The Asset trait, which is implemented by all structures that have their data stored in the -/// filesystem. fn reload(specifier: &str) -> Result<(), Error> { let asset = Arc::new(A::parse(load_file(specifier, A::ENDINGS)?)?); let clone = Arc::clone(&asset); @@ -157,7 +192,8 @@ fn reload(specifier: &str) -> Result<(), Error> { Ok(()) } -/// Asset Trait +/// The Asset trait, which is implemented by all structures that have their data stored in the +/// filesystem. pub trait Asset: Send + Sync + Sized { const ENDINGS: &'static [&'static str]; /// Parse the input file and return the correct Asset. @@ -268,6 +304,22 @@ pub fn load_file(specifier: &str, endings: &[&str]) -> Result, E Err(Error::NotFound(path.to_string_lossy().into_owned())) } +/// Loads a file based on the specifier and possible extensions +pub fn load_file_glob(specifier: &str, endings: &[&str]) -> Result, Error> { + let path = unpack_specifier(specifier); + for ending in endings { + let mut path = path.clone(); + path.set_extension(ending); + + debug!("Trying to access \"{:?}\"", path); + if let Ok(file) = File::open(path) { + return Ok(BufReader::new(file)); + } + } + + Err(Error::NotFound(path.to_string_lossy().into_owned())) +} + /// Read directory from `veloren/assets/*` pub fn read_dir(specifier: &str) -> Result { let dir_name = unpack_specifier(specifier); diff --git a/common/src/comp/inventory/item.rs b/common/src/comp/inventory/item.rs index 385877881e..cd1d2c407e 100644 --- a/common/src/comp/inventory/item.rs +++ b/common/src/comp/inventory/item.rs @@ -3,10 +3,12 @@ use crate::{ effect::Effect, terrain::{Block, BlockKind}, }; +use rand::prelude::*; use specs::{Component, FlaggedStorage}; use specs_idvs::IDVStorage; use std::fs::File; use std::io::BufReader; +use std::sync::Arc; #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Tool { @@ -112,16 +114,11 @@ impl Item { BlockKind::Chest => Some(match rand::random::() % 4 { 0 => assets::load_expect_cloned("common.items.apple"), 1 => assets::load_expect_cloned("common.items.velorite"), - // TODO: Implement random asset loading - //2 => Item::Tool { - // kind: *(&ALL_TOOLS).choose(&mut rand::thread_rng()), - // power: 8 + rand::random::() % (rand::random::() % 29 + 1), - // stamina: 0, - // strength: 0, - // dexterity: 0, - // intelligence: 0, - //}, - 2 => assets::load_expect_cloned("common.items.apple"), + 2 => (**assets::load_glob::("common.items.weapons.*") + .expect("Error getting glob") + .choose(&mut rand::thread_rng()) + .expect("Empty glob")) + .clone(), 3 => assets::load_expect_cloned("common.items.veloritefrag"), _ => unreachable!(), }), From 52dbfde5106291bb50c28af7f40933114c1e873c Mon Sep 17 00:00:00 2001 From: pestilence Date: Thu, 24 Oct 2019 16:05:10 -0500 Subject: [PATCH 5/6] add giveitem command --- server/src/cmd.rs | 26 ++++++++++++++++++++++++-- server/src/sys/message.rs | 3 ++- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/server/src/cmd.rs b/server/src/cmd.rs index 7f57fcf463..0b967a36db 100644 --- a/server/src/cmd.rs +++ b/server/src/cmd.rs @@ -5,7 +5,7 @@ use crate::{Server, StateExt}; use chrono::{NaiveTime, Timelike}; use common::{ - comp, + assets, comp, event::{EventBus, ServerEvent}, msg::ServerMsg, npc::{get_npc_name, NpcKind}, @@ -82,6 +82,12 @@ impl ChatCommand { lazy_static! { /// Static list of chat commands available to the server. pub static ref CHAT_COMMANDS: Vec = vec![ + ChatCommand::new( + "giveitem", + "{d}", + "/giveitem : Give yourself an item.", + true, + handle_give,), ChatCommand::new( "jump", "{d} {d} {d}", @@ -233,7 +239,23 @@ lazy_static! { ), ]; } - +fn handle_give(server: &mut Server, entity: EcsEntity, args: String, _action: &ChatCommand) { + if let Ok(item) = assets::load_cloned(&args) { + server + .state + .ecs() + .write_storage::() + .get_mut(entity) + .map(|inv| inv.push(item)); + let _ = server + .state + .ecs() + .write_storage::() + .insert(entity, comp::InventoryUpdate); + } else { + server.notify_client(entity, ServerMsg::private(String::from("Invalid item!"))); + } +} fn handle_jump(server: &mut Server, entity: EcsEntity, args: String, action: &ChatCommand) { if let Ok((x, y, z)) = scan_fmt!(&args, action.arg_fmt, f32, f32, f32) { match server.state.read_component_cloned::(entity) { diff --git a/server/src/sys/message.rs b/server/src/sys/message.rs index 3cb71e71a6..f35279c087 100644 --- a/server/src/sys/message.rs +++ b/server/src/sys/message.rs @@ -169,7 +169,8 @@ impl<'a> System<'a> for Sys { entity, name, body, - main: main.and_then(|specifier| assets::load_cloned(&specifier)), + main: main + .and_then(|specifier| assets::load_cloned(&specifier).ok()), }); } ClientState::Character => client.error_state(RequestStateError::Already), From 3ceb3a9d6d1e38e65129f0586fdcaa11e956e98e Mon Sep 17 00:00:00 2001 From: timokoesters Date: Fri, 25 Oct 2019 09:47:28 +0200 Subject: [PATCH 6/6] refactor: small adjustments --- common/src/assets/mod.rs | 6 ++---- common/src/comp/inventory/item.rs | 1 - 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/common/src/assets/mod.rs b/common/src/assets/mod.rs index 8acc12d5b6..4b27dd9983 100644 --- a/common/src/assets/mod.rs +++ b/common/src/assets/mod.rs @@ -123,8 +123,7 @@ pub fn load(specifier: &str) -> Result, Error> { /// Function used to load assets from the filesystem or the cache and return a clone. pub fn load_cloned(specifier: &str) -> Result { - let asset = load(specifier); - asset.map(|asset: Arc| (*asset).clone()) + load::(specifier).map(|asset| (*asset).clone()) } /// Function used to load essential assets from the filesystem or the cache. It will panic if the asset is not found. @@ -141,8 +140,7 @@ pub fn load_expect(specifier: &str) -> Arc { /// Function used to load essential assets from the filesystem or the cache and return a clone. It will panic if the asset is not found. pub fn load_expect_cloned(specifier: &str) -> A { - let asset: Arc = load_expect(specifier); - (*asset).clone() + load_expect::(specifier).as_ref().clone() } /// Load an asset while registering it to be watched and reloaded when it changes diff --git a/common/src/comp/inventory/item.rs b/common/src/comp/inventory/item.rs index cd1d2c407e..17ad624b3d 100644 --- a/common/src/comp/inventory/item.rs +++ b/common/src/comp/inventory/item.rs @@ -8,7 +8,6 @@ use specs::{Component, FlaggedStorage}; use specs_idvs::IDVStorage; use std::fs::File; use std::io::BufReader; -use std::sync::Arc; #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Tool {