More graphical finesse: own beds per creature, animated room furniture, treasure chests, elaborate core and portals, worn floors

- props.rs: furniture drawn near the camera every frame
  - beds built by each creature on arrival, matching its kind (straw, web, starry cushion,
    fur pile, chain bunk, ember cushion, rock hollow, camp bed); gone when the owner is
  - training: spinning dummies, weapon racks, wobbling targets; torture: turning wheel,
    iron maiden, brazier with glowing coals; temple: altar with candles and fire bowl,
    candle stands; library: book shelves, lecterns with floating books while studying
  - treasure chests in the treasury, closed when empty, filled with their treasure otherwise
- Soul core: stepped obsidian pedestal, four spikes with energy threads, circling runes,
  unsteady pulse when hurt
- Portals: circle of standing stones with runes, column of light and rising sparks
- Floors: cracked, chipped and shattered stones, grit and crack decals

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard ZinkandClaude Opus 5.5 committed 2026-11-03 12:30:30 +01:00
1 parent 036c13577c
commit 75232d95ee
5 files changed
+609 -42

No files matched your search

+48 -1
View File
@@ -62,6 +62,8 @@ pub const T_DIAMOND: u32 = 119;
pub const D_SILVER: u32 = 121; // treasury content
pub const D_RUBY: u32 = 122;
pub const D_DIAMOND: u32 = 123;
pub const D_RUBBLE: u32 = 124; // floor decals: pebbles and fragments
pub const D_CRACK: u32 = 125; // a long crack through several stones
pub struct Gfx {
pub atlas: Texture2D,
@@ -149,7 +151,7 @@ impl Canvas {
}
}
// flagstone pattern with grout
// flagstone pattern with grout; stones are whole, cracked or broken (chipped corner with grit)
fn stones(x: i32, y: i32, v: u32, base: (i32, i32, i32), grout: (i32, i32, i32), var: i32) -> Color {
let row = y / 8;
let off = if row % 2 == 1 { 4 } else { 0 };
@@ -157,6 +159,31 @@ fn stones(x: i32, y: i32, v: u32, base: (i32, i32, i32), grout: (i32, i32, i32),
if y % 8 == 0 || sx % 8 == 0 {
return shade(grout, (rnd(x, y, v + 7) * 6.0) as i32);
}
let (lx, ly) = (sx % 8, y % 8); // position inside the stone (1..7)
let damage = hash((x + off) / 8, row, v + 17) % 9;
match damage {
// a crack running across the stone
0 | 1 => {
let k = (hash((x + off) / 8, row, v + 18) % 3) as i32;
let on = if damage == 0 { lx + k == ly || lx + k == ly + 1 && ly % 3 == 0 } else { 8 - lx == ly + k - 1 };
if on {
return shade(grout, -6);
}
}
// broken corner: the piece is missing, grit lies in the hole
2 => {
if lx + ly < 5 {
return if hash(x, y, v + 19) % 3 == 0 { shade(base, -18) } else { shade(grout, (rnd(x, y, v + 20) * 10.0) as i32 - 4) };
}
}
// shattered: several small fragments
3 => {
if (lx * 3 + ly * 5 + v as i32) % 7 == 0 || lx == ly / 2 + 2 {
return shade(grout, 2);
}
}
_ => {}
}
let stone = hash((x + off) / 8, row, v + 3) % 5;
let d = (rnd(x, y, v) * var as f32) as i32 - var / 2 + stone as i32 * 3 - 6;
// highlight top/left, shadow bottom/right
@@ -699,6 +726,26 @@ fn gen_atlas() -> Image {
let h = hash(cu, cv, seed) % 3;
Some(if e { lo } else if h == 0 || (u % 4 == 1 && v % 4 == 1) { hi } else if d > 0.65 { lo } else { mid })
};
// floor decals
cv.cell(D_RUBBLE, |x, y| {
for k in 0..9 {
let gx = 1 + (hash(k, 5, 220) % 14) as i32;
let gy = 1 + (hash(k, 6, 220) % 14) as i32;
let s = (hash(k, 7, 220) % 3) as i32;
if (x - gx).abs() + (y - gy).abs() <= s {
return Some(if y < gy { c(120, 110, 104) } else if (x + y) % 2 == 0 { c(84, 76, 72) } else { c(66, 60, 56) });
}
}
None
});
cv.cell(D_CRACK, |x, y| {
let cx = 8.0 + ((y as f32) * 0.7).sin() * 3.0 + (y as f32 * 1.9).sin();
if (x as f32 - cx).abs() < 0.7 || (y > 9 && (x as f32 - cx - (y - 9) as f32 * 0.8).abs() < 0.6) {
Some(Color::from_rgba(20, 14, 14, 200))
} else {
None
}
});
cv.cell(D_RUBY, |x, y| gems(x, y, 200, c(255, 150, 170), c(215, 30, 60), c(120, 12, 36)));
cv.cell(D_DIAMOND, |x, y| gems(x, y, 210, c(255, 255, 255), c(170, 232, 255), c(80, 150, 200)));
cv.img