* 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 <seconds>', '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
This commit is contained in:
helixhorned 2011-02-10 23:15:02 +00:00
parent f4b4234ce1
commit cf9e3fd3f6
5 changed files with 361 additions and 226 deletions

View file

@ -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);

View file

@ -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

View file

@ -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<highlightsectorcnt; i++)
{
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))
{
dax += wall[j].x;
day += wall[j].y;
@ -2385,9 +2372,7 @@ void overheadeditor(void)
day = 0;
for (i=0; i<highlightsectorcnt; i++)
{
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))
{
dax += wall[j].x;
day += wall[j].y;
@ -2410,9 +2395,7 @@ void overheadeditor(void)
for (i=0; i<highlightsectorcnt; i++)
{
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 (k == 0)
{
@ -2755,9 +2738,7 @@ void overheadeditor(void)
for (i=0; i<highlightsectorcnt; i++)
{
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);
@ -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<bytesperline*(ydim-STATUS2DSIZ2); i++, cp++)
if (*cp==greycol)
*cp = blackcol;
else if (*cp != blackcol)
*cp = greycol;
enddrawing();
showframe(1);
didmakered |= !ask_if_sure("Insert outer loop and make red walls?", 0);
clearkeys();
}
while (!didmakered && newnumwalls<0) // if
{
int32_t tmpnumwalls=0, refwall, n;
int16_t refsect, ignore;
int32_t tmpnumwalls=0, refwall;
uint8_t *visitedwall = Bcalloc((numwalls+7)>>3,1);
if (!visitedwall)
@ -2782,12 +2781,15 @@ void overheadeditor(void)
for (i=0; i<highlightsectorcnt; i++)
{
startwall = sector[highlightsector[i]].wallptr;
endwall = startwall+sector[highlightsector[i]].wallnum-1;
for (j=startwall; j<=endwall; j++)
if (wall[j].nextwall<0 && !(visitedwall[j>>3]&(1<<(j&7))))
for (WALLS_OF_SECTOR(highlightsector[i], j))
{
n=tmpnumwalls;
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;
@ -2810,7 +2812,7 @@ void overheadeditor(void)
{
if (k>=MAXWALLS)
{
message("Wall limits exceeded while trying to trace outer loop.");
message("Wall limits exceeded while tracing outer loop.");
goto outtathis;
}
@ -2833,9 +2835,10 @@ void overheadeditor(void)
}
}
while (j!=refwall && n>0);
if (j!=refwall)
{
message("internal error while trying to trace outer loop: j!=refwall");
message("internal error while tracing outer loop: didn't reach refwall");
goto outtathis;
}
@ -2859,7 +2862,9 @@ void overheadeditor(void)
if (!tmpwall)
{
message("out of memory!");
goto outtathis;
ExtUnInit();
uninitsystem();
exit(1);
}
for (m=0; m<numwalls; m++)
@ -2883,10 +2888,10 @@ void overheadeditor(void)
numwalls = newnumwalls;
newnumwalls = -1;
message("Attached new inner loop to sector %d", refsect);
for (m=begwalltomove; m<begwalltomove+n; m++)
checksectorpointer(m, refsect);
message("Attached new inner loop to sector %d", refsect);
}
}
}
@ -2894,6 +2899,7 @@ void overheadeditor(void)
outtathis:
newnumwalls = -1;
Bfree(visitedwall);
break; // --|
} // <---------/
@ -2923,10 +2929,8 @@ outtathis:
for (i=0; i<numsectors; i++)
{
startwall = sector[i].wallptr;
endwall = startwall + sector[i].wallnum;
bad = 0;
for (j=startwall; j<endwall; j++)
for (WALLS_OF_SECTOR(i, j))
{
if (wall[j].x < highlightx1) bad = 1;
if (wall[j].x > highlightx2) bad = 1;
@ -3118,9 +3122,7 @@ SKIP:
for (i=0; i<highlightsectorcnt; i++)
{
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))
{ wall[j].x += dax; wall[j].y += day; }
for (j=headspritesect[highlightsector[i]]; j>=0; j=nextspritesect[j])
@ -3218,7 +3220,7 @@ SKIP:
vec.z = sprite[daspr].z;
if (setsprite(daspr, &vec) == -1 && osec>=0)
Bmemcpy(&sprite[daspr], &ovec, sizeof(vec3_t));
/*
#if 0
daz = ((tilesizy[sprite[daspr].picnum]*sprite[daspr].yrepeat)<<2);
for (i=0; i<numsectors; i++)
@ -3232,7 +3234,7 @@ SKIP:
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<numsectors; i++)
{
startwall = sector[i].wallptr;
endwall = startwall + sector[i].wallnum;
for (j=startwall; j<endwall; j++)
checksectorpointer((int16_t)j,(int16_t)i);
for (WALLS_OF_SECTOR(i, j))
checksectorpointer(j, i);
}
printmessage16("ALL POINTERS CHECKED!");
asksave = 1;
@ -4858,7 +4852,7 @@ CANCEL:
}
else if (ch == 'a' || ch == 'A') //A
{
int32_t corrupt = CheckMapCorruption(4);
int32_t corrupt = CheckMapCorruption(4, 0);
bad = 0;
@ -4947,7 +4941,7 @@ CANCEL:
bad = 0;
if (CheckMapCorruption(4)>=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<highlightsectorcnt; i++)
{
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);
@ -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<numwalls; i++)
if (wall[i].nextwall >= startwall)

View file

@ -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

View file

@ -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)
{
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 = 0; // force checking now
corruptchecktimer = totalclock + 120*autocorruptcheck;
}
}
if (parm->numparms <= 1)
@ -8172,9 +8183,9 @@ static int32_t registerosdcommands(void)
OSD_RegisterFunction("pk_uedaccel", "pk_uedaccel <value>: 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 <seconds>: 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 {<seconds>|now|tryfix}: sets auto corruption check interval if <seconds> given, otherwise as indicated", osdcmd_vars_pk);
#ifdef POLYMOST
OSD_RegisterFunction("tint", "tint <pal> <r> <g> <b> <flags>: 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 <all|EVENT_...|(event number)>", osdcmd_endisableevent);
OSD_RegisterFunction("disableevent", "disableevent <all|EVENT_...|(event number)>", 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<MAXCORRUPTTHINGS) \
corruptthings[numcorruptthings++] = what; \
if (errlev >= 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<numwalls)
{
// maybe nextwall is right?
if (wall[nw].nextwall==j && wall[j].x==POINT2(nw).x && wall[j].y==POINT2(nw).y)
OSD_Printf(" suggest setting wall[%d].nextsector to %d\n", j, sectorofwall_noquick(nw));
}
}
static void do_nextsector_correction(int32_t nw, int32_t j)
{
if (nw>=0 && nw<numwalls)
if (wall[nw].nextwall==j && wall[j].x==POINT2(nw).x && wall[j].y==POINT2(nw).y)
{
int32_t newns = sectorofwall_noquick(nw);
wall[j].nextsector = newns;
OSD_Printf(CCHK_CORRECTED "auto-correction: set wall[%d].nextsector=%d\n", j, newns);
}
}
int32_t CheckMapCorruption(int32_t printfromlev, int32_t tryfixing)
{
int32_t i, j, w0, numw, endwall, ns, nw;
int32_t ewall=0; // expected wall index
int32_t errlevel=0, bad=0;
uint8_t *seen_nextwalls;
int16_t *lastnextwallsource;
numcorruptthings = 0;
if (numsectors>MAXSECTORS)
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<numsectors; i++)
{
bad = 0;
@ -10058,7 +10105,7 @@ int32_t CheckMapCorruption(int32_t printfromlev)
CORRUPTCHK_PRINT(4, CORRUPT_SECTOR|i, "SECTOR[%d].WALLPTR=%d inconsistent, expected %d", i, w0, ewall);
if (numw <= 1)
CORRUPTCHK_PRINT(5, CORRUPT_SECTOR|i, "PANIC!!! SECTOR[%d].WALLNUM=%d INVALID!!!", i, numw);
CORRUPTCHK_PRINT(5, CORRUPT_SECTOR|i, CCHK_PANIC "SECTOR[%d].WALLNUM=%d INVALID!!!", i, numw);
else if (numw==2)
CORRUPTCHK_PRINT(3, CORRUPT_SECTOR|i, "SECTOR[%d].WALLNUM=2, expected at least 3", i);
@ -10079,8 +10126,14 @@ int32_t CheckMapCorruption(int32_t printfromlev)
bad = 0;
if (wall[j].point2 < w0 || wall[j].point2 > 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 (ns == i)
{
CORRUPTCHK_PRINT(4, CORRUPT_WALL|j, "WALL[%d].NEXTSECTOR is its own sector", j);
if (!bad)
{
if (ns>=0 || (ns^nw)<0)
if (tryfixing)
do_nextsector_correction(nw, j);
else if (4>=printfromlev)
suggest_nextsector_correction(nw, j);
}
}
if (nw>=0 && nw<numwalls)
{
if ((ns^nw)<0 || nw<sector[ns].wallptr || 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 (seen_nextwalls[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 || 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;
}
////