From 07c7b885210d30748a0d1330b69444b2008595f3 Mon Sep 17 00:00:00 2001 From: Emil Date: Sun, 21 Jun 2026 18:39:58 +0300 Subject: [PATCH] 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. --- src/entity/item.rs | 64 ++++++++++++++++++++++++++++++++++++++++++ src/render/graphics.rs | 10 +++++-- 2 files changed, 71 insertions(+), 3 deletions(-) diff --git a/src/entity/item.rs b/src/entity/item.rs index c305804..25fa98a 100644 --- a/src/entity/item.rs +++ b/src/entity/item.rs @@ -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], diff --git a/src/render/graphics.rs b/src/render/graphics.rs index d1b25be..1991da7 100644 --- a/src/render/graphics.rs +++ b/src/render/graphics.rs @@ -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() {