Merge branch 'master' into NetHack-3.7

This commit is contained in:
nhmall
2019-07-14 09:57:32 -04:00
18 changed files with 517 additions and 40 deletions

View File

@@ -4,7 +4,7 @@
/* NetHack may be freely redistributed. See license for details. */
/* various code that was replicated in *main.c */
#define NEED_VARARGS
#include "hack.h"
#include <ctype.h>
@@ -441,6 +441,8 @@ boolean resuming;
#ifdef MAIL
ckmailstatus();
#endif
fuzzer_check();
rhack((char *) 0);
}
if (u.utotype) /* change dungeon level */
@@ -588,6 +590,8 @@ newgame()
{
int i;
fuzzer_auto_start();
#ifdef MFLOPPY
gameDiskPrompt();
#endif
@@ -927,4 +931,131 @@ const char *opts;
#endif
return;
}
static FILE * g_fuzzer_log_file = NULL;
static int g_fuzzer_log_level = LOG_MINIMAL;
/* fuzzer_start() starts the fuzzer opening the fuzzer log file */
void
fuzzer_start()
{
if (!iflags.debug_fuzzer) {
const char * fq_replay;
iflags.debug_fuzzer = TRUE;
iflags.fuzzer_auto_start = FALSE;
nhassert(g_fuzzer_log_file == NULL);
fq_replay = fqname("fuzzer.log", SAVEPREFIX, 0);
g_fuzzer_log_file = fopen(fq_replay, "w");
}
}
/* fuzzer_stop() stops the fuzzer and close the fuzzer log file */
void
fuzzer_stop()
{
if (iflags.debug_fuzzer) {
if(g_fuzzer_log_file != NULL) {
fclose(g_fuzzer_log_file);
g_fuzzer_log_file = NULL;
}
}
}
/* fuzzer_toggle() toggles fuzzer state */
void
fuzzer_toggle()
{
if (iflags.debug_fuzzer)
fuzzer_stop();
else
fuzzer_start();
}
/* fuzzer_log() is used to place messages in the file 'fuzzer.log'. This
* log is the primary tool for monitoring fuzzer activity and tracking down
* issues that the fuzzer is able to reproduce.
*/
void
fuzzer_log
VA_DECL2(int, level, const char *, str)
{
VA_START(str);
VA_INIT(str, char *);
if (!g_fuzzer_log_file)
return;
if (iflags.verbose_logging_start != 0 && g.moves >= iflags.verbose_logging_start)
g_fuzzer_log_level = LOG_VERBOSE;
if (level <= g_fuzzer_log_level)
Vfprintf(g_fuzzer_log_file, str, VA_ARGS);
VA_END();
}
/* fuzzer_check() is called prior to rhack(0) to allow the fuzzer to
* check if it should stop and to allow it to reseed the game.
*/
void
fuzzer_check()
{
if (iflags.debug_fuzzer)
{
if (g.moves >= iflags.fuzzer_stop_and_save) {
iflags.fuzzer_saving = TRUE;
dosave0();
exit_nhwindows("Goodbye from the fuzzer...");
fuzzer_stop();
nh_terminate(EXIT_SUCCESS);
}
unsigned long seed = rul();
set_random(seed, rn2);
fuzzer_log(LOG_MINIMAL, "SEED:%ld:%lu\n", g.moves, seed);
}
}
/* fuzzer_auto_start is called when creating a new game to allow
* the fuzzer to start itself.
*/
void
fuzzer_auto_start()
{
if (iflags.fuzzer_auto_start) {
nhassert(!iflags.debug_fuzzer);
fuzzer_start();
unsigned long seed = rul();
set_random(seed, rn2);
fuzzer_log(LOG_MINIMAL, "START:%ld:%lu\n", g.moves, seed);
}
}
/* fuzzer_msg_history is called during save file recovery to allow
* the fuzzer to snoop the messages being recovered. The fuzzer
* saves a seed as a message in save files and this is the mechanism
* used to recover that seed if the fuzzer is being auto started.
*/
boolean
fuzzer_msg_history(msg)
const char * msg;
{
long saved_moves;
unsigned long saved_seed;
if (sscanf(msg, "SEED:%ld:%lu", &saved_moves, &saved_seed) == 2) {
nhassert(saved_moves == g.moves);
if (iflags.fuzzer_auto_start) {
fuzzer_start();
set_random(saved_seed, rn2);
fuzzer_log(LOG_MINIMAL, "START:%ld:%lu\n", g.moves, saved_seed);
}
return TRUE;
}
return FALSE;
}
/*allmain.c*/

View File

@@ -2516,7 +2516,8 @@ recalc_mapseen()
struct cemetery *bp, **bonesaddr;
struct trap *t;
unsigned i, ridx;
int x, y, ltyp, count, atmp;
int x, y, ltyp, count;
unsigned int atmp;
/* Should not happen in general, but possible if in the process
* of being booted from the quest. The mapseen object gets

View File

@@ -854,7 +854,7 @@ STATIC_DCL struct tm *NDECL(getlt);
/* Sets the seed for the random number generator */
#ifdef USE_ISAAC64
static void
void
set_random(seed, fn)
unsigned long seed;
int FDECL((*fn), (int));
@@ -865,7 +865,7 @@ int FDECL((*fn), (int));
#else /* USE_ISAAC64 */
/*ARGSUSED*/
static void
void
set_random(seed, fn)
unsigned long seed;
int FDECL((*fn), (int)) UNUSED;
@@ -917,7 +917,7 @@ int FDECL((*fn), (int));
{
/* only reseed if we are certain that the seed generation is unguessable
* by the players. */
if (has_strong_rngseed)
if (has_strong_rngseed && !iflags.debug_fuzzer)
init_random(fn);
}
@@ -1108,6 +1108,9 @@ phase_of_the_moon() /* 0-7, with 0: new, 4: full */
register struct tm *lt = getlt();
register int epact, diy, goldn;
if(iflags.debug_fuzzer)
return rn2(8);
diy = lt->tm_yday;
goldn = (lt->tm_year % 19) + 1;
epact = (11 * goldn + 18) % 30;
@@ -1122,6 +1125,9 @@ friday_13th()
{
register struct tm *lt = getlt();
if(iflags.debug_fuzzer)
return rn2(30);
/* tm_wday (day of week; 0==Sunday) == 5 => Friday */
return (boolean) (lt->tm_wday == 5 && lt->tm_mday == 13);
}
@@ -1223,4 +1229,38 @@ strbuf_t *strbuf;
}
}
ptr_array_t *
ptr_array_new(max_length)
size_t max_length;
{
size_t esize = max_length * sizeof(void *);
ptr_array_t * a = (ptr_array_t *) malloc(sizeof(ptr_array_t) + esize);
a->elements = (void **)(a + 1);
a->length = 0;
a->max_length = max_length;
memset(a->elements, 0, esize);
return a;
}
void
ptr_array_free(a)
ptr_array_t * a;
{
size_t i;
nhassert(a->length <= a->max_length);
for(i = 0; i < a->length; i++)
if(a->elements[i])
free(a->elements[i]);
for (i = a->length; i < a->max_length; i++) {
nhassert(a->elements[i] == NULL);
if(a->elements[i])
free(a->elements[i]);
}
free(a);
}
/*hacklib.c*/

View File

@@ -1509,6 +1509,8 @@ NHFILE *nhfp;
if (nhfp->fieldlevel)
sfi_str(nhfp, msg, "msghistory", "msg", msgsize);
msg[msgsize] = '\0';
if(fuzzer_msg_history(msg))
continue;
putmsghistory(msg, TRUE);
++msgcount;
}

View File

@@ -56,10 +56,21 @@ int FDECL((*fn), (int));
(int) sizeof seed);
}
unsigned long
rul()
{
unsigned long value;
value = (unsigned long) isaac64_next_uint64(&rnglist[CORE].rng_state);
fuzzer_log(LOG_VERBOSE, "RANDOM:%llu\n", value);
return value;
}
static int
RND(int x)
{
return (isaac64_next_uint64(&rnglist[CORE].rng_state) % x);
return (rul() % x);
}
/* 0 <= rn2(x) < x, but on a different sequence from the "main" rn2;
@@ -69,6 +80,8 @@ int
rn2_on_display_rng(x)
register int x;
{
if (iflags.debug_fuzzer)
return rn2(x);
return (isaac64_next_uint64(&rnglist[DISP].rng_state) % x);
}
@@ -94,6 +107,20 @@ register int x;
seed *= 2739110765;
return (int)((seed >> 16) % (unsigned)x);
}
unsigned long
rul()
{
#if defined(LINT) && defined(UNIX)
return (unsigned long) rand();
#else /* LINT */
#if defined(UNIX) || defined(RANDOM)
return (unsigned long) Rand();
#else
return (unsigned long) (Rand() >> 3);
#endif /* defined(UNIX) || defined(RANDOM) */
#endif /* LINT */
}
#endif /* USE_ISAAC64 */
/* 0 <= rn2(x) < x */

View File

@@ -132,7 +132,7 @@ dosave0()
return 0;
#endif
HUP if (iflags.window_inited) {
HUP if (!iflags.debug_fuzzer && iflags.window_inited) {
nh_uncompress(fq_save);
nhfp = open_savefile();
if (nhfp) {
@@ -1225,6 +1225,25 @@ NHFILE *nhfp;
}
++msgcount;
}
/* If the fuzzer is stopping and saving, save a seed as a message.
In 3.7, we will modify the save file format and save the seed
directly in the saved game state. */
if (iflags.fuzzer_saving) {
char message[BUFSIZ];
unsigned long seed = rul();
sprintf(message, "SEED:%ld:%lu", g.moves, seed);
fuzzer_log(LOG_MINIMAL, "STOP:%ld:%lu\n", g.moves, seed);
msglen = strlen(message);
if (nhfp->structlevel) {
bwrite(nhfp->fd, (genericptr_t) &msglen, sizeof msglen);
bwrite(nhfp->fd, (genericptr_t) message, msglen);
}
if (nhfp->fieldlevel) {
sfo_int(nhfp, &msglen, "msghistory", "msghistory_length", 1);
sfo_str(nhfp, message, "msghistory", "msg", msglen);
}
}
if (nhfp->structlevel)
bwrite(nhfp->fd, (genericptr_t) &minusone, sizeof (int));
if (nhfp->fieldlevel)

View File

@@ -3742,7 +3742,7 @@ struct opvar *mc;
{
int x, y;
schar mapc;
xchar lit;
uchar lit;
struct opvar *ret = selection_opvar((char *) 0);
if (!ov || !mc || !ret)