Index: config.doc ================================================================== --- config.doc +++ config.doc @@ -55,10 +55,16 @@ .margin The X coordinate of the left margin. To the left is the status area, and to the right of the margin is the playfield. This should be at least 64, or the picture size, whichever is greater. +.maxTrigger + If nonzero, the maximum number of times that the trigger phase may loop + during each turn (it starts counting from zero each turn). If it loops + more, it displays an error message and results in loss of game. (This + does not prevent other kinds of infinite loops, though.) + .palette If defined, the file name of the palette to use (if not set, then the internal palette is used instead). The file format is hex rrggbb format separated by any kind of whitespaces. Index: default.heromeshrc ================================================================== --- default.heromeshrc +++ default.heromeshrc @@ -2,10 +2,11 @@ ?.screenWidth: 800 ?.screenHeight: 600 ?.imageSize: 24 ?.traceAll: true ?.showInventory: 0 +?.maxTrigger: 32767 ! Game inputs ?.gameKey.A: 'A ?.gameKey.B: 'B ?.gameKey.C: 'C Index: exec.c ================================================================== --- exec.c +++ exec.c @@ -38,10 +38,11 @@ Uint16 nlevelstrings; Value*array_data; Uint16 ndeadanim; DeadAnimation*deadanim; Uint8 no_dead_anim; +Uint32 max_trigger; typedef struct { Uint16 msg; Uint32 from; Value arg1,arg2,arg3; @@ -1931,11 +1932,11 @@ } } const char*execute_turn(int key) { Uint8 busy,clock,x,y; - Uint32 m,n,turn; + Uint32 m,n,turn,tc; Object*o; Value v; int i; if(!key) { // This is part of initialization; if anything triggered, it must be executed now @@ -1957,10 +1958,11 @@ key_ignored=0; all_flushed=0; lastimage_processing=0; vstackptr=0; current_key=key; + tc=0; for(n=0;ndistance=0; o->oflags&=~(OF_KEYCLEARED|OF_DONE); if(o->anim) { o->anim->count=0; @@ -1997,10 +1999,13 @@ broadcast(m,0,MSG_BEGIN_TURN,NVALUE(x),NVALUE(y),v,0); } turn=0; // Trigger phase trig: + if(max_trigger) { + if(tc++>=max_trigger) return "Turn looped too many times"; + } busy=0; clock=255; for(i=0;i<64*pfheight;i++) { n=playfield[i]; while(n!=VOIDLINK) { Index: heromesh.h ================================================================== --- heromesh.h +++ heromesh.h @@ -262,10 +262,11 @@ extern Uint16 nlevelstrings; extern Value*array_data; extern Uint16 ndeadanim; extern DeadAnimation*deadanim; extern Uint8 no_dead_anim; +extern Uint32 max_trigger; const unsigned char*value_string_ptr(Value v); void pfunlink(Uint32 n); void pflink(Uint32 n); Uint32 objalloc(Uint16 c); Index: main.c ================================================================== --- main.c +++ main.c @@ -913,10 +913,12 @@ max_objects=strtoll(xrm_get_resource(resourcedb,optionquery,optionquery,2)?:"",0,0)?:0xFFFF0000L; set_tracing(); annihilate(); optionquery[1]=Q_level; if(level_ord=strtol(xrm_get_resource(resourcedb,optionquery,optionquery,2)?:"",0,10)) log_if_error(load_level(-level_ord)); + optionquery[1]=Q_maxTrigger; + max_trigger=strtol(xrm_get_resource(resourcedb,optionquery,optionquery,2)?:"",0,10); if(main_options['a']) run_auto_test(); if(main_options['x']) { fprintf(stderr,"Ready for executing SQL statements.\n"); no_dead_anim=1; do_sql_mode(); Index: quarks ================================================================== --- quarks +++ quarks @@ -216,6 +216,7 @@ traceAll traceObject showInventory progress autoSave +maxTrigger Index: quarks.h ================================================================== --- quarks.h +++ quarks.h @@ -181,10 +181,11 @@ #define Q_traceAll 182 #define Q_traceObject 183 #define Q_showInventory 184 #define Q_progress 185 #define Q_autoSave 186 +#define Q_maxTrigger 187 static const char*const global_quarks[]={ "screenWidth", "screenHeight", "margin", "palette", @@ -367,10 +368,11 @@ "traceAll", "traceObject", "showInventory", "progress", "autoSave", + "maxTrigger", 0}; #ifdef HEROMESH_BINDINGS static const SDLKey quark_to_key[Q_undo+1-Q_backspace]={ SDLK_BACKSPACE, SDLK_TAB,