diff --git a/include/config.h b/include/config.h index 43861f058..95f0d526b 100644 --- a/include/config.h +++ b/include/config.h @@ -556,6 +556,7 @@ typedef unsigned char uchar; #endif +#define USE_ISAAC64 /* Use cross-plattform, bundled RNG */ /* End of Section 4 */ diff --git a/include/decl.h b/include/decl.h index e7d09fa6e..28b4bf6b1 100644 --- a/include/decl.h +++ b/include/decl.h @@ -190,6 +190,7 @@ struct multishot { boolean s; }; +E NEARDATA boolean has_strong_rngseed; E const int shield_static[]; #include "spell.h" diff --git a/include/display.h b/include/display.h index d58ed2a3d..ef7bd362a 100644 --- a/include/display.h +++ b/include/display.h @@ -146,9 +146,9 @@ * * Respectively return a random monster, object, or trap number. */ -#define random_monster() rn2(NUMMONS) -#define random_object() rn1(NUM_OBJECTS - 1, 1) -#define random_trap() rn1(TRAPNUM - 1, 1) +#define random_monster(rng) rng(NUMMONS) +#define random_object(rng) (rng(NUM_OBJECTS - 1) + 1) +#define random_trap(rng) (rng(TRAPNUM - 1) + 1) /* * what_obj() @@ -156,11 +156,23 @@ * what_trap() * * If hallucinating, choose a random object/monster, otherwise, use the one - * given. + * given. Use the given rng to handle hallucination. */ -#define what_obj(obj) (Hallucination ? random_object() : obj) -#define what_mon(mon) (Hallucination ? random_monster() : mon) -#define what_trap(trp) (Hallucination ? random_trap() : trp) +#define what_obj(obj, rng) (Hallucination ? random_object(rng) : obj) +#define what_mon(mon, rng) (Hallucination ? random_monster(rng) : mon) +#define what_trap(trp, rng) (Hallucination ? random_trap(rng) : trp) + +/* + * newsym_rn2 + * + * An appropriate random number generator for use with newsym(), when + * randomness is needed there. This is currently hardcoded as + * rn2_on_display_rng, but is futureproofed for cases where we might + * want to prevent display-random objects entering the character's + * memory (this isn't important at present but may be if we need + * reproducible gameplay for some reason). + */ +#define newsym_rn2 rn2_on_display_rng /* * covers_objects() @@ -196,9 +208,10 @@ * Display the hero. It is assumed that all checks necessary to determine * _if_ the hero can be seen have already been done. */ -#define maybe_display_usteed(otherwise_self) \ - ((u.usteed && mon_visible(u.usteed)) ? ridden_mon_to_glyph(u.usteed) \ - : (otherwise_self)) +#define maybe_display_usteed(otherwise_self) \ + ((u.usteed && mon_visible(u.usteed)) \ + ? ridden_mon_to_glyph(u.usteed, rn2_on_display_rng) \ + : (otherwise_self)) #define display_self() \ show_glyph(u.ux, u.uy, \ @@ -282,27 +295,27 @@ #define GLYPH_INVISIBLE GLYPH_INVIS_OFF #define warning_to_glyph(mwarnlev) ((mwarnlev) + GLYPH_WARNING_OFF) -#define mon_to_glyph(mon) \ - ((int) what_mon(monsndx((mon)->data)) + GLYPH_MON_OFF) -#define detected_mon_to_glyph(mon) \ - ((int) what_mon(monsndx((mon)->data)) + GLYPH_DETECT_OFF) -#define ridden_mon_to_glyph(mon) \ - ((int) what_mon(monsndx((mon)->data)) + GLYPH_RIDDEN_OFF) -#define pet_to_glyph(mon) \ - ((int) what_mon(monsndx((mon)->data)) + GLYPH_PET_OFF) +#define mon_to_glyph(mon, rng) \ + ((int) what_mon(monsndx((mon)->data), rng) + GLYPH_MON_OFF) +#define detected_mon_to_glyph(mon, rng) \ + ((int) what_mon(monsndx((mon)->data), rng) + GLYPH_DETECT_OFF) +#define ridden_mon_to_glyph(mon, rng) \ + ((int) what_mon(monsndx((mon)->data), rng) + GLYPH_RIDDEN_OFF) +#define pet_to_glyph(mon, rng) \ + ((int) what_mon(monsndx((mon)->data), rng) + GLYPH_PET_OFF) /* This has the unfortunate side effect of needing a global variable */ /* to store a result. 'otg_temp' is defined and declared in decl.{ch}. */ -#define random_obj_to_glyph() \ - ((g.otg_temp = random_object()) == CORPSE \ - ? random_monster() + GLYPH_BODY_OFF \ +#define random_obj_to_glyph(rng) \ + ((g.otg_temp = random_object(rng)) == CORPSE \ + ? random_monster(rng) + GLYPH_BODY_OFF \ : g.otg_temp + GLYPH_OBJ_OFF) -#define obj_to_glyph(obj) \ +#define obj_to_glyph(obj, rng) \ (((obj)->otyp == STATUE) \ - ? statue_to_glyph(obj) \ + ? statue_to_glyph(obj, rng) \ : Hallucination \ - ? random_obj_to_glyph() \ + ? random_obj_to_glyph(rng) \ : ((obj)->otyp == CORPSE) \ ? (int) (obj)->corpsenm + GLYPH_BODY_OFF \ : (int) (obj)->otyp + GLYPH_OBJ_OFF) @@ -310,16 +323,16 @@ /* MRKR: Statues now have glyphs corresponding to the monster they */ /* represent and look like monsters when you are hallucinating. */ -#define statue_to_glyph(obj) \ - (Hallucination ? random_monster() + GLYPH_MON_OFF \ +#define statue_to_glyph(obj, rng) \ + (Hallucination ? random_monster(rng) + GLYPH_MON_OFF \ : (int) (obj)->corpsenm + GLYPH_STATUE_OFF) #define cmap_to_glyph(cmap_idx) ((int) (cmap_idx) + GLYPH_CMAP_OFF) #define explosion_to_glyph(expltype, idx) \ ((((expltype) * MAXEXPCHARS) + ((idx) - S_explode1)) + GLYPH_EXPLODE_OFF) -#define trap_to_glyph(trap) \ - cmap_to_glyph(trap_to_defsym(what_trap((trap)->ttyp))) +#define trap_to_glyph(trap, rng) \ + cmap_to_glyph(trap_to_defsym(what_trap((trap)->ttyp, rng))) /* Not affected by hallucination. Gives a generic body for CORPSE */ /* MRKR: ...and the generic statue */ diff --git a/include/extern.h b/include/extern.h index 6c7384fb7..1733f17f8 100644 --- a/include/extern.h +++ b/include/extern.h @@ -926,7 +926,8 @@ E char *FDECL(strstri, (const char *, const char *)); #endif E boolean FDECL(fuzzymatch, (const char *, const char *, const char *, BOOLEAN_P)); -E void NDECL(setrandom); +E void FDECL(init_random, (int FDECL((*fn), (int)))); +E void FDECL(reseed_random, (int FDECL((*fn), (int)))); E time_t NDECL(getnow); E int NDECL(getyear); #if 0 @@ -2104,7 +2105,12 @@ E void FDECL(genl_outrip, (winid, int, time_t)); /* ### rnd.c ### */ +#ifdef USE_ISAAC64 +E void FDECL(init_isaac64, (unsigned long, int FDECL((*fn), (int)))); +E long NDECL(nhrand); +#endif E int FDECL(rn2, (int)); +E int FDECL(rn2_on_display_rng, (int)); E int FDECL(rnl, (int)); E int FDECL(rnd, (int)); E int FDECL(d, (int, int)); @@ -2149,7 +2155,7 @@ E const char *NDECL(Goodbye); /* ### rumors.c ### */ E char *FDECL(getrumor, (int, char *, BOOLEAN_P)); -E char *FDECL(get_rnd_text, (const char *, char *)); +E char *FDECL(get_rnd_text, (const char *, char *, int FDECL((*), (int)))); E void FDECL(outrumor, (int, int)); E void FDECL(outoracle, (BOOLEAN_P, BOOLEAN_P)); E void FDECL(save_oracles, (int, int)); diff --git a/include/integer.h b/include/integer.h index 044da028d..9f16a592d 100644 --- a/include/integer.h +++ b/include/integer.h @@ -7,35 +7,47 @@ #ifndef INTEGER_H #define INTEGER_H -#if defined(__STDC__) && __STDC__ >= 199101L - +#if defined(__STDC__) && __STDC_VERSION__ >= 199101L /* The compiler claims to conform to C99. Use stdint.h */ #include +#define SKIP_STDINT_WORKAROUND +#else +# if defined(HAS_STDINT_H) +/* Some compilers have stdint.h but don't conform to all of C99. */ +#include +#define SKIP_STDINT_WORKAROUND +# endif +#endif + +#ifndef SKIP_STDINT_WORKAROUND /* !C99 */ +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; + +#if defined(__WATCOMC__) && !defined(__386__) +/* Open Watcom providing a 16 bit build for MS-DOS or OS/2 */ +/* int is 16 bits; use long for 32 bits */ +typedef long int32_t; +typedef unsigned long uint32_t; +#else +/* Otherwise, assume either a 32- or 64-bit compiler */ +/* long may be 64 bits; use int for 32 bits */ +typedef int int32_t; +typedef unsigned int uint32_t; +#endif + +typedef long long int64_t; +typedef unsigned long long uint64_t; + +#endif /* !C99 */ + +/* Provide uint8, int16, uint16, int32, uint32, int64 and uint64 */ typedef uint8_t uint8; typedef int16_t int16; typedef uint16_t uint16; typedef int32_t int32; typedef uint32_t uint32; - -#else /* !C99 */ - -/* Provide uint8, int16, uint16, int32 and uint32 */ -typedef unsigned char uint8; -typedef short int16; -typedef unsigned short uint16; - -#if defined(__WATCOMC__) && !defined(__386__) -/* Open Watcom providing a 16 bit build for MS-DOS or OS/2 */ -/* int is 16 bits; use long for 32 bits */ -typedef long int32; -typedef unsigned long uint32; -#else -/* Otherwise, assume either a 32- or 64-bit compiler */ -/* long may be 64 bits; use int for 32 bits */ -typedef int int32; -typedef unsigned int uint32; -#endif - -#endif /* !C99 */ +typedef int64_t int64; +typedef uint64_t uint64; #endif /* INTEGER_H */ diff --git a/include/isaac64.h b/include/isaac64.h new file mode 100644 index 000000000..6c9b45b52 --- /dev/null +++ b/include/isaac64.h @@ -0,0 +1,89 @@ +/* CC0 (Public domain) - see http://creativecommons.org/publicdomain/zero/1.0/ for details */ +#if !defined(_isaac64_H) +# define _isaac64_H (1) +# include + + + +typedef struct isaac64_ctx isaac64_ctx; + + + +#define ISAAC64_SZ_LOG (8) +#define ISAAC64_SZ (1< #define USE_STDARG -#ifdef RANDOM + /* Use the high quality random number routines. */ -#define Rand() random() +#ifdef USE_ISAAC64 +#undef RANDOM #else +#define RANDOM +#define Rand() random() +#endif + +/* Fall back to C's if nothing else, but this really isn't acceptable */ +#if !defined(USE_ISAAC64) && !defined(RANDOM) #define Rand() rand() #endif diff --git a/include/os2conf.h b/include/os2conf.h index f033ef584..fd625512a 100644 --- a/include/os2conf.h +++ b/include/os2conf.h @@ -78,11 +78,12 @@ #include /* the high quality random number routines */ - -#ifdef RANDOM -#define Rand() random() -#else -#define Rand() rand() +#ifndef USE_ISAAC64 +# ifdef RANDOM +# define Rand() random() +# else +# define Rand() rand() +# endif #endif /* file creation mask */ diff --git a/include/pcconf.h b/include/pcconf.h index c5b46bea9..fb210b8ca 100644 --- a/include/pcconf.h +++ b/include/pcconf.h @@ -236,11 +236,13 @@ #include #endif -#ifdef RANDOM -/* Use the high quality random number routines. */ -#define Rand() random() -#else -#define Rand() rand() +/* the high quality random number routines */ +#ifndef USE_ISAAC64 +# ifdef RANDOM +# define Rand() random() +# else +# define Rand() rand() +# endif #endif #ifndef TOS diff --git a/include/unixconf.h b/include/unixconf.h index 0c42c6040..781e3563e 100644 --- a/include/unixconf.h +++ b/include/unixconf.h @@ -347,11 +347,14 @@ #endif /* Use the high quality random number routines. */ -#if defined(BSD) || defined(LINUX) || defined(ULTRIX) || defined(CYGWIN32) \ +/* the high quality random number routines */ +#ifndef USE_ISAAC64 +# if defined(BSD) || defined(LINUX) || defined(ULTRIX) || defined(CYGWIN32) \ || defined(RANDOM) || defined(__APPLE__) -#define Rand() random() -#else -#define Rand() lrand48() +# define Rand() random() +# else +# define Rand() lrand48() +# endif #endif #ifdef TIMED_DELAY @@ -408,5 +411,18 @@ # define RUNTIME_PASTEBUF_SUPPORT #endif +/* + * /dev/random is blocking on Linux, so there we default to /dev/urandom which + * should still be good enough. + * BSD systems usually have /dev/random that is supposed to be used. + */ +#ifdef LINUX +# define DEV_RANDOM "/dev/urandom" +#else +# ifdef BSD +# define DEV_RANDOM "/dev/random" +# endif +#endif + #endif /* UNIXCONF_H */ #endif /* UNIX */ diff --git a/include/vmsconf.h b/include/vmsconf.h index 7674e8558..40cde73a0 100644 --- a/include/vmsconf.h +++ b/include/vmsconf.h @@ -243,17 +243,19 @@ typedef __mode_t mode_t; #define rindex strrchr /* Use the high quality random number routines. */ -#if defined(RANDOM) -#define Rand() random() +#ifndef USE_ISAAC64 +# if defined(RANDOM) +# define Rand() random() /* VMS V7 adds these entry points to DECC$SHR; stick with the nethack-supplied code to avoid having to deal with version-specific conditionalized builds */ -#define random nh_random -#define srandom nh_srandom -#define initstate nh_initstate -#define setstate nh_setstate -#else -#define Rand() rand() +# define random nh_random +# define srandom nh_srandom +# define initstate nh_initstate +# define setstate nh_setstate +# else +# define Rand() rand() +# endif #endif #ifndef __GNUC__ diff --git a/include/wceconf.h b/include/wceconf.h index 7ab03f672..dcc7b6f95 100644 --- a/include/wceconf.h +++ b/include/wceconf.h @@ -141,11 +141,14 @@ #define index strchr #define rindex strrchr #define USE_STDARG -#ifdef RANDOM + /* Use the high quality random number routines. */ -#define Rand() random() -#else -#define Rand() rand() +#ifndef USE_ISAAC64 +# ifdef RANDOM +# define Rand() random() +# else +# define Rand() rand() +# endif #endif #define FCMASK 0660 /* file creation mask */ diff --git a/src/apply.c b/src/apply.c index 1e49c8283..2fc3cf8fd 100644 --- a/src/apply.c +++ b/src/apply.c @@ -239,7 +239,7 @@ int rx, ry, *resp; int visglyph, corpseglyph; visglyph = glyph_at(rx, ry); - corpseglyph = obj_to_glyph(corpse); + corpseglyph = obj_to_glyph(corpse, rn2); if (Blind && (visglyph != corpseglyph)) map_object(corpse, TRUE); @@ -2491,7 +2491,7 @@ struct obj *otmp; if (otmp == g.trapinfo.tobj && u.ux == g.trapinfo.tx && u.uy == g.trapinfo.ty) { You("resume setting %s%s.", shk_your(buf, otmp), - defsyms[trap_to_defsym(what_trap(ttyp))].explanation); + defsyms[trap_to_defsym(what_trap(ttyp, rn2))].explanation); set_occupation(set_trap, occutext, 0); return; } @@ -2516,7 +2516,8 @@ struct obj *otmp; chance = (rnl(10) > 5); You("aren't very skilled at reaching from %s.", mon_nam(u.usteed)); Sprintf(buf, "Continue your attempt to set %s?", - the(defsyms[trap_to_defsym(what_trap(ttyp))].explanation)); + the(defsyms[trap_to_defsym(what_trap(ttyp, rn2))] + .explanation)); if (yn(buf) == 'y') { if (chance) { switch (ttyp) { @@ -2527,7 +2528,7 @@ struct obj *otmp; case BEAR_TRAP: /* drop it without arming it */ reset_trapset(); You("drop %s!", - the(defsyms[trap_to_defsym(what_trap(ttyp))] + the(defsyms[trap_to_defsym(what_trap(ttyp, rn2))] .explanation)); dropx(otmp); return; @@ -2539,7 +2540,7 @@ struct obj *otmp; } } You("begin setting %s%s.", shk_your(buf, otmp), - defsyms[trap_to_defsym(what_trap(ttyp))].explanation); + defsyms[trap_to_defsym(what_trap(ttyp, rn2))].explanation); set_occupation(set_trap, occutext, 0); return; } @@ -2572,7 +2573,7 @@ set_trap() } if (!g.trapinfo.force_bungle) You("finish arming %s.", - the(defsyms[trap_to_defsym(what_trap(ttyp))].explanation)); + the(defsyms[trap_to_defsym(what_trap(ttyp, rn2))].explanation)); if (((otmp->cursed || Fumbling) && (rnl(10) > 5)) || g.trapinfo.force_bungle) dotrap(ttmp, diff --git a/src/decl.c b/src/decl.c index 74ffd9ffd..7cd721a80 100644 --- a/src/decl.c +++ b/src/decl.c @@ -21,6 +21,7 @@ const schar ydir[10] = { 0, -1, -1, -1, 0, 1, 1, 1, 0, 0 }; const schar zdir[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, -1 }; NEARDATA struct flag flags; +NEARDATA boolean has_strong_rngseed = FALSE; #ifdef SYSFLAGS NEARDATA struct sysflag sysflags; #endif diff --git a/src/detect.c b/src/detect.c index 20c9f8fc4..d0969b8d1 100644 --- a/src/detect.c +++ b/src/detect.c @@ -76,10 +76,12 @@ struct monst *mtmp; boolean showtail; { if (def_monsyms[(int) mtmp->data->mlet].sym == ' ') - show_glyph(mtmp->mx, mtmp->my, detected_mon_to_glyph(mtmp)); - else show_glyph(mtmp->mx, mtmp->my, - mtmp->mtame ? pet_to_glyph(mtmp) : mon_to_glyph(mtmp)); + detected_mon_to_glyph(mtmp, newsym_rn2)); + else + show_glyph(mtmp->mx, mtmp->my, mtmp->mtame + ? pet_to_glyph(mtmp, newsym_rn2) + : mon_to_glyph(mtmp, newsym_rn2)); if (showtail && mtmp->data == &mons[PM_LONG_WORM]) detect_wsegs(mtmp, 0); @@ -865,10 +867,10 @@ int src_cursed; obj.ox = x; obj.oy = y; } - obj.otyp = !Hallucination ? GOLD_PIECE : random_object(); + obj.otyp = !Hallucination ? GOLD_PIECE : random_object(rn2); obj.quan = (long) ((obj.otyp == GOLD_PIECE) ? rnd(10) : objects[obj.otyp].oc_merge ? rnd(2) : 1); - obj.corpsenm = random_monster(); /* if otyp == CORPSE */ + obj.corpsenm = random_monster(rn2); /* if otyp == CORPSE */ map_object(&obj, 1); } else if (trap) { map_trap(trap, 1); @@ -1589,14 +1591,20 @@ void find_trap(trap) struct trap *trap; { - int tt = what_trap(trap->ttyp); + int tt = what_trap(trap->ttyp, rn2); boolean cleared = FALSE; trap->tseen = 1; exercise(A_WIS, TRUE); feel_newsym(trap->tx, trap->ty); - if (levl[trap->tx][trap->ty].glyph != trap_to_glyph(trap)) { + /* The "Hallucination ||" is to preserve 3.6.1 behaviour, but this + behaviour might need a rework in the hallucination case + (e.g. to not prompt if any trap glyph appears on the + square). */ + if (Hallucination || + levl[trap->tx][trap->ty].glyph != + trap_to_glyph(trap, rn2_on_display_rng)) { /* There's too much clutter to see your find otherwise */ cls(); map_trap(trap, 1); @@ -1830,7 +1838,7 @@ int default_glyph, which_subset; an object, replacing any object or trap at its spot) */ glyph = !swallowed ? glyph_at(x, y) : levl_glyph; if (keep_mons && x == u.ux && y == u.uy && swallowed) - glyph = mon_to_glyph(u.ustuck); + glyph = mon_to_glyph(u.ustuck, rn2_on_display_rng); else if (((glyph_is_monster(glyph) || glyph_is_warning(glyph)) && !keep_mons) || glyph_is_swallow(glyph)) @@ -1839,7 +1847,7 @@ int default_glyph, which_subset; || glyph_is_invisible(glyph)) && keep_traps && !covers_traps(x, y)) { if ((t = t_at(x, y)) != 0 && t->tseen) - glyph = trap_to_glyph(t); + glyph = trap_to_glyph(t, rn2_on_display_rng); } if ((glyph_is_object(glyph) && !keep_objs) || (glyph_is_trap(glyph) && !keep_traps) diff --git a/src/display.c b/src/display.c index 70c8bfc96..a8fe3248d 100644 --- a/src/display.c +++ b/src/display.c @@ -222,7 +222,7 @@ register struct trap *trap; register int show; { register int x = trap->tx, y = trap->ty; - register int glyph = trap_to_glyph(trap); + register int glyph = trap_to_glyph(trap, newsym_rn2); if (g.level.flags.hero_memory) levl[x][y].glyph = glyph; @@ -242,14 +242,14 @@ register struct obj *obj; register int show; { register int x = obj->ox, y = obj->oy; - register int glyph = obj_to_glyph(obj); + register int glyph = obj_to_glyph(obj, newsym_rn2); if (g.level.flags.hero_memory) { /* MRKR: While hallucinating, statues are seen as random monsters */ /* but remembered as random objects. */ if (Hallucination && obj->otyp == STATUE) { - levl[x][y].glyph = random_obj_to_glyph(); + levl[x][y].glyph = random_obj_to_glyph(newsym_rn2); } else { levl[x][y].glyph = glyph; } @@ -394,7 +394,7 @@ xchar worm_tail; /* mon is actually a worm tail */ (int) mon->m_ap_type); /*FALLTHRU*/ case M_AP_NOTHING: - show_glyph(x, y, mon_to_glyph(mon)); + show_glyph(x, y, mon_to_glyph(mon, newsym_rn2)); break; case M_AP_FURNITURE: { @@ -434,7 +434,8 @@ xchar worm_tail; /* mon is actually a worm tail */ case M_AP_MONSTER: show_glyph(x, y, - monnum_to_glyph(what_mon((int) mon->mappearance))); + monnum_to_glyph(what_mon((int) mon->mappearance, + rn2_on_display_rng))); break; } } @@ -456,17 +457,19 @@ xchar worm_tail; /* mon is actually a worm tail */ if (worm_tail) num = petnum_to_glyph(PM_LONG_WORM_TAIL); else - num = pet_to_glyph(mon); + num = pet_to_glyph(mon, rn2_on_display_rng); } else if (sightflags == DETECTED) { if (worm_tail) - num = detected_monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL)); + num = detected_monnum_to_glyph( + what_mon(PM_LONG_WORM_TAIL, rn2_on_display_rng)); else - num = detected_mon_to_glyph(mon); + num = detected_mon_to_glyph(mon, rn2_on_display_rng); } else { if (worm_tail) - num = monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL)); + num = monnum_to_glyph( + what_mon(PM_LONG_WORM_TAIL, rn2_on_display_rng)); else - num = mon_to_glyph(mon); + num = mon_to_glyph(mon, rn2_on_display_rng); } show_glyph(x, y, num); } @@ -489,10 +492,11 @@ register struct monst *mon; int glyph; if (mon_warning(mon)) { - int wl = Hallucination ? rn1(WARNCOUNT - 1, 1) : warning_of(mon); + int wl = Hallucination ? + rn2_on_display_rng(WARNCOUNT - 1) + 1 : warning_of(mon); glyph = warning_to_glyph(wl); } else if (MATCH_WARN_OF_MON(mon)) { - glyph = mon_to_glyph(mon); + glyph = mon_to_glyph(mon, rn2_on_display_rng); } else { impossible("display_warning did not match warning type?"); return; @@ -1742,7 +1746,8 @@ int loc; impossible("swallow_to_glyph: bad swallow location"); loc = S_sw_br; } - return ((int) (what_mon(mnum) << 3) | (loc - S_sw_tl)) + GLYPH_SWALLOW_OFF; + return ((int) (what_mon(mnum, rn2_on_display_rng) << 3) | + (loc - S_sw_tl)) + GLYPH_SWALLOW_OFF; } /* diff --git a/src/do.c b/src/do.c index 60fcd5bcb..1439cbcd9 100644 --- a/src/do.c +++ b/src/do.c @@ -1413,6 +1413,8 @@ boolean at_stairs, falling, portal; /* we'll reach here if running in wizard mode */ error("Cannot continue this game."); } + reseed_random(rn2); + reseed_random(rn2_on_display_rng); minit(); /* ZEROCOMP */ getlev(fd, g.hackpid, new_ledger, FALSE); (void) nhclose(fd); diff --git a/src/do_name.c b/src/do_name.c index 816f82d55..f9b794d6b 100644 --- a/src/do_name.c +++ b/src/do_name.c @@ -1533,8 +1533,12 @@ namefloorobj() unames[0] = ((Upolyd ? u.mfemale : flags.female) && g.urole.name.f) ? g.urole.name.f : g.urole.name.m; - /* random rank title for hero's role */ - unames[1] = rank_of(rnd(30), Role_switch, flags.female); + /* random rank title for hero's role + + note: the 30 is hardcoded in xlev_to_rank, so should be + hardcoded here too */ + unames[1] = rank_of(rn2_on_display_rng(30) + 1, + Role_switch, flags.female); /* random fake monster */ unames[2] = bogusmon(tmpbuf, (char *) 0); /* increased chance for fake monster */ @@ -1545,7 +1549,7 @@ namefloorobj() unames[5] = "Wibbly Wobbly"; pline("%s %s to call you \"%s.\"", The(buf), use_plural ? "decide" : "decides", - unames[rn2(SIZE(unames))]); + unames[rn2_on_display_rng(SIZE(unames))]); } else if (!objtyp_is_callable(obj->otyp)) { pline("%s %s can't be assigned a type name.", use_plural ? "Those" : "That", buf); @@ -1925,7 +1929,7 @@ char *buf, *code; { char *mname = buf; - get_rnd_text(BOGUSMONFILE, buf); + get_rnd_text(BOGUSMONFILE, buf, rn2_on_display_rng); /* strip prefix if present */ if (!letter(*mname)) { if (code) @@ -1952,7 +1956,7 @@ char *code; *code = '\0'; do { - name = rn1(SPECIAL_PM + BOGUSMONSIZE - LOW_PM, LOW_PM); + name = rn2_on_display_rng(SPECIAL_PM + BOGUSMONSIZE - LOW_PM) + LOW_PM; } while (name < SPECIAL_PM && (type_is_pname(&mons[name]) || (mons[name].geno & G_NOGEN))); @@ -2008,8 +2012,9 @@ const char * hcolor(colorpref) const char *colorpref; { - return (Hallucination || !colorpref) ? hcolors[rn2(SIZE(hcolors))] - : colorpref; + return (Hallucination || !colorpref) + ? hcolors[rn2_on_display_rng(SIZE(hcolors))] + : colorpref; } /* return a random real color unless hallucinating */ diff --git a/src/dothrow.c b/src/dothrow.c index 1453c4b43..922898572 100644 --- a/src/dothrow.c +++ b/src/dothrow.c @@ -1074,7 +1074,7 @@ struct obj *obj; if ((u.dx || u.dy) && (g.bhitpos.x != u.ux || g.bhitpos.y != u.uy)) { int x = g.bhitpos.x - u.dx, y = g.bhitpos.y - u.dy; - tmp_at(DISP_FLASH, obj_to_glyph(obj)); + tmp_at(DISP_FLASH, obj_to_glyph(obj, rn2_on_display_rng)); while (isok(x,y) && (x != u.ux || y != u.uy)) { tmp_at(x, y); delay_output(); @@ -1143,7 +1143,7 @@ boolean twoweap; /* used to restore twoweapon mode if wielded weapon returns */ g.bhitpos.x = mon->mx; g.bhitpos.y = mon->my; if (tethered_weapon) - tmp_at(DISP_TETHER, obj_to_glyph(obj)); + tmp_at(DISP_TETHER, obj_to_glyph(obj, rn2_on_display_rng)); } else if (u.dz) { if (u.dz < 0 /* Mjollnir must we wielded to be thrown--caller verifies this; @@ -1372,7 +1372,7 @@ boolean twoweap; /* used to restore twoweapon mode if wielded weapon returns */ } if (!IS_SOFT(levl[g.bhitpos.x][g.bhitpos.y].typ) && breaktest(obj)) { - tmp_at(DISP_FLASH, obj_to_glyph(obj)); + tmp_at(DISP_FLASH, obj_to_glyph(obj, rn2_on_display_rng)); tmp_at(g.bhitpos.x, g.bhitpos.y); delay_output(); tmp_at(DISP_END, 0); diff --git a/src/engrave.c b/src/engrave.c index 40791d514..808501bd3 100644 --- a/src/engrave.c +++ b/src/engrave.c @@ -18,7 +18,7 @@ char *outbuf; /* a random engraving may come from the "rumors" file, or from the "engrave" file (formerly in an array here) */ if (!rn2(4) || !(rumor = getrumor(0, outbuf, TRUE)) || !*rumor) - (void) get_rnd_text(ENGRAVEFILE, outbuf); + (void) get_rnd_text(ENGRAVEFILE, outbuf, rn2); wipeout_text(outbuf, (int) (strlen(outbuf) / 4), 0); return outbuf; @@ -1294,7 +1294,7 @@ const char *str; /* Engrave the headstone */ del_engr_at(x, y); if (!str) - str = get_rnd_text(EPITAPHFILE, buf); + str = get_rnd_text(EPITAPHFILE, buf, rn2); make_engr_at(x, y, str, 0L, HEADSTONE); return; } diff --git a/src/hack.c b/src/hack.c index 12c3a3804..2ee3eade9 100644 --- a/src/hack.c +++ b/src/hack.c @@ -1464,7 +1464,7 @@ domove_core() if (g.context.run >= 2) { if (iflags.mention_walls) { if (trap && trap->tseen) { - int tt = what_trap(trap->ttyp); + int tt = what_trap(trap->ttyp, rn2_on_display_rng); You("stop in front of %s.", an(defsyms[trap_to_defsym(tt)].explanation)); @@ -2708,7 +2708,7 @@ lookaround() goto bcorr; /* if you must */ if (x == u.ux + u.dx && y == u.uy + u.dy) { if (iflags.mention_walls) { - int tt = what_trap(trap->ttyp); + int tt = what_trap(trap->ttyp, rn2_on_display_rng); You("stop in front of %s.", an(defsyms[trap_to_defsym(tt)].explanation)); } diff --git a/src/hacklib.c b/src/hacklib.c index a6facde7b..eb1561293 100644 --- a/src/hacklib.c +++ b/src/hacklib.c @@ -51,6 +51,8 @@ boolean fuzzymatch (const char *, const char *, const char *, boolean) void setrandom (void) + void init_random (fn) + void reseed_random (fn) time_t getnow (void) int getyear (void) char * yymmdd (time_t) @@ -848,44 +850,69 @@ extern struct tm *FDECL(localtime, (time_t *)); #endif STATIC_DCL struct tm *NDECL(getlt); -void -setrandom() +/* Sets the seed for the random number generator */ +#ifdef USE_ISAAC64 +static void +set_random(seed, fn) +unsigned long seed; +int FDECL((*fn), (int)); +{ + init_isaac64(seed, fn); +} +#else /* USE_ISAAC64 */ +static void +set_random(seed, fn) +unsigned long seed; +int FDECL((*fn),(int)); { - unsigned long seed = (unsigned long) getnow(); /* time((TIME_type) 0) */ - -#if defined(UNIX) || defined(VMS) - { - unsigned long pid = (unsigned long) getpid(); - - /* Quick dirty band-aid to prevent PRNG prediction */ - if (pid) { - if (!(pid & 3L)) - pid -= 1L; - seed *= pid; - } - } -#endif - /* the types are different enough here that sweeping the different * routine names into one via #defines is even more confusing */ -#ifdef RANDOM /* srandom() from sys/share/random.c */ +# ifdef RANDOM /* srandom() from sys/share/random.c */ srandom((unsigned int) seed); -#else -#if defined(__APPLE__) || defined(BSD) || defined(LINUX) || defined(ULTRIX) \ +# else +# if defined(__APPLE__) || defined(BSD) || defined(LINUX) || defined(ULTRIX) \ || defined(CYGWIN32) /* system srandom() */ -#if defined(BSD) && !defined(POSIX_TYPES) && defined(SUNOS4) +# if defined(BSD) && !defined(POSIX_TYPES) && defined(SUNOS4) (void) -#endif +# endif srandom((int) seed); -#else -#ifdef UNIX /* system srand48() */ +# else +# ifdef UNIX /* system srand48() */ srand48((long) seed); -#else /* poor quality system routine */ +# else /* poor quality system routine */ srand((int) seed); -#endif -#endif -#endif +# endif +# endif +# endif +} +#endif /* USE_ISAAC64 */ + +/* An appropriate version of this must always be provided in + port-specific code somewhere. It returns a number suitable + as seed for the random number generator */ +extern unsigned long NDECL(sys_random_seed); + +/* + * Initializes the random number generator. + * Only call once. + */ +void +init_random(fn) +int FDECL((*fn),(int)); +{ + set_random(sys_random_seed(), fn); +} + +/* Reshuffles the random number generator. */ +void +reseed_random(fn) +int FDECL((*fn),(int)); +{ + /* only reseed if we are certain that the seed generation is unguessable + * by the players. */ + if (has_strong_rngseed) + init_random(fn); } time_t diff --git a/src/invent.c b/src/invent.c index 90ccf3d2c..96e0084d7 100644 --- a/src/invent.c +++ b/src/invent.c @@ -2681,8 +2681,8 @@ long *out_cnt; any.a_obj = otmp; else any.a_char = ilet; - add_menu(win, obj_to_glyph(otmp), &any, ilet, 0, ATR_NONE, - doname(otmp), MENU_UNSELECTED); + add_menu(win, obj_to_glyph(otmp, rn2_on_display_rng), &any, ilet, + 0, ATR_NONE, doname(otmp), MENU_UNSELECTED); } } if (flags.sortpack) { @@ -2795,7 +2795,8 @@ char avoidlet; classcount++; } any.a_char = ilet; - add_menu(win, obj_to_glyph(otmp), &any, ilet, 0, ATR_NONE, + add_menu(win, obj_to_glyph(otmp, rn2_on_display_rng), + &any, ilet, 0, ATR_NONE, doname(otmp), MENU_UNSELECTED); } } diff --git a/src/isaac64.c b/src/isaac64.c new file mode 100644 index 000000000..6928ff72b --- /dev/null +++ b/src/isaac64.c @@ -0,0 +1,161 @@ +/*Written by Timothy B. Terriberry (tterribe@xiph.org) 1999-2009 + CC0 (Public domain) - see http://creativecommons.org/publicdomain/zero/1.0/ for details + Based on the public domain ISAAC implementation by Robert J. Jenkins Jr.*/ +#include +#include +#include "isaac64.h" + +#define ISAAC64_MASK ((uint64_t)0xFFFFFFFFFFFFFFFFULL) + +#if (defined(__STDC__) && __STDC_VERSION__ >= 199901L) +#define HAS_INLINE +#endif + +/* Extract ISAAC64_SZ_LOG bits (starting at bit 3). */ +#ifdef HAS_INLINE +static inline uint32_t lower_bits(uint64_t x) +#else +static uint32_t lower_bits(uint64_t x) +#endif +{ + return (x & ((ISAAC64_SZ-1) << 3)) >>3; +} + +/* Extract next ISAAC64_SZ_LOG bits (starting at bit ISAAC64_SZ_LOG+2). */ +#ifdef HAS_INLINE +static inline uint32_t upper_bits(uint64_t y) +#else +static uint32_t upper_bits(uint64_t y) +#endif +{ + return (y >> (ISAAC64_SZ_LOG+3)) & (ISAAC64_SZ-1); +} + +static void isaac64_update(isaac64_ctx *_ctx){ + uint64_t *m; + uint64_t *r; + uint64_t a; + uint64_t b; + uint64_t x; + uint64_t y; + int i; + m=_ctx->m; + r=_ctx->r; + a=_ctx->a; + b=_ctx->b+(++_ctx->c); + for(i=0;i>5)+m[i+ISAAC64_SZ/2]; + m[i]=y=m[lower_bits(x)]+a+b; + r[i]=b=m[upper_bits(y)]+x; + x=m[++i]; + a=(a^a<<12)+m[i+ISAAC64_SZ/2]; + m[i]=y=m[lower_bits(x)]+a+b; + r[i]=b=m[upper_bits(y)]+x; + x=m[++i]; + a=(a^a>>33)+m[i+ISAAC64_SZ/2]; + m[i]=y=m[lower_bits(x)]+a+b; + r[i]=b=m[upper_bits(y)]+x; + } + for(i=ISAAC64_SZ/2;i>5)+m[i-ISAAC64_SZ/2]; + m[i]=y=m[lower_bits(x)]+a+b; + r[i]=b=m[upper_bits(y)]+x; + x=m[++i]; + a=(a^a<<12)+m[i-ISAAC64_SZ/2]; + m[i]=y=m[lower_bits(x)]+a+b; + r[i]=b=m[upper_bits(y)]+x; + x=m[++i]; + a=(a^a>>33)+m[i-ISAAC64_SZ/2]; + m[i]=y=m[lower_bits(x)]+a+b; + r[i]=b=m[upper_bits(y)]+x; + } + _ctx->b=b; + _ctx->a=a; + _ctx->n=ISAAC64_SZ; +} + +static void isaac64_mix(uint64_t _x[8]){ + static const unsigned char SHIFT[8]={9,9,23,15,14,20,17,14}; + int i; + for(i=0;i<8;i++){ + _x[i]-=_x[(i+4)&7]; + _x[(i+5)&7]^=_x[(i+7)&7]>>SHIFT[i]; + _x[(i+7)&7]+=_x[i]; + i++; + _x[i]-=_x[(i+4)&7]; + _x[(i+5)&7]^=_x[(i+7)&7]<a=_ctx->b=_ctx->c=0; + memset(_ctx->r,0,sizeof(_ctx->r)); + isaac64_reseed(_ctx,_seed,_nseed); +} + +void isaac64_reseed(isaac64_ctx *_ctx,const unsigned char *_seed,int _nseed){ + uint64_t *m; + uint64_t *r; + uint64_t x[8]; + int i; + int j; + m=_ctx->m; + r=_ctx->r; + if(_nseed>ISAAC64_SEED_SZ_MAX)_nseed=ISAAC64_SEED_SZ_MAX; + for(i=0;i<_nseed>>3;i++){ + r[i]^=(uint64_t)_seed[i<<3|7]<<56|(uint64_t)_seed[i<<3|6]<<48| + (uint64_t)_seed[i<<3|5]<<40|(uint64_t)_seed[i<<3|4]<<32| + (uint64_t)_seed[i<<3|3]<<24|(uint64_t)_seed[i<<3|2]<<16| + (uint64_t)_seed[i<<3|1]<<8|_seed[i<<3]; + } + _nseed-=i<<3; + if(_nseed>0){ + uint64_t ri; + ri=_seed[i<<3]; + for(j=1;j<_nseed;j++)ri|=(uint64_t)_seed[i<<3|j]<<(j<<3); + r[i++]^=ri; + } + x[0]=x[1]=x[2]=x[3]=x[4]=x[5]=x[6]=x[7]=(uint64_t)0x9E3779B97F4A7C13ULL; + for(i=0;i<4;i++)isaac64_mix(x); + for(i=0;in)isaac64_update(_ctx); + return _ctx->r[--_ctx->n]; +} + +uint64_t isaac64_next_uint(isaac64_ctx *_ctx,uint64_t _n){ + uint64_t r; + uint64_t v; + uint64_t d; + do{ + r=isaac64_next_uint64(_ctx); + v=r%_n; + d=r-v; + } + while(((d+_n-1)&ISAAC64_MASK) 0) { /* Actually the loop is always exited by break */ g.bhitpos.x += dx; g.bhitpos.y += dy; diff --git a/src/muse.c b/src/muse.c index 4a919ed03..9308c1013 100644 --- a/src/muse.c +++ b/src/muse.c @@ -1957,7 +1957,7 @@ struct monst *mtmp; #ifdef CLIPPING cliparound(mtmp->mx, mtmp->my); #endif - show_glyph(mtmp->mx, mtmp->my, mon_to_glyph(mtmp)); + show_glyph(mtmp->mx, mtmp->my, mon_to_glyph(mtmp, rn2)); display_self(); You_feel("aggravated at %s.", noit_mon_nam(mtmp)); display_nhwindow(WIN_MAP, TRUE); diff --git a/src/options.c b/src/options.c index 46476bc52..d83bd49e5 100644 --- a/src/options.c +++ b/src/options.c @@ -683,8 +683,9 @@ initoptions_init() /* set up the command parsing */ reset_commands(TRUE); /* init */ - /* initialize the random number generator */ - setrandom(); + /* initialize the random number generator(s) */ + init_random(rn2); + init_random(rn2_on_display_rng); /* for detection of configfile options specified multiple times */ iflags.opt_booldup = iflags.opt_compdup = (int *) 0; diff --git a/src/pager.c b/src/pager.c index f78dfd85b..9928d9583 100644 --- a/src/pager.c +++ b/src/pager.c @@ -381,7 +381,8 @@ char *buf, *monbuf; buf[0] = monbuf[0] = '\0'; glyph = glyph_at(x, y); if (u.ux == x && u.uy == y && canspotself() - && !(iflags.save_uswallow && glyph == mon_to_glyph(u.ustuck)) + && !(iflags.save_uswallow && + glyph == mon_to_glyph(u.ustuck, rn2_on_display_rng)) && (!iflags.terrainmode || (iflags.terrainmode & TER_MON) != 0)) { /* fill in buf[] */ (void) self_lookat(buf); @@ -435,7 +436,7 @@ char *buf, *monbuf; } else if (glyph_is_object(glyph)) { look_at_object(buf, x, y, glyph); /* fill in buf[] */ } else if (glyph_is_trap(glyph)) { - int tnum = what_trap(glyph_to_trap(glyph)); + int tnum = what_trap(glyph_to_trap(glyph), rn2_on_display_rng); /* Trap detection displays a bear trap at locations having * a trapped door or trapped container or both. @@ -1487,7 +1488,7 @@ doidtrap() if (u.dz < 0 ? is_hole(tt) : tt == ROCKTRAP) break; } - tt = what_trap(tt); + tt = what_trap(tt, rn2_on_display_rng); pline("That is %s%s%s.", an(defsyms[trap_to_defsym(tt)].explanation), !trap->madeby_u diff --git a/src/pickup.c b/src/pickup.c index c4a0080a3..84ac8e448 100644 --- a/src/pickup.c +++ b/src/pickup.c @@ -902,7 +902,7 @@ boolean FDECL((*allow), (OBJ_P)); /* allow function */ } any.a_obj = curr; - add_menu(win, obj_to_glyph(curr), &any, + add_menu(win, obj_to_glyph(curr, rn2_on_display_rng), &any, (qflags & USE_INVLET) ? curr->invlet : (first && curr->oclass == COIN_CLASS) ? '$' : 0, def_oc_syms[(int) objects[curr->otyp].oc_class].sym, @@ -927,7 +927,7 @@ boolean FDECL((*allow), (OBJ_P)); /* allow function */ fake_hero_object = cg.zeroobj; fake_hero_object.quan = 1L; /* not strictly necessary... */ any.a_obj = &fake_hero_object; - add_menu(win, mon_to_glyph(&g.youmonst), &any, + add_menu(win, mon_to_glyph(&g.youmonst, rn2_on_display_rng), &any, /* fake inventory letter, no group accelerator */ CONTAINED_SYM, 0, ATR_NONE, an(self_lookat(buf)), MENU_UNSELECTED); diff --git a/src/pray.c b/src/pray.c index 2f946c861..b03a509a3 100644 --- a/src/pray.c +++ b/src/pray.c @@ -2090,13 +2090,18 @@ aligntyp alignment; if (!Hallucination) return align_gname(alignment); + /* Count the roles, so that we can pick one at random. */ + int rolecount = 0; + while (roles[rolecount].filecode) + rolecount++; + /* The priest may not have initialized god names. If this is the - * case, and we roll priest, we need to try again. */ + case, and we roll priest, we need to try again. */ do - which = randrole(); + which = rn2_on_display_rng(rolecount); while (!roles[which].lgod); - switch (rn2(9)) { + switch (rn2_on_display_rng(9)) { case 0: case 1: gnam = roles[which].lgod; @@ -2111,7 +2116,7 @@ aligntyp alignment; break; case 6: case 7: - gnam = hallu_gods[rn2(sizeof hallu_gods / sizeof *hallu_gods)]; + gnam = hallu_gods[rn2_on_display_rng(SIZE(hallu_gods))]; break; case 8: gnam = Moloch; diff --git a/src/rnd.c b/src/rnd.c index c3627e854..fa8ce0e20 100644 --- a/src/rnd.c +++ b/src/rnd.c @@ -4,6 +4,74 @@ #include "hack.h" +#ifdef USE_ISAAC64 +#include "isaac64.h" + +#if 0 +static isaac64_ctx rng_state; +#endif + +struct rnglist_t { + int FDECL((*fn), (int)); + boolean init; + isaac64_ctx rng_state; +}; + +enum {CORE = 0, DISP}; + +static struct rnglist_t rnglist[] = { + {rn2, FALSE, {0}}, /* CORE */ + {rn2_on_display_rng, FALSE, {0}}, /* DISP */ +}; + +int +whichrng(fn) +int (*fn)(int); +{ + int i; + + for (i = 0; i < SIZE(rnglist); ++i) + if (rnglist[i].fn == fn) + return i; + return -1; +} + +void +init_isaac64(seed, fn) +unsigned long seed; +int FDECL((*fn),(int)); +{ + unsigned char new_rng_state[sizeof(seed)]; + int i, rngindx = whichrng(fn); + + if (rngindx < 0) + panic("Bad rng function passed to init_isaac64()."); + + for (i=0; i>= 8; + } + isaac64_init(&rnglist[rngindx].rng_state, new_rng_state, sizeof(seed)); +} + +static int +RND(int x) +{ + return (isaac64_next_uint64(&rnglist[CORE].rng_state) % x); +} + +/* 0 <= rn2(x) < x, but on a different sequence from the "main" rn2; + used in cases where the answer doesn't affect gameplay and we don't + want to give users easy control over the main RNG sequence. */ +int +rn2_on_display_rng(x) +register int x; +{ + return (isaac64_next_uint64(&rnglist[DISP].rng_state) % x); +} + +#else /* USE_ISAAC64 */ + /* "Rand()"s definition is determined by [OS]conf.h */ #if defined(LINT) && defined(UNIX) /* rand() is long... */ extern int NDECL(rand); @@ -16,6 +84,15 @@ extern int NDECL(rand); #define RND(x) ((int) ((Rand() >> 3) % (x))) #endif #endif /* LINT */ +int +rn2_on_display_rng(x) +register int x; +{ + static unsigned seed = 1; + seed *= 2739110765; + return (int)((seed >> 16) % (unsigned)x); +} +#endif /* USE_ISAAC64 */ /* 0 <= rn2(x) < x */ int diff --git a/src/rumors.c b/src/rumors.c index eeb47e9e3..9a3cb62bd 100644 --- a/src/rumors.c +++ b/src/rumors.c @@ -114,12 +114,12 @@ boolean exclude_cookie; case 2: /*(might let a bogus input arg sneak thru)*/ case 1: beginning = (long) g.true_rumor_start; - tidbit = Rand() % g.true_rumor_size; + tidbit = rn2(g.true_rumor_size); break; case 0: /* once here, 0 => false rather than "either"*/ case -1: beginning = (long) g.false_rumor_start; - tidbit = Rand() % g.false_rumor_size; + tidbit = rn2(g.false_rumor_size); break; default: impossible("strange truth value for rumor"); @@ -269,11 +269,13 @@ rumor_check() } } -/* Gets a random line of text from file 'fname', and returns it. */ +/* Gets a random line of text from file 'fname', and returns it. + rng is the random number generator to use, and should act like rn2 does. */ char * -get_rnd_text(fname, buf) +get_rnd_text(fname, buf, rng) const char *fname; char *buf; +int FDECL((*rng), (int)); { dlb *fh; @@ -294,7 +296,7 @@ char *buf; (void) dlb_fseek(fh, 0L, SEEK_END); endtxt = dlb_ftell(fh); sizetxt = endtxt - starttxt; - tidbit = Rand() % sizetxt; + tidbit = rng(sizetxt); (void) dlb_fseek(fh, starttxt + tidbit, SEEK_SET); (void) dlb_fgets(line, sizeof line, fh); diff --git a/src/trap.c b/src/trap.c index 09c5bcbb6..67dc4ed6c 100644 --- a/src/trap.c +++ b/src/trap.c @@ -1801,7 +1801,7 @@ int style; delaycnt = 1; if (!cansee(g.bhitpos.x, g.bhitpos.y)) curs_on_u(); - tmp_at(DISP_FLASH, obj_to_glyph(singleobj)); + tmp_at(DISP_FLASH, obj_to_glyph(singleobj, rn2_on_display_rng)); tmp_at(g.bhitpos.x, g.bhitpos.y); } /* Mark a spot to place object in bones files to prevent diff --git a/src/uhitm.c b/src/uhitm.c index 8c7ba404c..f871b4ea7 100644 --- a/src/uhitm.c +++ b/src/uhitm.c @@ -2018,7 +2018,7 @@ struct monst *mdef; { if (!Invisible) { map_location(u.ux, u.uy, TRUE); - tmp_at(DISP_ALWAYS, mon_to_glyph(&g.youmonst)); + tmp_at(DISP_ALWAYS, mon_to_glyph(&g.youmonst, rn2_on_display_rng)); tmp_at(mdef->mx, mdef->my); } You("engulf %s!", mon_nam(mdef)); diff --git a/src/worm.c b/src/worm.c index de1833bd7..98ed3b6a0 100644 --- a/src/worm.c +++ b/src/worm.c @@ -457,13 +457,14 @@ boolean use_detection_glyph; struct wseg *curr = wtails[worm->wormno]; /* if (!mtmp->wormno) return; bullet proofing */ + int what_tail = what_mon(PM_LONG_WORM_TAIL, newsym_rn2); while (curr != wheads[worm->wormno]) { num = use_detection_glyph - ? detected_monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL)) + ? detected_monnum_to_glyph(what_tail) : (worm->mtame - ? petnum_to_glyph(what_mon(PM_LONG_WORM_TAIL)) - : monnum_to_glyph(what_mon(PM_LONG_WORM_TAIL))); + ? petnum_to_glyph(what_tail) + : monnum_to_glyph(what_tail)); show_glyph(curr->wx, curr->wy, num); curr = curr->nseg; } diff --git a/src/zap.c b/src/zap.c index 0b0b5c5e8..b212e64d9 100644 --- a/src/zap.c +++ b/src/zap.c @@ -1480,7 +1480,7 @@ int id; /* now change it into something laid by the hero */ while (tryct--) { - mnum = can_be_hatched(random_monster()); + mnum = can_be_hatched(random_monster(rn2)); if (mnum != NON_PM && !dead_species(mnum, TRUE)) { otmp->spe = 1; /* laid by hero */ set_corpsenm(otmp, mnum); /* also sets hatch timer */ @@ -3192,9 +3192,9 @@ struct obj **pobj; /* object tossed/used, set to NULL } else if (weapon == THROWN_TETHERED_WEAPON && obj) { tethered_weapon = TRUE; weapon = THROWN_WEAPON; /* simplify if's that follow below */ - tmp_at(DISP_TETHER, obj_to_glyph(obj)); + tmp_at(DISP_TETHER, obj_to_glyph(obj, rn2_on_display_rng)); } else if (weapon != ZAPPED_WAND && weapon != INVIS_BEAM) - tmp_at(DISP_FLASH, obj_to_glyph(obj)); + tmp_at(DISP_FLASH, obj_to_glyph(obj, rn2_on_display_rng)); while (range-- > 0) { int x, y; diff --git a/sys/msdos/msdos.c b/sys/msdos/msdos.c index d943b864d..69f994be6 100644 --- a/sys/msdos/msdos.c +++ b/sys/msdos/msdos.c @@ -519,4 +519,15 @@ unsigned setvalue; return (regs.x.dx); } +unsigned long +sys_random_seed(VOID_ARGS) +{ + unsigned long ourseed = 0UL; + time_t datetime = 0; + + (void) time(&datetime); + ourseed = (unsigned long) datetime; + return ourseed; +} + #endif /* MSDOS */ diff --git a/sys/unix/Makefile.src b/sys/unix/Makefile.src index 5548ed479..c6f25e029 100644 --- a/sys/unix/Makefile.src +++ b/sys/unix/Makefile.src @@ -441,9 +441,9 @@ HACKCSRC = allmain.c alloc.c apply.c artifact.c attrib.c ball.c bones.c \ botl.c cmd.c dbridge.c decl.c detect.c dig.c display.c dlb.c do.c \ do_name.c do_wear.c dog.c dogmove.c dokick.c dothrow.c drawing.c \ dungeon.c eat.c end.c engrave.c exper.c explode.c extralev.c \ - files.c fountain.c hack.c hacklib.c invent.c light.c lock.c \ - mail.c makemon.c mapglyph.c mcastu.c mhitm.c mhitu.c minion.c \ - mklev.c mkmap.c \ + files.c fountain.c hack.c hacklib.c invent.c isaac64.c light.c \ + lock.c mail.c makemon.c mapglyph.c mcastu.c mhitm.c mhitu.c \ + minion.c mklev.c mkmap.c \ mkmaze.c mkobj.c mkroom.c mon.c mondata.c monmove.c monst.c \ mplayer.c mthrowu.c muse.c music.c o_init.c objects.c objnam.c \ options.c pager.c pickup.c pline.c polyself.c potion.c pray.c \ @@ -508,8 +508,8 @@ HOBJ = $(FIRSTOBJ) allmain.o alloc.o apply.o artifact.o attrib.o ball.o \ bones.o botl.o cmd.o dbridge.o decl.o detect.o dig.o display.o dlb.o \ do.o do_name.o do_wear.o dog.o dogmove.o dokick.o dothrow.o \ drawing.o dungeon.o eat.o end.o engrave.o exper.o explode.o \ - extralev.o files.o fountain.o hack.o hacklib.o invent.o light.o \ - lock.o mail.o makemon.o mapglyph.o mcastu.o mhitm.o mhitu.o \ + extralev.o files.o fountain.o hack.o hacklib.o invent.o isaac64.o \ + light.o lock.o mail.o makemon.o mapglyph.o mcastu.o mhitm.o mhitu.o \ minion.o mklev.o mkmap.o \ mkmaze.o mkobj.o mkroom.o mon.o mondata.o monmove.o \ mplayer.o mthrowu.o muse.o music.o o_init.o objnam.o options.o \ @@ -1013,6 +1013,7 @@ fountain.o: fountain.c $(HACK_H) hack.o: hack.c $(HACK_H) hacklib.o: hacklib.c $(HACK_H) invent.o: invent.c $(HACK_H) +isaac64.o: isaac64.c ../include/isaac64.h ../include/integer.h light.o: light.c $(HACK_H) ../include/lev.h lock.o: lock.c $(HACK_H) mail.o: mail.c $(HACK_H) ../include/mail.h diff --git a/sys/unix/hints/macosx10.10 b/sys/unix/hints/macosx10.10 index 85d4b63fa..e53a80d77 100644 --- a/sys/unix/hints/macosx10.10 +++ b/sys/unix/hints/macosx10.10 @@ -69,7 +69,7 @@ CC=gcc # #CFLAGS+=-W -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wcast-qual -Wwrite-strings -DGCC_WARN -CFLAGS+=-Wall -Wextra -Wno-missing-field-initializers -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wwrite-strings -DGCC_WARN -ansi -pedantic +CFLAGS+=-Wall -Wextra -Wno-missing-field-initializers -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wwrite-strings -DGCC_WARN -ansi -pedantic -Wno-long-long # As of LLVM build 2336.1.00, this gives dozens of spurious messages, so # leave it out by default. #CFLAGS+=-Wunreachable-code diff --git a/sys/unix/hints/macosx10.14 b/sys/unix/hints/macosx10.14 index 2255ddb9e..c5e5a0cf1 100644 --- a/sys/unix/hints/macosx10.14 +++ b/sys/unix/hints/macosx10.14 @@ -69,7 +69,7 @@ CC=gcc # #CFLAGS+=-W -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wcast-qual -Wwrite-strings -DGCC_WARN -CFLAGS+=-Wall -Wextra -Wno-missing-field-initializers -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wwrite-strings -DGCC_WARN -ansi -pedantic +CFLAGS+=-Wall -Wextra -Wno-missing-field-initializers -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wwrite-strings -DGCC_WARN -ansi -pedantic -Wno-long-long # As of LLVM build 2336.1.00, this gives dozens of spurious messages, so # leave it out by default. #CFLAGS+=-Wunreachable-code diff --git a/sys/unix/hints/macosx10.5 b/sys/unix/hints/macosx10.5 index 668b6b2b5..f6d9e5483 100644 --- a/sys/unix/hints/macosx10.5 +++ b/sys/unix/hints/macosx10.5 @@ -53,7 +53,7 @@ GAMEGRP = games #WANT_SOURCE_INSTALL=1 #CC=gcc -W -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wcast-qual -Wwrite-strings -DGCC_WARN -CC=gcc -Wall -Wextra -Wno-missing-field-initializers -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wwrite-strings -DGCC_WARN -ansi -pedantic +CC=gcc -Wall -Wextra -Wno-missing-field-initializers -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wwrite-strings -DGCC_WARN -ansi -pedantic -Wno-long-long # # You shouldn't need to change anything below here. diff --git a/sys/unix/hints/macosx10.7 b/sys/unix/hints/macosx10.7 index cc9216884..776cb4b81 100644 --- a/sys/unix/hints/macosx10.7 +++ b/sys/unix/hints/macosx10.7 @@ -63,7 +63,7 @@ CC=gcc # #CFLAGS+=-W -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wcast-qual -Wwrite-strings -DGCC_WARN -CFLAGS+=-Wall -Wextra -Wno-missing-field-initializers -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wwrite-strings -DGCC_WARN -ansi -pedantic +CFLAGS+=-Wall -Wextra -Wno-missing-field-initializers -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wwrite-strings -DGCC_WARN -ansi -pedantic -Wno-long-long # As of LLVM build 2336.1.00, this gives dozens of spurious messages, so # leave it out by default. #CFLAGS+=-Wunreachable-code diff --git a/sys/unix/hints/macosx10.8 b/sys/unix/hints/macosx10.8 index 6a1f69d4b..87d0e8305 100644 --- a/sys/unix/hints/macosx10.8 +++ b/sys/unix/hints/macosx10.8 @@ -70,7 +70,7 @@ CC=gcc # #CFLAGS+=-W -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wcast-qual -Wwrite-strings -DGCC_WARN -CFLAGS+=-Wall -Wextra -Wno-missing-field-initializers -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wwrite-strings -DGCC_WARN -ansi -pedantic +CFLAGS+=-Wall -Wextra -Wno-missing-field-initializers -Wimplicit -Wreturn-type -Wunused -Wformat -Wswitch -Wshadow -Wwrite-strings -DGCC_WARN -ansi -pedantic -Wno-long-long # As of LLVM build 2336.1.00, this gives dozens of spurious messages, so # leave it out by default. #CFLAGS+=-Wunreachable-code diff --git a/sys/unix/unixmain.c b/sys/unix/unixmain.c index 6237b46a3..cc593b954 100644 --- a/sys/unix/unixmain.c +++ b/sys/unix/unixmain.c @@ -765,4 +765,36 @@ error: } #endif +unsigned long +sys_random_seed() +{ + unsigned long seed; + unsigned long pid = (unsigned long) getpid(); + boolean no_seed = TRUE; +#ifdef DEV_RANDOM + FILE *fptr = NULL; + + fptr = fopen(DEV_RANDOM, "r"); + if (fptr) { + fread(&seed, sizeof(long), 1, fptr); + has_strong_rngseed = TRUE; /* decl.c */ + no_seed = FALSE; + fclose(fptr); + } else { + /* leaves clue, doesn't exit */ + paniclog("sys_random_seed", "falling back to weak seed"); + } +#endif + if (no_seed) { + seed = (unsigned long) getnow(); /* time((TIME_type) 0) */ + /* Quick dirty band-aid to prevent PRNG prediction */ + if (pid) { + if (!(pid & 3L)) + pid -= 1L; + seed *= pid; + } + } + return seed; +} + /*unixmain.c*/ diff --git a/sys/vms/vmsmain.c b/sys/vms/vmsmain.c index 29e5c8cd3..c28bcaa03 100644 --- a/sys/vms/vmsmain.c +++ b/sys/vms/vmsmain.c @@ -465,4 +465,20 @@ wd_message() You("are in non-scoring explore/discovery mode."); } +unsigned long +sys_random_seed() +{ + unsigned long seed; + unsigned long pid = (unsigned long) getpid(); + + seed = (unsigned long) getnow(); /* time((TIME_type) 0) */ + /* Quick dirty band-aid to prevent PRNG prediction */ + if (pid) { + if (!(pid & 3L)) + pid -= 1L; + seed *= pid; + } + return seed; +} + /*vmsmain.c*/ diff --git a/sys/winnt/Makefile.msc b/sys/winnt/Makefile.msc index 6dcd10d4d..97001da6e 100644 --- a/sys/winnt/Makefile.msc +++ b/sys/winnt/Makefile.msc @@ -129,9 +129,13 @@ OBJ = o # (see pcconf.h). Set to nothing if not used. # -RANDOM = $(OBJ)\random.o +RANDOM = $(OBJ)\isaac64.o +#RANDOM = $(OBJ)\random.o #RANDOM = - +BCRYPT= +! IF ("$(RANDOM)"=="$(OBJ)\isaac64.o") +BCRYPT=bcrypt.lib +! ENDIF WINPFLAG= -DTILES -DMSWIN_GRAPHICS -DWIN32CON # To store all the level files, @@ -460,7 +464,8 @@ CURSESLIB= ccommon= -c -nologo -D"_CONSOLE" -D"_CRT_NONSTDC_NO_DEPRECATE" -D"_CRT_SECURE_NO_DEPRECATE" \ -D"_LIB" -D"_SCL_SECURE_NO_DEPRECATE" -D"_VC80_UPGRADE=0x0600" -D"DLB" -D"_MBCS" \ - -DCRTAPI1=_cdecl -DCRTAPI2=_cdecl -D"NDEBUG" -D"YY_NO_UNISTD_H" $(CURSESDEF) \ + -DCRTAPI1=_cdecl -DCRTAPI2=_cdecl -D"NDEBUG" -D"YY_NO_UNISTD_H" \ + -DHAS_STDINT_H -DHAS_INLINE $(CURSESDEF) \ -EHsc -fp:precise -Gd -GF -GS -Gy \ $(CL_RECENT) -WX- -Zc:forScope -Zc:wchar_t -Zi cdebug= -analyze- -D"_DEBUG" -Gm -MTd -RTC1 -Od @@ -801,7 +806,7 @@ $(GAMEDIR)\NetHack.exe : $(O)gamedir.tag $(PDCLIB) $(O)tile.o $(O)nttty.o $(O)gu @if not exist $(GAMEDIR)\*.* mkdir $(GAMEDIR) @echo Linking $(@:\=/) $(link) $(lflagsBuild) $(conlflags) /STACK:2048 /PDB:$(GAMEDIR)\$(@B).PDB /MAP:$(O)$(@B).MAP \ - $(LIBS) $(PDCLIB) $(conlibs) -out:$@ @<<$(@B).lnk + $(LIBS) $(PDCLIB) $(conlibs) $(BCRYPT) -out:$@ @<<$(@B).lnk $(GAMEOBJ) $(TTYOBJ) $(O)nttty.o @@ -824,7 +829,7 @@ $(GAMEDIR)\NetHackW.exe : $(O)gamedir.tag $(O)tile.o $(O)ttystub.o \ @if not exist $(GAMEDIR)\*.* mkdir $(GAMEDIR) @echo Linking $(@:\=/) $(link) $(lflagsBuild) $(guilflags) /STACK:2048 /PDB:$(GAMEDIR)\$(@B).PDB \ - /MAP:$(O)$(@B).MAP $(LIBS) $(PDCLIB) $(guilibs) $(COMCTRL) -out:$@ @<<$(@B).lnk + /MAP:$(O)$(@B).MAP $(LIBS) $(PDCLIB) $(guilibs) $(COMCTRL) $(BCRYPT) -out:$@ @<<$(@B).lnk $(GAMEOBJ) $(GUIOBJ) $(O)tile.o @@ -1514,6 +1519,8 @@ $(O)tos.o: ..\sys\atari\tos.c $(HACK_H) $(INCL)\tcap.h @$(CC) $(cflagsBuild) -Fo$@ ..\sys\atari\tos.c $(O)pctty.o: ..\sys\share\pctty.c $(HACK_H) @$(CC) $(cflagsBuild) -Fo$@ ..\sys\share\pctty.c +$(O)isaac64.o: ..\src\isaac64.c $(HACK_H) $(INCL)\isaac64.h $(INCL)\integer.h + @$(CC) $(cflagsBuild) -Fo$@ ..\src\isaac64.c $(O)random.o: ..\sys\share\random.c $(HACK_H) @$(CC) $(cflagsBuild) -Fo$@ ..\sys\share\random.c $(O)ioctl.o: ..\sys\share\ioctl.c $(HACK_H) $(INCL)\tcap.h diff --git a/sys/winnt/winnt.c b/sys/winnt/winnt.c index 035ea7457..fc75071d8 100644 --- a/sys/winnt/winnt.c +++ b/sys/winnt/winnt.c @@ -680,6 +680,54 @@ char *name; } return; } + +#include /* Windows Crypto Next Gen (CNG) */ + +#ifndef STATUS_SUCCESS +#define STATUS_SUCCESS 0 +#endif +#ifndef STATUS_NOT_FOUND +#define STATUS_NOT_FOUND 0xC0000225 +#endif +#ifndef STATUS_UNSUCCESSFUL +#define STATUS_UNSUCCESSFUL 0xC0000001 +#endif + +unsigned long +sys_random_seed(VOID_ARGS) +{ + unsigned long ourseed = 0UL; + BCRYPT_ALG_HANDLE hRa = (BCRYPT_ALG_HANDLE) 0; + NTSTATUS status = STATUS_UNSUCCESSFUL; + boolean Plan_B = TRUE; + + status = BCryptOpenAlgorithmProvider(&hRa, BCRYPT_RNG_ALGORITHM, + (LPCWSTR) 0, 0); + if (hRa && status == STATUS_SUCCESS) { + status = BCryptGenRandom(hRa, (PUCHAR) &ourseed, + (ULONG) sizeof ourseed, 0); + if (status == STATUS_SUCCESS) { + BCryptCloseAlgorithmProvider(hRa,0); + has_strong_rngseed = TRUE; + Plan_B = FALSE; + } + } + + if (Plan_B) { + time_t datetime = 0; + const char *emsg; + + if (status == STATUS_NOT_FOUND) + emsg = "BCRYPT_RNG_ALGORITHM not avail, falling back"; + else + emsg = "Other failure than algorithm not avail"; + paniclog("sys_random_seed", emsg); /* leaves clue, doesn't exit */ + (void) time(&datetime); + ourseed = (unsigned long) datetime; + } + return ourseed; +} + #endif /* WIN32 */ /*winnt.c*/ diff --git a/win/win32/vs2017/NetHack.vcxproj b/win/win32/vs2017/NetHack.vcxproj index ee086fcc5..3a4412efe 100644 --- a/win/win32/vs2017/NetHack.vcxproj +++ b/win/win32/vs2017/NetHack.vcxproj @@ -37,7 +37,7 @@ TILES;WIN32CON;DLB;MSWIN_GRAPHICS;SAFEPROCS;_LIB;%(PreprocessorDefinitions) - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;winmm.lib;Winmm.lib;%(AdditionalDependencies) + kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;winmm.lib;Winmm.lib;bcrypt.lib;%(AdditionalDependencies) @@ -76,6 +76,7 @@ + @@ -151,7 +152,6 @@ - @@ -194,6 +194,7 @@ + diff --git a/win/win32/vs2017/NetHackW.vcxproj b/win/win32/vs2017/NetHackW.vcxproj index 93c2e447b..e801b1583 100644 --- a/win/win32/vs2017/NetHackW.vcxproj +++ b/win/win32/vs2017/NetHackW.vcxproj @@ -28,7 +28,7 @@ Windows - comctl32.lib;winmm.lib;%(AdditionalDependencies) + comctl32.lib;winmm.lib;bcrypt.lib;%(AdditionalDependencies) $(WinWin32Dir)NethackW.exe.manifest;%(AdditionalManifestFiles) @@ -70,6 +70,7 @@ + @@ -146,7 +147,6 @@ - TTYSTUB;