Holiday headwear on every unit: Christmas hats, carved pumpkins, bunny ears
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
6ff1cc5f8d
commit
a24fc51605
2 files changed
+111
-1
No files matched your search
+81
-1
@@ -1935,13 +1935,39 @@ fn gear_anchor(g: &Cell) -> GearAnchor {
|
||||
|
||||
// the gear's parts in their texture (grey, tinted by the metal or cloth colour at draw time):
|
||||
// (x, y, w, h) in texels of GEAR_TEX
|
||||
pub const GEAR_TEX: u32 = 64;
|
||||
pub const GEAR_TEX: u32 = 96;
|
||||
pub const GEAR_HELMET: (u32, u32, u32, u32) = (0, 0, 24, 12);
|
||||
pub const GEAR_PAULDRON: (u32, u32, u32, u32) = (24, 0, 12, 9);
|
||||
pub const GEAR_CROWN: (u32, u32, u32, u32) = (36, 0, 20, 10);
|
||||
pub const GEAR_CAPE: (u32, u32, u32, u32) = (0, 14, 28, 40);
|
||||
pub const GEAR_HORN: (u32, u32, u32, u32) = (28, 14, 7, 10);
|
||||
pub const GEAR_PLUME: (u32, u32, u32, u32) = (36, 14, 7, 12);
|
||||
// the holidays' headwear (in its own colours, not tinted): a Christmas hat, a carved pumpkin, bunny ears
|
||||
pub const GEAR_SANTA: (u32, u32, u32, u32) = (44, 14, 20, 20);
|
||||
pub const GEAR_PUMPKIN: (u32, u32, u32, u32) = (66, 14, 22, 20);
|
||||
pub const GEAR_EARS: (u32, u32, u32, u32) = (44, 36, 18, 18);
|
||||
|
||||
// where the gear of a 10x10 sprite goes (its cell, standing; per kind and view), for the
|
||||
// holidays' headwear in the pixel-art style
|
||||
static SMALL_ANCHORS: std::sync::OnceLock<Vec<GearAnchor>> = std::sync::OnceLock::new();
|
||||
|
||||
pub fn small_anchor(k: EK, view: u32) -> GearAnchor {
|
||||
let i = sprite_index(k) as usize * VIEWS as usize + view.min(VIEWS - 1) as usize;
|
||||
SMALL_ANCHORS
|
||||
.get_or_init(|| {
|
||||
let mut v = Vec::new();
|
||||
for &k in SPRITE_KINDS.iter() {
|
||||
for view in 0..VIEWS {
|
||||
let g: Cell = sprite_with_gear(k, 0, view).iter().map(|r| r.to_vec()).collect();
|
||||
v.push(gear_anchor(&g));
|
||||
}
|
||||
}
|
||||
v
|
||||
})
|
||||
.get(i)
|
||||
.copied()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
// kinds that carry treasure in a sack on the back (instead of the coin sign over the head);
|
||||
// their 10x10 sprite with the sack gets an own atlas column after SPRITE_KINDS
|
||||
@@ -2842,6 +2868,60 @@ fn gen_gear() -> Image {
|
||||
shape(GEAR_HORN, &|x, y| (x - (1.0 - y) * 0.4 - 0.3).abs() < 0.16 + 0.3 * y, &|x, y| 0.95 - y * 0.25 - x * 0.1);
|
||||
// plume: a feather bush
|
||||
shape(GEAR_PLUME, &|x, y| (x - 0.5).powi(2) * 3.2 + (y - 0.5).powi(2) * 1.1 <= 0.26 + 0.04 * (y * 14.0).sin(), &|_x, y| 0.95 - y * 0.3);
|
||||
// the holidays' headwear, coloured: a shape, outlined, its colour per texel
|
||||
let mut cshape = |(ox, oy, w, h): (u32, u32, u32, u32), inside: &dyn Fn(f32, f32) -> bool, paint: &dyn Fn(f32, f32) -> Color| {
|
||||
for y in 0..h {
|
||||
for x in 0..w {
|
||||
let (fx, fy) = ((x as f32 + 0.5) / w as f32, (y as f32 + 0.5) / h as f32);
|
||||
if !inside(fx, fy) {
|
||||
continue;
|
||||
}
|
||||
let edge = [(-1i32, 0i32), (1, 0), (0, -1), (0, 1)].iter().any(|&(dx, dy)| {
|
||||
let (nx, ny) = (x as i32 + dx, y as i32 + dy);
|
||||
nx < 0 || ny < 0 || nx >= w as i32 || ny >= h as i32 || !inside((nx as f32 + 0.5) / w as f32, (ny as f32 + 0.5) / h as f32)
|
||||
});
|
||||
img.set_pixel(ox + x, oy + y, if edge { outline } else { paint(fx, fy) });
|
||||
}
|
||||
}
|
||||
};
|
||||
// Christmas: a red hat bending to the side, white brim and bobble
|
||||
let santa_in = |x: f32, y: f32| {
|
||||
let bobble = (x - 0.85).powi(2) + (y - 0.12).powi(2) < 0.018;
|
||||
let brim = y > 0.72 && (x - 0.45).abs() < 0.45;
|
||||
let cone = y > 0.08 && y <= 0.75 && (x - (0.45 + (0.75 - y) * 0.5)).abs() < (y - 0.05) * 0.5;
|
||||
bobble || brim || cone
|
||||
};
|
||||
cshape(GEAR_SANTA, &santa_in, &|x, y| {
|
||||
if y > 0.72 || (x - 0.85).powi(2) + (y - 0.12).powi(2) < 0.018 {
|
||||
Color::new(0.95, 0.95, 0.97, 1.0)
|
||||
} else {
|
||||
Color::new(0.78 - x * 0.15, 0.1, 0.12, 1.0)
|
||||
}
|
||||
});
|
||||
// Halloween: a carved pumpkin over the head, a glowing face, a stalk
|
||||
cshape(GEAR_PUMPKIN, &|x, y| (x - 0.5).powi(2) * 3.6 + (y - 0.56).powi(2) * 4.4 <= 0.85 || ((x - 0.5).abs() < 0.07 && y < 0.25), &|x, y| {
|
||||
let eye = (y - 0.48).abs() < 0.08 && ((x - 0.33).abs() < 0.08 || (x - 0.67).abs() < 0.08);
|
||||
let mouth = (y - 0.72).abs() < 0.05 && (x - 0.5).abs() < 0.25 && ((x * 12.0) as i32 % 2 == 0 || (y - 0.72).abs() < 0.025);
|
||||
if y < 0.2 {
|
||||
Color::new(0.3, 0.5, 0.15, 1.0)
|
||||
} else if eye || mouth {
|
||||
Color::new(1.0, 0.85, 0.3, 1.0)
|
||||
} else if ((x - 0.5) * 6.0).fract().abs() < 0.12 {
|
||||
Color::new(0.75, 0.35, 0.05, 1.0)
|
||||
} else {
|
||||
Color::new(0.95, 0.5, 0.1, 1.0)
|
||||
}
|
||||
});
|
||||
// Easter: two upright bunny ears, pink inside
|
||||
let ear = |x: f32, y: f32, cx: f32, k: f32| (x - cx - (0.5 - y) * 0.12 * (cx - 0.5).signum()).powi(2) * k + (y - 0.5).powi(2) * 4.4 <= 1.0;
|
||||
cshape(GEAR_EARS, &|x, y| ear(x, y, 0.3, 70.0) || ear(x, y, 0.7, 70.0), &|x, y| {
|
||||
let inner = ear(x, y, 0.3, 260.0) || ear(x, y, 0.7, 260.0);
|
||||
if inner {
|
||||
Color::new(1.0, 0.65, 0.75, 1.0)
|
||||
} else {
|
||||
Color::new(0.97, 0.96, 0.94, 1.0)
|
||||
}
|
||||
});
|
||||
img
|
||||
}
|
||||
|
||||
|
||||
@@ -2048,6 +2048,36 @@ impl R3d {
|
||||
}
|
||||
}
|
||||
}
|
||||
// the holidays' headwear on everybody (both styles): a Christmas hat, a carved
|
||||
// pumpkin, bunny ears
|
||||
let holiday = crate::holiday::current();
|
||||
if holiday != crate::holiday::NONE && !white && e.captive == 0 && !sleeping {
|
||||
let an = match pic {
|
||||
Some(p) => Gfx::hd_anchor(p),
|
||||
None => crate::gfx::small_anchor(e.kind, v),
|
||||
};
|
||||
let at = |fx: f32, fy: f32| {
|
||||
let fx = if mirror { 1.0 - fx } else { fx };
|
||||
corner((fx - 0.5) * 1.2 * w, (1.0 - fy) * 1.2 * h - 0.1 * h) + toward * 0.01
|
||||
};
|
||||
let mid = (an.head.0 + an.head.1) * 0.5;
|
||||
let hw = (an.head.1 - an.head.0).max(0.12);
|
||||
let neck = an.top + (an.shoulder - an.top) * 0.75;
|
||||
let (x0, y0, x1, y1, part) = match holiday {
|
||||
crate::holiday::CHRISTMAS => (mid - hw * 0.62, an.top - hw * 0.75, mid + hw * 0.72, an.top + hw * 0.2, crate::gfx::GEAR_SANTA),
|
||||
crate::holiday::HALLOWEEN => (mid - hw * 0.68, an.top - hw * 0.25, mid + hw * 0.68, neck, crate::gfx::GEAR_PUMPKIN),
|
||||
_ => (mid - hw * 0.5, an.top - hw * 0.95, mid + hw * 0.5, an.top + hw * 0.05, crate::gfx::GEAR_EARS),
|
||||
};
|
||||
let gt = crate::gfx::GEAR_TEX as f32;
|
||||
let (mut a0, b0) = (part.0 as f32 / gt, part.1 as f32 / gt);
|
||||
let (mut a1, b1) = ((part.0 + part.2) as f32 / gt, (part.1 + part.3) as f32 / gt);
|
||||
if mirror {
|
||||
std::mem::swap(&mut a0, &mut a1);
|
||||
}
|
||||
let k = (a * 1.3).min(1.0);
|
||||
let hc = [(255.0 * k) as u8, (255.0 * k) as u8, (255.0 * k) as u8, 255];
|
||||
mb_gear.quad([at(x0, y0), at(x1, y0), at(x1, y1), at(x0, y1)], [vec2(a0, b0), vec2(a1, b0), vec2(a1, b1), vec2(a0, b1)], [hc; 4], [toward; 4]);
|
||||
}
|
||||
let mb = match pic {
|
||||
Some(_) if fine => &mut mb_hd,
|
||||
Some(_) => &mut mb_hd32,
|
||||
|
||||
Reference in new issue
Block a user