Item icons, chests and more

This commit is contained in:
Monty Marz 2019-10-09 19:28:05 +00:00
parent c0732d7787
commit d82ec6715a
57 changed files with 731 additions and 160 deletions

BIN
assets/voxygen/element/bag/slot.vox (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

BIN
assets/voxygen/element/buttons/inv_slot_sel.vox (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

BIN
assets/voxygen/element/icons/item_flower.png (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
assets/voxygen/element/not_found.png (Stored with Git LFS) Normal file

Binary file not shown.

View 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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
assets/world/structure/dungeon/ruins.vox (Stored with Git LFS)

Binary file not shown.

Binary file not shown.

Binary file not shown.

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)

Binary file not shown.

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)

Binary file not shown.

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)

Binary file not shown.

View File

@ -3,13 +3,14 @@ use crate::{
effect::Effect, effect::Effect,
terrain::{Block, BlockKind}, terrain::{Block, BlockKind},
}; };
use rand::prelude::*;
use specs::{Component, FlaggedStorage}; use specs::{Component, FlaggedStorage};
use specs_idvs::IDVStorage; use specs_idvs::IDVStorage;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Tool { pub enum Tool {
Daggers, Dagger,
SwordShield, Shield,
Sword, Sword,
Axe, Axe,
Hammer, Hammer,
@ -20,20 +21,43 @@ pub enum Tool {
impl Tool { impl Tool {
pub fn name(&self) -> &'static str { pub fn name(&self) -> &'static str {
match self { match self {
Tool::Daggers => "daggers", Tool::Dagger => "Dagger",
Tool::SwordShield => "sword and shield", Tool::Shield => "Shield",
Tool::Sword => "sword", Tool::Sword => "Sword",
Tool::Axe => "axe", Tool::Axe => "Axe",
Tool::Hammer => "hammer", Tool::Hammer => "Hammer",
Tool::Bow => "bow", Tool::Bow => "Bow",
Tool::Staff => "staff", 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] = [ pub const ALL_TOOLS: [Tool; 7] = [
Tool::Daggers, Tool::Dagger,
Tool::SwordShield, Tool::Shield,
Tool::Sword, Tool::Sword,
Tool::Axe, Tool::Axe,
Tool::Hammer, Tool::Hammer,
@ -43,7 +67,7 @@ pub const ALL_TOOLS: [Tool; 7] = [
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Armor { 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, Helmet,
Shoulders, Shoulders,
Chestplate, Chestplate,
@ -60,19 +84,23 @@ pub enum Armor {
impl Armor { impl Armor {
pub fn name(&self) -> &'static str { pub fn name(&self) -> &'static str {
match self { match self {
Armor::Helmet => "helmet", Armor::Helmet => "Helmet",
Armor::Shoulders => "shoulder pads", Armor::Shoulders => "Shoulder Pads",
Armor::Chestplate => "chestplate", Armor::Chestplate => "Chestplate",
Armor::Belt => "belt", Armor::Belt => "Belt",
Armor::Gloves => "gloves", Armor::Gloves => "Gloves",
Armor::Pants => "pants", Armor::Pants => "Pants",
Armor::Boots => "boots", Armor::Boots => "Boots",
Armor::Back => "back", Armor::Back => "Back",
Armor::Tabard => "tabard", Armor::Tabard => "Tabard",
Armor::Gem => "gem", Armor::Gem => "Gem",
Armor::Necklace => "necklace", Armor::Necklace => "Necklace",
} }
} }
pub fn description(&self) -> &'static str {
self.name()
}
} }
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
@ -86,10 +114,19 @@ pub enum Consumable {
impl Consumable { impl Consumable {
pub fn name(&self) -> &'static str { pub fn name(&self) -> &'static str {
match self { match self {
Consumable::Apple => "apple", Consumable::Apple => "Apple",
Consumable::Potion => "potion", Consumable::Potion => "Potion",
Consumable::Mushroom => "mushroom", Consumable::Mushroom => "Mushroom",
Consumable::Velorite => "velorite", 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 { impl Ingredient {
pub fn name(&self) -> &'static str { pub fn name(&self) -> &'static str {
match self { match self {
Ingredient::Flower => "flower", Ingredient::Flower => "Flower",
Ingredient::Grass => "grass", 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)] #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Debug { pub enum Debug {
Boost, Boost,
Possess,
} }
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
@ -119,11 +164,17 @@ pub enum Item {
Tool { Tool {
kind: Tool, kind: Tool,
power: u32, power: u32,
stamina: i32,
strength: i32,
dexterity: i32,
intelligence: i32,
}, },
Armor { Armor {
kind: Armor, kind: Armor,
defense: i32, stamina: i32,
health_bonus: i32, strength: i32,
dexterity: i32,
intelligence: i32,
}, },
Consumable { Consumable {
kind: Consumable, kind: Consumable,
@ -141,23 +192,43 @@ impl Item {
Item::Tool { kind, .. } => kind.name(), Item::Tool { kind, .. } => kind.name(),
Item::Armor { kind, .. } => kind.name(), Item::Armor { kind, .. } => kind.name(),
Item::Consumable { kind, .. } => kind.name(), Item::Consumable { kind, .. } => kind.name(),
Item::Ingredient { kind } => kind.name(), Item::Ingredient { kind, .. } => kind.name(),
Item::Debug(_) => "Debugging item", 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 { pub fn category(&self) -> &'static str {
match self { match self {
Item::Tool { .. } => "tool", Item::Tool { .. } => "Tool",
Item::Armor { .. } => "armour", Item::Armor { .. } => "Armor",
Item::Consumable { .. } => "consumable", Item::Consumable { .. } => "Consumable",
Item::Ingredient { .. } => "ingredient", Item::Ingredient { .. } => "Ingredient",
Item::Debug(_) => "debug", Item::Debug(_) => "Debug",
} }
} }
pub fn description(&self) -> String { 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> { pub fn try_reclaim_from_block(block: Block) -> Option<Self> {
@ -175,6 +246,19 @@ impl Item {
BlockKind::LongGrass => Some(Self::grass()), BlockKind::LongGrass => Some(Self::grass()),
BlockKind::MediumGrass => Some(Self::grass()), BlockKind::MediumGrass => Some(Self::grass()),
BlockKind::ShortGrass => 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, _ => None,
} }
} }
@ -184,7 +268,7 @@ impl Item {
pub fn apple() -> Self { pub fn apple() -> Self {
Item::Consumable { Item::Consumable {
kind: Consumable::Apple, 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 { pub fn velorite() -> Self {
Item::Consumable { Item::Consumable {
kind: Consumable::Mushroom, kind: Consumable::Velorite,
effect: Effect::Xp(250), effect: Effect::Xp(50),
} }
} }
@ -220,6 +304,10 @@ impl Default for Item {
Item::Tool { Item::Tool {
kind: Tool::Hammer, kind: Tool::Hammer,
power: 0, power: 0,
stamina: 0,
strength: 0,
dexterity: 0,
intelligence: 0,
} }
} }
} }

View File

@ -1,4 +1,3 @@
//Re-Exports
pub mod item; pub mod item;
// Reexports // Reexports
@ -77,22 +76,42 @@ impl Default for Inventory {
inventory.push(Item::Tool { inventory.push(Item::Tool {
kind: Tool::Bow, kind: Tool::Bow,
power: 10, power: 10,
stamina: 0,
strength: 0,
dexterity: 0,
intelligence: 0,
}); });
inventory.push(Item::Tool { inventory.push(Item::Tool {
kind: Tool::Daggers, kind: Tool::Dagger,
power: 10, power: 10,
stamina: 0,
strength: 0,
dexterity: 0,
intelligence: 0,
}); });
inventory.push(Item::Tool { inventory.push(Item::Tool {
kind: Tool::Sword, kind: Tool::Sword,
power: 10, power: 10,
stamina: 0,
strength: 0,
dexterity: 0,
intelligence: 0,
}); });
inventory.push(Item::Tool { inventory.push(Item::Tool {
kind: Tool::Axe, kind: Tool::Axe,
power: 10, power: 10,
stamina: 0,
strength: 0,
dexterity: 0,
intelligence: 0,
}); });
inventory.push(Item::Tool { inventory.push(Item::Tool {
kind: Tool::Hammer, kind: Tool::Hammer,
power: 10, power: 10,
stamina: 0,
strength: 0,
dexterity: 0,
intelligence: 0,
}); });
inventory inventory

View File

@ -6,3 +6,12 @@ pub enum Effect {
Health(i32, comp::HealthSource), Health(i32, comp::HealthSource),
Xp(i64), Xp(i64),
} }
impl Effect {
pub fn info(&self) -> String {
match self {
Effect::Health(n, _) => format!("{:+} health", n),
Effect::Xp(n) => format!("{:+} exp", n),
}
}
}

View File

@ -30,6 +30,7 @@ pub enum BlockKind {
Mushroom, Mushroom,
Liana, Liana,
Velorite, Velorite,
Chest,
} }
impl BlockKind { impl BlockKind {
@ -63,6 +64,7 @@ impl BlockKind {
BlockKind::Mushroom => true, BlockKind::Mushroom => true,
BlockKind::Liana => true, BlockKind::Liana => true,
BlockKind::Velorite => true, BlockKind::Velorite => true,
BlockKind::Chest => true,
_ => false, _ => false,
} }
} }
@ -98,6 +100,7 @@ impl BlockKind {
BlockKind::Mushroom => false, BlockKind::Mushroom => false,
BlockKind::Liana => false, BlockKind::Liana => false,
BlockKind::Velorite => false, BlockKind::Velorite => false,
BlockKind::Chest => false,
_ => true, _ => true,
} }
} }
@ -125,6 +128,7 @@ impl BlockKind {
BlockKind::Apple => true, BlockKind::Apple => true,
BlockKind::Mushroom => false, BlockKind::Mushroom => false,
BlockKind::Liana => false, BlockKind::Liana => false,
BlockKind::Chest => true,
_ => true, _ => true,
} }
} }
@ -144,6 +148,7 @@ impl BlockKind {
BlockKind::Apple => true, BlockKind::Apple => true,
BlockKind::Mushroom => true, BlockKind::Mushroom => true,
BlockKind::Velorite => true, BlockKind::Velorite => true,
BlockKind::Chest => true,
_ => false, _ => false,
} }
} }

View File

@ -20,6 +20,7 @@ pub enum StructureBlock {
Water, Water,
GreenSludge, GreenSludge,
Fruit, Fruit,
Chest,
Hollow, Hollow,
Liana, Liana,
Normal(Rgb<u8>), Normal(Rgb<u8>),
@ -116,6 +117,7 @@ impl Asset for Structure {
6 => StructureBlock::GreenSludge, 6 => StructureBlock::GreenSludge,
7 => StructureBlock::Fruit, 7 => StructureBlock::Fruit,
9 => StructureBlock::Liana, 9 => StructureBlock::Liana,
10 => StructureBlock::Chest,
15 => StructureBlock::Hollow, 15 => StructureBlock::Hollow,
index => { index => {
let color = palette let color = palette

View File

@ -567,6 +567,10 @@ impl Server {
Some(comp::Item::Tool { Some(comp::Item::Tool {
kind: comp::item::Tool::Sword, kind: comp::item::Tool::Sword,
power: 5, power: 5,
stamina: 0,
strength: 0,
dexterity: 0,
intelligence: 0,
}), }),
); );
let body = comp::Body::Humanoid(comp::humanoid::Body::random()); let body = comp::Body::Humanoid(comp::humanoid::Body::random());
@ -588,6 +592,10 @@ impl Server {
Some(comp::Item::Tool { Some(comp::Item::Tool {
kind: comp::item::Tool::Sword, kind: comp::item::Tool::Sword,
power: 10, power: 10,
stamina: 0,
strength: 0,
dexterity: 0,
intelligence: 0,
}), }),
); );
body = comp::Body::Humanoid(comp::humanoid::Body::random()); body = comp::Body::Humanoid(comp::humanoid::Body::random());
@ -1020,7 +1028,14 @@ impl Server {
client, client,
name, name,
body, 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, &server_settings,
); );
} }

View File

@ -153,7 +153,7 @@ impl Animation for BlockAnimation {
* Quaternion::rotation_z(0.0); * Quaternion::rotation_z(0.0);
next.weapon.scale = Vec3::one(); next.weapon.scale = Vec3::one();
} }
Tool::SwordShield => { Tool::Shield => {
next.l_hand.offset = Vec3::new( next.l_hand.offset = Vec3::new(
-6.0 + wave_ultra_slow_cos * 1.0, -6.0 + wave_ultra_slow_cos * 1.0,
3.5 + wave_ultra_slow_cos * 0.5, 3.5 + wave_ultra_slow_cos * 0.5,
@ -203,7 +203,7 @@ impl Animation for BlockAnimation {
* Quaternion::rotation_z(0.0); * Quaternion::rotation_z(0.0);
next.weapon.scale = Vec3::one(); next.weapon.scale = Vec3::one();
} }
Tool::Daggers => { Tool::Dagger => {
next.l_hand.offset = Vec3::new( next.l_hand.offset = Vec3::new(
-6.0 + wave_ultra_slow_cos * 1.0, -6.0 + wave_ultra_slow_cos * 1.0,
3.5 + wave_ultra_slow_cos * 0.5, 3.5 + wave_ultra_slow_cos * 0.5,

View File

@ -152,7 +152,7 @@ impl Animation for BlockIdleAnimation {
* Quaternion::rotation_z(0.0); * Quaternion::rotation_z(0.0);
next.weapon.scale = Vec3::one(); next.weapon.scale = Vec3::one();
} }
Tool::SwordShield => { Tool::Shield => {
next.l_hand.offset = Vec3::new( next.l_hand.offset = Vec3::new(
-6.0 + wave_ultra_slow_cos * 1.0, -6.0 + wave_ultra_slow_cos * 1.0,
3.5 + wave_ultra_slow_cos * 0.5, 3.5 + wave_ultra_slow_cos * 0.5,
@ -202,7 +202,7 @@ impl Animation for BlockIdleAnimation {
* Quaternion::rotation_z(0.0); * Quaternion::rotation_z(0.0);
next.weapon.scale = Vec3::one(); next.weapon.scale = Vec3::one();
} }
Tool::Daggers => { Tool::Dagger => {
next.l_hand.offset = Vec3::new( next.l_hand.offset = Vec3::new(
-6.0 + wave_ultra_slow_cos * 1.0, -6.0 + wave_ultra_slow_cos * 1.0,
3.5 + wave_ultra_slow_cos * 0.5, 3.5 + wave_ultra_slow_cos * 0.5,

View File

@ -160,7 +160,7 @@ impl Animation for CidleAnimation {
* Quaternion::rotation_z(0.0); * Quaternion::rotation_z(0.0);
next.weapon.scale = Vec3::one(); next.weapon.scale = Vec3::one();
} }
Tool::SwordShield => { Tool::Shield => {
next.l_hand.offset = Vec3::new( next.l_hand.offset = Vec3::new(
-6.0 + wave_ultra_slow_cos * 1.0, -6.0 + wave_ultra_slow_cos * 1.0,
3.5 + wave_ultra_slow_cos * 0.5, 3.5 + wave_ultra_slow_cos * 0.5,
@ -214,7 +214,7 @@ impl Animation for CidleAnimation {
* Quaternion::rotation_z(0.85); * Quaternion::rotation_z(0.85);
next.weapon.scale = Vec3::one(); next.weapon.scale = Vec3::one();
} }
Tool::Daggers => { Tool::Dagger => {
next.l_hand.offset = Vec3::new( next.l_hand.offset = Vec3::new(
-6.0 + wave_ultra_slow_cos * 1.0, -6.0 + wave_ultra_slow_cos * 1.0,
3.5 + wave_ultra_slow_cos * 0.5, 3.5 + wave_ultra_slow_cos * 0.5,

View File

@ -96,7 +96,7 @@ impl Animation for WieldAnimation {
* Quaternion::rotation_z(0.0); * Quaternion::rotation_z(0.0);
next.weapon.scale = Vec3::one(); next.weapon.scale = Vec3::one();
} }
Tool::SwordShield => { Tool::Shield => {
next.l_hand.offset = Vec3::new(-6.0, 3.5, 0.0); next.l_hand.offset = Vec3::new(-6.0, 3.5, 0.0);
next.l_hand.ori = Quaternion::rotation_x(-0.3); next.l_hand.ori = Quaternion::rotation_x(-0.3);
next.l_hand.scale = Vec3::one() * 1.01; next.l_hand.scale = Vec3::one() * 1.01;
@ -134,7 +134,7 @@ impl Animation for WieldAnimation {
* Quaternion::rotation_z(0.85); * Quaternion::rotation_z(0.85);
next.weapon.scale = Vec3::one(); next.weapon.scale = Vec3::one();
} }
Tool::Daggers => { Tool::Dagger => {
next.l_hand.offset = Vec3::new(-6.0, 3.5, 0.0); next.l_hand.offset = Vec3::new(-6.0, 3.5, 0.0);
next.l_hand.ori = Quaternion::rotation_x(-0.3); next.l_hand.ori = Quaternion::rotation_x(-0.3);
next.l_hand.scale = Vec3::one() * 1.01; next.l_hand.scale = Vec3::one() * 1.01;

View File

@ -150,20 +150,20 @@ impl<'a> From<&'a comp::humanoid::Body> for SkeletonAttr {
Tool::Sword => 0.0, Tool::Sword => 0.0,
Tool::Axe => 3.0, Tool::Axe => 3.0,
Tool::Hammer => 0.0, Tool::Hammer => 0.0,
Tool::SwordShield => 3.0, Tool::Shield => 3.0,
Tool::Staff => 3.0, Tool::Staff => 3.0,
Tool::Bow => 0.0, Tool::Bow => 0.0,
Tool::Daggers => 0.0, Tool::Dagger => 0.0,
}, },
weapon_y: match Tool::Hammer { weapon_y: match Tool::Hammer {
// TODO: Inventory // TODO: Inventory
Tool::Sword => -1.25, Tool::Sword => -1.25,
Tool::Axe => 0.0, Tool::Axe => 0.0,
Tool::Hammer => -2.0, Tool::Hammer => -2.0,
Tool::SwordShield => 0.0, Tool::Shield => 0.0,
Tool::Staff => 0.0, Tool::Staff => 0.0,
Tool::Bow => -2.0, Tool::Bow => -2.0,
Tool::Daggers => -2.0, Tool::Dagger => -2.0,
}, },
} }
} }

View File

@ -1,11 +1,12 @@
use super::{ use super::{
img_ids::{Imgs, ImgsRot}, img_ids::{Imgs, ImgsRot},
item_imgs::{ItemImgs, ItemKind},
Event as HudEvent, Fonts, TEXT_COLOR, Event as HudEvent, Fonts, TEXT_COLOR,
}; };
use crate::ui::{ImageFrame, Tooltip, TooltipManager, Tooltipable}; use crate::ui::{ImageFrame, Tooltip, TooltipManager, Tooltipable};
use client::Client; use client::Client;
use conrod_core::{ use conrod_core::{
color, color, image,
position::Relative, position::Relative,
widget::{self, Button, Image, Rectangle /*, Scrollbar*/}, widget::{self, Button, Image, Rectangle /*, Scrollbar*/},
widget_ids, Color, Labelable, Positionable, Sizeable, Widget, WidgetCommon, widget_ids, Color, Labelable, Positionable, Sizeable, Widget, WidgetCommon,
@ -33,6 +34,7 @@ widget_ids! {
pub struct Bag<'a> { pub struct Bag<'a> {
client: &'a Client, client: &'a Client,
imgs: &'a Imgs, imgs: &'a Imgs,
item_imgs: &'a ItemImgs,
fonts: &'a Fonts, fonts: &'a Fonts,
#[conrod(common_builder)] #[conrod(common_builder)]
common: widget::CommonBuilder, common: widget::CommonBuilder,
@ -44,6 +46,7 @@ impl<'a> Bag<'a> {
pub fn new( pub fn new(
client: &'a Client, client: &'a Client,
imgs: &'a Imgs, imgs: &'a Imgs,
item_imgs: &'a ItemImgs,
fonts: &'a Fonts, fonts: &'a Fonts,
rot_imgs: &'a ImgsRot, rot_imgs: &'a ImgsRot,
tooltip_manager: &'a mut TooltipManager, tooltip_manager: &'a mut TooltipManager,
@ -51,6 +54,7 @@ impl<'a> Bag<'a> {
Self { Self {
client, client,
imgs, imgs,
item_imgs,
fonts, fonts,
common: widget::CommonBuilder::default(), common: widget::CommonBuilder::default(),
rot_imgs, rot_imgs,
@ -61,6 +65,7 @@ impl<'a> Bag<'a> {
pub struct State { pub struct State {
ids: Ids, ids: Ids,
img_id_cache: Vec<Option<(ItemKind, image::Id)>>,
selected_slot: Option<usize>, 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 { fn init_state(&self, id_gen: widget::id::Generator) -> Self::State {
State { State {
ids: Ids::new(id_gen), ids: Ids::new(id_gen),
img_id_cache: Vec::new(),
selected_slot: None, selected_slot: None,
} }
} }
@ -111,27 +117,28 @@ impl<'a> Widget for Bag<'a> {
) )
}) })
.title_font_size(15) .title_font_size(15)
.desc_font_size(10) .parent(ui.window)
.desc_font_size(12)
.title_text_color(TEXT_COLOR) .title_text_color(TEXT_COLOR)
.desc_text_color(TEXT_COLOR); .desc_text_color(TEXT_COLOR);
// Bag parts // Bag parts
Image::new(self.imgs.bag_bot) 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) .bottom_right_with_margins_on(ui.window, 60.0, 5.0)
.set(state.ids.bag_bot, ui); .set(state.ids.bag_bot, ui);
let mid_height = ((inventory.len() + 4) / 5) as f64 * 44.0; let mid_height = ((inventory.len() + 4) / 5) as f64 * 44.0;
Image::new(self.imgs.bag_mid) 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) .up_from(state.ids.bag_bot, 0.0)
.set(state.ids.bag_mid, ui); .set(state.ids.bag_mid, ui);
Image::new(self.imgs.bag_top) Image::new(self.imgs.bag_top)
.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) .up_from(state.ids.bag_mid, 0.0)
.set(state.ids.bag_top, ui); .set(state.ids.bag_top, ui);
// Alignment for Grid // 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) .top_left_with_margins_on(state.ids.bag_mid, 0.0, 3.0 * BAG_SCALE)
.scroll_kids_vertically() .scroll_kids_vertically()
.set(state.ids.inv_alignment, ui); .set(state.ids.inv_alignment, ui);
@ -151,6 +158,12 @@ impl<'a> Widget for Bag<'a> {
.resize(inventory.len(), &mut ui.widget_id_generator()); .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 // Display inventory contents
for (i, item) in inventory.slots().iter().enumerate() { for (i, item) in inventory.slots().iter().enumerate() {
@ -160,11 +173,15 @@ impl<'a> Widget for Bag<'a> {
let is_selected = Some(i) == state.selected_slot; let is_selected = Some(i) == state.selected_slot;
// Slot // Slot
let slot_widget = Button::image(self.imgs.inv_slot) let slot_widget = Button::image(if !is_selected {
self.imgs.inv_slot
} else {
self.imgs.inv_slot_sel
})
.top_left_with_margins_on( .top_left_with_margins_on(
state.ids.inv_alignment, state.ids.inv_alignment,
4.0 + y as f64 * (40.0 + 4.0), 0.0 + y as f64 * (40.0 + 2.0),
4.0 + x as f64 * (40.0 + 4.0), 0.0 + x as f64 * (40.0 + 2.0),
) // conrod uses a (y,x) format for placing... ) // conrod uses a (y,x) format for placing...
// (the margin placement functions do this because that is the same order as "top left") // (the margin placement functions do this because that is the same order as "top left")
.w_h(40.0, 40.0) .w_h(40.0, 40.0)
@ -178,8 +195,8 @@ impl<'a> Widget for Bag<'a> {
slot_widget slot_widget
.with_tooltip( .with_tooltip(
self.tooltip_manager, self.tooltip_manager,
&item.description(), &item.title(),
&item.category(), &format!("{}\n{}", item.info(), item.description()),
&item_tooltip, &item_tooltip,
) )
.set(state.ids.inv_slots[i], ui) .set(state.ids.inv_slots[i], ui)
@ -205,17 +222,27 @@ impl<'a> Widget for Bag<'a> {
state.update(|s| s.selected_slot = selected_slot); state.update(|s| s.selected_slot = selected_slot);
} }
// Item // Item
if item.is_some() { if let Some(kind) = item.as_ref().map(|i| ItemKind::from(i)) {
Button::image(self.imgs.flower) // TODO: Insert variable image depending on the item displayed in that slot Button::image(match &state.img_id_cache[i] {
.w_h(28.0, 28.0) // TODO: Fix height and scale width correctly to that to avoid a stretched item image 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 .middle_of(state.ids.inv_slots[i]) // TODO: Items need to be assigned to a certain slot and then placed like in this example
.label("5x") // TODO: Quantity goes here... //.label("5x") // TODO: Quantity goes here...
.label_font_id(self.fonts.opensans) //.label_font_id(self.fonts.opensans)
.label_font_size(12) //.label_font_size(12)
.label_x(Relative::Scalar(10.0)) //.label_x(Relative::Scalar(10.0))
.label_y(Relative::Scalar(-10.0)) //.label_y(Relative::Scalar(-10.0))
.label_color(TEXT_COLOR) //.label_color(TEXT_COLOR)
.parent(state.ids.inv_slots[i]) //.parent(state.ids.inv_slots[i])
.graphics_for(state.ids.inv_slots[i]) .graphics_for(state.ids.inv_slots[i])
.set(state.ids.items[i], ui); .set(state.ids.items[i], ui);
} }

View File

@ -19,6 +19,7 @@ image_ids! {
bag_contents: "voxygen.element.frames.bag", bag_contents: "voxygen.element.frames.bag",
inv_grid: "voxygen.element.frames.inv_grid", inv_grid: "voxygen.element.frames.inv_grid",
inv_slot: "voxygen.element.buttons.inv_slot", inv_slot: "voxygen.element.buttons.inv_slot",
inv_slot_sel: "voxygen.element.buttons.inv_slot_sel",
grid_inv: "voxygen.element.buttons.grid_inv", grid_inv: "voxygen.element.buttons.grid_inv",
bag_top: "voxygen.element.bag.top", bag_top: "voxygen.element.bag.top",
bag_mid: "voxygen.element.bag.mid", bag_mid: "voxygen.element.bag.mid",
@ -223,6 +224,8 @@ image_ids! {
<ImageGraphic> <ImageGraphic>
not_found:"voxygen.element.not_found",
help:"voxygen.element.help", help:"voxygen.element.help",
charwindow_gradient:"voxygen.element.misc_bg.charwindow", charwindow_gradient:"voxygen.element.misc_bg.charwindow",

View 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")
}
}
}

View File

@ -4,6 +4,7 @@ mod character_window;
mod chat; mod chat;
mod esc_menu; mod esc_menu;
mod img_ids; mod img_ids;
mod item_imgs;
mod map; mod map;
mod minimap; mod minimap;
mod quest; mod quest;
@ -22,6 +23,7 @@ use chat::Chat;
use chrono::NaiveTime; use chrono::NaiveTime;
use esc_menu::EscMenu; use esc_menu::EscMenu;
use img_ids::Imgs; use img_ids::Imgs;
use item_imgs::ItemImgs;
use map::Map; use map::Map;
use minimap::MiniMap; use minimap::MiniMap;
use quest::Quest; use quest::Quest;
@ -370,6 +372,7 @@ pub struct Hud {
ui: Ui, ui: Ui,
ids: Ids, ids: Ids,
imgs: Imgs, imgs: Imgs,
item_imgs: ItemImgs,
fonts: Fonts, fonts: Fonts,
rot_imgs: ImgsRot, rot_imgs: ImgsRot,
new_messages: VecDeque<ClientEvent>, new_messages: VecDeque<ClientEvent>,
@ -394,6 +397,8 @@ impl Hud {
let imgs = Imgs::load(&mut ui).expect("Failed to load images!"); let imgs = Imgs::load(&mut ui).expect("Failed to load images!");
// Load rotation images. // Load rotation images.
let rot_imgs = ImgsRot::load(&mut ui).expect("Failed to load rot 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. // Load fonts.
let fonts = Fonts::load(&mut ui).expect("Failed to load fonts!"); let fonts = Fonts::load(&mut ui).expect("Failed to load fonts!");
@ -401,6 +406,7 @@ impl Hud {
ui, ui,
imgs, imgs,
rot_imgs, rot_imgs,
item_imgs,
fonts, fonts,
ids, ids,
new_messages: VecDeque::new(), new_messages: VecDeque::new(),
@ -743,6 +749,7 @@ impl Hud {
match Bag::new( match Bag::new(
client, client,
&self.imgs, &self.imgs,
&self.item_imgs,
&self.fonts, &self.fonts,
&self.rot_imgs, &self.rot_imgs,
tooltip_manager, tooltip_manager,
@ -1112,6 +1119,10 @@ impl Hud {
&mut global_state.window.renderer_mut(), &mut global_state.window.renderer_mut(),
Some((view_mat, fov)), Some((view_mat, fov)),
); );
// Check if item images need to be reloaded
self.item_imgs.reload_if_changed(&mut self.ui);
events events
} }

View File

@ -97,6 +97,10 @@ impl PlayState for CharSelectionState {
Some(comp::Item::Tool { Some(comp::Item::Tool {
kind: kind, kind: kind,
power: 10, power: 10,
stamina: 0,
strength: 0,
dexterity: 0,
intelligence: 0,
}) })
} else { } else {
None None

View File

@ -939,7 +939,7 @@ impl CharSelectionUi {
.w_h(70.0, 70.0) .w_h(70.0, 70.0)
.right_from(self.ids.sword, 2.0) .right_from(self.ids.sword, 2.0)
.set(self.ids.daggers, ui_widgets); .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 self.imgs.icon_border_pressed
} else { } else {
self.imgs.icon_border self.imgs.icon_border

View File

@ -253,9 +253,8 @@ impl MainMenuUi {
Before you dive into the fun, please keep a few things in mind:\n\ Before you dive into the fun, please keep a few things in mind:\n\
\n\ \n\
- This is a very early alpha. Expect bugs, extremely unfinished gameplay, unpolished mechanics, and missing features. \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\ \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\ \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\ - 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). (provided derived work is also under GPL 3).

View File

@ -217,7 +217,7 @@ impl<V: RectRasterableVol<Vox = Block> + ReadVol + Debug> Meshable<TerrainPipeli
self, self,
pos, pos,
offs, offs,
&colors, &colors, //&[[[colors[1][1][1]; 3]; 3]; 3],
|pos, norm, col, ao, light| { |pos, norm, col, ao, light| {
TerrainVertex::new(pos, norm, col, light.min(ao)) TerrainVertex::new(pos, norm, col, light.min(ao))
}, },

View File

@ -146,7 +146,7 @@ impl Camera {
let t = self.tgt_dist + delta; let t = self.tgt_dist + delta;
match self.mode { match self.mode {
CameraMode::ThirdPerson => { CameraMode::ThirdPerson => {
if t < 2_f32 { if t < 1_f32 {
self.set_mode(CameraMode::FirstPerson); self.set_mode(CameraMode::FirstPerson);
} else { } else {
self.tgt_dist = t; self.tgt_dist = t;

View File

@ -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::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::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::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::Dagger => ("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::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::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)), Tool::Staff => ("weapon.axe.rusty_2h", Vec3::new(-2.5, -6.5, -2.0)),
}, },

View File

@ -132,7 +132,8 @@ impl Scene {
} }
// Zoom the camera when a zoom event occurs // Zoom the camera when a zoom event occurs
Event::Zoom(delta) => { Event::Zoom(delta) => {
self.camera.zoom_switch(delta * 0.3); self.camera
.zoom_switch(delta * (0.05 + self.camera.get_distance() * 0.01));
true true
} }
// All other events are unhandled // All other events are unhandled

View File

@ -135,6 +135,10 @@ fn sprite_config_for(kind: BlockKind) -> Option<SpriteConfig> {
variations: 1, variations: 1,
wind_sway: 0.0, wind_sway: 0.0,
}), }),
BlockKind::Chest => Some(SpriteConfig {
variations: 4,
wind_sway: 0.0,
}),
_ => None, _ => None,
} }
} }
@ -621,6 +625,34 @@ impl<V: RectRasterableVol> Terrain<V> {
Vec3::new(-5.0, -5.0, -5.0), 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() .into_iter()
.collect(), .collect(),

View File

@ -61,6 +61,9 @@ impl Cache {
pub fn add_graphic(&mut self, graphic: Graphic) -> GraphicId { pub fn add_graphic(&mut self, graphic: Graphic) -> GraphicId {
self.graphic_cache.add_graphic(graphic) 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 // Resizes and clears the GraphicCache
pub fn resize_graphic_cache(&mut self, renderer: &mut Renderer) -> Result<(), Error> { pub fn resize_graphic_cache(&mut self, renderer: &mut Renderer) -> Result<(), Error> {
let max_texture_size = renderer.max_texture_size(); let max_texture_size = renderer.max_texture_size();

View File

@ -8,10 +8,30 @@ use log::{error, warn};
use std::sync::Arc; use std::sync::Arc;
use vek::*; 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)] #[derive(Clone)]
pub enum Graphic { pub enum Graphic {
Image(Arc<DynamicImage>), Image(Arc<DynamicImage>),
Voxel(Arc<DotVoxData>, Option<Quaternion<f32>>, Option<u8>), Voxel(Arc<DotVoxData>, Transform, Option<u8>),
Blank, Blank,
} }
@ -72,6 +92,26 @@ impl GraphicCache {
id 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> { pub fn get_graphic(&self, id: Id) -> Option<&Graphic> {
self.graphic_map.get(&id) self.graphic_map.get(&id)
} }
@ -129,9 +169,12 @@ impl GraphicCache {
image::FilterType::Nearest, image::FilterType::Nearest,
) )
.to_rgba(), .to_rgba(),
Some(Graphic::Voxel(ref vox, ori, min_samples)) => { Some(Graphic::Voxel(ref vox, trans, min_samples)) => renderer::draw_vox(
renderer::draw_vox(&vox.as_ref().into(), dims, *ori, *min_samples) &vox.as_ref().into(),
} dims,
trans.clone(),
*min_samples,
),
None => { None => {
warn!("A graphic was requested via an id which is not in use"); warn!("A graphic was requested via an id which is not in use");
return None; return None;

View File

@ -1,3 +1,4 @@
use super::Transform;
use common::{ use common::{
figure::Segment, figure::Segment,
util::{linear_to_srgba, srgba_to_linear}, util::{linear_to_srgba, srgba_to_linear},
@ -61,7 +62,7 @@ impl<'a> Pipeline for Voxel {
pub fn draw_vox( pub fn draw_vox(
segment: &Segment, segment: &Segment,
output_size: Vec2<u16>, output_size: Vec2<u16>,
ori: Option<Quaternion<f32>>, transform: Transform,
min_samples: Option<u8>, min_samples: Option<u8>,
) -> RgbaImage { ) -> RgbaImage {
let scale = min_samples.map_or(1.0, |s| s as f32).sqrt().ceil() as usize; 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 (w, h, d) = segment.size().map(|e| e as f32).into_tuple();
let mvp = Mat4::<f32>::orthographic_rh_no(FrustumPlanes { let mvp = if transform.orth {
Mat4::<f32>::orthographic_rh_no(FrustumPlanes {
left: -1.0, left: -1.0,
right: 1.0, right: 1.0,
bottom: -1.0, bottom: -1.0,
top: 1.0, top: 1.0,
near: 0.0, near: 0.0,
far: 1.0, far: 1.0,
}) * Mat4::from(ori.unwrap_or(Quaternion::identity())) })
* Mat4::rotation_x(-std::f32::consts::PI / 2.0) // TODO: remove } else {
* Mat4::scaling_3d([2.0 / w, 2.0 / h, 2.0 / d]) 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]); * Mat4::translation_3d([-w / 2.0, -h / 2.0, -d / 2.0]);
Voxel { mvp }.draw::<rasterizer::Triangles<_>, _>( Voxel { mvp }.draw::<rasterizer::Triangles<_>, _>(
&generate_mesh(segment, Vec3::from(0.0)), &generate_mesh(segment, Vec3::from(0.0)),
&mut color, &mut color,

View File

@ -1,7 +1,8 @@
use super::Graphic; use super::{Graphic, Transform};
use common::assets::{load, Error}; use common::assets::{load, Error};
use dot_vox::DotVoxData; use dot_vox::DotVoxData;
use image::DynamicImage; use image::DynamicImage;
use vek::*;
pub enum BlankGraphic {} pub enum BlankGraphic {}
pub enum ImageGraphic {} pub enum ImageGraphic {}
@ -31,7 +32,14 @@ pub enum VoxelMs9Graphic {}
impl<'a> GraphicCreator<'a> for VoxelGraphic { impl<'a> GraphicCreator<'a> for VoxelGraphic {
type Specifier = &'a str; type Specifier = &'a str;
fn new_graphic(specifier: Self::Specifier) -> Result<Graphic, Error> { 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 { 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> { fn new_graphic(specifier: Self::Specifier) -> Result<Graphic, Error> {
Ok(Graphic::Voxel( Ok(Graphic::Voxel(
load::<DotVoxData>(specifier.0)?, load::<DotVoxData>(specifier.0)?,
None, Transform {
ori: Quaternion::rotation_x(-std::f32::consts::PI / 2.0),
..Default::default()
},
Some(specifier.1), Some(specifier.1),
)) ))
} }
@ -49,7 +60,10 @@ impl<'a> GraphicCreator<'a> for VoxelMs4Graphic {
fn new_graphic(specifier: Self::Specifier) -> Result<Graphic, Error> { fn new_graphic(specifier: Self::Specifier) -> Result<Graphic, Error> {
Ok(Graphic::Voxel( Ok(Graphic::Voxel(
load::<DotVoxData>(specifier)?, load::<DotVoxData>(specifier)?,
None, Transform {
ori: Quaternion::rotation_x(-std::f32::consts::PI / 2.0),
..Default::default()
},
Some(4), Some(4),
)) ))
} }
@ -59,7 +73,10 @@ impl<'a> GraphicCreator<'a> for VoxelMs9Graphic {
fn new_graphic(specifier: Self::Specifier) -> Result<Graphic, Error> { fn new_graphic(specifier: Self::Specifier) -> Result<Graphic, Error> {
Ok(Graphic::Voxel( Ok(Graphic::Voxel(
load::<DotVoxData>(specifier)?, load::<DotVoxData>(specifier)?,
None, Transform {
ori: Quaternion::rotation_x(-std::f32::consts::PI / 2.0),
..Default::default()
},
Some(9), Some(9),
)) ))
} }

View File

@ -9,7 +9,7 @@ pub mod img_ids;
mod font_ids; mod font_ids;
pub use event::Event; pub use event::Event;
pub use graphic::Graphic; pub use graphic::{Graphic, Transform};
pub use scale::{Scale, ScaleMode}; pub use scale::{Scale, ScaleMode};
pub use widgets::{ pub use widgets::{
image_frame::ImageFrame, image_frame::ImageFrame,
@ -41,7 +41,7 @@ use conrod_core::{
Rect, UiBuilder, UiCell, Rect, UiBuilder, UiCell,
}; };
use graphic::Rotation; use graphic::Rotation;
use log::warn; use log::{error, warn};
use std::{ use std::{
fs::File, fs::File,
io::{BufReader, Read}, 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 { pub fn new_font(&mut self, font: Arc<Font>) -> font::Id {
self.ui.fonts.insert(font.as_ref().0.clone()) self.ui.fonts.insert(font.as_ref().0.clone())
} }

View File

@ -176,10 +176,10 @@ impl<'a> BlockGen<'a> {
let wposf = wpos.map(|e| e as f64); let wposf = wpos.map(|e| e as f64);
let (block, height) = if !only_structures { 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 { if (wposf.z as f32) < alt - 64.0 * chaos {
// Shortcut warping // Shortcut warping
(true, alt, CONFIG.sea_level /*water_level*/) (true, alt, false, CONFIG.sea_level /*water_level*/)
} else { } else {
// Apply warping // Apply warping
let warp = world let warp = world
@ -190,9 +190,11 @@ impl<'a> BlockGen<'a> {
.mul((chaos - 0.1).max(0.0).powf(2.0)) .mul((chaos - 0.1).max(0.0).powf(2.0))
.mul(48.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 // Shortcut cliffs
alt + warp (surface_height, false)
} else { } else {
let turb = Vec2::new( let turb = Vec2::new(
world.sim().gen_ctx.fast_turb_x_nz.get(wposf.div(25.0)) as f32, 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, 0.0,
); );
(alt + warp).max(cliff_height) (
surface_height.max(cliff_height),
cliff_height > surface_height + 16.0,
)
}; };
( (
false, false,
height, height,
on_cliff,
/*(water_level + warp).max(*/ CONFIG.sea_level, /*)*/ /*(water_level + warp).max(*/ CONFIG.sea_level, /*)*/
) )
}; };
@ -270,6 +276,11 @@ impl<'a> BlockGen<'a> {
&& (marble * 3173.7).fract() < 0.6 && (marble * 3173.7).fract() < 0.6
&& humidity > 0.4 && humidity > 0.4
{ {
let treasures = [
BlockKind::Chest,
//BlockKind::Velorite,
];
let flowers = [ let flowers = [
BlockKind::BlueFlower, BlockKind::BlueFlower,
BlockKind::PinkFlower, BlockKind::PinkFlower,
@ -288,7 +299,9 @@ impl<'a> BlockGen<'a> {
]; ];
Some(Block::new( 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()] flowers[(height * 0.2) as usize % flowers.len()]
} else { } else {
grasses[(height * 103.3) as usize % grasses.len()] grasses[(height * 103.3) as usize % grasses.len()]
@ -604,6 +617,7 @@ pub fn block_from_structure(
.map(|e| e as u8), .map(|e| e as u8),
)), )),
StructureBlock::Fruit => Some(Block::new(BlockKind::Apple, Rgb::new(194, 30, 37))), 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( StructureBlock::Liana => Some(Block::new(
BlockKind::Liana, BlockKind::Liana,
Lerp::lerp( Lerp::lerp(