Pixel-art mouse pointers and hand actions

- pointing monster hand with the active tool's icon, grabbing hand / fist, animated backhand and punch
- active tool highlighted in the toolbar (pulsing frame, arrow)
- hand: pick up unconscious heroes on own ground, drop prisoners anywhere on own ground
  (onto a free torture place = locked up), Shift+click backhand (speed-up) / punch (stun)
- fix: hint slots overflowed with the new hints; hint times are no longer saved
- test for the hand rules

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard ZinkandClaude Opus 5.5 committed 2026-11-03 08:53:21 +01:00
1 parent 50d013bb28
commit f113e1085c
9 files changed
+372 -32

No files matched your search

+107 -1
View File
@@ -52,6 +52,7 @@ pub const D_ALTAR: u32 = 88;
pub struct Gfx {
pub atlas: Texture2D,
pub sprites: Texture2D,
pub cursors: Texture2D, // mouse pointer frames, 16x16 each (see CURSOR_*)
pub font: Texture2D, // DINOBYTE, CP437, 16x16 glyphs of 6x8 px
}
@@ -746,6 +747,109 @@ fn gen_sprites() -> Image {
img
}
// ------------------------------------------------------------------ mouse pointers (16x16)
pub const CURSOR_POINT: u32 = 0; // pointing monster hand (hot spot: finger tip)
pub const CURSOR_OPEN: u32 = 1; // open grabbing hand (hot spot: palm centre)
pub const CURSOR_FIST: u32 = 2; // holding something
pub const CURSOR_BACKHAND: u32 = 3; // slap, with motion streaks
pub const CURSOR_PUNCH: u32 = 4; // punch, with impact star
pub const CURSOR_HOT: [(f32, f32); 5] = [(2.0, 1.0), (7.0, 7.0), (7.0, 7.0), (7.0, 7.0), (7.0, 7.0)];
const CUR_POINT: [&str; 16] = [
"..kk............",
".kwwk...........",
".kggk...........",
".kggk...........",
".kggkkk.........",
".kggkggkkk......",
".kggkggkggkk....",
"kkggggggggggk...",
"kgkgggggggggk...",
"kggggggggggGk...",
".kgggggggggGk...",
"..kggggggggGk...",
"..kgggggggGk....",
"...kGGGGGGk.....",
"...kkkkkkkk.....",
"................",
];
const CUR_OPEN: [&str; 16] = [
"................",
".kw.kw.kw.......",
".kgkkgkkgk..kw..",
".kgkkgkkgk.kgk..",
".kgkkgkkgkkggk..",
".kgggggggggggk..",
"kkgggggggggggk..",
"kgkggggggggggk..",
"kggkgggggggGk...",
".kggggggggggk...",
"..kgggggggGk....",
"...kggggggGk....",
"...kgggggGk.....",
"....kGGGGk......",
"....kkkkkk......",
"................",
];
const CUR_FIST: [&str; 16] = [
"................",
"................",
"................",
"...kkkkkkkk.....",
"..kgkgkgkgGk....",
"..kgkgkgkgGk....",
".kkggggggggGk...",
"kggkgggggggGk...",
"kgggggggggGGk...",
".kggggggggGk....",
"..kgggggggGk....",
"...kggggggGk....",
"...kGGGGGGk.....",
"....kkkkkk......",
"................",
"................",
];
fn cursor_pal(ch: char) -> Option<Color> {
Some(match ch {
'k' => c(20, 16, 18),
'g' => c(112, 152, 84),
'G' => c(70, 100, 56),
'w' => c(236, 230, 208),
'y' => c(255, 220, 80),
's' => c(255, 255, 255),
_ => return None,
})
}
fn gen_cursors() -> Image {
let mut img = Image::gen_image_color(16 * 5, 16, Color::new(0.0, 0.0, 0.0, 0.0));
let mut put = |frame: u32, rows: &[&str; 16], mirror: bool| {
for (y, row) in rows.iter().enumerate() {
for (x, ch) in row.chars().enumerate() {
if let Some(col) = cursor_pal(ch) {
let xx = if mirror { 15 - x } else { x };
img.set_pixel(frame * 16 + xx as u32, y as u32, col);
}
}
}
};
put(CURSOR_POINT, &CUR_POINT, false);
put(CURSOR_OPEN, &CUR_OPEN, false);
put(CURSOR_FIST, &CUR_FIST, false);
put(CURSOR_BACKHAND, &CUR_OPEN, true);
put(CURSOR_PUNCH, &CUR_FIST, false);
// motion streaks for the backhand, impact star for the punch
for &(x, y) in &[(0, 5), (1, 5), (0, 7), (1, 7), (2, 7), (0, 9), (1, 9)] {
img.set_pixel(CURSOR_BACKHAND * 16 + x, y, c(255, 255, 255));
}
for &(x, y) in &[(0, 0), (2, 1), (1, 2), (0, 3), (3, 0), (4, 2), (2, 4)] {
img.set_pixel(CURSOR_PUNCH * 16 + x, y, c(255, 220, 80));
}
img
}
impl Gfx {
pub fn new() -> Gfx {
let atlas = Texture2D::from_image(&gen_atlas());
@@ -760,7 +864,9 @@ impl Gfx {
}
let font = Texture2D::from_image(&img);
font.set_filter(FilterMode::Nearest);
Gfx { atlas, sprites, font }
let cursors = Texture2D::from_image(&gen_cursors());
cursors.set_filter(FilterMode::Nearest);
Gfx { atlas, sprites, cursors, font }
}
pub fn cell(id: u32) -> Rect {