Holidays: Christmas and Easter beside Halloween, two weeks before to a few days after; decorations in the dungeon and around the title
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c23c4d28ec
commit
8f670554c7
5 files changed
+281
-5
No files matched your search
+109
@@ -0,0 +1,109 @@
|
||||
// Holidays of the real date: the dungeon and the title menu dress up for them (pumpkins,
|
||||
// fir trees and presents, painted eggs; see render3d's room decor and menu's draw_title).
|
||||
// Every holiday runs from about two weeks before its day to a few days after it.
|
||||
|
||||
pub const NONE: u8 = 0;
|
||||
pub const HALLOWEEN: u8 = 1;
|
||||
pub const CHRISTMAS: u8 = 2;
|
||||
pub const EASTER: u8 = 3;
|
||||
|
||||
// days since 1970-01-01 of a date (proleptic Gregorian)
|
||||
fn days_from_civil(y: i64, m: i64, d: i64) -> i64 {
|
||||
let y = if m <= 2 { y - 1 } else { y };
|
||||
let era = y.div_euclid(400);
|
||||
let yoe = y - era * 400;
|
||||
let mp = (m + 9) % 12;
|
||||
let doy = (153 * mp + 2) / 5 + d - 1;
|
||||
let doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
|
||||
era * 146097 + doe - 719468
|
||||
}
|
||||
|
||||
// Easter Sunday of a year (month, day): the anonymous Gregorian algorithm
|
||||
pub fn easter(y: i64) -> (i64, i64) {
|
||||
let a = y % 19;
|
||||
let b = y / 100;
|
||||
let c = y % 100;
|
||||
let d = b / 4;
|
||||
let e = b % 4;
|
||||
let f = (b + 8) / 25;
|
||||
let g = (b - f + 1) / 3;
|
||||
let h = (19 * a + b - d - g + 15) % 30;
|
||||
let i = c / 4;
|
||||
let k = c % 4;
|
||||
let l = (32 + 2 * e + 2 * i - h - k) % 7;
|
||||
let m = (a + 11 * h + 22 * l) / 451;
|
||||
let n = h + l - 7 * m + 114;
|
||||
(n / 31, n % 31 + 1)
|
||||
}
|
||||
|
||||
// the holiday on a date: Halloween 17 Oct - 3 Nov, Christmas 10 Dec - 1 Jan, Easter from two
|
||||
// weeks before Easter Sunday to the Wednesday after it
|
||||
pub fn holiday_on(y: i64, m: i64, d: i64) -> u8 {
|
||||
match (m, d) {
|
||||
(10, 17..=31) | (11, 1..=3) => return HALLOWEEN,
|
||||
(12, 10..=31) | (1, 1) => return CHRISTMAS,
|
||||
_ => {}
|
||||
}
|
||||
let (em, ed) = easter(y);
|
||||
let off = days_from_civil(y, m, d) - days_from_civil(y, em, ed);
|
||||
if (-14..=3).contains(&off) {
|
||||
EASTER
|
||||
} else {
|
||||
NONE
|
||||
}
|
||||
}
|
||||
|
||||
// today's holiday (worked out once); on the desktop DUNGEONCRAFT_HOLIDAY=halloween / christmas /
|
||||
// easter / none shows one at any time
|
||||
pub fn current() -> u8 {
|
||||
thread_local! {
|
||||
static HOLIDAY: std::cell::Cell<u8> = const { std::cell::Cell::new(255) };
|
||||
}
|
||||
HOLIDAY.with(|h| {
|
||||
if h.get() == 255 {
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let forced = std::env::var("DUNGEONCRAFT_HOLIDAY").ok().and_then(|v| match v.to_lowercase().as_str() {
|
||||
"halloween" => Some(HALLOWEEN),
|
||||
"christmas" | "xmas" => Some(CHRISTMAS),
|
||||
"easter" => Some(EASTER),
|
||||
"none" => Some(NONE),
|
||||
_ => None,
|
||||
});
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let forced: Option<u8> = None;
|
||||
let (y, m, d, _, _) = crate::cloud::civil(macroquad::miniquad::date::now() as i64);
|
||||
h.set(forced.unwrap_or_else(|| holiday_on(y, m, d)));
|
||||
}
|
||||
h.get()
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn easter_dates() {
|
||||
assert_eq!(easter(2024), (3, 31));
|
||||
assert_eq!(easter(2025), (4, 20));
|
||||
assert_eq!(easter(2026), (4, 5));
|
||||
assert_eq!(easter(2027), (3, 28));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn holiday_windows() {
|
||||
assert_eq!(holiday_on(2026, 10, 16), NONE);
|
||||
assert_eq!(holiday_on(2026, 10, 17), HALLOWEEN);
|
||||
assert_eq!(holiday_on(2026, 11, 3), HALLOWEEN);
|
||||
assert_eq!(holiday_on(2026, 11, 7), NONE);
|
||||
assert_eq!(holiday_on(2026, 12, 9), NONE);
|
||||
assert_eq!(holiday_on(2026, 12, 10), CHRISTMAS);
|
||||
assert_eq!(holiday_on(2027, 1, 1), CHRISTMAS);
|
||||
assert_eq!(holiday_on(2027, 1, 2), NONE);
|
||||
// Easter 2026: 5 April
|
||||
assert_eq!(holiday_on(2026, 3, 21), NONE);
|
||||
assert_eq!(holiday_on(2026, 3, 22), EASTER);
|
||||
assert_eq!(holiday_on(2026, 4, 8), EASTER);
|
||||
assert_eq!(holiday_on(2026, 4, 9), NONE);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user