fix: 15+ bug fixes — item dup, descend, slime AI, combat, camera, UI
CRITICAL: - Fix use_item duplicating weapons/armor (not removed from inventory) - Fix unwrap() panic in update_ragdoll_entity - Fix descend proceeding without stairs when player entity missing HIGH: - Fix projectile hardcoded id==0 preventing enemy projectiles hitting player - Fix previously equipped item lost on re-equip (returned to inventory) - Fix i32::abs() overflow panic in background_color (use wrapping_abs) MEDIUM: - Fix slime AI ignoring vertical direction to player - Fix combat damage applied to dead player - Fix camera movement keys non-functional (added cam_offset_x/y) - Fix Unicode emoji status icons (replaced with ASCII F/P/I/B) - Fix Unicode UI chars (█░·─│┌┐└┘◆■ → ASCII #-./|++++*#) - Add missing char_bitmap glyphs (+, =, >, <, *, %, #, |, @, _) LOW: - Fix draw_messages writing to negative y coordinates - Fix WindowInput losing key state on focus loss (clear_keys on Focused(false)) - Fix compute_lighting using full grid scan instead of gather_sources_in_range All 171 tests + 14 scenarios pass.
This commit is contained in:
+42
-10
@@ -25,6 +25,8 @@ pub struct Game {
|
|||||||
pub ui: UiLayer,
|
pub ui: UiLayer,
|
||||||
pub cam_x: i32,
|
pub cam_x: i32,
|
||||||
pub cam_y: i32,
|
pub cam_y: i32,
|
||||||
|
pub cam_offset_x: i32,
|
||||||
|
pub cam_offset_y: i32,
|
||||||
pub running: bool,
|
pub running: bool,
|
||||||
pub tick: u64,
|
pub tick: u64,
|
||||||
pub fixed_dt: Duration,
|
pub fixed_dt: Duration,
|
||||||
@@ -56,6 +58,8 @@ impl Game {
|
|||||||
ui: UiLayer::new(),
|
ui: UiLayer::new(),
|
||||||
cam_x: 100,
|
cam_x: 100,
|
||||||
cam_y: 100,
|
cam_y: 100,
|
||||||
|
cam_offset_x: 0,
|
||||||
|
cam_offset_y: 0,
|
||||||
running: true,
|
running: true,
|
||||||
tick: 0,
|
tick: 0,
|
||||||
fixed_dt: Duration::from_millis(16),
|
fixed_dt: Duration::from_millis(16),
|
||||||
@@ -239,8 +243,8 @@ impl Game {
|
|||||||
let vw = renderer.viewport_w();
|
let vw = renderer.viewport_w();
|
||||||
let vh = renderer.viewport_h();
|
let vh = renderer.viewport_h();
|
||||||
let (px, py) = self.player.center(&self.entities);
|
let (px, py) = self.player.center(&self.entities);
|
||||||
self.cam_x = px as i32 - (vw as i32 / 2);
|
self.cam_x = px as i32 - (vw as i32 / 2) + self.cam_offset_x;
|
||||||
self.cam_y = py as i32 - (vh as i32 / 2);
|
self.cam_y = py as i32 - (vh as i32 / 2) + self.cam_offset_y;
|
||||||
|
|
||||||
self.build_ui(vw, vh);
|
self.build_ui(vw, vh);
|
||||||
|
|
||||||
@@ -520,12 +524,16 @@ impl Game {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn descend(&mut self) {
|
pub fn descend(&mut self) {
|
||||||
if let Some(e) = self.player.entity(&self.entities) {
|
let can_descend = match self.player.entity(&self.entities) {
|
||||||
let foot_x = e.cx as i32;
|
Some(e) => {
|
||||||
let foot_y = (e.cy + e.half_h).ceil() as i32;
|
let foot_x = e.cx as i32;
|
||||||
if self.grid.get(foot_x, foot_y).material != MaterialId::Stairs {
|
let foot_y = (e.cy + e.half_h).ceil() as i32;
|
||||||
return;
|
self.grid.get(foot_x, foot_y).material == MaterialId::Stairs
|
||||||
}
|
}
|
||||||
|
None => false,
|
||||||
|
};
|
||||||
|
if !can_descend {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
self.depth += 1;
|
self.depth += 1;
|
||||||
self.grid = Grid::new();
|
self.grid = Grid::new();
|
||||||
@@ -546,10 +554,18 @@ impl Game {
|
|||||||
let item = self.player.inventory[index].clone();
|
let item = self.player.inventory[index].clone();
|
||||||
let name = item.name();
|
let name = item.name();
|
||||||
if item.is_weapon() {
|
if item.is_weapon() {
|
||||||
|
if let Some(old) = self.player.weapon.take() {
|
||||||
|
self.player.inventory.push(old);
|
||||||
|
}
|
||||||
self.player.weapon = Some(item);
|
self.player.weapon = Some(item);
|
||||||
|
self.player.inventory.remove(index);
|
||||||
self.ui.add_message(&format!("Equipped {}", name));
|
self.ui.add_message(&format!("Equipped {}", name));
|
||||||
} else if item.is_armor() {
|
} else if item.is_armor() {
|
||||||
|
if let Some(old) = self.player.armor.take() {
|
||||||
|
self.player.inventory.push(old);
|
||||||
|
}
|
||||||
self.player.armor = Some(item);
|
self.player.armor = Some(item);
|
||||||
|
self.player.inventory.remove(index);
|
||||||
self.ui.add_message(&format!("Equipped {}", name));
|
self.ui.add_message(&format!("Equipped {}", name));
|
||||||
} else if item.is_consumable() {
|
} else if item.is_consumable() {
|
||||||
let heal = item.heal_amount();
|
let heal = item.heal_amount();
|
||||||
@@ -752,11 +768,16 @@ impl Game {
|
|||||||
let jump_phase = tick % 60;
|
let jump_phase = tick % 60;
|
||||||
if jump_phase == 0 && dist < 40.0 {
|
if jump_phase == 0 && dist < 40.0 {
|
||||||
let dir_x = dx / dist;
|
let dir_x = dx / dist;
|
||||||
let _dir_y = dy / dist;
|
let dir_y = dy / dist;
|
||||||
let jump_power = 0.8 + (1.0 - dist / 40.0).min(0.5) * 0.5;
|
let jump_power = 0.8 + (1.0 - dist / 40.0).min(0.5) * 0.5;
|
||||||
if let Some(e) = self.entities.all_mut().get_mut(idx) {
|
if let Some(e) = self.entities.all_mut().get_mut(idx) {
|
||||||
e.set_horizontal_vel(dir_x * jump_power);
|
e.set_horizontal_vel(dir_x * jump_power);
|
||||||
e.set_vertical_vel(-jump_power * 0.8);
|
let vy = if dy < -1.0 {
|
||||||
|
-jump_power * 0.8
|
||||||
|
} else {
|
||||||
|
-jump_power * 0.6
|
||||||
|
};
|
||||||
|
e.set_vertical_vel(vy + dir_y * jump_power * 0.3);
|
||||||
}
|
}
|
||||||
} else if jump_phase == 30 {
|
} else if jump_phase == 30 {
|
||||||
if let Some(e) = self.entities.all_mut().get_mut(idx) {
|
if let Some(e) = self.entities.all_mut().get_mut(idx) {
|
||||||
@@ -768,6 +789,14 @@ impl Game {
|
|||||||
|
|
||||||
fn update_combat(&mut self) {
|
fn update_combat(&mut self) {
|
||||||
let player_id = self.player.entity_id;
|
let player_id = self.player.entity_id;
|
||||||
|
let player_alive = self
|
||||||
|
.entities
|
||||||
|
.get(player_id)
|
||||||
|
.map(|e| e.alive)
|
||||||
|
.unwrap_or(false);
|
||||||
|
if !player_alive {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let player_center = self.player.center(&self.entities);
|
let player_center = self.player.center(&self.entities);
|
||||||
let player_half_w = self
|
let player_half_w = self
|
||||||
.entities
|
.entities
|
||||||
@@ -1196,7 +1225,10 @@ impl Game {
|
|||||||
substeps: u32,
|
substeps: u32,
|
||||||
) {
|
) {
|
||||||
let grid = &self.grid;
|
let grid = &self.grid;
|
||||||
let e = self.entities.all_mut().get_mut(idx).unwrap();
|
let e = match self.entities.all_mut().get_mut(idx) {
|
||||||
|
Some(e) => e,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
let alive = e.alive;
|
let alive = e.alive;
|
||||||
let bodies = &mut e.bodies;
|
let bodies = &mut e.bodies;
|
||||||
let constraints = &e.constraints;
|
let constraints = &e.constraints;
|
||||||
|
|||||||
+9
-6
@@ -229,6 +229,9 @@ fn run_gpu_mode<R: GpuRenderer>(title: &str) {
|
|||||||
} => {
|
} => {
|
||||||
input.on_key_event(key_event.physical_key, key_event.state);
|
input.on_key_event(key_event.physical_key, key_event.state);
|
||||||
}
|
}
|
||||||
|
WindowEvent::Focused(false) => {
|
||||||
|
input.clear_keys();
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
Event::AboutToWait => {
|
Event::AboutToWait => {
|
||||||
@@ -296,16 +299,16 @@ fn run_gpu_mode<R: GpuRenderer>(title: &str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if input.cam_left {
|
if input.cam_left {
|
||||||
game.cam_x -= 3;
|
game.cam_offset_x -= 3;
|
||||||
}
|
}
|
||||||
if input.cam_right {
|
if input.cam_right {
|
||||||
game.cam_x += 3;
|
game.cam_offset_x += 3;
|
||||||
}
|
}
|
||||||
if input.cam_up {
|
if input.cam_up {
|
||||||
game.cam_y -= 3;
|
game.cam_offset_y -= 3;
|
||||||
}
|
}
|
||||||
if input.cam_down {
|
if input.cam_down {
|
||||||
game.cam_y += 3;
|
game.cam_offset_y += 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(brush_id) = input.paint {
|
if let Some(brush_id) = input.paint {
|
||||||
@@ -344,8 +347,8 @@ fn run_gpu_mode<R: GpuRenderer>(title: &str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let (px, py) = game.player.center(&game.entities);
|
let (px, py) = game.player.center(&game.entities);
|
||||||
game.cam_x = px as i32 - (vw as i32 / 2);
|
game.cam_x = px as i32 - (vw as i32 / 2) + game.cam_offset_x;
|
||||||
game.cam_y = py as i32 - (vh as i32 / 2);
|
game.cam_y = py as i32 - (vh as i32 / 2) + game.cam_offset_y;
|
||||||
|
|
||||||
game.build_ui(vw, vh);
|
game.build_ui(vw, vh);
|
||||||
|
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ impl Projectile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if entity.id != self.owner && entity.id != 0 {
|
if entity.id != self.owner {
|
||||||
let before = entity.health;
|
let before = entity.health;
|
||||||
entity.take_damage(self.total_damage());
|
entity.take_damage(self.total_damage());
|
||||||
ui.add_damage_number(
|
ui.add_damage_number(
|
||||||
@@ -155,7 +155,7 @@ impl Projectile {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if entity.id == self.owner || entity.id == 0 {
|
if entity.id == self.owner {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ fn background_color(wx: i32, wy: i32, vy: i32, view_h: i32) -> [u8; 3] {
|
|||||||
let base_g = (10.0 + t * 25.0) as u8;
|
let base_g = (10.0 + t * 25.0) as u8;
|
||||||
let base_b = (25.0 + t * 35.0) as u8;
|
let base_b = (25.0 + t * 35.0) as u8;
|
||||||
|
|
||||||
let hash = ((wx.wrapping_mul(73856093)) ^ (wy.wrapping_mul(19349663))).abs();
|
let hash = ((wx.wrapping_mul(73856093)) ^ (wy.wrapping_mul(19349663))).wrapping_abs();
|
||||||
if hash % 80 == 0 {
|
if hash % 80 == 0 {
|
||||||
let brightness = (60 + (hash % 120) as u8).min(255);
|
let brightness = (60 + (hash % 120) as u8).min(255);
|
||||||
return [brightness, brightness, brightness + 20];
|
return [brightness, brightness, brightness + 20];
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ fn background_color(wx: i32, wy: i32, vy: i32, view_h: i32) -> [u8; 4] {
|
|||||||
let base_g = (10.0 + t * 25.0) as u8;
|
let base_g = (10.0 + t * 25.0) as u8;
|
||||||
let base_b = (25.0 + t * 35.0) as u8;
|
let base_b = (25.0 + t * 35.0) as u8;
|
||||||
|
|
||||||
let hash = ((wx.wrapping_mul(73856093)) ^ (wy.wrapping_mul(19349663))).abs();
|
let hash = ((wx.wrapping_mul(73856093)) ^ (wy.wrapping_mul(19349663))).wrapping_abs();
|
||||||
if hash % 80 == 0 {
|
if hash % 80 == 0 {
|
||||||
let brightness = (60 + (hash % 120) as u8).min(255);
|
let brightness = (60 + (hash % 120) as u8).min(255);
|
||||||
return [brightness, brightness, brightness + 20, 255];
|
return [brightness, brightness, brightness + 20, 255];
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ pub fn compute_lighting(
|
|||||||
let mut grid_light = LightGrid::new(view_w, view_h);
|
let mut grid_light = LightGrid::new(view_w, view_h);
|
||||||
grid_light.clear(ambient);
|
grid_light.clear(ambient);
|
||||||
|
|
||||||
let sources = gather_sources(grid);
|
let sources = gather_sources_in_range(grid, cam_x, cam_y, view_w, view_h, 30);
|
||||||
let cap = sources.len().min(32);
|
let cap = sources.len().min(32);
|
||||||
let radius_limit = 30u32;
|
let radius_limit = 30u32;
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ fn background_color(wx: i32, wy: i32, vy: i32, view_h: i32) -> [u8; 4] {
|
|||||||
let base_g = (10.0 + t * 25.0) as u8;
|
let base_g = (10.0 + t * 25.0) as u8;
|
||||||
let base_b = (25.0 + t * 35.0) as u8;
|
let base_b = (25.0 + t * 35.0) as u8;
|
||||||
|
|
||||||
let hash = ((wx.wrapping_mul(73856093)) ^ (wy.wrapping_mul(19349663))).abs();
|
let hash = ((wx.wrapping_mul(73856093)) ^ (wy.wrapping_mul(19349663))).wrapping_abs();
|
||||||
if hash % 80 == 0 {
|
if hash % 80 == 0 {
|
||||||
let brightness = (60 + (hash % 120) as u8).min(255);
|
let brightness = (60 + (hash % 120) as u8).min(255);
|
||||||
return [brightness, brightness, brightness + 20, 255];
|
return [brightness, brightness, brightness + 20, 255];
|
||||||
|
|||||||
@@ -80,6 +80,10 @@ impl WindowInput {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clear_keys(&mut self) {
|
||||||
|
self.down_keys.clear();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn update(&mut self) {
|
pub fn update(&mut self) {
|
||||||
let keys = &self.down_keys;
|
let keys = &self.down_keys;
|
||||||
|
|
||||||
|
|||||||
+46
-31
@@ -183,7 +183,7 @@ impl UiLayer {
|
|||||||
};
|
};
|
||||||
for i in 0..width {
|
for i in 0..width {
|
||||||
let x = screen_x + i;
|
let x = screen_x + i;
|
||||||
let ch = if i < filled { '█' } else { '░' };
|
let ch = if i < filled { '#' } else { '-' };
|
||||||
let fg = if i < filled { color } else { [80, 80, 80] };
|
let fg = if i < filled { color } else { [80, 80, 80] };
|
||||||
self.set(x, screen_y, ch, fg, [0, 0, 0]);
|
self.set(x, screen_y, ch, fg, [0, 0, 0]);
|
||||||
}
|
}
|
||||||
@@ -212,19 +212,19 @@ impl UiLayer {
|
|||||||
let icon_x = sx + (e.half_w as i32 * UI_SCALE) + 1;
|
let icon_x = sx + (e.half_w as i32 * UI_SCALE) + 1;
|
||||||
let mut icon_y = sy - (e.half_h as i32 * UI_SCALE) - 7;
|
let mut icon_y = sy - (e.half_h as i32 * UI_SCALE) - 7;
|
||||||
if e.on_fire {
|
if e.on_fire {
|
||||||
self.set(icon_x, icon_y, '🔥', [255, 100, 20], [0, 0, 0]);
|
self.set(icon_x, icon_y, 'F', [255, 100, 20], [0, 0, 0]);
|
||||||
icon_y += 1;
|
icon_y += 1;
|
||||||
}
|
}
|
||||||
if e.poisoned {
|
if e.poisoned {
|
||||||
self.set(icon_x, icon_y, '☠', [80, 255, 80], [0, 0, 0]);
|
self.set(icon_x, icon_y, 'P', [80, 255, 80], [0, 0, 0]);
|
||||||
icon_y += 1;
|
icon_y += 1;
|
||||||
}
|
}
|
||||||
if e.frozen {
|
if e.frozen {
|
||||||
self.set(icon_x, icon_y, '❄', [120, 220, 255], [0, 0, 0]);
|
self.set(icon_x, icon_y, 'I', [120, 220, 255], [0, 0, 0]);
|
||||||
icon_y += 1;
|
icon_y += 1;
|
||||||
}
|
}
|
||||||
if e.bleeding {
|
if e.bleeding {
|
||||||
self.set(icon_x, icon_y, '✚', [255, 40, 40], [0, 0, 0]);
|
self.set(icon_x, icon_y, 'B', [255, 40, 40], [0, 0, 0]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -286,7 +286,7 @@ impl UiLayer {
|
|||||||
[40, 40, 50]
|
[40, 40, 50]
|
||||||
};
|
};
|
||||||
let bg = [20, 20, 30];
|
let bg = [20, 20, 30];
|
||||||
self.set(start_x + dx, start_y + dy, '·', fg, bg);
|
self.set(start_x + dx, start_y + dy, '.', fg, bg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for e in entities {
|
for e in entities {
|
||||||
@@ -308,20 +308,20 @@ impl UiLayer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for dx in 0..size {
|
for dx in 0..size {
|
||||||
self.set(start_x + dx, start_y - 1, '─', [80, 80, 100], [0, 0, 0]);
|
self.set(start_x + dx, start_y - 1, '-', [80, 80, 100], [0, 0, 0]);
|
||||||
self.set(start_x + dx, start_y + size, '─', [80, 80, 100], [0, 0, 0]);
|
self.set(start_x + dx, start_y + size, '-', [80, 80, 100], [0, 0, 0]);
|
||||||
}
|
}
|
||||||
for dy in 0..size {
|
for dy in 0..size {
|
||||||
self.set(start_x - 1, start_y + dy, '│', [80, 80, 100], [0, 0, 0]);
|
self.set(start_x - 1, start_y + dy, '|', [80, 80, 100], [0, 0, 0]);
|
||||||
self.set(start_x + size, start_y + dy, '│', [80, 80, 100], [0, 0, 0]);
|
self.set(start_x + size, start_y + dy, '|', [80, 80, 100], [0, 0, 0]);
|
||||||
}
|
}
|
||||||
self.set(start_x - 1, start_y - 1, '┌', [80, 80, 100], [0, 0, 0]);
|
self.set(start_x - 1, start_y - 1, '+', [80, 80, 100], [0, 0, 0]);
|
||||||
self.set(start_x + size, start_y - 1, '┐', [80, 80, 100], [0, 0, 0]);
|
self.set(start_x + size, start_y - 1, '+', [80, 80, 100], [0, 0, 0]);
|
||||||
self.set(start_x - 1, start_y + size, '└', [80, 80, 100], [0, 0, 0]);
|
self.set(start_x - 1, start_y + size, '+', [80, 80, 100], [0, 0, 0]);
|
||||||
self.set(
|
self.set(
|
||||||
start_x + size,
|
start_x + size,
|
||||||
start_y + size,
|
start_y + size,
|
||||||
'┘',
|
'+',
|
||||||
[80, 80, 100],
|
[80, 80, 100],
|
||||||
[0, 0, 0],
|
[0, 0, 0],
|
||||||
);
|
);
|
||||||
@@ -351,23 +351,23 @@ impl UiLayer {
|
|||||||
}
|
}
|
||||||
for x in 0..w {
|
for x in 0..w {
|
||||||
if (start_x + x) % 2 == 0 {
|
if (start_x + x) % 2 == 0 {
|
||||||
self.set_alpha(start_x + x, start_y, '·', border, bg, border_alpha);
|
self.set_alpha(start_x + x, start_y, '.', border, bg, border_alpha);
|
||||||
self.set_alpha(start_x + x, start_y + h - 1, '·', border, bg, border_alpha);
|
self.set_alpha(start_x + x, start_y + h - 1, '.', border, bg, border_alpha);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for y in 0..h {
|
for y in 0..h {
|
||||||
if (start_y + y) % 2 == 0 {
|
if (start_y + y) % 2 == 0 {
|
||||||
self.set_alpha(start_x, start_y + y, '·', border, bg, border_alpha);
|
self.set_alpha(start_x, start_y + y, '.', border, bg, border_alpha);
|
||||||
self.set_alpha(start_x + w - 1, start_y + y, '·', border, bg, border_alpha);
|
self.set_alpha(start_x + w - 1, start_y + y, '.', border, bg, border_alpha);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.set_alpha(start_x, start_y, '◆', border, bg, border_alpha);
|
self.set_alpha(start_x, start_y, '*', border, bg, border_alpha);
|
||||||
self.set_alpha(start_x + w - 1, start_y, '◆', border, bg, border_alpha);
|
self.set_alpha(start_x + w - 1, start_y, '*', border, bg, border_alpha);
|
||||||
self.set_alpha(start_x, start_y + h - 1, '◆', border, bg, border_alpha);
|
self.set_alpha(start_x, start_y + h - 1, '*', border, bg, border_alpha);
|
||||||
self.set_alpha(
|
self.set_alpha(
|
||||||
start_x + w - 1,
|
start_x + w - 1,
|
||||||
start_y + h - 1,
|
start_y + h - 1,
|
||||||
'◆',
|
'*',
|
||||||
border,
|
border,
|
||||||
bg,
|
bg,
|
||||||
border_alpha,
|
border_alpha,
|
||||||
@@ -389,7 +389,7 @@ impl UiLayer {
|
|||||||
};
|
};
|
||||||
self.draw_text(start_x + 2, start_y + 7, "HP", fg, 255);
|
self.draw_text(start_x + 2, start_y + 7, "HP", fg, 255);
|
||||||
for i in 0..32 {
|
for i in 0..32 {
|
||||||
let ch = if i < hp_filled { '█' } else { '░' };
|
let ch = if i < hp_filled { '#' } else { '-' };
|
||||||
let c = if i < hp_filled {
|
let c = if i < hp_filled {
|
||||||
bar_color
|
bar_color
|
||||||
} else {
|
} else {
|
||||||
@@ -404,7 +404,7 @@ impl UiLayer {
|
|||||||
let xp_filled = (xp_ratio * 32.0).round() as i32;
|
let xp_filled = (xp_ratio * 32.0).round() as i32;
|
||||||
self.draw_text(start_x + 2, start_y + 19, "XP", fg, 255);
|
self.draw_text(start_x + 2, start_y + 19, "XP", fg, 255);
|
||||||
for i in 0..32 {
|
for i in 0..32 {
|
||||||
let ch = if i < xp_filled { '█' } else { '░' };
|
let ch = if i < xp_filled { '#' } else { '-' };
|
||||||
let c = if i < xp_filled {
|
let c = if i < xp_filled {
|
||||||
[80, 160, 240]
|
[80, 160, 240]
|
||||||
} else {
|
} else {
|
||||||
@@ -431,16 +431,16 @@ impl UiLayer {
|
|||||||
let status = if let Some(p) = player {
|
let status = if let Some(p) = player {
|
||||||
let mut s = String::new();
|
let mut s = String::new();
|
||||||
if p.on_fire {
|
if p.on_fire {
|
||||||
s.push('🔥');
|
s.push_str("[FIRE] ");
|
||||||
}
|
}
|
||||||
if p.poisoned {
|
if p.poisoned {
|
||||||
s.push('☠');
|
s.push_str("[PSN] ");
|
||||||
}
|
}
|
||||||
if p.frozen {
|
if p.frozen {
|
||||||
s.push('❄');
|
s.push_str("[ICE] ");
|
||||||
}
|
}
|
||||||
if p.bleeding {
|
if p.bleeding {
|
||||||
s.push('✚');
|
s.push_str("[BLD] ");
|
||||||
}
|
}
|
||||||
s
|
s
|
||||||
} else {
|
} else {
|
||||||
@@ -508,7 +508,7 @@ impl UiLayer {
|
|||||||
}
|
}
|
||||||
for x in 0..screen_w {
|
for x in 0..screen_w {
|
||||||
if x % 2 == 0 {
|
if x % 2 == 0 {
|
||||||
self.set_alpha(x as i32, y_top - 1, '·', border, bg, 220);
|
self.set_alpha(x as i32, y_top - 1, '.', border, bg, 220);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -524,7 +524,7 @@ impl UiLayer {
|
|||||||
[255, 60, 60]
|
[255, 60, 60]
|
||||||
};
|
};
|
||||||
for i in 0..28 {
|
for i in 0..28 {
|
||||||
let ch = if i < hp_filled { '█' } else { '░' };
|
let ch = if i < hp_filled { '#' } else { '-' };
|
||||||
let c = if i < hp_filled { bar_fg } else { [70, 70, 90] };
|
let c = if i < hp_filled { bar_fg } else { [70, 70, 90] };
|
||||||
self.set(10 + i, y_row1 + 4, ch, c, bg);
|
self.set(10 + i, y_row1 + 4, ch, c, bg);
|
||||||
}
|
}
|
||||||
@@ -533,7 +533,7 @@ impl UiLayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let brush_color = brush_color(brush);
|
let brush_color = brush_color(brush);
|
||||||
self.set(0, y_row2 + 4, '■', brush_color, bg);
|
self.set(0, y_row2 + 4, '#', brush_color, bg);
|
||||||
let brush_text = format!(" {}", brush_name);
|
let brush_text = format!(" {}", brush_name);
|
||||||
self.draw_text(1, y_row2, &brush_text, [200, 200, 140], 255);
|
self.draw_text(1, y_row2, &brush_text, [200, 200, 140], 255);
|
||||||
|
|
||||||
@@ -573,6 +573,9 @@ impl UiLayer {
|
|||||||
let mut yy = y;
|
let mut yy = y;
|
||||||
let messages: Vec<(String, u32)> = self.messages.iter().rev().take(8).cloned().collect();
|
let messages: Vec<(String, u32)> = self.messages.iter().rev().take(8).cloned().collect();
|
||||||
for (msg, life) in messages {
|
for (msg, life) in messages {
|
||||||
|
if yy < 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
let fade = (life as f32 / 300.0).clamp(0.3, 1.0);
|
let fade = (life as f32 / 300.0).clamp(0.3, 1.0);
|
||||||
let fg = [
|
let fg = [
|
||||||
(200.0 * fade) as u8,
|
(200.0 * fade) as u8,
|
||||||
@@ -732,6 +735,18 @@ fn char_bitmap(c: char) -> Option<[u8; 5]> {
|
|||||||
'?' => Some([0b111, 0b001, 0b011, 0b000, 0b010]),
|
'?' => Some([0b111, 0b001, 0b011, 0b000, 0b010]),
|
||||||
'!' => Some([0b010, 0b010, 0b010, 0b000, 0b010]),
|
'!' => Some([0b010, 0b010, 0b010, 0b000, 0b010]),
|
||||||
'.' => Some([0b000, 0b000, 0b000, 0b000, 0b010]),
|
'.' => Some([0b000, 0b000, 0b000, 0b000, 0b010]),
|
||||||
|
',' => Some([0b000, 0b000, 0b000, 0b010, 0b100]),
|
||||||
|
'\'' => Some([0b010, 0b010, 0b000, 0b000, 0b000]),
|
||||||
|
'+' => Some([0b000, 0b010, 0b111, 0b010, 0b000]),
|
||||||
|
'=' => Some([0b000, 0b111, 0b000, 0b111, 0b000]),
|
||||||
|
'>' => Some([0b100, 0b010, 0b001, 0b010, 0b100]),
|
||||||
|
'<' => Some([0b001, 0b010, 0b100, 0b010, 0b001]),
|
||||||
|
'*' => Some([0b000, 0b101, 0b010, 0b101, 0b000]),
|
||||||
|
'%' => Some([0b101, 0b001, 0b010, 0b100, 0b101]),
|
||||||
|
'#' => Some([0b101, 0b111, 0b101, 0b111, 0b101]),
|
||||||
|
'|' => Some([0b010, 0b010, 0b010, 0b010, 0b010]),
|
||||||
|
'@' => Some([0b111, 0b101, 0b111, 0b101, 0b111]),
|
||||||
|
'_' => Some([0b000, 0b000, 0b000, 0b000, 0b111]),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user