mirror of
https://gitlab.com/veloren/veloren.git
synced 2025-07-26 05:12:29 +00:00
Owned sprites
This commit is contained in:
@ -46,6 +46,7 @@ hud-deactivate = Deactivate
|
||||
hud-collect = Collect
|
||||
hud-pick_up = Pick up
|
||||
hud-open = Open
|
||||
hud-steal = Steal
|
||||
hud-use = Use
|
||||
hud-read = Read
|
||||
hud-unlock-requires = Open with { $item }
|
||||
|
@ -593,6 +593,12 @@ impl Block {
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_owned(&self) -> bool {
|
||||
self.get_attr::<sprite::Owned>()
|
||||
.is_ok_and(|sprite::Owned(b)| b)
|
||||
}
|
||||
|
||||
/// The tool required to mine this block. For blocks that cannot be mined,
|
||||
/// `None` is returned.
|
||||
#[inline]
|
||||
@ -657,6 +663,16 @@ impl Block {
|
||||
#[inline]
|
||||
pub fn kind(&self) -> BlockKind { self.kind }
|
||||
|
||||
/// If possible, copy the sprite/color data of the other block.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn with_data_of(mut self, other: Block) -> Self {
|
||||
if self.is_filled() == other.is_filled() {
|
||||
self = self.with_data(other.data());
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// If this block is a fluid, replace its sprite.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
|
@ -114,23 +114,6 @@ sprites! {
|
||||
Loom = 0x27,
|
||||
DismantlingBench = 0x28,
|
||||
RepairBench = 0x29,
|
||||
// Containers
|
||||
Chest = 0x30,
|
||||
DungeonChest0 = 0x31,
|
||||
DungeonChest1 = 0x32,
|
||||
DungeonChest2 = 0x33,
|
||||
DungeonChest3 = 0x34,
|
||||
DungeonChest4 = 0x35,
|
||||
DungeonChest5 = 0x36,
|
||||
CoralChest = 0x37,
|
||||
HaniwaUrn = 0x38,
|
||||
TerracottaChest = 0x39,
|
||||
SahaginChest = 0x3A,
|
||||
CommonLockedChest = 0x3B,
|
||||
ChestBuried = 0x3C,
|
||||
Crate = 0x3D,
|
||||
Barrel = 0x3E,
|
||||
CrateBlock = 0x3F,
|
||||
// Wall
|
||||
HangingBasket = 0x50,
|
||||
HangingSign = 0x51,
|
||||
@ -155,7 +138,7 @@ sprites! {
|
||||
Hearth = 0x72,
|
||||
},
|
||||
// Sprites representing plants that may grow over time (this does not include plant parts, like fruit).
|
||||
Plant = 3 has Growth {
|
||||
Plant = 3 has Growth, Owned {
|
||||
// Cacti
|
||||
BarrelCactus = 0x00,
|
||||
RoundCactus = 0x01,
|
||||
@ -251,7 +234,7 @@ sprites! {
|
||||
},
|
||||
// Solid resources
|
||||
// TODO: Remove small variants, make deposit size be an attribute
|
||||
Resources = 4 {
|
||||
Resources = 4 has Owned {
|
||||
// Gems and ores
|
||||
// Woods and twigs
|
||||
Twigs = 0x00,
|
||||
@ -394,6 +377,24 @@ sprites! {
|
||||
FireBowlGround = 4,
|
||||
MesaLantern = 5,
|
||||
},
|
||||
Container = 9 has Ori, Owned {
|
||||
Chest = 0x00,
|
||||
DungeonChest0 = 0x01,
|
||||
DungeonChest1 = 0x02,
|
||||
DungeonChest2 = 0x03,
|
||||
DungeonChest3 = 0x04,
|
||||
DungeonChest4 = 0x05,
|
||||
DungeonChest5 = 0x06,
|
||||
CoralChest = 0x07,
|
||||
HaniwaUrn = 0x08,
|
||||
TerracottaChest = 0x09,
|
||||
SahaginChest = 0x0A,
|
||||
CommonLockedChest = 0x0B,
|
||||
ChestBuried = 0x0C,
|
||||
Crate = 0x0D,
|
||||
Barrel = 0x0E,
|
||||
CrateBlock = 0x0F,
|
||||
},
|
||||
}
|
||||
|
||||
attributes! {
|
||||
@ -401,6 +402,7 @@ attributes! {
|
||||
Growth { bits: 4, err: Infallible, from: |bits| Ok(Self(bits as u8)), into: |Growth(x)| x as u16 },
|
||||
LightEnabled { bits: 1, err: Infallible, from: |bits| Ok(Self(bits == 1)), into: |LightEnabled(x)| x as u16 },
|
||||
Damage { bits: 3, err: Infallible, from: |bits| Ok(Self(bits as u8)), into: |Damage(x)| x as u16 },
|
||||
Owned { bits: 1, err: Infallible, from: |bits| Ok(Self(bits == 1)), into: |Owned(x)| x as u16 },
|
||||
}
|
||||
|
||||
// The orientation of the sprite, 0..16
|
||||
@ -419,6 +421,9 @@ impl Default for Growth {
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct LightEnabled(pub bool);
|
||||
|
||||
#[derive(Default, Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub struct Owned(pub bool);
|
||||
|
||||
impl Default for LightEnabled {
|
||||
fn default() -> Self { Self(true) }
|
||||
}
|
||||
|
@ -2046,6 +2046,7 @@ impl Hud {
|
||||
vec![(
|
||||
Some(GameInput::Interact),
|
||||
i18n.get_msg("hud-pick_up").to_string(),
|
||||
overitem::TEXT_COLOR,
|
||||
)],
|
||||
)
|
||||
.set(overitem_id, ui_widgets);
|
||||
@ -2077,17 +2078,19 @@ impl Hud {
|
||||
let pos = mat.mul_point(Vec3::broadcast(0.5));
|
||||
let over_pos = pos + Vec3::unit_z() * 0.7;
|
||||
|
||||
let interaction_text = |collect_default| match interaction {
|
||||
let interaction_text = |collect_default, color| match interaction {
|
||||
BlockInteraction::Collect => {
|
||||
vec![(
|
||||
Some(GameInput::Interact),
|
||||
i18n.get_msg(collect_default).to_string(),
|
||||
color,
|
||||
)]
|
||||
},
|
||||
BlockInteraction::Craft(_) => {
|
||||
vec![(
|
||||
Some(GameInput::Interact),
|
||||
i18n.get_msg("hud-use").to_string(),
|
||||
color,
|
||||
)]
|
||||
},
|
||||
BlockInteraction::Unlock(kind) => {
|
||||
@ -2103,19 +2106,23 @@ impl Hud {
|
||||
.unwrap_or_else(|| "modular item".to_string())
|
||||
};
|
||||
|
||||
vec![(Some(GameInput::Interact), match kind {
|
||||
UnlockKind::Free => i18n.get_msg("hud-open").to_string(),
|
||||
UnlockKind::Requires(item_id) => i18n
|
||||
.get_msg_ctx("hud-unlock-requires", &i18n::fluent_args! {
|
||||
"item" => item_name(item_id),
|
||||
})
|
||||
.to_string(),
|
||||
UnlockKind::Consumes(item_id) => i18n
|
||||
.get_msg_ctx("hud-unlock-requires", &i18n::fluent_args! {
|
||||
"item" => item_name(item_id),
|
||||
})
|
||||
.to_string(),
|
||||
})]
|
||||
vec![(
|
||||
Some(GameInput::Interact),
|
||||
match kind {
|
||||
UnlockKind::Free => i18n.get_msg("hud-open").to_string(),
|
||||
UnlockKind::Requires(item_id) => i18n
|
||||
.get_msg_ctx("hud-unlock-requires", &i18n::fluent_args! {
|
||||
"item" => item_name(item_id),
|
||||
})
|
||||
.to_string(),
|
||||
UnlockKind::Consumes(item_id) => i18n
|
||||
.get_msg_ctx("hud-unlock-requires", &i18n::fluent_args! {
|
||||
"item" => item_name(item_id),
|
||||
})
|
||||
.to_string(),
|
||||
},
|
||||
color,
|
||||
)]
|
||||
},
|
||||
BlockInteraction::Mine(mine_tool) => {
|
||||
match (mine_tool, &info.active_mine_tool) {
|
||||
@ -2123,24 +2130,35 @@ impl Hud {
|
||||
vec![(
|
||||
Some(GameInput::Primary),
|
||||
i18n.get_msg("hud-mine").to_string(),
|
||||
color,
|
||||
)]
|
||||
},
|
||||
(ToolKind::Pick, _) => {
|
||||
vec![(None, i18n.get_msg("hud-mine-needs_pickaxe").to_string())]
|
||||
vec![(
|
||||
None,
|
||||
i18n.get_msg("hud-mine-needs_pickaxe").to_string(),
|
||||
color,
|
||||
)]
|
||||
},
|
||||
(ToolKind::Shovel, Some(ToolKind::Shovel)) => {
|
||||
vec![(
|
||||
Some(GameInput::Primary),
|
||||
i18n.get_msg("hud-dig").to_string(),
|
||||
color,
|
||||
)]
|
||||
},
|
||||
(ToolKind::Shovel, _) => {
|
||||
vec![(None, i18n.get_msg("hud-mine-needs_shovel").to_string())]
|
||||
vec![(
|
||||
None,
|
||||
i18n.get_msg("hud-mine-needs_shovel").to_string(),
|
||||
color,
|
||||
)]
|
||||
},
|
||||
_ => {
|
||||
vec![(
|
||||
None,
|
||||
i18n.get_msg("hud-mine-needs_unhandled_case").to_string(),
|
||||
color,
|
||||
)]
|
||||
},
|
||||
}
|
||||
@ -2156,11 +2174,12 @@ impl Hud {
|
||||
) => "hud-lay",
|
||||
_ => "hud-sit",
|
||||
};
|
||||
vec![(Some(GameInput::Mount), i18n.get_msg(key).to_string())]
|
||||
vec![(Some(GameInput::Mount), i18n.get_msg(key).to_string(), color)]
|
||||
},
|
||||
BlockInteraction::Read(_) => vec![(
|
||||
Some(GameInput::Interact),
|
||||
i18n.get_msg("hud-read").to_string(),
|
||||
color,
|
||||
)],
|
||||
// TODO: change to turn on/turn off?
|
||||
BlockInteraction::LightToggle(enable) => vec![(
|
||||
@ -2171,6 +2190,7 @@ impl Hud {
|
||||
"hud-deactivate"
|
||||
})
|
||||
.to_string(),
|
||||
color,
|
||||
)],
|
||||
};
|
||||
|
||||
@ -2180,6 +2200,12 @@ impl Hud {
|
||||
.filter(|s| s.is_container())
|
||||
.and_then(|s| get_sprite_desc(s, i18n))
|
||||
{
|
||||
let (text, color) = if block.is_owned() {
|
||||
("hud-steal", overitem::NEGATIVE_TEXT_COLOR)
|
||||
} else {
|
||||
("hud-open", overitem::TEXT_COLOR)
|
||||
};
|
||||
|
||||
overitem::Overitem::new(
|
||||
desc,
|
||||
overitem::TEXT_COLOR,
|
||||
@ -2190,7 +2216,7 @@ impl Hud {
|
||||
overitem_properties,
|
||||
self.pulse,
|
||||
&global_state.window.key_layout,
|
||||
interaction_text("hud-open"),
|
||||
interaction_text(text, color),
|
||||
)
|
||||
.x_y(0.0, 100.0)
|
||||
.position_ingame(over_pos)
|
||||
@ -2204,6 +2230,11 @@ impl Hud {
|
||||
.flatten()
|
||||
.next()
|
||||
{
|
||||
let (text, color) = if block.is_owned() {
|
||||
("hud-steal", overitem::NEGATIVE_TEXT_COLOR)
|
||||
} else {
|
||||
("hud-collect", overitem::TEXT_COLOR)
|
||||
};
|
||||
item.set_amount(amount.clamp(1, item.max_amount()))
|
||||
.expect("amount >= 1 and <= max_amount is always a valid amount");
|
||||
make_overitem(
|
||||
@ -2212,11 +2243,16 @@ impl Hud {
|
||||
pos.distance_squared(player_pos),
|
||||
overitem_properties,
|
||||
&self.fonts,
|
||||
interaction_text("hud-collect"),
|
||||
interaction_text(text, color),
|
||||
)
|
||||
.set(overitem_id, ui_widgets);
|
||||
} else if let Some(desc) = block.get_sprite().and_then(|s| get_sprite_desc(s, i18n))
|
||||
{
|
||||
let (text, color) = if block.is_owned() {
|
||||
("hud-steal", overitem::NEGATIVE_TEXT_COLOR)
|
||||
} else {
|
||||
("hud-collect", overitem::TEXT_COLOR)
|
||||
};
|
||||
overitem::Overitem::new(
|
||||
desc,
|
||||
overitem::TEXT_COLOR,
|
||||
@ -2227,7 +2263,7 @@ impl Hud {
|
||||
overitem_properties,
|
||||
self.pulse,
|
||||
&global_state.window.key_layout,
|
||||
interaction_text("hud-collect"),
|
||||
interaction_text(text, color),
|
||||
)
|
||||
.x_y(0.0, 100.0)
|
||||
.position_ingame(over_pos)
|
||||
@ -2285,6 +2321,7 @@ impl Hud {
|
||||
"hud-use"
|
||||
})
|
||||
.to_string(),
|
||||
overitem::TEXT_COLOR,
|
||||
)],
|
||||
)
|
||||
.x_y(0.0, 100.0)
|
||||
|
@ -15,6 +15,7 @@ use crate::hud::{CollectFailedData, HudCollectFailedReason, HudLootOwner};
|
||||
use keyboard_keynames::key_layout::KeyLayout;
|
||||
|
||||
pub const TEXT_COLOR: Color = Color::Rgba(0.61, 0.61, 0.89, 1.0);
|
||||
pub const NEGATIVE_TEXT_COLOR: Color = Color::Rgba(0.91, 0.15, 0.17, 1.0);
|
||||
pub const PICKUP_FAILED_FADE_OUT_TIME: f32 = 1.5;
|
||||
|
||||
widget_ids! {
|
||||
@ -24,7 +25,7 @@ widget_ids! {
|
||||
name,
|
||||
// Interaction hints
|
||||
btn_bg,
|
||||
btn,
|
||||
btns[],
|
||||
// Inventory full
|
||||
inv_full_bg,
|
||||
inv_full,
|
||||
@ -47,7 +48,7 @@ pub struct Overitem<'a> {
|
||||
pulse: f32,
|
||||
key_layout: &'a Option<KeyLayout>,
|
||||
// GameInput optional so we can just show stuff like "needs pickaxe"
|
||||
interaction_options: Vec<(Option<GameInput>, String)>,
|
||||
interaction_options: Vec<(Option<GameInput>, String, Color)>,
|
||||
}
|
||||
|
||||
impl<'a> Overitem<'a> {
|
||||
@ -61,7 +62,7 @@ impl<'a> Overitem<'a> {
|
||||
properties: OveritemProperties,
|
||||
pulse: f32,
|
||||
key_layout: &'a Option<KeyLayout>,
|
||||
interaction_options: Vec<(Option<GameInput>, String)>,
|
||||
interaction_options: Vec<(Option<GameInput>, String, Color)>,
|
||||
) -> Self {
|
||||
Self {
|
||||
name,
|
||||
@ -174,42 +175,56 @@ impl<'a> Widget for Overitem<'a> {
|
||||
|
||||
// Interaction hints
|
||||
if !self.interaction_options.is_empty() && self.properties.active {
|
||||
let text = self
|
||||
let texts = self
|
||||
.interaction_options
|
||||
.iter()
|
||||
.filter_map(|(input, action)| {
|
||||
.filter_map(|(input, action, color)| {
|
||||
let binding = if let Some(input) = input {
|
||||
Some(self.controls.get_binding(*input)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Some((binding, action))
|
||||
Some((binding, action, color))
|
||||
})
|
||||
.map(|(input, action)| {
|
||||
.map(|(input, action, color)| {
|
||||
if let Some(input) = input {
|
||||
let input = input.display_string(self.key_layout);
|
||||
format!("{} {action}", input.as_str())
|
||||
(format!("{} {action}", input.as_str()), color)
|
||||
} else {
|
||||
action.to_string()
|
||||
(action.to_string(), color)
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
.collect::<Vec<_>>();
|
||||
if state.ids.btns.len() < texts.len() {
|
||||
state.update(|state| {
|
||||
state
|
||||
.ids
|
||||
.btns
|
||||
.resize(texts.len(), &mut ui.widget_id_generator());
|
||||
})
|
||||
}
|
||||
|
||||
let hints_text = Text::new(&text)
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.font_size(btn_font_size as u32)
|
||||
.color(TEXT_COLOR)
|
||||
.x_y(0.0, btn_text_pos_y)
|
||||
.depth(self.distance_from_player_sqr + 1.0)
|
||||
.parent(id);
|
||||
let mut max_w = btn_rect_size;
|
||||
let mut max_h = 0.0;
|
||||
|
||||
let [w, h] = hints_text.get_wh(ui).unwrap_or([btn_rect_size; 2]);
|
||||
for (idx, (text, color)) in texts.iter().enumerate() {
|
||||
let hints_text = Text::new(text)
|
||||
.font_id(self.fonts.cyri.conrod_id)
|
||||
.font_size(btn_font_size as u32)
|
||||
.color(**color)
|
||||
.x_y(0.0, btn_text_pos_y + max_h)
|
||||
.depth(self.distance_from_player_sqr + 1.0)
|
||||
.parent(id);
|
||||
let [w, h] = hints_text.get_wh(ui).unwrap_or([btn_rect_size; 2]);
|
||||
max_w = max_w.max(w);
|
||||
max_h += h;
|
||||
hints_text.set(state.ids.btns[idx], ui);
|
||||
}
|
||||
|
||||
hints_text.set(state.ids.btn, ui);
|
||||
max_h = max_h.max(btn_rect_size);
|
||||
|
||||
RoundedRectangle::fill_with(
|
||||
[w + btn_radius * 2.0, h + btn_radius * 2.0],
|
||||
[max_w + btn_radius * 2.0, max_h + btn_radius * 2.0],
|
||||
btn_radius,
|
||||
btn_color,
|
||||
)
|
||||
|
@ -233,10 +233,10 @@ impl Primitive {
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Fill {
|
||||
Sprite(SpriteKind),
|
||||
RotatedSprite(SpriteKind, u8),
|
||||
RotatedSpriteWithCfg(SpriteKind, u8, SpriteCfg),
|
||||
ResourceSprite(SpriteKind, u8),
|
||||
Sprite(Block),
|
||||
ResourceSprite(Block),
|
||||
CfgSprite(Block, SpriteCfg),
|
||||
|
||||
Block(Block),
|
||||
Brick(BlockKind, Rgb<u8>, u8),
|
||||
Gradient(util::gradient::Gradient, BlockKind),
|
||||
@ -248,6 +248,44 @@ pub enum Fill {
|
||||
}
|
||||
|
||||
impl Fill {
|
||||
pub fn sprite(kind: SpriteKind) -> Self { Fill::Block(Block::empty().with_sprite(kind)) }
|
||||
|
||||
pub fn sprite_ori(kind: SpriteKind, ori: u8) -> Self {
|
||||
let block = Block::empty().with_sprite(kind);
|
||||
|
||||
let block = block.with_ori(ori).unwrap_or(block);
|
||||
Fill::Sprite(block)
|
||||
}
|
||||
|
||||
pub fn resource_sprite(kind: SpriteKind) -> Self {
|
||||
Fill::ResourceSprite(Block::empty().with_sprite(kind))
|
||||
}
|
||||
|
||||
pub fn resource_sprite_ori(kind: SpriteKind, ori: u8) -> Self {
|
||||
let block = Block::empty().with_sprite(kind);
|
||||
|
||||
let block = block.with_ori(ori).unwrap_or(block);
|
||||
Fill::ResourceSprite(block)
|
||||
}
|
||||
|
||||
pub fn owned_resource_sprite_ori(kind: SpriteKind, ori: u8) -> Self {
|
||||
let block = Block::empty().with_sprite(kind);
|
||||
|
||||
let block = block.with_ori(ori).unwrap_or(block);
|
||||
let block = block
|
||||
.with_attr(common::terrain::sprite::Owned(true))
|
||||
.unwrap_or(block);
|
||||
|
||||
Fill::ResourceSprite(block)
|
||||
}
|
||||
|
||||
pub fn sprite_ori_cfg(kind: SpriteKind, ori: u8, cfg: SpriteCfg) -> Self {
|
||||
let block = Block::empty().with_sprite(kind);
|
||||
|
||||
let block = block.with_ori(ori).unwrap_or(block);
|
||||
Fill::CfgSprite(block, cfg)
|
||||
}
|
||||
|
||||
fn contains_at(
|
||||
tree: &Store<Primitive>,
|
||||
prim: Id<Primitive>,
|
||||
@ -480,37 +518,22 @@ impl Fill {
|
||||
) -> Option<Block> {
|
||||
if Self::contains_at(tree, prim, pos, col) {
|
||||
match self {
|
||||
Fill::Block(block) => Some(*block),
|
||||
Fill::Sprite(sprite) => Some(if old_block.is_filled() {
|
||||
Block::air(*sprite)
|
||||
} else {
|
||||
old_block.with_sprite(*sprite)
|
||||
}),
|
||||
Fill::RotatedSprite(sprite, ori) | Fill::ResourceSprite(sprite, ori) => {
|
||||
Fill::Sprite(sprite) | Fill::ResourceSprite(sprite) => {
|
||||
Some(if old_block.is_filled() {
|
||||
Block::air(*sprite)
|
||||
.with_ori(*ori)
|
||||
.unwrap_or_else(|| Block::air(*sprite))
|
||||
*sprite
|
||||
} else {
|
||||
old_block
|
||||
.with_sprite(*sprite)
|
||||
.with_ori(*ori)
|
||||
.unwrap_or_else(|| old_block.with_sprite(*sprite))
|
||||
old_block.with_data_of(*sprite)
|
||||
})
|
||||
},
|
||||
Fill::RotatedSpriteWithCfg(sprite, ori, cfg) => Some({
|
||||
Fill::CfgSprite(sprite, cfg) => {
|
||||
*sprite_cfg = Some(cfg.clone());
|
||||
if old_block.is_filled() {
|
||||
Block::air(*sprite)
|
||||
.with_ori(*ori)
|
||||
.unwrap_or_else(|| Block::air(*sprite))
|
||||
Some(if old_block.is_filled() {
|
||||
*sprite
|
||||
} else {
|
||||
old_block
|
||||
.with_sprite(*sprite)
|
||||
.with_ori(*ori)
|
||||
.unwrap_or_else(|| old_block.with_sprite(*sprite))
|
||||
}
|
||||
}),
|
||||
old_block.with_data_of(*sprite)
|
||||
})
|
||||
},
|
||||
Fill::Block(block) => Some(*block),
|
||||
Fill::Brick(bk, col, range) => Some(Block::new(
|
||||
*bk,
|
||||
*col + (RandomField::new(13)
|
||||
@ -1080,7 +1103,7 @@ impl Painter {
|
||||
min: pos,
|
||||
max: pos + 1,
|
||||
})
|
||||
.fill(Fill::Sprite(sprite))
|
||||
.fill(Fill::sprite(sprite))
|
||||
}
|
||||
|
||||
/// Places a sprite at the provided location with the provided orientation.
|
||||
@ -1089,7 +1112,7 @@ impl Painter {
|
||||
min: pos,
|
||||
max: pos + 1,
|
||||
})
|
||||
.fill(Fill::RotatedSprite(sprite, ori))
|
||||
.fill(Fill::sprite_ori(sprite, ori))
|
||||
}
|
||||
|
||||
/// Places a sprite at the provided location with the provided orientation
|
||||
@ -1105,7 +1128,7 @@ impl Painter {
|
||||
min: pos,
|
||||
max: pos + 1,
|
||||
})
|
||||
.fill(Fill::RotatedSpriteWithCfg(sprite, ori, cfg))
|
||||
.fill(Fill::sprite_ori_cfg(sprite, ori, cfg))
|
||||
}
|
||||
|
||||
/// Places a sprite at the provided location with the provided orientation
|
||||
@ -1116,7 +1139,18 @@ impl Painter {
|
||||
min: pos,
|
||||
max: pos + 1,
|
||||
})
|
||||
.fill(Fill::ResourceSprite(sprite, ori))
|
||||
.fill(Fill::resource_sprite_ori(sprite, ori))
|
||||
}
|
||||
|
||||
/// Places a sprite at the provided location with the provided orientation
|
||||
/// which will be tracked by rtsim nature if the sprite has an associated
|
||||
/// [`ChunkResource`].
|
||||
pub fn owned_resource_sprite(&self, pos: Vec3<i32>, sprite: SpriteKind, ori: u8) {
|
||||
self.aabb(Aabb {
|
||||
min: pos,
|
||||
max: pos + 1,
|
||||
})
|
||||
.fill(Fill::owned_resource_sprite_ori(sprite, ori))
|
||||
}
|
||||
|
||||
/// Returns a `PrimitiveRef` of the largest pyramid with a slope of 1 that
|
||||
|
@ -671,7 +671,7 @@ fn render_tower(bridge: &Bridge, painter: &Painter, roof_kind: &RoofKind) {
|
||||
1,
|
||||
4,
|
||||
)
|
||||
.fill(Fill::Sprite(SpriteKind::FireBowlGround));
|
||||
.fill(Fill::sprite(SpriteKind::FireBowlGround));
|
||||
},
|
||||
RoofKind::Hipped => {
|
||||
painter
|
||||
@ -829,7 +829,7 @@ fn render_hang(bridge: &Bridge, painter: &Painter) {
|
||||
|
||||
edges
|
||||
.translate(Vec3::unit_z())
|
||||
.fill(Fill::Sprite(SpriteKind::Rope));
|
||||
.fill(Fill::sprite(SpriteKind::Rope));
|
||||
|
||||
edges.translate(Vec3::unit_z() * 2).fill(wood);
|
||||
|
||||
|
@ -220,7 +220,7 @@ impl Structure for CliffTower {
|
||||
max: (sprite_pos + 1).with_z(floor_level + 2),
|
||||
})
|
||||
.clear();
|
||||
painter.sprite(
|
||||
painter.owned_resource_sprite(
|
||||
sprite_pos.with_z(floor_level + 1),
|
||||
match (RandomField::new(0).get(sprite_pos.with_z(floor_level + 1)))
|
||||
% 8
|
||||
@ -231,6 +231,7 @@ impl Structure for CliffTower {
|
||||
3 => SpriteKind::Pot,
|
||||
_ => SpriteKind::MesaLantern,
|
||||
},
|
||||
0,
|
||||
);
|
||||
}
|
||||
// planters
|
||||
@ -504,7 +505,7 @@ impl Structure for CliffTower {
|
||||
// distribute small sprites
|
||||
for dir in LOCALITY {
|
||||
let pos = plot_center + dir * ((length / 3) - 1);
|
||||
painter.sprite(
|
||||
painter.owned_resource_sprite(
|
||||
pos.with_z(floor_level + 1),
|
||||
match (RandomField::new(0).get(pos.with_z(floor_level)))
|
||||
% 9
|
||||
@ -519,6 +520,7 @@ impl Structure for CliffTower {
|
||||
7 => SpriteKind::Bowl,
|
||||
_ => SpriteKind::MesaLantern,
|
||||
},
|
||||
0,
|
||||
);
|
||||
}
|
||||
// beds & wardrobes
|
||||
@ -605,7 +607,7 @@ impl Structure for CliffTower {
|
||||
SpriteKind::WallTableMesa,
|
||||
(4 * d) as u8,
|
||||
);
|
||||
painter.rotated_sprite(
|
||||
painter.owned_resource_sprite(
|
||||
pos.with_z(floor_level + 4),
|
||||
match (RandomField::new(0).get(pos.with_z(floor_level)))
|
||||
% 3
|
||||
@ -620,7 +622,7 @@ impl Structure for CliffTower {
|
||||
// distribute small sprites
|
||||
for dir in LOCALITY {
|
||||
let pos = plot_center + dir * ((length / 3) + 1);
|
||||
painter.sprite(
|
||||
painter.owned_resource_sprite(
|
||||
pos.with_z(floor_level + 1),
|
||||
match (RandomField::new(0).get(pos.with_z(floor_level)))
|
||||
% 12
|
||||
@ -638,6 +640,7 @@ impl Structure for CliffTower {
|
||||
10 => SpriteKind::MesaLantern,
|
||||
_ => SpriteKind::FountainArabic,
|
||||
},
|
||||
0,
|
||||
);
|
||||
}
|
||||
},
|
||||
@ -666,7 +669,7 @@ impl Structure for CliffTower {
|
||||
SpriteKind::WallTableMesa,
|
||||
(4 * d) as u8,
|
||||
);
|
||||
painter.rotated_sprite(
|
||||
painter.owned_resource_sprite(
|
||||
pos.with_z(floor_level + 3),
|
||||
match (RandomField::new(0).get(pos.with_z(floor_level)))
|
||||
% 4
|
||||
@ -682,7 +685,7 @@ impl Structure for CliffTower {
|
||||
// distribute small sprites
|
||||
for dir in LOCALITY {
|
||||
let pos = plot_center + dir * ((length / 3) + 1);
|
||||
painter.sprite(
|
||||
painter.owned_resource_sprite(
|
||||
pos.with_z(floor_level + 1),
|
||||
match (RandomField::new(0).get(pos.with_z(floor_level)))
|
||||
% 11
|
||||
@ -700,6 +703,7 @@ impl Structure for CliffTower {
|
||||
10 => SpriteKind::JugAndBowlArabic,
|
||||
_ => SpriteKind::OvenArabic,
|
||||
},
|
||||
0,
|
||||
);
|
||||
}
|
||||
},
|
||||
|
@ -364,7 +364,11 @@ impl Structure for CoastalHouse {
|
||||
let sprite = sprites.swap_remove(
|
||||
RandomField::new(0).get(position.with_z(base)) as usize % sprites.len(),
|
||||
);
|
||||
painter.sprite(position.with_z(base - 2 + (s * height)), sprite);
|
||||
painter.owned_resource_sprite(
|
||||
position.with_z(base - 2 + (s * height)),
|
||||
sprite,
|
||||
0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -489,7 +489,11 @@ impl Structure for DesertCityMultiPlot {
|
||||
0 => {
|
||||
for dir in NEIGHBORS {
|
||||
let pos = center + dir * 4;
|
||||
painter.sprite(pos.with_z(floor_level), SpriteKind::Crate);
|
||||
painter.owned_resource_sprite(
|
||||
pos.with_z(floor_level),
|
||||
SpriteKind::Crate,
|
||||
0,
|
||||
);
|
||||
}
|
||||
for dir in NEIGHBORS {
|
||||
let pos = center + dir * 8;
|
||||
@ -1222,7 +1226,7 @@ impl Structure for DesertCityMultiPlot {
|
||||
SpriteKind::WallTableArabic,
|
||||
6 - (4 * d) as u8,
|
||||
);
|
||||
painter.rotated_sprite(
|
||||
painter.owned_resource_sprite(
|
||||
c_pos.with_z(floor_level + 1),
|
||||
match (RandomField::new(0)
|
||||
.get(c_pos.with_z(floor_level)))
|
||||
@ -1317,7 +1321,7 @@ impl Structure for DesertCityMultiPlot {
|
||||
SpriteKind::WallTableArabic,
|
||||
6 - (4 * d) as u8,
|
||||
);
|
||||
painter.rotated_sprite(
|
||||
painter.owned_resource_sprite(
|
||||
a_pos.with_z(floor_level + 1),
|
||||
match (RandomField::new(0)
|
||||
.get(a_pos.with_z(floor_level)))
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::*;
|
||||
use crate::{ColumnSample, Land};
|
||||
use common::terrain::{Block, BlockKind, SpriteKind};
|
||||
use common::terrain::{sprite::Owned, Block, BlockKind, SpriteKind};
|
||||
use rand::prelude::*;
|
||||
use strum::{EnumIter, IntoEnumIterator};
|
||||
use vek::*;
|
||||
@ -253,7 +253,12 @@ impl Structure for FarmField {
|
||||
.sprites()
|
||||
.choose_weighted(rng, |(w, _)| *w)
|
||||
.ok()
|
||||
.and_then(|&(_, s)| Some(old.into_vacant().with_sprite(s?)))
|
||||
.and_then(|&(_, s)| {
|
||||
let new = old.into_vacant().with_sprite(s?);
|
||||
let new = new.with_attr(Owned(true)).unwrap_or(new);
|
||||
|
||||
Some(new)
|
||||
})
|
||||
} else if z_off == 1 && rng.gen_bool(0.001) {
|
||||
Some(old.into_vacant().with_sprite(SpriteKind::Scarecrow))
|
||||
} else {
|
||||
|
@ -9,6 +9,7 @@ use common::{
|
||||
terrain::{Block, BlockKind, SpriteKind},
|
||||
};
|
||||
use rand::prelude::*;
|
||||
use strum::IntoEnumIterator;
|
||||
use vek::*;
|
||||
|
||||
/// Represents house data generated by the `generate()` method
|
||||
@ -1564,14 +1565,19 @@ impl Structure for House {
|
||||
// drawer next to bed
|
||||
painter.sprite(nightstand_pos.with_z(base), SpriteKind::DrawerSmall);
|
||||
// collectible on top of drawer
|
||||
let rng = RandomField::new(0).get(nightstand_pos.with_z(base + 1));
|
||||
painter.sprite(nightstand_pos.with_z(base + 1), match rng % 5 {
|
||||
0 => SpriteKind::Lantern,
|
||||
1 => SpriteKind::PotionMinor,
|
||||
2 => SpriteKind::VialEmpty,
|
||||
3 => SpriteKind::Bowl,
|
||||
_ => SpriteKind::Empty,
|
||||
});
|
||||
let rng0 = RandomField::new(0).get(nightstand_pos.with_z(base + 1));
|
||||
let rng1 = RandomField::new(1).get(nightstand_pos.with_z(base + 1));
|
||||
painter.owned_resource_sprite(
|
||||
nightstand_pos.with_z(base + 1),
|
||||
match rng0 % 5 {
|
||||
0 => SpriteKind::Lantern,
|
||||
1 => SpriteKind::PotionMinor,
|
||||
2 => SpriteKind::VialEmpty,
|
||||
3 => SpriteKind::Bowl,
|
||||
_ => SpriteKind::Empty,
|
||||
},
|
||||
(rng1 % 4) as u8 * 2,
|
||||
);
|
||||
// wardrobe along wall in corner of the room
|
||||
let (wardrobe_pos, drawer_ori) = match self.front {
|
||||
Dir::Y => (Vec2::new(self.bounds.max.x - 2, self.bounds.min.y + 1), 4),
|
||||
@ -1589,14 +1595,19 @@ impl Structure for House {
|
||||
for dir in DIRS {
|
||||
// random accent pieces and loot
|
||||
let sprite_pos = self.bounds.center() + dir * 5;
|
||||
let rng = RandomField::new(0).get(sprite_pos.with_z(base));
|
||||
painter.sprite(sprite_pos.with_z(base), match rng % 32 {
|
||||
0..=2 => SpriteKind::Crate,
|
||||
3..=4 => SpriteKind::CoatRack,
|
||||
5..=7 => SpriteKind::Pot,
|
||||
8..=9 => SpriteKind::Lantern,
|
||||
_ => SpriteKind::Empty,
|
||||
});
|
||||
let rng0 = RandomField::new(0).get(sprite_pos.with_z(base));
|
||||
let rng1 = RandomField::new(1).get(sprite_pos.with_z(base));
|
||||
painter.owned_resource_sprite(
|
||||
sprite_pos.with_z(base),
|
||||
match rng0 % 32 {
|
||||
0..=2 => SpriteKind::Crate,
|
||||
3..=4 => SpriteKind::CoatRack,
|
||||
5..=7 => SpriteKind::Pot,
|
||||
8..=9 => SpriteKind::Lantern,
|
||||
_ => SpriteKind::Empty,
|
||||
},
|
||||
(rng1 % 4) as u8 * 2,
|
||||
);
|
||||
}
|
||||
|
||||
if self.bounds.max.x - self.bounds.min.x < 16
|
||||
@ -1605,12 +1616,12 @@ impl Structure for House {
|
||||
let table_pos = Vec2::new(half_x, half_y);
|
||||
// room is smaller, so use small table
|
||||
painter.sprite(table_pos.with_z(base), SpriteKind::TableDining);
|
||||
for (idx, dir) in CARDINALS.iter().enumerate() {
|
||||
let chair_pos = table_pos + dir;
|
||||
for dir in Dir::iter() {
|
||||
let chair_pos = table_pos + dir.to_vec2();
|
||||
painter.rotated_sprite(
|
||||
chair_pos.with_z(base),
|
||||
SpriteKind::ChairSingle,
|
||||
(idx * 2 + ((idx % 2) * 4)) as u8,
|
||||
dir.opposite().sprite_ori(),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
@ -3,7 +3,7 @@ use crate::{
|
||||
util::{RandomField, Sampler, CARDINALS, DIAGONALS},
|
||||
Land,
|
||||
};
|
||||
use common::terrain::{BlockKind, SpriteKind};
|
||||
use common::terrain::{sprite::Owned, BlockKind, SpriteKind};
|
||||
use rand::prelude::*;
|
||||
use std::{f32::consts::TAU, sync::Arc};
|
||||
use vek::*;
|
||||
@ -50,11 +50,15 @@ impl Structure for SavannahHut {
|
||||
let center = self.bounds.center();
|
||||
let sprite_fill = Fill::Sampling(Arc::new(|wpos| {
|
||||
Some(match (RandomField::new(0).get(wpos)) % 25 {
|
||||
0 => Block::air(SpriteKind::Bowl),
|
||||
1 => Block::air(SpriteKind::VialEmpty),
|
||||
0 => Block::air(SpriteKind::Bowl).with_attr(Owned(true)).unwrap(),
|
||||
1 => Block::air(SpriteKind::VialEmpty)
|
||||
.with_attr(Owned(true))
|
||||
.unwrap(),
|
||||
2 => Block::air(SpriteKind::Lantern),
|
||||
3 => Block::air(SpriteKind::JugArabic),
|
||||
4 => Block::air(SpriteKind::Crate),
|
||||
4 => Block::air(SpriteKind::Crate)
|
||||
.with_attr(Owned(true))
|
||||
.unwrap(),
|
||||
_ => Block::new(BlockKind::Air, Rgb::new(0, 0, 0)),
|
||||
})
|
||||
}));
|
||||
@ -244,7 +248,7 @@ impl Structure for SavannahHut {
|
||||
let sprite = sprites.swap_remove(
|
||||
RandomField::new(0).get(position.with_z(base)) as usize % sprites.len(),
|
||||
);
|
||||
painter.sprite(position.with_z(base - 2), sprite);
|
||||
painter.owned_resource_sprite(position.with_z(base - 2), sprite, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ use crate::{
|
||||
};
|
||||
use common::{
|
||||
generation::{EntityInfo, SpecialEntity},
|
||||
terrain::{BlockKind, SpriteKind},
|
||||
terrain::{sprite::Owned, BlockKind, SpriteKind},
|
||||
};
|
||||
use rand::prelude::*;
|
||||
use std::sync::Arc;
|
||||
@ -43,11 +43,15 @@ impl Structure for SavannahPit {
|
||||
let center = self.bounds.center();
|
||||
let sprite_fill = Fill::Sampling(Arc::new(|wpos| {
|
||||
Some(match (RandomField::new(0).get(wpos)) % 50 {
|
||||
0 => Block::air(SpriteKind::Bowl),
|
||||
1 => Block::air(SpriteKind::VialEmpty),
|
||||
0 => Block::air(SpriteKind::Bowl).with_attr(Owned(true)).unwrap(),
|
||||
1 => Block::air(SpriteKind::VialEmpty)
|
||||
.with_attr(Owned(true))
|
||||
.unwrap(),
|
||||
2 => Block::air(SpriteKind::Lantern),
|
||||
3 => Block::air(SpriteKind::JugArabic),
|
||||
4 => Block::air(SpriteKind::Crate),
|
||||
4 => Block::air(SpriteKind::Crate)
|
||||
.with_attr(Owned(true))
|
||||
.unwrap(),
|
||||
_ => Block::new(BlockKind::Air, Rgb::new(0, 0, 0)),
|
||||
})
|
||||
}));
|
||||
@ -727,7 +731,11 @@ impl Structure for SavannahPit {
|
||||
RandomField::new(0).get(position.with_z(base)) as usize
|
||||
% sprites.len(),
|
||||
);
|
||||
painter.sprite(position.with_z(base - ((1 + f) * length)), sprite);
|
||||
painter.owned_resource_sprite(
|
||||
position.with_z(base - ((1 + f) * length)),
|
||||
sprite,
|
||||
0,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -5,7 +5,7 @@ use crate::{
|
||||
};
|
||||
use common::{
|
||||
generation::SpecialEntity,
|
||||
terrain::{BlockKind, SpriteKind},
|
||||
terrain::{sprite::Owned, BlockKind, SpriteKind},
|
||||
};
|
||||
use rand::prelude::*;
|
||||
use std::{f32::consts::TAU, sync::Arc};
|
||||
@ -53,11 +53,15 @@ impl Structure for SavannahWorkshop {
|
||||
let center = self.bounds.center();
|
||||
let sprite_fill = Fill::Sampling(Arc::new(|wpos| {
|
||||
Some(match (RandomField::new(0).get(wpos)) % 25 {
|
||||
0 => Block::air(SpriteKind::Bowl),
|
||||
1 => Block::air(SpriteKind::VialEmpty),
|
||||
0 => Block::air(SpriteKind::Bowl).with_attr(Owned(true)).unwrap(),
|
||||
1 => Block::air(SpriteKind::VialEmpty)
|
||||
.with_attr(Owned(true))
|
||||
.unwrap(),
|
||||
2 => Block::air(SpriteKind::Lantern),
|
||||
3 => Block::air(SpriteKind::JugArabic),
|
||||
4 => Block::air(SpriteKind::Crate),
|
||||
4 => Block::air(SpriteKind::Crate)
|
||||
.with_attr(Owned(true))
|
||||
.unwrap(),
|
||||
_ => Block::new(BlockKind::Air, Rgb::new(0, 0, 0)),
|
||||
})
|
||||
}));
|
||||
|
@ -1491,10 +1491,7 @@ impl Structure for Tavern {
|
||||
max: (wall_center + in_dir.rotated_cw().to_vec2())
|
||||
.with_z(wall.base_alt + 2),
|
||||
}))
|
||||
.fill(Fill::RotatedSprite(
|
||||
SpriteKind::Window1,
|
||||
in_dir.sprite_ori(),
|
||||
));
|
||||
.fill(Fill::sprite_ori(SpriteKind::Window1, in_dir.sprite_ori()));
|
||||
}
|
||||
},
|
||||
}
|
||||
|
Reference in New Issue
Block a user