From cf9e3fd3f6834dbe92f7bdfc19f525699d3ee59e Mon Sep 17 00:00:00 2001 From: helixhorned Date: Thu, 10 Feb 2011 23:15:02 +0000 Subject: [PATCH] * Fix a serious logic mistake with checksectorpointer. Previously, a white wall could 'connect' to a red one, leaving the reverse link intact and creating a situation like this: w_new <-> w <-- w_old. * Have the corruption checker catch this case among a few other new ones. Rename OSD command 'autocorruptcheck' to simply 'corruptcheck' with options 'corruptcheck ', 'corruptcheck now' and 'corruptcheck tryfix'. * When pasting sector selection into valid player space (releasing AltGr), ask whether a surrounding outer loop should be created since this is probably not always desired. git-svn-id: https://svn.eduke32.com/eduke32@1790 1a8010ca-5511-0410-912e-c29ae57300e0 --- polymer/eduke32/build/include/build.h | 1 + polymer/eduke32/build/include/editor.h | 9 +- polymer/eduke32/build/src/build.c | 377 ++++++++++++------------- polymer/eduke32/build/src/engine.c | 27 +- polymer/eduke32/source/astub.c | 173 ++++++++++-- 5 files changed, 361 insertions(+), 226 deletions(-) diff --git a/polymer/eduke32/build/include/build.h b/polymer/eduke32/build/include/build.h index 83369abe3..68053f942 100644 --- a/polymer/eduke32/build/include/build.h +++ b/polymer/eduke32/build/include/build.h @@ -528,6 +528,7 @@ void getzsofslope(int16_t sectnum, int32_t dax, int32_t day, int32_t *ceilz, i void alignceilslope(int16_t dasect, int32_t x, int32_t y, int32_t z); void alignflorslope(int16_t dasect, int32_t x, int32_t y, int32_t z); int32_t sectorofwall(int16_t theline); +int32_t sectorofwall_noquick(int16_t theline); int32_t loopnumofsector(int16_t sectnum, int16_t wallnum); // int32_t insertsprite(int16_t sectnum, int16_t statnum); diff --git a/polymer/eduke32/build/include/editor.h b/polymer/eduke32/build/include/editor.h index 04fd5ea28..f507f2534 100644 --- a/polymer/eduke32/build/include/editor.h +++ b/polymer/eduke32/build/include/editor.h @@ -116,7 +116,7 @@ extern const char *SaveBoard(const char *fn, uint32_t flags); #define MAXCORRUPTTHINGS 64 extern int32_t numcorruptthings, corruptthings[MAXCORRUPTTHINGS]; extern int32_t autocorruptcheck; -extern int32_t CheckMapCorruption(int32_t printfromlev); +extern int32_t CheckMapCorruption(int32_t printfromlev, int32_t tryfixing); extern void showsectordata(int16_t sectnum, int16_t small); extern void showwalldata(int16_t wallnum, int16_t small); @@ -215,4 +215,11 @@ extern int32_t scripthistend; // showdebug is now used as a general informational on-screen display #define M32_SHOWDEBUG +// this should be only used if there's no dependency on endwall after the loop. +// of course, users of this macro should know that it modifies startwall and endwall. +#define WALLS_OF_SECTOR(Sect, Itervar) \ + startwall=sector[(Sect)].wallptr, endwall=startwall+sector[(Sect)].wallnum, Itervar=startwall; \ + Itervar < endwall; \ + Itervar++ + #endif diff --git a/polymer/eduke32/build/src/build.c b/polymer/eduke32/build/src/build.c index 28c41dcd9..12a459a5f 100644 --- a/polymer/eduke32/build/src/build.c +++ b/polymer/eduke32/build/src/build.c @@ -617,7 +617,7 @@ CANCEL: if (asksave) { - i = CheckMapCorruption(4); + i = CheckMapCorruption(4, 0); printext256(0,8,whitecol,0,i<4?"Save changes?":"Map is heavily corrupt. Save changes?",0); showframe(1); @@ -1259,6 +1259,18 @@ static inline void drawline16base(int32_t bx, int32_t by, int32_t x1, int32_t y1 drawline16(bx+x1, by+y1, bx+x2, by+y2, col); } +static void drawsmalllabel(const char *text, char col, char backcol, + int32_t x1, int32_t y1, int32_t x2, int32_t y2) +{ + printext16(x1,y1, col,backcol, text,1); + drawline16(x1-1,y1-1, x2-3,y1-1, backcol); + drawline16(x1-1,y2+1, x2-3,y2+1, backcol); + + drawline16(x1-2,y1, x1-2,y2, backcol); + drawline16(x2-2,y1, x2-2,y2, backcol); + drawline16(x2-3,y1, x2-3,y2, backcol); +} + // backup highlighted sectors with sprites as mapinfo for later restoration // return values: // -1: highlightsectorcnt<=0 @@ -1483,9 +1495,7 @@ static void duplicate_selected_sectors() { // first, make red lines of old selected sectors, effectively // restoring the original state - startwall = sector[highlightsector[i]].wallptr; - endwall = startwall+sector[highlightsector[i]].wallnum-1; - for (j=startwall; j<=endwall; j++) + for (WALLS_OF_SECTOR(highlightsector[i], j)) { if (wall[j].nextwall >= 0) checksectorpointer(wall[j].nextwall,wall[j].nextsector); @@ -1917,17 +1927,15 @@ void overheadeditor(void) dax = 0; //Get average point of sector day = 0; - startwall = sector[i].wallptr; - endwall = startwall + sector[i].wallnum - 1; - for (j=startwall; j<=endwall; j++) + for (WALLS_OF_SECTOR(i, j)) { dax += wall[j].x; day += wall[j].y; } - if (endwall > startwall) + if (sector[i].wallnum > 0) { - dax /= (endwall-startwall+1); - day /= (endwall-startwall+1); + dax /= sector[i].wallnum; + day /= sector[i].wallnum; } if (m32_sideview) @@ -1941,15 +1949,8 @@ void overheadeditor(void) x2 = x1 + (Bstrlen(dabuffer)<<2)+2; y2 = y1 + 7; if ((x1 > 3) && (x2 < xdim) && (y1 > 1) && (y2 < ydim16)) - { - printext16(x1,y1,editorcolors[0],editorcolors[7],dabuffer,1); - drawline16(x1-1,y1-1, x2-3,y1-1, editorcolors[7]); - drawline16(x1-1,y2+1, x2-3,y2+1, editorcolors[7]); - - drawline16(x1-2,y1, x1-2,y2, editorcolors[7]); - drawline16(x2-2,y1, x2-2,y2, editorcolors[7]); - drawline16(x2-3,y1, x2-3,y2, editorcolors[7]); - } + drawsmalllabel(dabuffer, editorcolors[0], editorcolors[7], + x1,y1, x2,y2); } } } @@ -1971,6 +1972,7 @@ void overheadeditor(void) for (wal=&wall[i]; i>=0; i--,wal--) { if (zoom < 768 && !(wal->cstat & (1<<14))) continue; + //Get average point of wall dax = (wal->x+wall[wal->point2].x)>>1; day = (wal->y+wall[wal->point2].y)>>1; @@ -1989,15 +1991,8 @@ void overheadeditor(void) y2 = y1 + 7; if ((x1 > 3) && (x2 < xdim) && (y1 > 1) && (y2 < ydim16)) - { - printext16(x1,y1,editorcolors[0],editorcolors[31],dabuffer,1); - drawline16(x1-1,y1-1, x2-3,y1-1, editorcolors[31]); - drawline16(x1-1,y2+1, x2-3,y2+1, editorcolors[31]); - - drawline16(x1-2,y1, x1-2,y2, editorcolors[31]); - drawline16(x2-2,y1, x2-2,y2, editorcolors[31]); - drawline16(x2-3,y1, x2-3,y2, editorcolors[31]); - } + drawsmalllabel(dabuffer, editorcolors[0], editorcolors[31], + x1,y1, x2,y2); } } } @@ -2043,14 +2038,8 @@ void overheadeditor(void) if ((i == pointhighlight-16384) && (totalclock & 32)) col += (2<<2); - printext16(x1,y1,editorcolors[0],editorcolors[col],dabuffer,1); - - drawline16(x1-1,y1-1, x2-3,y1-1, editorcolors[col]); - drawline16(x1-1,y2+1, x2-3,y2+1, editorcolors[col]); - - drawline16(x1-2,y1, x1-2,y2, editorcolors[col]); - drawline16(x2-2,y1, x2-2,y2, editorcolors[col]); - drawline16(x2-3,y1, x2-3,y2, editorcolors[col]); + drawsmalllabel(dabuffer, editorcolors[0], editorcolors[col], + x1,y1, x2,y2); } } j--; @@ -2164,9 +2153,7 @@ void overheadeditor(void) for (i=0; i= 0) checksectorpointer(wall[j].nextwall,wall[j].nextsector); @@ -2765,10 +2746,28 @@ void overheadeditor(void) } } + if (!didmakered && newnumwalls<0) + { + char blackcol=editorcolors[0], greycol=whitecol-25, *cp; + + // fade the screen to have the user's attention + begindrawing(); + cp = (char *)frameplace; + for (i=0; i>3,1); if (!visitedwall) @@ -2782,118 +2781,125 @@ void overheadeditor(void) for (i=0; i>3]&(1<<(j&7)))) + for (WALLS_OF_SECTOR(highlightsector[i], j)) + { + int16_t refsect, ignore; + int32_t n; + + if (wall[j].nextwall>=0 || (visitedwall[j>>3]&(1<<(j&7)))) + continue; + + n=2*tmpnumwalls; // simple inf loop check + refwall = j; + k = numwalls; + + ignore = 0; + refsect = -1; + updatesectorexclude(wall[j].x, wall[j].y, &refsect, hlsectorbitmap); + if (refsect<0) + goto outtathis; + + do { - n=tmpnumwalls; - refwall = j; - k = numwalls; + if (j!=refwall && visitedwall[j>>3]&(1<<(j&7))) + ignore = 1; + visitedwall[j>>3] |= (1<<(j&7)); - ignore = 0; - refsect = -1; - updatesectorexclude(wall[j].x, wall[j].y, &refsect, hlsectorbitmap); - if (refsect<0) - goto outtathis; - - do - { - if (j!=refwall && visitedwall[j>>3]&(1<<(j&7))) - ignore = 1; - visitedwall[j>>3] |= (1<<(j&7)); - - if (inside(wall[j].x, wall[j].y, refsect)!=1) - ignore = 1; - - if (!ignore) - { - if (k>=MAXWALLS) - { - message("Wall limits exceeded while trying to trace outer loop."); - goto outtathis; - } - - Bmemcpy(&wall[k], &wall[j], sizeof(walltype)); - wall[k].point2 = k+1; - wall[k].nextsector = wall[k].nextwall = wall[k].extra = -1; - k++; - } - - j = wall[j].point2; - n--; - - while (wall[j].nextwall>=0 && n>0) - { - j = wall[wall[j].nextwall].point2; -// if (j!=refwall && (visitedwall[j>>3]&(1<<(j&7)))) -// ignore = 1; -// visitedwall[j>>3] |= (1<<(j&7)); - n--; - } - } - while (j!=refwall && n>0); - if (j!=refwall) - { - message("internal error while trying to trace outer loop: j!=refwall"); - goto outtathis; - } + if (inside(wall[j].x, wall[j].y, refsect)!=1) + ignore = 1; if (!ignore) { - wall[k-1].point2 = numwalls; // close the loop - newnumwalls = k; - n = (newnumwalls-numwalls); // number of walls in just constructed loop - - if (clockdir(numwalls)==0) + if (k>=MAXWALLS) { - int16_t begwalltomove = sector[refsect].wallptr+sector[refsect].wallnum; - - flipwalls(numwalls, newnumwalls); - - sector[refsect].wallnum += n; - if (refsect != numsectors-1) - { - walltype *tmpwall = Bmalloc(n * sizeof(walltype)); - - if (!tmpwall) - { - message("out of memory!"); - goto outtathis; - } - - for (m=0; m= begwalltomove) - wall[m].nextwall += n; - } - for (m=refsect+1; m=0 && n>0) + { + j = wall[wall[j].nextwall].point2; +// if (j!=refwall && (visitedwall[j>>3]&(1<<(j&7)))) +// ignore = 1; +// visitedwall[j>>3] |= (1<<(j&7)); + n--; } } + while (j!=refwall && n>0); + + if (j!=refwall) + { + message("internal error while tracing outer loop: didn't reach refwall"); + goto outtathis; + } + + if (!ignore) + { + wall[k-1].point2 = numwalls; // close the loop + newnumwalls = k; + n = (newnumwalls-numwalls); // number of walls in just constructed loop + + if (clockdir(numwalls)==0) + { + int16_t begwalltomove = sector[refsect].wallptr+sector[refsect].wallnum; + + flipwalls(numwalls, newnumwalls); + + sector[refsect].wallnum += n; + if (refsect != numsectors-1) + { + walltype *tmpwall = Bmalloc(n * sizeof(walltype)); + + if (!tmpwall) + { + message("out of memory!"); + ExtUnInit(); + uninitsystem(); + exit(1); + } + + for (m=0; m= begwalltomove) + wall[m].nextwall += n; + } + for (m=refsect+1; m highlightx2) bad = 1; @@ -3118,9 +3122,7 @@ SKIP: for (i=0; i=0; j=nextspritesect[j]) @@ -3218,21 +3220,21 @@ SKIP: vec.z = sprite[daspr].z; if (setsprite(daspr, &vec) == -1 && osec>=0) Bmemcpy(&sprite[daspr], &ovec, sizeof(vec3_t)); - /* - daz = ((tilesizy[sprite[daspr].picnum]*sprite[daspr].yrepeat)<<2); +#if 0 + daz = ((tilesizy[sprite[daspr].picnum]*sprite[daspr].yrepeat)<<2); - for (i=0; i= getceilzofslope(i,dax,day)) - if (sprite[daspr].z-daz <= getflorzofslope(i,dax,day)) - { - sprite[daspr].x = dax; - sprite[daspr].y = day; - if (sprite[daspr].sectnum != i) - changespritesect(daspr,(int16_t)i); - break; - } - */ + for (i=0; i= getceilzofslope(i,dax,day)) + if (sprite[daspr].z-daz <= getflorzofslope(i,dax,day)) + { + sprite[daspr].x = dax; + sprite[daspr].y = day; + if (sprite[daspr].sectnum != i) + changespritesect(daspr,(int16_t)i); + break; + } +#endif } } asksave = 1; @@ -3497,9 +3499,7 @@ SKIP: for (k=0; k<2; k++) { - startwall = sector[joinsector[k]].wallptr; - endwall = startwall + sector[joinsector[k]].wallnum - 1; - for (j=startwall; j<=endwall; j++) + for (WALLS_OF_SECTOR(joinsector[k], j)) { if (wall[j].cstat == 255) continue; @@ -3565,9 +3565,7 @@ SKIP: for (k=0; k<2; k++) { - startwall = sector[joinsector[k]].wallptr; - endwall = startwall + sector[joinsector[k]].wallnum - 1; - for (j=startwall; j<=endwall; j++) + for (WALLS_OF_SECTOR(joinsector[k], j)) { wall[j].nextwall = -1; wall[j].nextsector = -1; @@ -3935,9 +3933,7 @@ SKIP: { //check if first point at point of sector m = -1; - startwall = sector[i].wallptr; - endwall = startwall + sector[i].wallnum - 1; - for (k=startwall; k<=endwall; k++) + for (WALLS_OF_SECTOR(i, k)) if (wall[k].x==wall[numwalls].x && wall[k].y==wall[numwalls].y) { m = k; @@ -4490,10 +4486,8 @@ SKIP: } for (i=0; i=4) + if (CheckMapCorruption(4, 0)>=4) if (!ask_if_sure("Map is corrupt. Are you sure you want to save?", 0)) break; @@ -4987,7 +4981,7 @@ CANCEL: { //QUIT! - int32_t corrupt = CheckMapCorruption(4); + int32_t corrupt = CheckMapCorruption(4, 0); if (ask_if_sure(corrupt<4?"Save changes?":"Map corrupt. Save changes?", corrupt<4?0:1)) SaveBoard(NULL, 0); @@ -5002,10 +4996,10 @@ CANCEL: goto CANCEL; } + ExtUnInit(); clearfilenames(); uninittimer(); uninitinput(); - ExtUnInit(); uninitengine(); exit(0); } @@ -5026,9 +5020,7 @@ CANCEL: for (i=0; i= 0) checksectorpointer(wall[j].nextwall,wall[j].nextsector); @@ -5040,10 +5032,10 @@ CANCEL: if (setgamemode(fullscreen,xdimgame,ydimgame,bppgame) < 0) { + initprintf("%d * %d not supported in this graphics mode\n",xdim,ydim); ExtUnInit(); uninitinput(); uninittimer(); - initprintf("%d * %d not supported in this graphics mode\n",xdim,ydim); uninitsystem(); clearfilenames(); exit(0); @@ -5071,6 +5063,7 @@ static int32_t ask_if_sure(const char *query, int32_t quit_is_yes) _printmessage16("%s", query); showframe(1); bflushchars(); + while ((keystatus[1]|keystatus[0x2e]) == 0) { if (handleevents()) @@ -5178,7 +5171,7 @@ int32_t LoadBoard(const char *filename, uint32_t flags) if (mapversion < 7) message("Map %s loaded successfully and autoconverted to V7!",boardfilename); else { - i = CheckMapCorruption(4); + i = CheckMapCorruption(4, 0); message("Loaded map %s %s",boardfilename, i==0?"successfully": (i<4 ? "(moderate corruption)" : "(HEAVY corruption)")); } @@ -5535,7 +5528,6 @@ static int32_t deletesector(int16_t sucksect) } numsectors--; - j = endwall-startwall+1; for (i=startwall; i<=endwall; i++) if (wall[i].nextwall != -1) { @@ -5543,6 +5535,7 @@ static int32_t deletesector(int16_t sucksect) NEXTWALL(i).nextsector = -1; } + j = endwall-startwall+1; movewalls(startwall,-j); for (i=0; i= startwall) diff --git a/polymer/eduke32/build/src/engine.c b/polymer/eduke32/build/src/engine.c index a9bf81d56..9e6e4252f 100644 --- a/polymer/eduke32/build/src/engine.c +++ b/polymer/eduke32/build/src/engine.c @@ -758,6 +758,11 @@ int32_t checksectorpointer(int16_t i, int16_t sectnum) if ((wall[wall[k].point2]).x == x1 && (wall[wall[k].point2]).y == y1) if (j != sectnum) { + // Don't create link if the other side is connected to another wall. + // The nextwall relation should be definitely one-to-one at all times! + if (wall[k].nextwall>=0 && wall[k].nextwall != i) + continue; + if (sectnum != -2) // -2 means dry run { wall[i].nextsector = j; @@ -11548,13 +11553,10 @@ void completemirror(void) // // sectorofwall // -int32_t sectorofwall(int16_t theline) +static int32_t sectorofwall_internal(int16_t theline) { int32_t i, gap; - if ((theline < 0) || (theline >= numwalls)) return(-1); - i = wall[theline].nextwall; if (i >= 0 && i < MAXWALLS) return(wall[i].nextsector); - gap = (numsectors>>1); i = gap; while (gap > 1) { @@ -11566,6 +11568,23 @@ int32_t sectorofwall(int16_t theline) return(i); } +int32_t sectorofwall(int16_t theline) +{ + int32_t i; + + if ((theline < 0) || (theline >= numwalls)) return(-1); + i = wall[theline].nextwall; if (i >= 0 && i < MAXWALLS) return(wall[i].nextsector); + + return sectorofwall_internal(theline); +} + +int32_t sectorofwall_noquick(int16_t theline) +{ + if ((theline < 0) || (theline >= numwalls)) return(-1); + + return sectorofwall_internal(theline); +} + // // getceilzofslope diff --git a/polymer/eduke32/source/astub.c b/polymer/eduke32/source/astub.c index 8c19ac977..642af9eac 100644 --- a/polymer/eduke32/source/astub.c +++ b/polymer/eduke32/source/astub.c @@ -7878,12 +7878,23 @@ static int32_t osdcmd_vars_pk(const osdfuncparm_t *parm) else return OSDCMD_SHOWHELP; } - else if (!Bstrcasecmp(parm->name, "autocorruptcheck")) + else if (!Bstrcasecmp(parm->name, "corruptcheck")) { if (parm->numparms == 1) { - autocorruptcheck = clamp(atoi(parm->parms[0]), 0, 3600); - corruptchecktimer = 0; // force checking now + if (!Bstrcasecmp(parm->parms[0], "now")) + { + CheckMapCorruption(1, 0); + } + else if (!Bstrcasecmp(parm->parms[0], "tryfix")) + { + CheckMapCorruption(3, 1); + } + else if (isdigit(parm->parms[0][0])) + { + autocorruptcheck = clamp(atoi(parm->parms[0]), 0, 3600); + corruptchecktimer = totalclock + 120*autocorruptcheck; + } } if (parm->numparms <= 1) @@ -8172,9 +8183,9 @@ static int32_t registerosdcommands(void) OSD_RegisterFunction("pk_uedaccel", "pk_uedaccel : sets UnrealEd movement speed factor (0-5, exponentially)", osdcmd_vars_pk); OSD_RegisterFunction("pk_quickmapcycling", "pk_quickmapcycling: toggles quick cycling of maps with (Shift-)Ctrl-X", osdcmd_vars_pk); OSD_RegisterFunction("testplay_addparam", "testplay_addparam \"string\": sets additional parameters for test playing", osdcmd_testplay_addparam); - OSD_RegisterFunction("show_heightindicators", "show_heightindicators <0, 1 or 2>: sets display of height indicators in 2D mode", osdcmd_vars_pk); - OSD_RegisterFunction("show_ambiencesounds", "show_ambiencesounds <0, 1 or 2>: sets display of MUSICANDSFX circles in 2D mode", osdcmd_vars_pk); - OSD_RegisterFunction("autocorruptcheck", "autocorruptcheck : sets auto corruption check interval", osdcmd_vars_pk); + OSD_RegisterFunction("show_heightindicators", "show_heightindicators {0, 1 or 2}: sets display of height indicators in 2D mode", osdcmd_vars_pk); + OSD_RegisterFunction("show_ambiencesounds", "show_ambiencesounds {0, 1 or 2}>: sets display of MUSICANDSFX circles in 2D mode", osdcmd_vars_pk); + OSD_RegisterFunction("corruptcheck", "corruptcheck {|now|tryfix}: sets auto corruption check interval if given, otherwise as indicated", osdcmd_vars_pk); #ifdef POLYMOST OSD_RegisterFunction("tint", "tint : queries or sets hightile tinting", osdcmd_tint); #endif @@ -8184,8 +8195,8 @@ static int32_t registerosdcommands(void) OSD_RegisterFunction("do", "do (m32 script ...): executes M32 script statements", osdcmd_do); OSD_RegisterFunction("script_info", "script_info: shows information about compiled M32 script", osdcmd_scriptinfo); OSD_RegisterFunction("script_expertmode", "script_expertmode: toggles M32 script expert mode", osdcmd_vars_pk); - OSD_RegisterFunction("enableevent", "enableevent ", osdcmd_endisableevent); - OSD_RegisterFunction("disableevent", "disableevent ", osdcmd_endisableevent); + OSD_RegisterFunction("enableevent", "enableevent {all|EVENT_...|(event number)}", osdcmd_endisableevent); + OSD_RegisterFunction("disableevent", "disableevent {all|EVENT_...|(event number)}", osdcmd_endisableevent); OSD_RegisterFunction("osd_tryscript", "osd_tryscript: toggles execution of M32 script on invalid OSD command", osdcmd_vars_pk); OSD_RegisterFunction("sideview_reversehorizrot", "sideview_reversehorizrot: toggles reversion of Q and W keys in side view mode", osdcmd_vars_pk); #ifdef DEBUGGINGAIDS @@ -8306,11 +8317,13 @@ void GAME_clearbackground(int32_t numcols, int32_t numrows) static void m32_osdsetfunctions() { OSD_SetFunctions( - /* GAME_drawosdchar, +/* + GAME_drawosdchar, GAME_drawosdstr, GAME_drawosdcursor, GAME_getcolumnwidth, - GAME_getrowheight,*/ + GAME_getrowheight, +*/ 0,0,0,0,0, GAME_clearbackground, (int32_t( *)(void))GetTime, @@ -9235,9 +9248,10 @@ void ExtUnInit(void) { int32_t i; // setvmode(0x03); + writesetup(setupfilename); + S_SoundShutdown(); uninitgroupfile(); - writesetup(setupfilename); for (i = MAX_TILE_GROUPS-1; i >= 0; i--) { @@ -9821,7 +9835,7 @@ static void Keys2d3d(void) { keystatus[KEYSC_S] = 0; - i = CheckMapCorruption(4); + i = CheckMapCorruption(4, 0); if (i<4) { SaveBoard(levelname, 0); @@ -9973,7 +9987,7 @@ void ExtCheckKeys(void) if (autocorruptcheck>0 && totalclock > corruptchecktimer) { - if (CheckMapCorruption(3)>=4) + if (CheckMapCorruption(3, 0)>=4) message("Corruption detected. See OSD for details."); corruptchecktimer = totalclock + 120*autocorruptcheck; } @@ -9991,7 +10005,7 @@ void ExtCheckKeys(void) { if (asksave == 3) { - if (CheckMapCorruption(6)>=4) + if (CheckMapCorruption(6, 0)>=4) { SaveBoard("autosave_corrupt.map", 1); message("Board autosaved to AUTOSAVE_CORRUPT.MAP"); @@ -10017,33 +10031,66 @@ void ExtCheckKeys(void) //// port of a.m32's corruptchk //// // returns value from 0 (all OK) to 5 (panic!) +#define CCHK_PANIC OSDTEXT_DARKRED "PANIC!!!^O " +#define CCHKPREF OSDTEXT_RED "* ^O" +#define CCHK_CORRECTED OSDTEXT_GREEN " -> " + #define CORRUPTCHK_PRINT(errlev, what, fmt, ...) do \ { \ bad = max(bad, errlev); \ if (numcorruptthings= printfromlev) \ - OSD_Printf(fmt "\n", ## __VA_ARGS__); \ + OSD_Printf(CCHKPREF fmt "\n", ## __VA_ARGS__); \ } while (0) -int32_t CheckMapCorruption(int32_t printfromlev) +static void suggest_nextsector_correction(int32_t nw, int32_t j) +{ + if (nw>=0 && nw=0 && nwMAXSECTORS) - CORRUPTCHK_PRINT(5, 0, "PANIC!!! SECTOR LIMIT EXCEEDED (MAXSECTORS=%d)!!!", MAXSECTORS); + CORRUPTCHK_PRINT(5, 0, CCHK_PANIC "SECTOR LIMIT EXCEEDED (MAXSECTORS=%d)!!!", MAXSECTORS); if (numwalls>MAXWALLS) - CORRUPTCHK_PRINT(5, 0, "PANIC!!! WALL LIMIT EXCEEDED (MAXWALLS=%d)!!!", MAXWALLS); + CORRUPTCHK_PRINT(5, 0, CCHK_PANIC "WALL LIMIT EXCEEDED (MAXWALLS=%d)!!!", MAXWALLS); if (numsectors>MAXSECTORS || numwalls>MAXWALLS) return bad; + seen_nextwalls = Bcalloc((numwalls+7)>>3,1); + if (!seen_nextwalls) return 5; + lastnextwallsource = Bmalloc(numwalls*sizeof(lastnextwallsource[0])); + if (!lastnextwallsource) { Bfree(seen_nextwalls); return 5; } + for (i=0; i endwall) - CORRUPTCHK_PRINT(4, CORRUPT_WALL|j, "WALL[%d].POINT2=%d out of range [%d, %d]", - j, wall[j].point2, w0, endwall); + { + if (wall[j].point2 < 0 || wall[j].point2 >= MAXWALLS) + CORRUPTCHK_PRINT(5, CORRUPT_WALL|j, CCHK_PANIC "WALL[%d].POINT2=%d INVALID!!!", + j, wall[j].point2); + else + CORRUPTCHK_PRINT(4, CORRUPT_WALL|j, "WALL[%d].POINT2=%d out of range [%d, %d]", + j, wall[j].point2, w0, endwall); + } nw = wall[j].nextwall; ns = wall[j].nextsector; @@ -10093,19 +10146,78 @@ int32_t CheckMapCorruption(int32_t printfromlev) CORRUPTCHK_PRINT(4, CORRUPT_WALL|j, "WALL[%d].NEXTSECTOR=%d out of range: numsectors=%d", j, ns, numsectors); - if (ns == i) - CORRUPTCHK_PRINT(4, CORRUPT_WALL|j, "WALL[%d].NEXTSECTOR is its own sector", j); - if (nw>=w0 && nw<=endwall) CORRUPTCHK_PRINT(4, CORRUPT_WALL|j, "WALL[%d].NEXTWALL is its own sector's wall", j); - if (!bad) + if (ns == i) { - if (ns>=0 || (ns^nw)<0) + CORRUPTCHK_PRINT(4, CORRUPT_WALL|j, "WALL[%d].NEXTSECTOR is its own sector", j); + if (!bad) { - if ((ns^nw)<0 || nw=sector[ns].wallptr+sector[ns].wallnum) - CORRUPTCHK_PRINT(4, CORRUPT_WALL|j, "WALL[%d].NEXTSECTOR=%d and .NEXTWALL=%d inconsistent", - j, ns, nw); + if (tryfixing) + do_nextsector_correction(nw, j); + else if (4>=printfromlev) + suggest_nextsector_correction(nw, j); + } + } + + if (nw>=0 && nw>3]&(1<<(nw&7))) + { + int16_t nwnw, lnws; + + lnws = lastnextwallsource[nw]; + CORRUPTCHK_PRINT(3, CORRUPT_WALL|j, "WALL[%d].NEXTWALL=%d already referenced from wall %d", + j, nw, lnws); + nwnw = wall[nw].nextwall; + if (nwnw==j || nwnw==lnws) + { + int32_t walltoclear = nwnw==j ? lnws : j; + if (tryfixing) + { + wall[walltoclear].nextsector = wall[walltoclear].nextwall = -1; + OSD_Printf(CCHK_CORRECTED "auto-correction: cleared wall %d's nextwall and nextsector tags to -1\n", + walltoclear); + } + else if (3 >= printfromlev) + OSD_Printf(" wall[%d].nextwall=%d, suggest clearing wall %d's nextwall and nextsector tags to -1\n", + nw, nwnw, walltoclear); + } + } + else + { + seen_nextwalls[nw>>3] |= 1<<(nw&7); + lastnextwallsource[nw] = j; + } + } + + if (bad<4) + { + if ((ns^nw)<0) + { + CORRUPTCHK_PRINT(4, CORRUPT_WALL|j, "WALL[%d].NEXTSECTOR=%d and .NEXTWALL=%d inconsistent:" + " missing one next pointer", j, ns, nw); + if (tryfixing) + do_nextsector_correction(nw, j); + else if (4>=printfromlev) + suggest_nextsector_correction(nw, j); + } + else if (ns>=0) + { + if (nw=sector[ns].wallptr+sector[ns].wallnum) + { + CORRUPTCHK_PRINT(4, CORRUPT_WALL|j, "WALL[%d].NEXTWALL=%d out of .NEXTSECTOR=%d's bounds", + j, nw, ns); + if (tryfixing) + do_nextsector_correction(nw, j); + else if (4 >= printfromlev) + { + OSD_Printf(" sector %d's walls: [%d .. %d]\n", ns, sector[ns].wallptr, + sector[ns].wallptr+sector[ns].wallnum-1); + suggest_nextsector_correction(nw, j); + } + } } } @@ -10138,6 +10250,9 @@ int32_t CheckMapCorruption(int32_t printfromlev) OSD_Printf("-- corruption level: %d\n", errlevel); } + Bfree(seen_nextwalls); + Bfree(lastnextwallsource); + return errlevel; } ////