diff --git a/include/nlernd.h b/include/nlernd.h index 113c789e9..21132ab90 100644 --- a/include/nlernd.h +++ b/include/nlernd.h @@ -22,4 +22,7 @@ void nle_get_seed(nle_ctx_t *, unsigned long *, unsigned long *, boolean *, /* Fill struct tm with deterministic values from seed via ISAAC64. */ void nle_fill_fixed_tm(struct tm *, unsigned long); +/* Deterministic ubirthday from seed via ISAAC64. */ +time_t nle_fixed_birthday(unsigned long); + #endif \ No newline at end of file diff --git a/src/hacklib.c b/src/hacklib.c index c0c877fc4..475accd09 100644 --- a/src/hacklib.c +++ b/src/hacklib.c @@ -955,7 +955,7 @@ nle_getlt_maybe_fixed() int getyear() { - return (1900 + getlt()->tm_year); + return (1900 + nle_getlt_maybe_fixed()->tm_year); } #if 0 diff --git a/src/nlernd.c b/src/nlernd.c index 73892c35f..fdf285ff9 100644 --- a/src/nlernd.c +++ b/src/nlernd.c @@ -163,6 +163,27 @@ nle_fill_fixed_tm(struct tm *tm, unsigned long seed) tm->tm_yday = tm->tm_mon * 30 + tm->tm_mday; } +/* + * Deterministic ubirthday derived from the seed. NetHack hashes + * ubirthday for between-game flavor variation without consuming game + * RNG (shopkeeper names in shknam.c, shop surcharge parity in shk.c, + * antholemon() in mkroom.c, scroll labels in read.c), so a wall-clock + * ubirthday leaks real time into otherwise fully seeded games. + */ +time_t +nle_fixed_birthday(unsigned long seed) +{ + isaac64_ctx time_rng; + unsigned char seed_bytes[sizeof(seed)]; + + memcpy(seed_bytes, &seed, sizeof(seed_bytes)); + isaac64_init(&time_rng, seed_bytes, sizeof(seed_bytes)); + + /* Arbitrary fixed epoch range: 2000-01-01 plus up to ~40 years. */ + return (time_t) (946684800UL + + isaac64_next_uint(&time_rng, 1262304000UL)); +} + void nle_set_seed(nle_ctx_t *nle, unsigned long core, unsigned long disp, boolean reseed, unsigned long lgen) diff --git a/src/u_init.c b/src/u_init.c index 77e7445c1..347ae5bf0 100644 --- a/src/u_init.c +++ b/src/u_init.c @@ -4,6 +4,10 @@ /* NetHack may be freely redistributed. See license for details. */ #include "hack.h" +#include "nlernd.h" +#include "nletypes.h" + +extern nle_settings settings; struct trobj { short trotyp; @@ -645,11 +649,16 @@ u_init() u.ualignbase[A_CURRENT] = u.ualignbase[A_ORIGINAL] = u.ualign.type = aligns[flags.initalign].value; + if (settings.fix_moon_phase && settings.time_seed_is_set) { + /* NLE: pin ubirthday to the seed; see nle_fixed_birthday(). */ + ubirthday = nle_fixed_birthday(settings.time_seed); + } else { #if defined(BSD) && !defined(POSIX_TYPES) - (void) time((long *) &ubirthday); + (void) time((long *) &ubirthday); #else - (void) time(&ubirthday); + (void) time(&ubirthday); #endif + } /* * For now, everyone starts out with a night vision range of 1 and