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,
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,
}
}
}

View File

@ -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

View File

@ -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),
}
}
}

View File

@ -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,
}
}

View File

@ -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

View File

@ -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,
);
}

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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;

View File

@ -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,
},
}
}

View File

@ -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,11 +173,15 @@ impl<'a> Widget for Bag<'a> {
let is_selected = Some(i) == state.selected_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(
state.ids.inv_alignment,
4.0 + y as f64 * (40.0 + 4.0),
4.0 + x as f64 * (40.0 + 4.0),
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)
@ -178,8 +195,8 @@ impl<'a> Widget for Bag<'a> {
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,17 +222,27 @@ 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
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])
//.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);
}

View File

@ -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",

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 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
}

View File

@ -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

View File

@ -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

View File

@ -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).

View File

@ -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))
},

View File

@ -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;

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::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)),
},

View File

@ -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

View File

@ -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(),

View File

@ -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();

View File

@ -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;

View File

@ -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 {
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,
}) * 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])
})
} 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,

View File

@ -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),
))
}

View File

@ -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())
}

View File

@ -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(