diff --git a/assets/voxygen/element/bag/slot.vox b/assets/voxygen/element/bag/slot.vox index 0ba79c16d2..b0a6dab7af 100644 --- a/assets/voxygen/element/bag/slot.vox +++ b/assets/voxygen/element/bag/slot.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:69d4eb3b262de7ce2280d6a648ddb0e461e513b6c4e74bbff8bc8ede51e73532 -size 46011 +oid sha256:f10b55993771bbf25a1b018195eb1e9a553e11d54972c8a9ef32d65b7c3187e9 +size 57163 diff --git a/assets/voxygen/element/buttons/inv_slot.vox b/assets/voxygen/element/buttons/inv_slot.vox index 0ba79c16d2..dc60c1323b 100644 --- a/assets/voxygen/element/buttons/inv_slot.vox +++ b/assets/voxygen/element/buttons/inv_slot.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:69d4eb3b262de7ce2280d6a648ddb0e461e513b6c4e74bbff8bc8ede51e73532 -size 46011 +oid sha256:ab46da914aa73fd0a7aff023883cd5392d01f0609383d4c143d5c3680b65250a +size 57195 diff --git a/assets/voxygen/element/buttons/inv_slot_sel.vox b/assets/voxygen/element/buttons/inv_slot_sel.vox new file mode 100644 index 0000000000..ebe08ff289 --- /dev/null +++ b/assets/voxygen/element/buttons/inv_slot_sel.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8ddf8f91a8229e95b3de37f22435a8570f0f5992f9593815c6a1bd8d8320236a +size 57307 diff --git a/assets/voxygen/element/icons/item_apple.vox b/assets/voxygen/element/icons/item_apple.vox index 04b06ca06f..c9d97c7b75 100644 --- a/assets/voxygen/element/icons/item_apple.vox +++ b/assets/voxygen/element/icons/item_apple.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ff0e7b2c304d0e953eef57729a6197a0d5a5a4bddb39f6ff5ea561879c8af657 -size 58035 +oid sha256:e65311bb72c275675103ad0fe307f0b53ef26cb7766a40a7542e6f6e887d8e1a +size 57215 diff --git a/assets/voxygen/element/icons/item_flower.png b/assets/voxygen/element/icons/item_flower.png new file mode 100644 index 0000000000..80ecd5f523 --- /dev/null +++ b/assets/voxygen/element/icons/item_flower.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3630ed8f161514e1fb5960c0faa59c88f1be17aae9bacc26f935b7ffc18332f9 +size 13979 diff --git a/assets/voxygen/element/icons/item_flower.vox b/assets/voxygen/element/icons/item_flower.vox index 4c904b4580..3c1534c865 100644 --- a/assets/voxygen/element/icons/item_flower.vox +++ b/assets/voxygen/element/icons/item_flower.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2332cf2148d446ad1d5bc87336733b4321c2912f20ea4cf53db2f275d8836b08 -size 56947 +oid sha256:5847dc60e18f08f5f2a1669d81d39d612664a654db05ffd144f2195e1452f652 +size 56791 diff --git a/assets/voxygen/element/icons/item_grass.vox b/assets/voxygen/element/icons/item_grass.vox index df64f091de..59916e0beb 100644 --- a/assets/voxygen/element/icons/item_grass.vox +++ b/assets/voxygen/element/icons/item_grass.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:12d2be86c3da4cd9f238aaa4914456c34f85f9589a9f559dce381c30c345a6ab -size 57780 +oid sha256:7da1daf731e78a6f83544eb6f8ebea201844004f844b5cd7deb878292741f430 +size 56512 diff --git a/assets/voxygen/element/icons/item_mushroom.vox b/assets/voxygen/element/icons/item_mushroom.vox index e5f71e5ec2..afb453857f 100644 --- a/assets/voxygen/element/icons/item_mushroom.vox +++ b/assets/voxygen/element/icons/item_mushroom.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6ad8292f8448d86fab32b78008bc81f63c7e140b8cf28c58385c423deb4d58c1 -size 58639 +oid sha256:3d777456ff641f2e4a0b3e87caa01b264cc93ec9554ed123c42ee91729ba6589 +size 57847 diff --git a/assets/voxygen/element/not_found.png b/assets/voxygen/element/not_found.png new file mode 100644 index 0000000000..b412f97549 --- /dev/null +++ b/assets/voxygen/element/not_found.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6fd63baa91714e5ca052d141e0c717b260196a8e4bc4cb7584fff53157a4cbf0 +size 5100 diff --git a/assets/voxygen/item_image_manifest.ron b/assets/voxygen/item_image_manifest.ron new file mode 100644 index 0000000000..a39a15ad18 --- /dev/null +++ b/assets/voxygen/item_image_manifest.ron @@ -0,0 +1,56 @@ +// 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, -7.0, 0.0), (90.0, 90.0, 0.0), 1.6, + ), + // Weapons + Tool(Bow): VoxTrans( + "voxel.weapon.bow.simple-bow", + (0.0, 0.0, 0.0), (90.0, 90.0, 0.0), 1.0, + ), + Tool(Dagger): VoxTrans( + "voxel.weapon.dagger.dagger_rusty", + (0.0, 0.0, -4.0), (-120.0, 90.0, 0.0), 1.1, + ), + Tool(Sword): VoxTrans( + "voxel.weapon.sword.rusty_2h", + (0.0, 9.0, 0.0), (-90.0, 90.0, 0.0), 2.4, + ), + Tool(Axe): VoxTrans( + "voxel.weapon.axe.rusty_2h", + (0.0, -8.0, 0.0), (-90.0, 90.0, 0.0), 2.0, + ), + Tool(Hammer): VoxTrans( + "voxel.weapon.hammer.rusty_2h", + (0.0, -8.0, 0.0), (-90.0, 90.0, 0.0), 2.0, + ), + // Consumables + Consumable(Apple): VoxTrans( + "element.icons.item_apple", + (0.0, 0.0, 0.0), (-90.0, 90.0, 0.0), 1.0, + ), + Consumable(Potion): VoxTrans( + "voxel.object.potion_red", + (0.0, 0.0, 0.0), (90.0, 90.0, 0.0), 1.0, + ), + Consumable(Mushroom): VoxTrans( + "voxel.sprite.mushrooms.mushroom-4", + (0.0, 0.0, 0.0), (-50.0, 70.0, 40.0), 1.0, + ), + Consumable(Velorite): VoxTrans( + "voxel.sprite.velorite.velorite_ore", + (0.0, -1.0, 0.0), (-50.0, 40.0, 20.0), 0.8, + ), + // Ingredients + Ingredient(Flower): VoxTrans( + "voxel.sprite.flowers.flower_red_2", + (0.0, -1.0, 0.0), (-50.0, 40.0, 20.0), 0.8, + ), + Ingredient(Grass): VoxTrans( + "voxel.sprite.grass.grass_long_5", + (0.0, 0.0, 0.0), (-90.0, 50.0, 0.0), 1.0, + ), +}) diff --git a/assets/voxygen/voxel/sprite/chests/chest.vox b/assets/voxygen/voxel/sprite/chests/chest.vox new file mode 100644 index 0000000000..5e6fe09e6d --- /dev/null +++ b/assets/voxygen/voxel/sprite/chests/chest.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:964619ec04d1d799d37fd4f7e6f7a9ff330cf10172baed9d551542172e7be84e +size 5092 diff --git a/assets/voxygen/voxel/sprite/chests/chest_dark.vox b/assets/voxygen/voxel/sprite/chests/chest_dark.vox new file mode 100644 index 0000000000..d46c0c1563 --- /dev/null +++ b/assets/voxygen/voxel/sprite/chests/chest_dark.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e31c3e53a5df23ac194dee70496d73d56a12966889acfb87ac94173a5672f83e +size 4720 diff --git a/assets/voxygen/voxel/sprite/chests/chest_demon.vox b/assets/voxygen/voxel/sprite/chests/chest_demon.vox new file mode 100644 index 0000000000..aa213775bf --- /dev/null +++ b/assets/voxygen/voxel/sprite/chests/chest_demon.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d1e58917b892e8209484b8f0596b97ad0a6b7dee17916eac06d66fa4fdeac332 +size 4712 diff --git a/assets/voxygen/voxel/sprite/chests/chest_gold.vox b/assets/voxygen/voxel/sprite/chests/chest_gold.vox new file mode 100644 index 0000000000..78f23a17bc --- /dev/null +++ b/assets/voxygen/voxel/sprite/chests/chest_gold.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e9e3e07cbcd142777f0ffbfc5a1d03ed278c37a7f15bf28052146d50376135d0 +size 4720 diff --git a/assets/voxygen/voxel/sprite/chests/chest_light.vox b/assets/voxygen/voxel/sprite/chests/chest_light.vox new file mode 100644 index 0000000000..fdb9bc30c3 --- /dev/null +++ b/assets/voxygen/voxel/sprite/chests/chest_light.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:97c3df0823abea550fae4a8346961e5ced496629328c476391c8f2c2d6410075 +size 4720 diff --git a/assets/voxygen/voxel/sprite/chests/chest_skull.vox b/assets/voxygen/voxel/sprite/chests/chest_skull.vox new file mode 100644 index 0000000000..36bbba84aa --- /dev/null +++ b/assets/voxygen/voxel/sprite/chests/chest_skull.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:597406e569312f237439d8c6b51fe1ace98b499dfe2cbc95566dee3ad1c037d4 +size 4708 diff --git a/assets/voxygen/voxel/sprite/chests/chest_vines.vox b/assets/voxygen/voxel/sprite/chests/chest_vines.vox new file mode 100644 index 0000000000..418c3cb5dc --- /dev/null +++ b/assets/voxygen/voxel/sprite/chests/chest_vines.vox @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8e0fc1699b25c1ac778001d6a9c498700abbe2a5a1ce9ef9ac7b0136c8db0043 +size 4996 diff --git a/assets/voxygen/voxel/sprite/mushrooms/mushroom-4.vox b/assets/voxygen/voxel/sprite/mushrooms/mushroom-4.vox index 5352f784a8..00ff0ad517 100644 --- a/assets/voxygen/voxel/sprite/mushrooms/mushroom-4.vox +++ b/assets/voxygen/voxel/sprite/mushrooms/mushroom-4.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9cca490440d326f62a78404d7f9eda391163ae81846ea044597f41d37b83247a -size 44555 +oid sha256:c0448145f03e200e4f09a78023d7f30b0899a6800c7ef1b293be259e69b70626 +size 55931 diff --git a/assets/world/structure/dungeon/meso_sewer_temple.vox b/assets/world/structure/dungeon/meso_sewer_temple.vox index 0dc46e18d8..a4b07531d5 100644 --- a/assets/world/structure/dungeon/meso_sewer_temple.vox +++ b/assets/world/structure/dungeon/meso_sewer_temple.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e360e6fbff3254e779ec209a9c0592d9e3c64d52bac04d7f0bace06d05254d7d -size 1328948 +oid sha256:b8245d680ce679cbbe9c88fce5111151a22922623824007a95ca95f382de62e7 +size 1384956 diff --git a/assets/world/structure/dungeon/ruins.vox b/assets/world/structure/dungeon/ruins.vox index 7a9a9d2e42..af0aa47308 100644 --- a/assets/world/structure/dungeon/ruins.vox +++ b/assets/world/structure/dungeon/ruins.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6a22c41df8b08d9c7a1497b7310d8c60f1ad34869f210a5509e842cb0f2096f8 -size 794904 +oid sha256:e5dd9935b439a64ecee8a58a5854189314a37714e76cc3388183afdff2ec2d10 +size 850124 diff --git a/assets/world/structure/natural/tower-ruin.vox b/assets/world/structure/natural/tower-ruin.vox index 5c2848837b..3a93401000 100644 --- a/assets/world/structure/natural/tower-ruin.vox +++ b/assets/world/structure/natural/tower-ruin.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4b5e9914ec44ad397b5745baac7482ff90078935883a3fecce5e2c2c7770dbd2 -size 99941 +oid sha256:b517ad8d5eec968b1fffb9a8b86d0a42841db2587e38fedd9c0be61c4f6668f3 +size 108341 diff --git a/assets/world/structure/natural/witch-hut.vox b/assets/world/structure/natural/witch-hut.vox index 509ca4884f..3f05d6b3e7 100644 --- a/assets/world/structure/natural/witch-hut.vox +++ b/assets/world/structure/natural/witch-hut.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:13880c69c5b854f69797825124d398d27b014ad6e019b64652d0b5f31fe4a964 -size 77844 +oid sha256:d9f7f0bbc418645705b40420e2ee4a235f7d2747c4123662ed0c77af2fd70e5a +size 72596 diff --git a/assets/world/tree/mangroves/5.vox b/assets/world/tree/mangroves/5.vox index cbc70ef76d..d54a3a625e 100644 --- a/assets/world/tree/mangroves/5.vox +++ b/assets/world/tree/mangroves/5.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e5ae14d3aac2cd3b36b1cc568343905d4c3092594c53cfb96f22b940942f2113 -size 87956 +oid sha256:ae18ec86742fa3acd4d0828e7b68e00e1f024d4156b60323674c2cd5435d3cea +size 99336 diff --git a/assets/world/tree/mangroves/7.vox b/assets/world/tree/mangroves/7.vox index 9e07228c28..ed7855e5e0 100644 --- a/assets/world/tree/mangroves/7.vox +++ b/assets/world/tree/mangroves/7.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8ccbb921bfb5612a9116f1562ef185af1e9e56c04cf2d5ee3b42f6bf4aba229f -size 92848 +oid sha256:2f3f7b4e9f4021f2a98cc124395c490736833a37d45aead6d14b89c81eeb11ab +size 104228 diff --git a/assets/world/tree/oak_green/3.vox b/assets/world/tree/oak_green/3.vox index 4e7048ba7c..988d4a93bd 100644 --- a/assets/world/tree/oak_green/3.vox +++ b/assets/world/tree/oak_green/3.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fcf106c505c957e78790ca4ad7ba2f481be82e32445d654284e541ab170f9023 -size 114920 +oid sha256:c7c63b94c8bdc6d41fdd22f1ce1426e8abbf2d7f1cc4d3e2feb24782a2015535 +size 126300 diff --git a/assets/world/tree/oak_green/5.vox b/assets/world/tree/oak_green/5.vox index bb1700709a..09686c3c71 100644 --- a/assets/world/tree/oak_green/5.vox +++ b/assets/world/tree/oak_green/5.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ee602e8454202dda569c4d03a2b52024f16b0b546c6b363f128d823f107d1e4f -size 95176 +oid sha256:ebac9342727decad370699b7e77517518fcd82062eba6496d4cafa35360b403d +size 106552 diff --git a/assets/world/tree/oak_green/9.vox b/assets/world/tree/oak_green/9.vox index 159806222c..50dcb81feb 100644 --- a/assets/world/tree/oak_green/9.vox +++ b/assets/world/tree/oak_green/9.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bddbc5e61b2f376653af7a567b946a1f8d7ede17c2ae8c3bc7053db5fa9575f8 -size 124118 +oid sha256:94bae0b39a4c902082c96deaee17371a3334ac6aa48fd268bf49c61258903344 +size 135498 diff --git a/assets/world/tree/oak_stump/3.vox b/assets/world/tree/oak_stump/3.vox index 17746d095b..c8e6bdcf19 100644 --- a/assets/world/tree/oak_stump/3.vox +++ b/assets/world/tree/oak_stump/3.vox @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:64d4b75d260f657e0c182452d571cb006b437b6a3ca322a93518c9ab69021a68 -size 50756 +oid sha256:2729b990855302cdca585049beddd7d1fd6277da8e24aaf82fc500f2390a53d5 +size 62136 diff --git a/common/src/comp/inventory/item.rs b/common/src/comp/inventory/item.rs index 108efc4795..4289057550 100644 --- a/common/src/comp/inventory/item.rs +++ b/common/src/comp/inventory/item.rs @@ -3,13 +3,14 @@ use crate::{ effect::Effect, terrain::{Block, BlockKind}, }; +use rand::prelude::*; use specs::{Component, FlaggedStorage}; use specs_idvs::IDVStorage; #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Tool { - Daggers, - SwordShield, + Dagger, + Shield, Sword, Axe, Hammer, @@ -20,20 +21,43 @@ pub enum Tool { impl Tool { pub fn name(&self) -> &'static str { match self { - Tool::Daggers => "daggers", - Tool::SwordShield => "sword and shield", - Tool::Sword => "sword", - Tool::Axe => "axe", - Tool::Hammer => "hammer", - Tool::Bow => "bow", - Tool::Staff => "staff", + 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.", + 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 => { + "A carved stick.\n\ + The wood smells like magic.\n\ + NOT YET AVAILABLE." + } } } } pub const ALL_TOOLS: [Tool; 7] = [ - Tool::Daggers, - Tool::SwordShield, + Tool::Dagger, + Tool::Shield, Tool::Sword, Tool::Axe, Tool::Hammer, @@ -43,7 +67,7 @@ pub const ALL_TOOLS: [Tool; 7] = [ #[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 creepy thing to do. + // TODO: Don't make armor be a body part. Wearing enemy's head is funny but also a creepy thing to do. Helmet, Shoulders, Chestplate, @@ -60,19 +84,23 @@ pub enum Armor { 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", + 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)] @@ -86,10 +114,19 @@ pub enum Consumable { impl Consumable { pub fn name(&self) -> &'static str { match self { - Consumable::Apple => "apple", - Consumable::Potion => "potion", - Consumable::Mushroom => "mushroom", - Consumable::Velorite => "velorite", + Consumable::Apple => "Apple", + Consumable::Potion => "Potion", + Consumable::Mushroom => "Mushroom", + Consumable::Velorite => "Velorite", + } + } + + 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.", } } } @@ -103,8 +140,15 @@ pub enum Ingredient { impl Ingredient { pub fn name(&self) -> &'static str { match self { - Ingredient::Flower => "flower", - Ingredient::Grass => "grass", + 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.", } } } @@ -112,6 +156,7 @@ impl Ingredient { #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Debug { Boost, + Possess, } #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] @@ -119,11 +164,17 @@ pub enum Item { Tool { kind: Tool, power: u32, + stamina: i32, + strength: i32, + dexterity: i32, + intelligence: i32, }, Armor { kind: Armor, - defense: i32, - health_bonus: i32, + stamina: i32, + strength: i32, + dexterity: i32, + intelligence: i32, }, Consumable { kind: Consumable, @@ -141,23 +192,43 @@ impl Item { Item::Tool { kind, .. } => kind.name(), Item::Armor { kind, .. } => kind.name(), Item::Consumable { kind, .. } => kind.name(), - Item::Ingredient { kind } => kind.name(), + Item::Ingredient { kind, .. } => kind.name(), Item::Debug(_) => "Debugging item", } } + 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 { .. } => "armour", - Item::Consumable { .. } => "consumable", - Item::Ingredient { .. } => "ingredient", - Item::Debug(_) => "debug", + Item::Tool { .. } => "Tool", + Item::Armor { .. } => "Armor", + Item::Consumable { .. } => "Consumable", + Item::Ingredient { .. } => "Ingredient", + Item::Debug(_) => "Debug", } } pub fn description(&self) -> String { - format!("{} ({})", self.name(), self.category()) + 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 { @@ -175,6 +246,19 @@ impl Item { BlockKind::LongGrass => Some(Self::grass()), BlockKind::MediumGrass => Some(Self::grass()), BlockKind::ShortGrass => Some(Self::grass()), + BlockKind::Chest => Some(match rand::random::() % 3 { + 0 => Self::apple(), + 1 => Self::velorite(), + 2 => Item::Tool { + kind: *(&ALL_TOOLS).choose(&mut rand::thread_rng()).unwrap(), + power: 8 + rand::random::() % (rand::random::() % 30), + stamina: 0, + strength: 0, + dexterity: 0, + intelligence: 0, + }, + _ => unreachable!(), + }), _ => None, } } @@ -184,7 +268,7 @@ impl Item { pub fn apple() -> Self { Item::Consumable { kind: Consumable::Apple, - effect: Effect::Health(20, comp::HealthSource::Item), + effect: Effect::Health(50, comp::HealthSource::Item), } } @@ -197,8 +281,8 @@ impl Item { pub fn velorite() -> Self { Item::Consumable { - kind: Consumable::Mushroom, - effect: Effect::Xp(250), + kind: Consumable::Velorite, + effect: Effect::Xp(50), } } @@ -220,6 +304,10 @@ impl Default for Item { Item::Tool { kind: Tool::Hammer, power: 0, + stamina: 0, + strength: 0, + dexterity: 0, + intelligence: 0, } } } diff --git a/common/src/comp/inventory/mod.rs b/common/src/comp/inventory/mod.rs index f9869ead91..68843c66bc 100644 --- a/common/src/comp/inventory/mod.rs +++ b/common/src/comp/inventory/mod.rs @@ -1,4 +1,3 @@ -//Re-Exports pub mod item; // Reexports @@ -77,22 +76,42 @@ impl Default for Inventory { inventory.push(Item::Tool { kind: Tool::Bow, power: 10, + stamina: 0, + strength: 0, + dexterity: 0, + intelligence: 0, }); inventory.push(Item::Tool { - kind: Tool::Daggers, + kind: Tool::Dagger, power: 10, + stamina: 0, + strength: 0, + dexterity: 0, + intelligence: 0, }); inventory.push(Item::Tool { kind: Tool::Sword, power: 10, + stamina: 0, + strength: 0, + dexterity: 0, + intelligence: 0, }); inventory.push(Item::Tool { kind: Tool::Axe, power: 10, + stamina: 0, + strength: 0, + dexterity: 0, + intelligence: 0, }); inventory.push(Item::Tool { kind: Tool::Hammer, power: 10, + stamina: 0, + strength: 0, + dexterity: 0, + intelligence: 0, }); inventory diff --git a/common/src/effect.rs b/common/src/effect.rs index 358f6429e1..2287f44ac0 100644 --- a/common/src/effect.rs +++ b/common/src/effect.rs @@ -6,3 +6,12 @@ pub enum Effect { Health(i32, comp::HealthSource), Xp(i64), } + +impl Effect { + pub fn info(&self) -> String { + match self { + Effect::Health(n, _) => format!("{:+} health", n), + Effect::Xp(n) => format!("{:+} exp", n), + } + } +} diff --git a/common/src/terrain/block.rs b/common/src/terrain/block.rs index 4fe321de12..f382a8de4b 100644 --- a/common/src/terrain/block.rs +++ b/common/src/terrain/block.rs @@ -30,6 +30,7 @@ pub enum BlockKind { Mushroom, Liana, Velorite, + Chest, } impl BlockKind { @@ -63,6 +64,7 @@ impl BlockKind { BlockKind::Mushroom => true, BlockKind::Liana => true, BlockKind::Velorite => true, + BlockKind::Chest => true, _ => false, } } @@ -98,6 +100,7 @@ impl BlockKind { BlockKind::Mushroom => false, BlockKind::Liana => false, BlockKind::Velorite => false, + BlockKind::Chest => false, _ => true, } } @@ -125,6 +128,7 @@ impl BlockKind { BlockKind::Apple => true, BlockKind::Mushroom => false, BlockKind::Liana => false, + BlockKind::Chest => true, _ => true, } } @@ -144,6 +148,7 @@ impl BlockKind { BlockKind::Apple => true, BlockKind::Mushroom => true, BlockKind::Velorite => true, + BlockKind::Chest => true, _ => false, } } diff --git a/common/src/terrain/structure.rs b/common/src/terrain/structure.rs index 78b0a9521f..65a5ba7000 100644 --- a/common/src/terrain/structure.rs +++ b/common/src/terrain/structure.rs @@ -20,6 +20,7 @@ pub enum StructureBlock { Water, GreenSludge, Fruit, + Chest, Hollow, Liana, Normal(Rgb), @@ -116,6 +117,7 @@ impl Asset for Structure { 6 => StructureBlock::GreenSludge, 7 => StructureBlock::Fruit, 9 => StructureBlock::Liana, + 10 => StructureBlock::Chest, 15 => StructureBlock::Hollow, index => { let color = palette diff --git a/server/src/lib.rs b/server/src/lib.rs index ded947b722..566881b8d6 100644 --- a/server/src/lib.rs +++ b/server/src/lib.rs @@ -567,6 +567,10 @@ impl Server { Some(comp::Item::Tool { kind: comp::item::Tool::Sword, power: 5, + stamina: 0, + strength: 0, + dexterity: 0, + intelligence: 0, }), ); let body = comp::Body::Humanoid(comp::humanoid::Body::random()); @@ -588,6 +592,10 @@ impl Server { Some(comp::Item::Tool { kind: comp::item::Tool::Sword, power: 10, + stamina: 0, + strength: 0, + dexterity: 0, + intelligence: 0, }), ); body = comp::Body::Humanoid(comp::humanoid::Body::random()); @@ -1020,7 +1028,14 @@ impl Server { client, name, body, - main.map(|t| comp::Item::Tool { kind: t, power: 10 }), + main.map(|t| comp::Item::Tool { + kind: t, + power: 10, + stamina: 0, + strength: 0, + dexterity: 0, + intelligence: 0, + }), &server_settings, ); } diff --git a/voxygen/src/anim/character/block.rs b/voxygen/src/anim/character/block.rs index d641881d5d..3477153c74 100644 --- a/voxygen/src/anim/character/block.rs +++ b/voxygen/src/anim/character/block.rs @@ -153,7 +153,7 @@ impl Animation for BlockAnimation { * Quaternion::rotation_z(0.0); next.weapon.scale = Vec3::one(); } - Tool::SwordShield => { + Tool::Shield => { next.l_hand.offset = Vec3::new( -6.0 + wave_ultra_slow_cos * 1.0, 3.5 + wave_ultra_slow_cos * 0.5, @@ -203,7 +203,7 @@ impl Animation for BlockAnimation { * Quaternion::rotation_z(0.0); next.weapon.scale = Vec3::one(); } - Tool::Daggers => { + Tool::Dagger => { next.l_hand.offset = Vec3::new( -6.0 + wave_ultra_slow_cos * 1.0, 3.5 + wave_ultra_slow_cos * 0.5, diff --git a/voxygen/src/anim/character/blockidle.rs b/voxygen/src/anim/character/blockidle.rs index d438ed04f6..dfaedd3e75 100644 --- a/voxygen/src/anim/character/blockidle.rs +++ b/voxygen/src/anim/character/blockidle.rs @@ -152,7 +152,7 @@ impl Animation for BlockIdleAnimation { * Quaternion::rotation_z(0.0); next.weapon.scale = Vec3::one(); } - Tool::SwordShield => { + Tool::Shield => { next.l_hand.offset = Vec3::new( -6.0 + wave_ultra_slow_cos * 1.0, 3.5 + wave_ultra_slow_cos * 0.5, @@ -202,7 +202,7 @@ impl Animation for BlockIdleAnimation { * Quaternion::rotation_z(0.0); next.weapon.scale = Vec3::one(); } - Tool::Daggers => { + Tool::Dagger => { next.l_hand.offset = Vec3::new( -6.0 + wave_ultra_slow_cos * 1.0, 3.5 + wave_ultra_slow_cos * 0.5, diff --git a/voxygen/src/anim/character/cidle.rs b/voxygen/src/anim/character/cidle.rs index d830c2396d..67c5ee9011 100644 --- a/voxygen/src/anim/character/cidle.rs +++ b/voxygen/src/anim/character/cidle.rs @@ -160,7 +160,7 @@ impl Animation for CidleAnimation { * Quaternion::rotation_z(0.0); next.weapon.scale = Vec3::one(); } - Tool::SwordShield => { + Tool::Shield => { next.l_hand.offset = Vec3::new( -6.0 + wave_ultra_slow_cos * 1.0, 3.5 + wave_ultra_slow_cos * 0.5, @@ -214,7 +214,7 @@ impl Animation for CidleAnimation { * Quaternion::rotation_z(0.85); next.weapon.scale = Vec3::one(); } - Tool::Daggers => { + Tool::Dagger => { next.l_hand.offset = Vec3::new( -6.0 + wave_ultra_slow_cos * 1.0, 3.5 + wave_ultra_slow_cos * 0.5, diff --git a/voxygen/src/anim/character/wield.rs b/voxygen/src/anim/character/wield.rs index dece8f89bc..faeef5b6bc 100644 --- a/voxygen/src/anim/character/wield.rs +++ b/voxygen/src/anim/character/wield.rs @@ -96,7 +96,7 @@ impl Animation for WieldAnimation { * Quaternion::rotation_z(0.0); next.weapon.scale = Vec3::one(); } - Tool::SwordShield => { + Tool::Shield => { next.l_hand.offset = Vec3::new(-6.0, 3.5, 0.0); next.l_hand.ori = Quaternion::rotation_x(-0.3); next.l_hand.scale = Vec3::one() * 1.01; @@ -134,7 +134,7 @@ impl Animation for WieldAnimation { * Quaternion::rotation_z(0.85); next.weapon.scale = Vec3::one(); } - Tool::Daggers => { + Tool::Dagger => { next.l_hand.offset = Vec3::new(-6.0, 3.5, 0.0); next.l_hand.ori = Quaternion::rotation_x(-0.3); next.l_hand.scale = Vec3::one() * 1.01; diff --git a/voxygen/src/anim/mod.rs b/voxygen/src/anim/mod.rs index d1cf0483ef..5f92c1c6a4 100644 --- a/voxygen/src/anim/mod.rs +++ b/voxygen/src/anim/mod.rs @@ -150,20 +150,20 @@ impl<'a> From<&'a comp::humanoid::Body> for SkeletonAttr { Tool::Sword => 0.0, Tool::Axe => 3.0, Tool::Hammer => 0.0, - Tool::SwordShield => 3.0, + Tool::Shield => 3.0, Tool::Staff => 3.0, Tool::Bow => 0.0, - Tool::Daggers => 0.0, + Tool::Dagger => 0.0, }, weapon_y: match Tool::Hammer { // TODO: Inventory Tool::Sword => -1.25, Tool::Axe => 0.0, Tool::Hammer => -2.0, - Tool::SwordShield => 0.0, + Tool::Shield => 0.0, Tool::Staff => 0.0, Tool::Bow => -2.0, - Tool::Daggers => -2.0, + Tool::Dagger => -2.0, }, } } diff --git a/voxygen/src/hud/bag.rs b/voxygen/src/hud/bag.rs index 749b6b9666..15f2cbb855 100644 --- a/voxygen/src/hud/bag.rs +++ b/voxygen/src/hud/bag.rs @@ -1,11 +1,12 @@ use super::{ img_ids::{Imgs, ImgsRot}, + item_imgs::{ItemImgs, ItemKind}, Event as HudEvent, Fonts, TEXT_COLOR, }; use crate::ui::{ImageFrame, Tooltip, TooltipManager, Tooltipable}; use client::Client; use conrod_core::{ - color, + color, image, position::Relative, widget::{self, Button, Image, Rectangle /*, Scrollbar*/}, widget_ids, Color, Labelable, Positionable, Sizeable, Widget, WidgetCommon, @@ -33,6 +34,7 @@ widget_ids! { pub struct Bag<'a> { client: &'a Client, imgs: &'a Imgs, + item_imgs: &'a ItemImgs, fonts: &'a Fonts, #[conrod(common_builder)] common: widget::CommonBuilder, @@ -44,6 +46,7 @@ impl<'a> Bag<'a> { pub fn new( client: &'a Client, imgs: &'a Imgs, + item_imgs: &'a ItemImgs, fonts: &'a Fonts, rot_imgs: &'a ImgsRot, tooltip_manager: &'a mut TooltipManager, @@ -51,6 +54,7 @@ impl<'a> Bag<'a> { Self { client, imgs, + item_imgs, fonts, common: widget::CommonBuilder::default(), rot_imgs, @@ -61,6 +65,7 @@ impl<'a> Bag<'a> { pub struct State { ids: Ids, + img_id_cache: Vec>, selected_slot: Option, } @@ -79,6 +84,7 @@ impl<'a> Widget for Bag<'a> { fn init_state(&self, id_gen: widget::id::Generator) -> Self::State { State { ids: Ids::new(id_gen), + img_id_cache: Vec::new(), selected_slot: None, } } @@ -111,27 +117,28 @@ impl<'a> Widget for Bag<'a> { ) }) .title_font_size(15) - .desc_font_size(10) + .parent(ui.window) + .desc_font_size(12) .title_text_color(TEXT_COLOR) .desc_text_color(TEXT_COLOR); // Bag parts Image::new(self.imgs.bag_bot) - .w_h(61.0 * BAG_SCALE, 9.0 * BAG_SCALE) + .w_h(58.0 * BAG_SCALE, 9.0 * BAG_SCALE) .bottom_right_with_margins_on(ui.window, 60.0, 5.0) .set(state.ids.bag_bot, ui); let mid_height = ((inventory.len() + 4) / 5) as f64 * 44.0; Image::new(self.imgs.bag_mid) - .w_h(61.0 * BAG_SCALE, mid_height) + .w_h(58.0 * BAG_SCALE, mid_height) .up_from(state.ids.bag_bot, 0.0) .set(state.ids.bag_mid, ui); Image::new(self.imgs.bag_top) - .w_h(61.0 * BAG_SCALE, 9.0 * BAG_SCALE) + .w_h(58.0 * BAG_SCALE, 9.0 * BAG_SCALE) .up_from(state.ids.bag_mid, 0.0) .set(state.ids.bag_top, ui); // Alignment for Grid - Rectangle::fill_with([54.0 * BAG_SCALE, mid_height], color::TRANSPARENT) + Rectangle::fill_with([56.0 * BAG_SCALE, mid_height], color::TRANSPARENT) .top_left_with_margins_on(state.ids.bag_mid, 0.0, 3.0 * BAG_SCALE) .scroll_kids_vertically() .set(state.ids.inv_alignment, ui); @@ -151,6 +158,12 @@ impl<'a> Widget for Bag<'a> { .resize(inventory.len(), &mut ui.widget_id_generator()); }); } + // Expand img id cache to the number of slots + if state.img_id_cache.len() < inventory.len() { + state.update(|s| { + s.img_id_cache.resize(inventory.len(), None); + }); + } // Display inventory contents for (i, item) in inventory.slots().iter().enumerate() { @@ -160,26 +173,30 @@ impl<'a> Widget for Bag<'a> { let is_selected = Some(i) == state.selected_slot; // Slot - let slot_widget = Button::image(self.imgs.inv_slot) - .top_left_with_margins_on( - state.ids.inv_alignment, - 4.0 + y as f64 * (40.0 + 4.0), - 4.0 + x as f64 * (40.0 + 4.0), - ) // conrod uses a (y,x) format for placing... - // (the margin placement functions do this because that is the same order as "top left") - .w_h(40.0, 40.0) - .image_color(if is_selected { - color::WHITE - } else { - color::DARK_YELLOW - }); + let slot_widget = Button::image(if !is_selected { + self.imgs.inv_slot + } else { + self.imgs.inv_slot_sel + }) + .top_left_with_margins_on( + state.ids.inv_alignment, + 0.0 + y as f64 * (40.0 + 2.0), + 0.0 + x as f64 * (40.0 + 2.0), + ) // conrod uses a (y,x) format for placing... + // (the margin placement functions do this because that is the same order as "top left") + .w_h(40.0, 40.0) + .image_color(if is_selected { + color::WHITE + } else { + color::DARK_YELLOW + }); let slot_widget_clicked = if let Some(item) = item { slot_widget .with_tooltip( self.tooltip_manager, - &item.description(), - &item.category(), + &item.title(), + &format!("{}\n{}", item.info(), item.description()), &item_tooltip, ) .set(state.ids.inv_slots[i], ui) @@ -205,19 +222,29 @@ impl<'a> Widget for Bag<'a> { state.update(|s| s.selected_slot = selected_slot); } // Item - if item.is_some() { - Button::image(self.imgs.flower) // TODO: Insert variable image depending on the item displayed in that slot - .w_h(28.0, 28.0) // 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]) - .graphics_for(state.ids.inv_slots[i]) - .set(state.ids.items[i], ui); + if let Some(kind) = item.as_ref().map(|i| ItemKind::from(i)) { + Button::image(match &state.img_id_cache[i] { + Some((cached_kind, id)) if cached_kind == &kind => *id, + _ => { + let id = self + .item_imgs + .img_id(kind.clone()) + .unwrap_or(self.imgs.not_found); + state.update(|s| s.img_id_cache[i] = Some((kind, id))); + id + } + }) + .w_h(30.0, 30.0) + .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]) + .graphics_for(state.ids.inv_slots[i]) + .set(state.ids.items[i], ui); } } diff --git a/voxygen/src/hud/img_ids.rs b/voxygen/src/hud/img_ids.rs index 6b2e3e958d..10fd60f585 100644 --- a/voxygen/src/hud/img_ids.rs +++ b/voxygen/src/hud/img_ids.rs @@ -19,6 +19,7 @@ image_ids! { bag_contents: "voxygen.element.frames.bag", inv_grid: "voxygen.element.frames.inv_grid", inv_slot: "voxygen.element.buttons.inv_slot", + inv_slot_sel: "voxygen.element.buttons.inv_slot_sel", grid_inv: "voxygen.element.buttons.grid_inv", bag_top: "voxygen.element.bag.top", bag_mid: "voxygen.element.bag.mid", @@ -223,6 +224,8 @@ image_ids! { + not_found:"voxygen.element.not_found", + help:"voxygen.element.help", charwindow_gradient:"voxygen.element.misc_bg.charwindow", diff --git a/voxygen/src/hud/item_imgs.rs b/voxygen/src/hud/item_imgs.rs new file mode 100644 index 0000000000..a49bbea528 --- /dev/null +++ b/voxygen/src/hud/item_imgs.rs @@ -0,0 +1,163 @@ +use crate::ui::{Graphic, Transform, Ui}; +use common::{ + assets::{self, watch::ReloadIndicator, Asset}, + comp::item::{Armor, Consumable, Debug, Ingredient, Item, Tool}, +}; +use conrod_core::image::Id; +use dot_vox::DotVoxData; +use hashbrown::HashMap; +use image::DynamicImage; +use log::{error, warn}; +use serde_derive::{Deserialize, Serialize}; +use std::{fs::File, io::BufReader, sync::Arc}; +use vek::*; + +#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub enum ItemKind { + Tool(Tool), + Armor(Armor), + Consumable(Consumable), + Ingredient(Ingredient), + Debug(Debug), +} +impl From<&Item> for ItemKind { + 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()), + } + } +} + +#[derive(Serialize, Deserialize)] +enum ImageSpec { + Png(String), + Vox(String), + // (specifier, offset, (axis, 2 * angle / pi), zoom) + VoxTrans(String, [f32; 3], [f32; 3], f32), +} +impl ImageSpec { + fn create_graphic(&self) -> Graphic { + match self { + ImageSpec::Png(specifier) => Graphic::Image(graceful_load_img(&specifier)), + ImageSpec::Vox(specifier) => Graphic::Voxel( + graceful_load_vox(&specifier), + Transform { + stretch: false, + ..Default::default() + }, + None, + ), + ImageSpec::VoxTrans(specifier, offset, [rot_x, rot_y, rot_z], zoom) => Graphic::Voxel( + graceful_load_vox(&specifier), + Transform { + ori: Quaternion::rotation_x(rot_x * std::f32::consts::PI / 180.0) + .rotated_y(rot_y * std::f32::consts::PI / 180.0) + .rotated_z(rot_z * std::f32::consts::PI / 180.0), + offset: Vec3::from(*offset), + zoom: *zoom, + orth: true, // TODO: Is this what we want here? @Pfau + stretch: false, + }, + None, + ), + } + } +} +#[derive(Serialize, Deserialize)] +struct ItemImagesSpec(HashMap); +impl Asset for ItemImagesSpec { + const ENDINGS: &'static [&'static str] = &["ron"]; + fn parse(buf_reader: BufReader) -> Result { + Ok(ron::de::from_reader(buf_reader).expect("Error parsing item images spec")) + } +} + +pub struct ItemImgs { + map: HashMap, + indicator: ReloadIndicator, +} +impl ItemImgs { + pub fn new(ui: &mut Ui) -> Self { + let mut indicator = ReloadIndicator::new(); + Self { + map: assets::load_watched::( + "voxygen.item_image_manifest", + &mut indicator, + ) + .expect("Unable to load item image manifest") + .0 + .iter() + .map(|(kind, spec)| (kind.clone(), ui.add_graphic(spec.create_graphic()))) + .collect(), + indicator, + } + } + /// Checks if the manifest has been changed and reloads the images if so + /// Reuses img ids + pub fn reload_if_changed(&mut self, ui: &mut Ui) { + if self.indicator.reloaded() { + for (kind, spec) in assets::load::("voxygen.item_image_manifest") + .expect("Unable to load item image manifest") + .0 + .iter() + { + // Load new graphic + let graphic = spec.create_graphic(); + // 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 + None => { + self.map.insert(kind.clone(), ui.add_graphic(graphic)); + } + } + } + } + } + pub fn img_id(&self, item_kind: ItemKind) -> Option { + match self.map.get(&item_kind) { + Some(id) => Some(*id), + // There was no specification in the ron + None => { + warn!( + "{:?} has no specified image file (note: hot-reloading won't work here)", + item_kind + ); + None + } + } + } +} + +// Copied from figure/load.rs +// TODO: remove code dup? +fn graceful_load_vox(specifier: &str) -> Arc { + let full_specifier: String = ["voxygen.", specifier].concat(); + match assets::load::(full_specifier.as_str()) { + Ok(dot_vox) => dot_vox, + Err(_) => { + error!( + "Could not load vox file for item images: {}", + full_specifier + ); + assets::load_expect::("voxygen.voxel.not_found") + } + } +} +fn graceful_load_img(specifier: &str) -> Arc { + let full_specifier: String = ["voxygen.", specifier].concat(); + match assets::load::(full_specifier.as_str()) { + Ok(img) => img, + Err(_) => { + error!( + "Could not load image file for item images: {}", + full_specifier + ); + assets::load_expect::("voxygen.element.not_found") + } + } +} diff --git a/voxygen/src/hud/mod.rs b/voxygen/src/hud/mod.rs index cf56e46a07..abe145dea7 100644 --- a/voxygen/src/hud/mod.rs +++ b/voxygen/src/hud/mod.rs @@ -4,6 +4,7 @@ mod character_window; mod chat; mod esc_menu; mod img_ids; +mod item_imgs; mod map; mod minimap; mod quest; @@ -22,6 +23,7 @@ use chat::Chat; use chrono::NaiveTime; use esc_menu::EscMenu; use img_ids::Imgs; +use item_imgs::ItemImgs; use map::Map; use minimap::MiniMap; use quest::Quest; @@ -370,6 +372,7 @@ pub struct Hud { ui: Ui, ids: Ids, imgs: Imgs, + item_imgs: ItemImgs, fonts: Fonts, rot_imgs: ImgsRot, new_messages: VecDeque, @@ -394,6 +397,8 @@ impl Hud { let imgs = Imgs::load(&mut ui).expect("Failed to load images!"); // Load rotation images. let rot_imgs = ImgsRot::load(&mut ui).expect("Failed to load rot images!"); + // Load item images. + let item_imgs = ItemImgs::new(&mut ui); // Load fonts. let fonts = Fonts::load(&mut ui).expect("Failed to load fonts!"); @@ -401,6 +406,7 @@ impl Hud { ui, imgs, rot_imgs, + item_imgs, fonts, ids, new_messages: VecDeque::new(), @@ -743,6 +749,7 @@ impl Hud { match Bag::new( client, &self.imgs, + &self.item_imgs, &self.fonts, &self.rot_imgs, tooltip_manager, @@ -1112,6 +1119,10 @@ impl Hud { &mut global_state.window.renderer_mut(), Some((view_mat, fov)), ); + + // Check if item images need to be reloaded + self.item_imgs.reload_if_changed(&mut self.ui); + events } diff --git a/voxygen/src/menu/char_selection/mod.rs b/voxygen/src/menu/char_selection/mod.rs index 98aa14b23b..5a2bd9eff7 100644 --- a/voxygen/src/menu/char_selection/mod.rs +++ b/voxygen/src/menu/char_selection/mod.rs @@ -97,6 +97,10 @@ impl PlayState for CharSelectionState { Some(comp::Item::Tool { kind: kind, power: 10, + stamina: 0, + strength: 0, + dexterity: 0, + intelligence: 0, }) } else { None diff --git a/voxygen/src/menu/char_selection/ui.rs b/voxygen/src/menu/char_selection/ui.rs index b72ac1f39c..de942ca001 100644 --- a/voxygen/src/menu/char_selection/ui.rs +++ b/voxygen/src/menu/char_selection/ui.rs @@ -939,7 +939,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::Daggers) = self.character_tool { + if Button::image(if let Some(Tool::Dagger) = self.character_tool { self.imgs.icon_border_pressed } else { self.imgs.icon_border diff --git a/voxygen/src/menu/main/ui.rs b/voxygen/src/menu/main/ui.rs index a7f0d293d0..854d92383d 100644 --- a/voxygen/src/menu/main/ui.rs +++ b/voxygen/src/menu/main/ui.rs @@ -253,9 +253,8 @@ impl MainMenuUi { Before you dive into the fun, please keep a few things in mind:\n\ \n\ - This is a very early alpha. Expect bugs, extremely unfinished gameplay, unpolished mechanics, and missing features. \n\ - If you are a reviewer, please DO NOT review this version.\n\ \n\ - - If you have constructive feedback or bug reports, you can contact us via Reddit, GitLab, or our community Discord server.\n\ + -If you have constructive feedback or bug reports, you can contact us via Reddit, GitLab, or our community Discord server.\n\ \n\ - Veloren is licensed under the GPL 3 open-source licence. That means you're free to play, modify, and redistribute the game however you wish \n\ (provided derived work is also under GPL 3). diff --git a/voxygen/src/mesh/terrain.rs b/voxygen/src/mesh/terrain.rs index c28e76d17d..8c70dc3ed3 100644 --- a/voxygen/src/mesh/terrain.rs +++ b/voxygen/src/mesh/terrain.rs @@ -217,7 +217,7 @@ impl + ReadVol + Debug> Meshable { - if t < 2_f32 { + if t < 1_f32 { self.set_mode(CameraMode::FirstPerson); } else { self.tgt_dist = t; diff --git a/voxygen/src/scene/figure/load.rs b/voxygen/src/scene/figure/load.rs index db34806be3..cd862e51ef 100644 --- a/voxygen/src/scene/figure/load.rs +++ b/voxygen/src/scene/figure/load.rs @@ -355,8 +355,8 @@ pub fn mesh_main(item: Option<&Item>) -> Mesh { 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)), - Tool::Daggers => ("weapon.hammer.rusty_2h", Vec3::new(-2.5, -5.5, -4.0)), - Tool::SwordShield => ("weapon.axe.rusty_2h", Vec3::new(-2.5, -6.5, -2.0)), + Tool::Dagger => ("weapon.hammer.rusty_2h", Vec3::new(-2.5, -5.5, -4.0)), + 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.axe.rusty_2h", Vec3::new(-2.5, -6.5, -2.0)), }, diff --git a/voxygen/src/scene/mod.rs b/voxygen/src/scene/mod.rs index b863015478..bf3d6ef7b7 100644 --- a/voxygen/src/scene/mod.rs +++ b/voxygen/src/scene/mod.rs @@ -132,7 +132,8 @@ impl Scene { } // Zoom the camera when a zoom event occurs Event::Zoom(delta) => { - self.camera.zoom_switch(delta * 0.3); + self.camera + .zoom_switch(delta * (0.05 + self.camera.get_distance() * 0.01)); true } // All other events are unhandled diff --git a/voxygen/src/scene/terrain.rs b/voxygen/src/scene/terrain.rs index 124bb93697..a7a42f60a5 100644 --- a/voxygen/src/scene/terrain.rs +++ b/voxygen/src/scene/terrain.rs @@ -135,6 +135,10 @@ fn sprite_config_for(kind: BlockKind) -> Option { variations: 1, wind_sway: 0.0, }), + BlockKind::Chest => Some(SpriteConfig { + variations: 4, + wind_sway: 0.0, + }), _ => None, } } @@ -621,6 +625,34 @@ impl Terrain { Vec3::new(-5.0, -5.0, -5.0), ), ), + ( + (BlockKind::Chest, 0), + make_model( + "voxygen.voxel.sprite.chests.chest", + Vec3::new(-7.0, -5.0, -0.0), + ), + ), + ( + (BlockKind::Chest, 1), + make_model( + "voxygen.voxel.sprite.chests.chest_gold", + Vec3::new(-7.0, -5.0, -0.0), + ), + ), + ( + (BlockKind::Chest, 2), + make_model( + "voxygen.voxel.sprite.chests.chest_dark", + Vec3::new(-7.0, -5.0, -0.0), + ), + ), + ( + (BlockKind::Chest, 3), + make_model( + "voxygen.voxel.sprite.chests.chest_vines", + Vec3::new(-7.0, -5.0, -0.0), + ), + ), ] .into_iter() .collect(), diff --git a/voxygen/src/ui/cache.rs b/voxygen/src/ui/cache.rs index 405233cc48..06c4140007 100644 --- a/voxygen/src/ui/cache.rs +++ b/voxygen/src/ui/cache.rs @@ -61,6 +61,9 @@ impl Cache { pub fn add_graphic(&mut self, graphic: Graphic) -> GraphicId { self.graphic_cache.add_graphic(graphic) } + pub fn replace_graphic(&mut self, id: GraphicId, graphic: Graphic) { + self.graphic_cache.replace_graphic(id, graphic) + } // Resizes and clears the GraphicCache pub fn resize_graphic_cache(&mut self, renderer: &mut Renderer) -> Result<(), Error> { let max_texture_size = renderer.max_texture_size(); diff --git a/voxygen/src/ui/graphic/mod.rs b/voxygen/src/ui/graphic/mod.rs index c4707fdefc..8c90e350bf 100644 --- a/voxygen/src/ui/graphic/mod.rs +++ b/voxygen/src/ui/graphic/mod.rs @@ -8,10 +8,30 @@ use log::{error, warn}; use std::sync::Arc; use vek::*; +#[derive(Clone)] +pub struct Transform { + pub ori: Quaternion, + pub offset: Vec3, + pub zoom: f32, + pub orth: bool, + pub stretch: bool, +} +impl Default for Transform { + fn default() -> Self { + Self { + ori: Quaternion::identity(), + offset: Vec3::zero(), + zoom: 1.0, + orth: true, + stretch: true, + } + } +} + #[derive(Clone)] pub enum Graphic { Image(Arc), - Voxel(Arc, Option>, Option), + Voxel(Arc, Transform, Option), Blank, } @@ -72,6 +92,26 @@ impl GraphicCache { id } + pub fn replace_graphic(&mut self, id: Id, graphic: Graphic) { + self.graphic_map.insert(id, graphic); + + // Remove from caches + // Maybe make this more efficient if replace graphic is used more often + self.transfer_ready.retain(|(p, _)| p.0 != id); + let uses = self + .soft_cache + .keys() + .filter(|k| k.0 == id) + .copied() + .collect::>(); + for p in uses { + self.soft_cache.remove(&p); + if let Some(details) = self.cache_map.remove(&p) { + // Deallocate + self.atlas.deallocate(details.alloc_id); + } + } + } pub fn get_graphic(&self, id: Id) -> Option<&Graphic> { self.graphic_map.get(&id) } @@ -129,9 +169,12 @@ impl GraphicCache { image::FilterType::Nearest, ) .to_rgba(), - Some(Graphic::Voxel(ref vox, ori, min_samples)) => { - renderer::draw_vox(&vox.as_ref().into(), dims, *ori, *min_samples) - } + Some(Graphic::Voxel(ref vox, trans, min_samples)) => renderer::draw_vox( + &vox.as_ref().into(), + dims, + trans.clone(), + *min_samples, + ), None => { warn!("A graphic was requested via an id which is not in use"); return None; diff --git a/voxygen/src/ui/graphic/renderer.rs b/voxygen/src/ui/graphic/renderer.rs index c33bdd5a8b..c7c0ffc654 100644 --- a/voxygen/src/ui/graphic/renderer.rs +++ b/voxygen/src/ui/graphic/renderer.rs @@ -1,3 +1,4 @@ +use super::Transform; use common::{ figure::Segment, util::{linear_to_srgba, srgba_to_linear}, @@ -61,7 +62,7 @@ impl<'a> Pipeline for Voxel { pub fn draw_vox( segment: &Segment, output_size: Vec2, - ori: Option>, + transform: Transform, min_samples: Option, ) -> RgbaImage { let scale = min_samples.map_or(1.0, |s| s as f32).sqrt().ceil() as usize; @@ -71,17 +72,35 @@ pub fn draw_vox( let (w, h, d) = segment.size().map(|e| e as f32).into_tuple(); - let mvp = Mat4::::orthographic_rh_no(FrustumPlanes { - left: -1.0, - right: 1.0, - bottom: -1.0, - top: 1.0, - near: 0.0, - far: 1.0, - }) * Mat4::from(ori.unwrap_or(Quaternion::identity())) - * Mat4::rotation_x(-std::f32::consts::PI / 2.0) // TODO: remove - * Mat4::scaling_3d([2.0 / w, 2.0 / h, 2.0 / d]) + let mvp = if transform.orth { + Mat4::::orthographic_rh_no(FrustumPlanes { + left: -1.0, + right: 1.0, + bottom: -1.0, + top: 1.0, + near: 0.0, + far: 1.0, + }) + } else { + Mat4::::perspective_fov_rh_no( + 1.1, // fov + dims[0] as f32, // width + dims[1] as f32, // height + 0.0, + 1.0, + ) + } * Mat4::scaling_3d( + // TODO replace with camera-like parameters? + if transform.stretch { + Vec3::new(2.0 / w, 2.0 / d, 2.0 / h) // Only works with flipped models :( + } else { + let s = w.max(h).max(d); + Vec3::new(2.0 / s, 2.0 / s, 2.0 / s) + } * transform.zoom, + ) * Mat4::translation_3d(transform.offset) + * Mat4::from(transform.ori) * Mat4::translation_3d([-w / 2.0, -h / 2.0, -d / 2.0]); + Voxel { mvp }.draw::, _>( &generate_mesh(segment, Vec3::from(0.0)), &mut color, diff --git a/voxygen/src/ui/img_ids.rs b/voxygen/src/ui/img_ids.rs index 4dbba78796..5623b7952b 100644 --- a/voxygen/src/ui/img_ids.rs +++ b/voxygen/src/ui/img_ids.rs @@ -1,7 +1,8 @@ -use super::Graphic; +use super::{Graphic, Transform}; use common::assets::{load, Error}; use dot_vox::DotVoxData; use image::DynamicImage; +use vek::*; pub enum BlankGraphic {} pub enum ImageGraphic {} @@ -31,7 +32,14 @@ pub enum VoxelMs9Graphic {} impl<'a> GraphicCreator<'a> for VoxelGraphic { type Specifier = &'a str; fn new_graphic(specifier: Self::Specifier) -> Result { - Ok(Graphic::Voxel(load::(specifier)?, None, None)) + Ok(Graphic::Voxel( + load::(specifier)?, + Transform { + ori: Quaternion::rotation_x(-std::f32::consts::PI / 2.0), + ..Default::default() + }, + None, + )) } } impl<'a> GraphicCreator<'a> for VoxelMsGraphic { @@ -39,7 +47,10 @@ impl<'a> GraphicCreator<'a> for VoxelMsGraphic { fn new_graphic(specifier: Self::Specifier) -> Result { Ok(Graphic::Voxel( load::(specifier.0)?, - None, + Transform { + ori: Quaternion::rotation_x(-std::f32::consts::PI / 2.0), + ..Default::default() + }, Some(specifier.1), )) } @@ -49,7 +60,10 @@ impl<'a> GraphicCreator<'a> for VoxelMs4Graphic { fn new_graphic(specifier: Self::Specifier) -> Result { Ok(Graphic::Voxel( load::(specifier)?, - None, + Transform { + ori: Quaternion::rotation_x(-std::f32::consts::PI / 2.0), + ..Default::default() + }, Some(4), )) } @@ -59,7 +73,10 @@ impl<'a> GraphicCreator<'a> for VoxelMs9Graphic { fn new_graphic(specifier: Self::Specifier) -> Result { Ok(Graphic::Voxel( load::(specifier)?, - None, + Transform { + ori: Quaternion::rotation_x(-std::f32::consts::PI / 2.0), + ..Default::default() + }, Some(9), )) } diff --git a/voxygen/src/ui/mod.rs b/voxygen/src/ui/mod.rs index a8f8f5fd53..62f3ae9dd2 100644 --- a/voxygen/src/ui/mod.rs +++ b/voxygen/src/ui/mod.rs @@ -9,7 +9,7 @@ pub mod img_ids; mod font_ids; pub use event::Event; -pub use graphic::Graphic; +pub use graphic::{Graphic, Transform}; pub use scale::{Scale, ScaleMode}; pub use widgets::{ image_frame::ImageFrame, @@ -41,7 +41,7 @@ use conrod_core::{ Rect, UiBuilder, UiCell, }; use graphic::Rotation; -use log::warn; +use log::{error, warn}; use std::{ fs::File, io::{BufReader, Read}, @@ -175,6 +175,17 @@ impl Ui { } } + pub fn replace_graphic(&mut self, id: image::Id, graphic: Graphic) { + let graphic_id = if let Some((graphic_id, _)) = self.image_map.get(&id) { + *graphic_id + } else { + error!("Failed to replace graphic the provided id is not in use"); + return; + }; + self.cache.replace_graphic(graphic_id, graphic); + self.image_map.replace(id, (graphic_id, Rotation::None)); + } + pub fn new_font(&mut self, font: Arc) -> font::Id { self.ui.fonts.insert(font.as_ref().0.clone()) } diff --git a/world/src/block/mod.rs b/world/src/block/mod.rs index 300ba1e298..9cd41b481c 100644 --- a/world/src/block/mod.rs +++ b/world/src/block/mod.rs @@ -176,10 +176,10 @@ impl<'a> BlockGen<'a> { let wposf = wpos.map(|e| e as f64); let (block, height) = if !only_structures { - let (_definitely_underground, height, water_height) = + let (_definitely_underground, height, on_cliff, water_height) = if (wposf.z as f32) < alt - 64.0 * chaos { // Shortcut warping - (true, alt, CONFIG.sea_level /*water_level*/) + (true, alt, false, CONFIG.sea_level /*water_level*/) } else { // Apply warping let warp = world @@ -190,9 +190,11 @@ impl<'a> BlockGen<'a> { .mul((chaos - 0.1).max(0.0).powf(2.0)) .mul(48.0); - let height = if (wposf.z as f32) < alt + warp - 10.0 { + let surface_height = alt + warp; + + let (height, on_cliff) = if (wposf.z as f32) < alt + warp - 10.0 { // Shortcut cliffs - alt + warp + (surface_height, false) } else { let turb = Vec2::new( world.sim().gen_ctx.fast_turb_x_nz.get(wposf.div(25.0)) as f32, @@ -209,12 +211,16 @@ impl<'a> BlockGen<'a> { 0.0, ); - (alt + warp).max(cliff_height) + ( + surface_height.max(cliff_height), + cliff_height > surface_height + 16.0, + ) }; ( false, height, + on_cliff, /*(water_level + warp).max(*/ CONFIG.sea_level, /*)*/ ) }; @@ -270,6 +276,11 @@ impl<'a> BlockGen<'a> { && (marble * 3173.7).fract() < 0.6 && humidity > 0.4 { + let treasures = [ + BlockKind::Chest, + //BlockKind::Velorite, + ]; + let flowers = [ BlockKind::BlueFlower, BlockKind::PinkFlower, @@ -288,7 +299,9 @@ impl<'a> BlockGen<'a> { ]; Some(Block::new( - if (height * 1271.0).fract() < 0.1 { + if on_cliff && (height * 1271.0).fract() < 0.015 { + treasures[(height * 731.3) as usize % treasures.len()] + } else if (height * 1271.0).fract() < 0.1 { flowers[(height * 0.2) as usize % flowers.len()] } else { grasses[(height * 103.3) as usize % grasses.len()] @@ -604,6 +617,7 @@ pub fn block_from_structure( .map(|e| e as u8), )), StructureBlock::Fruit => Some(Block::new(BlockKind::Apple, Rgb::new(194, 30, 37))), + StructureBlock::Chest => Some(Block::new(BlockKind::Chest, Rgb::new(0, 0, 0))), StructureBlock::Liana => Some(Block::new( BlockKind::Liana, Lerp::lerp(