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
e40ffa4b02
Binary file not shown.
Binary file not shown.
BIN
assets/voxygen/element/buttons/inv_slot_sel.vox
Normal file
BIN
assets/voxygen/element/buttons/inv_slot_sel.vox
Normal file
Binary file not shown.
Binary file not shown.
BIN
assets/voxygen/element/icons/item_flower.png
Normal file
BIN
assets/voxygen/element/icons/item_flower.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
assets/voxygen/element/not_found.png
Normal file
BIN
assets/voxygen/element/not_found.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.0 KiB |
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
Normal file
BIN
assets/voxygen/voxel/sprite/chests/chest.vox
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/chests/chest_dark.vox
Normal file
BIN
assets/voxygen/voxel/sprite/chests/chest_dark.vox
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/chests/chest_demon.vox
Normal file
BIN
assets/voxygen/voxel/sprite/chests/chest_demon.vox
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/chests/chest_gold.vox
Normal file
BIN
assets/voxygen/voxel/sprite/chests/chest_gold.vox
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/chests/chest_light.vox
Normal file
BIN
assets/voxygen/voxel/sprite/chests/chest_light.vox
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/chests/chest_skull.vox
Normal file
BIN
assets/voxygen/voxel/sprite/chests/chest_skull.vox
Normal file
Binary file not shown.
BIN
assets/voxygen/voxel/sprite/chests/chest_vines.vox
Normal file
BIN
assets/voxygen/voxel/sprite/chests/chest_vines.vox
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
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…
x
Reference in New Issue
Block a user