mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
Merge branch 'imbris/item-images' into 'master'
Item icons, chests and more See merge request veloren/veloren!573
This commit is contained in:
commit
4742c4bffb
BIN
assets/voxygen/element/bag/slot.vox
(Stored with Git LFS)
BIN
assets/voxygen/element/bag/slot.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/element/buttons/inv_slot.vox
(Stored with Git LFS)
BIN
assets/voxygen/element/buttons/inv_slot.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/element/buttons/inv_slot_sel.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/buttons/inv_slot_sel.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/icons/item_apple.vox
(Stored with Git LFS)
BIN
assets/voxygen/element/icons/item_apple.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/element/icons/item_flower.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/icons/item_flower.png
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/element/icons/item_flower.vox
(Stored with Git LFS)
BIN
assets/voxygen/element/icons/item_flower.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/element/icons/item_grass.vox
(Stored with Git LFS)
BIN
assets/voxygen/element/icons/item_grass.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/element/icons/item_mushroom.vox
(Stored with Git LFS)
BIN
assets/voxygen/element/icons/item_mushroom.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/voxygen/element/not_found.png
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/element/not_found.png
(Stored with Git LFS)
Normal file
Binary file not shown.
56
assets/voxygen/item_image_manifest.ron
Normal file
56
assets/voxygen/item_image_manifest.ron
Normal file
@ -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,
|
||||
),
|
||||
})
|
BIN
assets/voxygen/voxel/sprite/chests/chest.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/chests/chest.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/chests/chest_dark.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/chests/chest_dark.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/chests/chest_demon.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/chests/chest_demon.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/chests/chest_gold.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/chests/chest_gold.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/chests/chest_light.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/chests/chest_light.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/chests/chest_skull.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/chests/chest_skull.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/chests/chest_vines.vox
(Stored with Git LFS)
Normal file
BIN
assets/voxygen/voxel/sprite/chests/chest_vines.vox
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/mushrooms/mushroom-4.vox
(Stored with Git LFS)
BIN
assets/voxygen/voxel/sprite/mushrooms/mushroom-4.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/structure/dungeon/meso_sewer_temple.vox
(Stored with Git LFS)
BIN
assets/world/structure/dungeon/meso_sewer_temple.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/structure/dungeon/ruins.vox
(Stored with Git LFS)
BIN
assets/world/structure/dungeon/ruins.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/structure/natural/tower-ruin.vox
(Stored with Git LFS)
BIN
assets/world/structure/natural/tower-ruin.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/structure/natural/witch-hut.vox
(Stored with Git LFS)
BIN
assets/world/structure/natural/witch-hut.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/tree/mangroves/5.vox
(Stored with Git LFS)
BIN
assets/world/tree/mangroves/5.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/tree/mangroves/7.vox
(Stored with Git LFS)
BIN
assets/world/tree/mangroves/7.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/tree/oak_green/3.vox
(Stored with Git LFS)
BIN
assets/world/tree/oak_green/3.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/tree/oak_green/5.vox
(Stored with Git LFS)
BIN
assets/world/tree/oak_green/5.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/tree/oak_green/9.vox
(Stored with Git LFS)
BIN
assets/world/tree/oak_green/9.vox
(Stored with Git LFS)
Binary file not shown.
BIN
assets/world/tree/oak_stump/3.vox
(Stored with Git LFS)
BIN
assets/world/tree/oak_stump/3.vox
(Stored with Git LFS)
Binary file not shown.
@ -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<Self> {
|
||||
@ -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::<usize>() % 3 {
|
||||
0 => Self::apple(),
|
||||
1 => Self::velorite(),
|
||||
2 => Item::Tool {
|
||||
kind: *(&ALL_TOOLS).choose(&mut rand::thread_rng()).unwrap(),
|
||||
power: 8 + rand::random::<u32>() % (rand::random::<u32>() % 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ pub enum StructureBlock {
|
||||
Water,
|
||||
GreenSludge,
|
||||
Fruit,
|
||||
Chest,
|
||||
Hollow,
|
||||
Liana,
|
||||
Normal(Rgb<u8>),
|
||||
@ -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
|
||||
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -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<Option<(ItemKind, image::Id)>>,
|
||||
selected_slot: Option<usize>,
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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! {
|
||||
|
||||
<ImageGraphic>
|
||||
|
||||
not_found:"voxygen.element.not_found",
|
||||
|
||||
help:"voxygen.element.help",
|
||||
|
||||
charwindow_gradient:"voxygen.element.misc_bg.charwindow",
|
||||
|
163
voxygen/src/hud/item_imgs.rs
Normal file
163
voxygen/src/hud/item_imgs.rs
Normal file
@ -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<ItemKind, ImageSpec>);
|
||||
impl Asset for ItemImagesSpec {
|
||||
const ENDINGS: &'static [&'static str] = &["ron"];
|
||||
fn parse(buf_reader: BufReader<File>) -> Result<Self, assets::Error> {
|
||||
Ok(ron::de::from_reader(buf_reader).expect("Error parsing item images spec"))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ItemImgs {
|
||||
map: HashMap<ItemKind, Id>,
|
||||
indicator: ReloadIndicator,
|
||||
}
|
||||
impl ItemImgs {
|
||||
pub fn new(ui: &mut Ui) -> Self {
|
||||
let mut indicator = ReloadIndicator::new();
|
||||
Self {
|
||||
map: assets::load_watched::<ItemImagesSpec>(
|
||||
"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::<ItemImagesSpec>("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<Id> {
|
||||
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<DotVoxData> {
|
||||
let full_specifier: String = ["voxygen.", specifier].concat();
|
||||
match assets::load::<DotVoxData>(full_specifier.as_str()) {
|
||||
Ok(dot_vox) => dot_vox,
|
||||
Err(_) => {
|
||||
error!(
|
||||
"Could not load vox file for item images: {}",
|
||||
full_specifier
|
||||
);
|
||||
assets::load_expect::<DotVoxData>("voxygen.voxel.not_found")
|
||||
}
|
||||
}
|
||||
}
|
||||
fn graceful_load_img(specifier: &str) -> Arc<DynamicImage> {
|
||||
let full_specifier: String = ["voxygen.", specifier].concat();
|
||||
match assets::load::<DynamicImage>(full_specifier.as_str()) {
|
||||
Ok(img) => img,
|
||||
Err(_) => {
|
||||
error!(
|
||||
"Could not load image file for item images: {}",
|
||||
full_specifier
|
||||
);
|
||||
assets::load_expect::<DynamicImage>("voxygen.element.not_found")
|
||||
}
|
||||
}
|
||||
}
|
@ -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<ClientEvent>,
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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).
|
||||
|
@ -217,7 +217,7 @@ impl<V: RectRasterableVol<Vox = Block> + ReadVol + Debug> Meshable<TerrainPipeli
|
||||
self,
|
||||
pos,
|
||||
offs,
|
||||
&colors,
|
||||
&colors, //&[[[colors[1][1][1]; 3]; 3]; 3],
|
||||
|pos, norm, col, ao, light| {
|
||||
TerrainVertex::new(pos, norm, col, light.min(ao))
|
||||
},
|
||||
|
@ -146,7 +146,7 @@ impl Camera {
|
||||
let t = self.tgt_dist + delta;
|
||||
match self.mode {
|
||||
CameraMode::ThirdPerson => {
|
||||
if t < 2_f32 {
|
||||
if t < 1_f32 {
|
||||
self.set_mode(CameraMode::FirstPerson);
|
||||
} else {
|
||||
self.tgt_dist = t;
|
||||
|
@ -355,8 +355,8 @@ pub fn mesh_main(item: Option<&Item>) -> Mesh<FigurePipeline> {
|
||||
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)),
|
||||
},
|
||||
|
@ -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
|
||||
|
@ -135,6 +135,10 @@ fn sprite_config_for(kind: BlockKind) -> Option<SpriteConfig> {
|
||||
variations: 1,
|
||||
wind_sway: 0.0,
|
||||
}),
|
||||
BlockKind::Chest => Some(SpriteConfig {
|
||||
variations: 4,
|
||||
wind_sway: 0.0,
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@ -621,6 +625,34 @@ impl<V: RectRasterableVol> Terrain<V> {
|
||||
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(),
|
||||
|
@ -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();
|
||||
|
@ -8,10 +8,30 @@ use log::{error, warn};
|
||||
use std::sync::Arc;
|
||||
use vek::*;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Transform {
|
||||
pub ori: Quaternion<f32>,
|
||||
pub offset: Vec3<f32>,
|
||||
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<DynamicImage>),
|
||||
Voxel(Arc<DotVoxData>, Option<Quaternion<f32>>, Option<u8>),
|
||||
Voxel(Arc<DotVoxData>, Transform, Option<u8>),
|
||||
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::<Vec<_>>();
|
||||
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;
|
||||
|
@ -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<u16>,
|
||||
ori: Option<Quaternion<f32>>,
|
||||
transform: Transform,
|
||||
min_samples: Option<u8>,
|
||||
) -> 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::<f32>::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::<f32>::orthographic_rh_no(FrustumPlanes {
|
||||
left: -1.0,
|
||||
right: 1.0,
|
||||
bottom: -1.0,
|
||||
top: 1.0,
|
||||
near: 0.0,
|
||||
far: 1.0,
|
||||
})
|
||||
} else {
|
||||
Mat4::<f32>::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::<rasterizer::Triangles<_>, _>(
|
||||
&generate_mesh(segment, Vec3::from(0.0)),
|
||||
&mut color,
|
||||
|
@ -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<Graphic, Error> {
|
||||
Ok(Graphic::Voxel(load::<DotVoxData>(specifier)?, None, None))
|
||||
Ok(Graphic::Voxel(
|
||||
load::<DotVoxData>(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<Graphic, Error> {
|
||||
Ok(Graphic::Voxel(
|
||||
load::<DotVoxData>(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<Graphic, Error> {
|
||||
Ok(Graphic::Voxel(
|
||||
load::<DotVoxData>(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<Graphic, Error> {
|
||||
Ok(Graphic::Voxel(
|
||||
load::<DotVoxData>(specifier)?,
|
||||
None,
|
||||
Transform {
|
||||
ori: Quaternion::rotation_x(-std::f32::consts::PI / 2.0),
|
||||
..Default::default()
|
||||
},
|
||||
Some(9),
|
||||
))
|
||||
}
|
||||
|
@ -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>) -> font::Id {
|
||||
self.ui.fonts.insert(font.as_ref().0.clone())
|
||||
}
|
||||
|
@ -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(
|
||||
|
Loading…
Reference in New Issue
Block a user