feat: items render as multi-cell pictures in graphics mode

- Item.shape() returns Vec<(dx, dy, color)> per type:
  Sword: 4-tall blade + crossguard + handle (6 cells)
  Dagger: blade + 2-cell handle (3 cells)
  Bow: curved arc + bowstring (4 cells)
  Leather/Plate Armor: 2x2 body shape (4 cells)
  Shield: 2x2 shield shape (4 cells)
  Health/Mana Potion: bottle with cork + body (4 cells)
  Food: 3-cell round shape
  Scroll: 3-cell horizontal scroll
- Graphics renderer paints all shape cells per item
- ASCII mode still uses 2-char glyph encoding in UI
- Items in world have visual shape, not just single colored cell

All 171 tests + 14 scenarios pass.
This commit is contained in:
Emil
2026-06-21 18:39:58 +03:00
parent 7a225b4320
commit 07c7b88521
2 changed files with 71 additions and 3 deletions
+64
View File
@@ -74,6 +74,70 @@ impl Item {
format!("{}{}", a, b)
}
pub fn shape(&self) -> Vec<(i32, i32, [u8; 3])> {
match self.typ {
ItemType::Dagger => vec![
(0, 0, [220, 220, 230]),
(-1, 1, [120, 80, 40]),
(0, 1, [120, 80, 40]),
],
ItemType::Sword => vec![
(0, -2, [235, 235, 245]),
(0, -1, [240, 240, 250]),
(-1, 0, [180, 130, 60]),
(1, 0, [180, 130, 60]),
(0, 0, [160, 110, 50]),
(0, 1, [100, 70, 30]),
],
ItemType::Bow => vec![
(0, -1, [170, 130, 70]),
(1, 0, [180, 140, 80]),
(0, 1, [170, 130, 70]),
(-1, 0, [220, 220, 220]),
],
ItemType::LeatherArmor => vec![
(-1, -1, [150, 100, 55]),
(0, -1, [160, 110, 60]),
(-1, 0, [140, 90, 50]),
(0, 0, [130, 80, 45]),
],
ItemType::PlateArmor => vec![
(-1, -1, [190, 195, 205]),
(0, -1, [200, 205, 215]),
(-1, 0, [180, 185, 195]),
(0, 0, [170, 175, 185]),
],
ItemType::Shield => vec![
(-1, -1, [170, 150, 70]),
(0, -1, [180, 160, 80]),
(-1, 0, [160, 140, 60]),
(0, 0, [150, 130, 50]),
],
ItemType::HealthPotion => vec![
(0, -1, [60, 40, 30]),
(0, 0, [220, 30, 30]),
(-1, 0, [180, 20, 20]),
(1, 0, [200, 25, 25]),
],
ItemType::ManaPotion => vec![
(0, -1, [60, 40, 30]),
(0, 0, [30, 30, 220]),
(-1, 0, [20, 20, 180]),
(1, 0, [25, 25, 200]),
],
ItemType::Food => vec![
(0, 0, [80, 200, 60]),
(-1, 0, [60, 180, 40]),
(1, 0, [70, 190, 50]),
],
ItemType::Scroll => vec![
(-1, 0, [240, 220, 120]),
(0, 0, [250, 230, 130]),
(1, 0, [240, 220, 120]),
],
}
}
pub fn color(&self) -> [u8; 3] {
match self.typ {
ItemType::Dagger => [200, 200, 200],
+7 -3
View File
@@ -800,9 +800,13 @@ impl GraphicsRenderer {
for item in items.all() {
let sx = item.x - cam_x;
let sy = item.y - cam_y;
if sx >= 0 && sx < self.grid_w as i32 && sy >= 0 && sy < self.grid_h as i32 {
let idx = sy as usize * self.grid_w + sx as usize;
item_color[idx] = [item.color()[0], item.color()[1], item.color()[2], 255];
for (dx, dy, col) in item.shape() {
let px = sx + dx;
let py = sy + dy;
if px >= 0 && px < self.grid_w as i32 && py >= 0 && py < self.grid_h as i32 {
let idx = py as usize * self.grid_w + px as usize;
item_color[idx] = [col[0], col[1], col[2], 255];
}
}
}
for e in entities.all() {