diff --git a/polymer/eduke32/Makefile b/polymer/eduke32/Makefile index cfb878f60..1bed4d3a3 100644 --- a/polymer/eduke32/Makefile +++ b/polymer/eduke32/Makefile @@ -217,7 +217,7 @@ EDUKE32_TARGET:=$(EDUKE32) MAPSTER32_TARGET:=$(MAPSTER32) COMMON_OBJS=rev -COMMON_EDITOR_OBJS=m32def m32exec m32vars mathutil rev +COMMON_EDITOR_OBJS=m32common m32def m32exec m32vars mathutil rev DUKE3D_OBJS=game actors anim common config demo gamedef gameexec gamevars global input menus namesdyn net player premap savegame sector rts osdfuncs osdcmds grpscan sounds soundsdyn $(MACT_OBJ) DUKE3D_EDITOR_OBJS=astub common grpscan sounds_mapster32 diff --git a/polymer/eduke32/Makefile.msvc b/polymer/eduke32/Makefile.msvc index 52b5ad43b..d450ee1ab 100644 --- a/polymer/eduke32/Makefile.msvc +++ b/polymer/eduke32/Makefile.msvc @@ -224,6 +224,7 @@ DUKE3D_OBJS=$(DUKE3D_OBJ)\game.$o \ DUKE3D_EDITOR_OBJS=$(DUKE3D_OBJ)\astub.$o \ $(DUKE3D_OBJ)\common.$o \ $(DUKE3D_OBJ)\mathutil.$o \ + $(DUKE3D_OBJ)\m32common.$o \ $(DUKE3D_OBJ)\m32def.$o \ $(DUKE3D_OBJ)\m32vars.$o \ $(DUKE3D_OBJ)\m32exec.$o \ diff --git a/polymer/eduke32/build/include/editor.h b/polymer/eduke32/build/include/editor.h index b4e647764..90542f575 100644 --- a/polymer/eduke32/build/include/editor.h +++ b/polymer/eduke32/build/include/editor.h @@ -117,6 +117,8 @@ extern uint8_t graysectbitmap[MAXSECTORS>>3]; extern uint8_t graywallbitmap[MAXWALLS>>3]; extern int32_t autogray, showinnergray; +extern void drawgradient(void); + #ifdef YAX_ENABLE int32_t yax_is121(int16_t bunchnum, int16_t getfloor); #endif @@ -133,6 +135,28 @@ extern int32_t kopen4loadfrommod(const char *filename, char searchfirst); extern int32_t map_revision; extern int32_t map_undoredo(int32_t dir); extern void map_undoredo_free(void); +extern void create_map_snapshot(void); + +typedef struct mapundo_ +{ + int32_t revision; + int32_t num[3]; // numsectors, numwalls, numsprites + + // These exist temporarily as sector/wall/sprite data, but are compressed + // most of the time. +4 bytes refcount at the beginning. + char *sws[3]; // sector, wall, sprite + + uint32_t crc[3]; + + struct mapundo_ *next; // 'redo' loads this + struct mapundo_ *prev; // 'undo' loads this +} mapundo_t; +extern mapundo_t *mapstate; + +extern void FuncMenu(void); +#ifdef LUNATIC +extern void LuaFuncMenu(void); +#endif // editor side view extern int32_t m32_sideview; @@ -200,6 +224,7 @@ extern const char *GetSaveBoardFilename(const char *fn); extern int32_t corruptlevel, numcorruptthings, corruptthings[MAXCORRUPTTHINGS]; extern int32_t autocorruptcheck; extern int32_t corruptcheck_noalreadyrefd; +extern int32_t corrupt_tryfix_alt; extern int32_t CheckMapCorruption(int32_t printfromlev, uint64_t tryfixing); extern int32_t fixmaponsave_sprites; @@ -225,14 +250,32 @@ void fade_editor_screen(int32_t keepcol); extern int32_t getnumber_internal1(char ch, int32_t *danumptr, int32_t maxnumber, char sign); extern int32_t getnumber_autocomplete(const char *namestart, char ch, int32_t *danum, int32_t flags); +// always CRLF for us +#ifdef _WIN32 +# define OURNEWL "\n" +#else +# define OURNEWL "\r\n" +#endif + +#ifdef YAX_ENABLE +extern const char *yupdownwall[2]; +extern const char *YUPDOWNWALL[2]; +#endif + int32_t _getnumber256(const char *namestart, int32_t num, int32_t maxnumber, char sign, const char *(func)(int32_t)); #define getnumber256(namestart, num, maxnumber, sign) _getnumber256(namestart, num, maxnumber, sign, NULL) int32_t _getnumber16(const char *namestart, int32_t num, int32_t maxnumber, char sign, const char *(func)(int32_t)); #define getnumber16(namestart, num, maxnumber, sign) _getnumber16(namestart, num, maxnumber, sign, NULL) void printmessage256(int32_t x, int32_t y, const char *name); void message(const char *fmt, ...) ATTRIBUTE((format(printf,1,2))); +void silentmessage(const char *fmt, ...) ATTRIBUTE((format(printf,1,2))); extern int32_t AskIfSure(const char *text); +extern char getmessage[162], getmessageleng; +extern int32_t getmessagetimeoff; + +extern int32_t mouseaction; + const char* getstring_simple(const char *querystr, const char *defaultstr, int32_t maxlen, int32_t completion); // like snprintf, but pads the output buffer with 'fill' at the end @@ -271,6 +314,7 @@ extern uint8_t hlsectorbitmap[MAXSECTORS>>3]; void test_map(int32_t mode); +extern void M32RunScript(const char *s); ////////// tag labeling system ////////// // max (strlen+1), i.e. array length to allocate for a tag label: diff --git a/polymer/eduke32/source/astub.c b/polymer/eduke32/source/astub.c index 9c624ccc9..0e6604472 100644 --- a/polymer/eduke32/source/astub.c +++ b/polymer/eduke32/source/astub.c @@ -98,7 +98,6 @@ static int32_t g_fillCurSector = 0; const char* defaultsetupfilename = SETUPFILENAME; char setupfilename[BMAX_PATH] = SETUPFILENAME; -int32_t fixmaponsave_sprites = 1; static int32_t fixmaponsave_walls = 0; static int32_t lastsave = -180*60; static int32_t NoAutoLoad = 0; @@ -120,18 +119,8 @@ static int16_t g_sndnum[MAXSOUNDS]; // maps current order index to g_sounds ind int32_t g_numsounds = 0; static int32_t lastupdate, mousecol, mouseadd = 1, bstatus; -char *scripthist[SCRIPTHISTSIZ]; -int32_t scripthistend = 0; - -int32_t g_lazy_tileselector = 0; -int32_t showambiencesounds=2; - -int32_t autocorruptcheck = 0; static int32_t corruptchecktimer; -static int32_t curcorruptthing=-1, corrupt_tryfix_alt=0; -int32_t corruptcheck_noalreadyrefd=0; - -int32_t corruptlevel=0, numcorruptthings=0, corruptthings[MAXCORRUPTTHINGS]; +static int32_t curcorruptthing=-1; static uint32_t templenrepquot=1; @@ -193,14 +182,7 @@ static const char *Typestr_wss[] = { "Wall", "Sector", "Sector", "Sprite", "Wall static const char *ONOFF_[] = {"OFF","ON"}; #define ONOFF(b) (ONOFF_[!!(b)]) -// always CRLF for us -#ifdef _WIN32 -# define OURNEWL "\n" -#else -# define OURNEWL "\r\n" -#endif - -static int32_t tsign, mouseaction=0, mouseax=0, mouseay=0; +static int32_t tsign, mouseax=0, mouseay=0; static int32_t repeatcountx, repeatcounty; static int32_t infobox=3; // bit0: current window, bit1: mouse pointer, the variable should be renamed @@ -213,13 +195,9 @@ static char spritepals[MAXSPRITES]; static uint8_t wallflag[MAXWALLS>>3]; #ifdef YAX_ENABLE -static const char *yupdownwall[2] = {"upwall","downwall"}; -static const char *YUPDOWNWALL[2] = {"UPWALL","DOWNWALL"}; - static uint8_t havebunch[YAX_MAXBUNCHES]; static int32_t *tempzar[YAX_MAXBUNCHES]; -static void silentmessage(const char *fmt, ...); static int32_t yax_invalidop() { silentmessage("Operation forbidden on extended sector."); @@ -327,304 +305,8 @@ extern int32_t mskip; //extern int32_t fillsector(int16_t sectnum, char fillcolor); -static void drawgradient(void) -{ - int32_t i, col = whitecol-21; - begindrawing(); - for (i=ydim-STATUS2DSIZ+16; i0; i++,col--) - CLEARLINES2D(i, 1, (col<<24)|(col<<16)|(col<<8)|col); - CLEARLINES2D(i, ydim-i, 0); - enddrawing(); -} - -static void message_common1(const char *tmpstr) -{ - Bstrncpyz(getmessage, tmpstr, sizeof(getmessage)); - - getmessageleng = Bstrlen(getmessage); - getmessagetimeoff = totalclock + 120*2 + getmessageleng*(120/30); -// lastmessagetime = totalclock; -} - -void message(const char *fmt, ...) -{ - char tmpstr[256]; - va_list va; - - va_start(va, fmt); - Bvsnprintf(tmpstr, 256, fmt, va); - va_end(va); - - message_common1(tmpstr); - - if (!mouseaction) - OSD_Printf("%s\n", tmpstr); -} - -static void silentmessage(const char *fmt, ...) -{ - char tmpstr[256]; - va_list va; - - va_start(va, fmt); - Bvsnprintf(tmpstr, 256, fmt, va); - va_end(va); - - message_common1(tmpstr); -} - - static int32_t osdcmd_quit(const osdfuncparm_t *parm); -////////// UNDO/REDO SYSTEM ////////// -#if M32_UNDO -typedef struct mapundo_ -{ - int32_t revision; - int32_t num[3]; // numsectors, numwalls, numsprites - - // These exist temporarily as sector/wall/sprite data, but are compressed - // most of the time. +4 bytes refcount at the beginning. - char *sws[3]; // sector, wall, sprite - - uint32_t crc[3]; - - struct mapundo_ *next; // 'redo' loads this - struct mapundo_ *prev; // 'undo' loads this -} mapundo_t; - -mapundo_t *mapstate = NULL; - -int32_t map_revision = 1; - -#define QADDNSZ 400 - - -static int32_t try_match_with_prev(int32_t idx, int32_t numsthgs, uint32_t crc) -{ - if (mapstate->prev && mapstate->prev->num[idx]==numsthgs && mapstate->prev->crc[idx]==crc) - { - // found match! - mapstate->sws[idx] = mapstate->prev->sws[idx]; - (*(int32_t *)mapstate->sws[idx])++; // increase refcount! - - return 1; - } - - return 0; -} - -static void create_compressed_block(int32_t idx, const void *srcdata, uint32_t size, uint32_t crc) -{ - uint32_t j; - - // allocate - mapstate->sws[idx] = (char *)Xmalloc(4 + size + QADDNSZ); - - // compress & realloc - j = LZ4_compress((const char*)srcdata, mapstate->sws[idx]+4, size); - mapstate->sws[idx] = (char *)Xrealloc(mapstate->sws[idx], 4 + j); - - // write refcount - *(int32_t *)mapstate->sws[idx] = 1; - - mapstate->crc[idx] = crc; -} - -static void free_self_and_successors(mapundo_t *mapst) -{ - mapundo_t *cur = mapst; - - mapst->prev = NULL; // break the back link - - while (cur->next) - cur = cur->next; - - while (1) - { - int32_t i; - mapundo_t *const prev = cur->prev; - - for (i=0; i<3; i++) - { - int32_t *const refcnt = (int32_t *)cur->sws[i]; - - if (refcnt) - { - (*refcnt)--; - if (*refcnt == 0) - Bfree(refcnt); // free the block! - } - } - - Bfree(cur); - - if (!prev) - break; - - cur = prev; - } -} - -// NOTE: only _consecutive_ matching (size+crc) sector/wall/sprite blocks are -// shared! -void create_map_snapshot(void) -{ - if (mapstate == NULL) - { - // create initial mapstate - - map_revision = 1; - - mapstate = (mapundo_t *)Xcalloc(1, sizeof(mapundo_t)); - mapstate->revision = map_revision; - mapstate->prev = mapstate->next = NULL; - } - else - { - if (mapstate->next) - free_self_and_successors(mapstate->next); - // now, have no successors - - // calloc because not everything may be set in the following: - mapstate->next = (mapundo_t *)Xcalloc(1, sizeof(mapundo_t)); - mapstate->next->prev = mapstate; - - mapstate = mapstate->next; - - mapstate->revision = ++map_revision; - } - - - fixspritesectors(); - - mapstate->num[0] = numsectors; - mapstate->num[1] = numwalls; - mapstate->num[2] = Numsprites; - - - if (numsectors) - { - int32_t j; - uint32_t temphash = XXH32((uint8_t *)sector, numsectors*sizeof(sectortype), numsectors*sizeof(sectortype)); - - if (!try_match_with_prev(0, numsectors, temphash)) - create_compressed_block(0, sector, numsectors*sizeof(sectortype), temphash); - - if (numwalls) - { - temphash = XXH32((uint8_t *)wall, numwalls*sizeof(walltype), numwalls*sizeof(walltype)); - - if (!try_match_with_prev(1, numwalls, temphash)) - create_compressed_block(1, wall, numwalls*sizeof(walltype), temphash); - } - - if (Numsprites) - { - temphash = XXH32((uint8_t *)sprite, MAXSPRITES*sizeof(spritetype), MAXSPRITES*sizeof(spritetype)); - - if (!try_match_with_prev(2, Numsprites, temphash)) - { - int32_t i = 0; - spritetype *const tspri = (spritetype *)Xmalloc(Numsprites*sizeof(spritetype) + 4); - spritetype *spri = tspri; - - for (j=0; jnext == NULL || !mapstate->next->num[0]) return 1; - - // while (map_revision+1 != mapstate->revision && mapstate->next) - mapstate = mapstate->next; - } - else - { - if (mapstate->prev == NULL || !mapstate->prev->num[0]) return 1; - - // while (map_revision-1 != mapstate->revision && mapstate->prev) - mapstate = mapstate->prev; - } - - numsectors = mapstate->num[0]; - numwalls = mapstate->num[1]; - map_revision = mapstate->revision; - - Bmemset(show2dsector, 0, sizeof(show2dsector)); - - reset_highlightsector(); - reset_highlight(); - - initspritelists(); - - if (mapstate->num[0]) - { - // restore sector[] - LZ4_decompress_fast(mapstate->sws[0]+4, (char*)sector, numsectors*sizeof(sectortype)); - - if (mapstate->num[1]) // restore wall[] - LZ4_decompress_fast(mapstate->sws[1]+4, (char*)wall, numwalls*sizeof(walltype)); - - if (mapstate->num[2]) // restore sprite[] - LZ4_decompress_fast(mapstate->sws[2]+4, (char*)sprite, (mapstate->num[2])*sizeof(spritetype)); - } - - // insert sprites - for (i=0; inum[2]; i++) - { - if ((sprite[i].cstat & 48) == 48) sprite[i].cstat &= ~48; - Bassert((unsigned)sprite[i].sectnum < (unsigned)numsectors - && (unsigned)sprite[i].statnum < MAXSTATUS); - insertsprite(sprite[i].sectnum, sprite[i].statnum); - } - - Bassert(Numsprites == mapstate->num[2]); - -#ifdef POLYMER - if (in3dmode() && getrendermode() == REND_POLYMER) - polymer_loadboard(); -#endif -#ifdef YAX_ENABLE - yax_update(0); - yax_updategrays(pos.z); -#endif - CheckMapCorruption(4, 0); - - return 0; -} -#endif - #define M32_NUM_SPRITE_MODES (signed)ARRAY_SIZE(SpriteMode) static const char *SpriteMode[]= @@ -730,236 +412,6 @@ void ExtSaveMap(const char *mapname) ////////// tag labeling system ////////// -typedef struct -{ - hashtable_t hashtab; - char *label[32768]; - int32_t numlabels; -} taglab_t; - -static taglab_t g_taglab; - -static void tstrtoupper(char *s) -{ - int32_t i; - for (i=0; s[i]; i++) - s[i] = Btoupper(s[i]); -} - -void taglab_init() -{ - int32_t i; - - g_taglab.numlabels = 0; - g_taglab.hashtab.size = 16384; - hash_init(&g_taglab.hashtab); - - for (i=0; i<32768; i++) - { - if (g_taglab.label[i]) - Bfree(g_taglab.label[i]); - g_taglab.label[i] = NULL; - } -} - -int32_t taglab_load(const char *filename, int32_t flags) -{ - int32_t fil, len, i; - char buf[BMAX_PATH], *dot, *filebuf; - - taglab_init(); - - len = Bstrlen(filename); - if (len >= BMAX_PATH-1) - return -1; - Bmemcpy(buf, filename, len+1); - - // - dot = Bstrrchr(buf, '.'); - if (!dot) - dot = &buf[len]; - - if (dot-buf+8 >= BMAX_PATH) - return -1; - Bmemcpy(dot, ".maptags", 9); - // - - if ((fil = kopen4load(buf,flags)) == -1) - return -1; - - len = kfilelength(fil); - - filebuf = (char *)Xmalloc(len+1); - if (!filebuf) - { - kclose(fil); - return -1; - } - - kread(fil, filebuf, len); - filebuf[len] = 0; - kclose(fil); - - // ---- - - { - int32_t tag; - char *cp=filebuf, *bp, *ep; - - while (1) - { -#define XTAGLAB_STRINGIFY(X) TAGLAB_STRINGIFY(X) -#define TAGLAB_STRINGIFY(X) #X - i = sscanf(cp, "%d %" XTAGLAB_STRINGIFY(TAGLAB_MAX) "s", &tag, buf); -#undef XTAGLAB_STRINGIFY -#undef TAGLAB_STRINGIFY - if (i != 2 || !buf[0] || tag<0 || tag>=32768) - goto nextline; - - buf[TAGLAB_MAX-1] = 0; - - i = Bstrlen(buf); - bp = buf; while (*bp && isspace(*bp)) bp++; - ep = &buf[i-1]; while (ep>buf && isspace(*ep)) ep--; - ep++; - - if (!(ep > bp)) - goto nextline; - *ep = 0; - - taglab_add(bp, tag); -//initprintf("add tag %s:%d\n", bp, tag); -nextline: - while (*cp && *cp!='\n') - cp++; - while (*cp=='\r' || *cp=='\n') - cp++; - if (*cp == 0) - break; - } - } - - // ---- - Bfree(filebuf); - - return 0; -} - -int32_t taglab_save(const char *mapname) -{ - int32_t fil, len, i; - char buf[BMAX_PATH], *dot; - const char *label; - - if (g_taglab.numlabels==0) - return 1; - - Bstrncpyz(buf, mapname, BMAX_PATH); - - len = Bstrlen(buf); - // - dot = Bstrrchr(buf, '.'); - if (!dot) - dot = &buf[len]; - - if (dot-buf+8 >= BMAX_PATH) - return -1; - Bmemcpy(dot, ".maptags", 9); - // - - if ((fil = Bopen(buf,BO_BINARY|BO_TRUNC|BO_CREAT|BO_WRONLY,BS_IREAD|BS_IWRITE)) == -1) - { - initprintf("Couldn't open \"%s\" for writing: %s\n", buf, strerror(errno)); - return -1; - } - - for (i=0; i<32768; i++) - { - label = taglab_getlabel(i); - if (!label) - continue; - - len = Bsprintf(buf, "%d %s" OURNEWL, i, label); - if (Bwrite(fil, buf, len)!=len) - break; - } - - Bclose(fil); - - return (i!=32768); -} - -int32_t taglab_add(const char *label, int16_t tag) -{ - const char *otaglabel; - char buf[TAGLAB_MAX]; - int32_t olabeltag, diddel=0; - - if (tag < 0) - return -1; - - Bstrncpyz(buf, label, sizeof(buf)); - // upcase the tag for storage and comparison - tstrtoupper(buf); - - otaglabel = g_taglab.label[tag]; - if (otaglabel) - { - if (!Bstrcasecmp(otaglabel, buf)) - return 0; - -// hash_delete(&g_taglab.hashtab, g_taglab.label[tag]); - - // a label having the same tag number as 'tag' is deleted - Bfree(g_taglab.label[tag]); - g_taglab.label[tag] = NULL; - diddel |= 1; - } - else - { - olabeltag = hash_findcase(&g_taglab.hashtab, buf); - if (olabeltag==tag) - return 0; - - if (olabeltag>=0) - { - // the label gets assigned to a new tag number ('tag deleted') - Bfree(g_taglab.label[olabeltag]); - g_taglab.label[olabeltag] = NULL; - diddel |= 2; - } - } - - if (!diddel) - g_taglab.numlabels++; - g_taglab.label[tag] = Xstrdup(buf); -//initprintf("added %s %d to hash\n", g_taglab.label[tag], tag); - hash_add(&g_taglab.hashtab, g_taglab.label[tag], tag, 1); - - return diddel; -} - -const char *taglab_getlabel(int16_t tag) -{ - if (tag < 0) // || tag>=32768 implicitly - return NULL; - - return g_taglab.label[tag]; -} - -int32_t taglab_gettag(const char *label) -{ - char buf[TAGLAB_MAX]; - - Bstrncpyz(buf, label, TAGLAB_MAX); - - // need to upcase since hash_findcase doesn't work as expected: - // getting the code is still (necessarily) case-sensitive... - tstrtoupper(buf); - - return hash_findcase(&g_taglab.hashtab, buf); -} - #define TLCHAR "+" #define TLCHR(Cond) ((Cond)?TLCHAR:"") static uint64_t taglab_nolink_SEs = (1ull<<10)|(1ull<<27)|(1ull<<28)|(1ull<<29)| @@ -8168,7 +7620,7 @@ static void Keys2d(void) if (tmpspritenum==refspritenum) { - silentmessage("No other sprites with tag %d"); + silentmessage("No other sprites with tag %d", reftag); break; } @@ -11238,750 +10690,6 @@ 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 " -> " - -#ifdef _MSC_VER -#define CORRUPTCHK_PRINT(errlev, what, fmt, ...) do \ -{ \ - bad = max(bad, errlev); \ - if (numcorruptthings>=MAXCORRUPTTHINGS) \ - goto too_many_errors; \ - corruptthings[numcorruptthings++] = (what); \ - if (errlev >= printfromlev) \ - OSD_Printf("#%d: " fmt "\n", numcorruptthings, ## __VA_ARGS__); \ -} while (0) -#else -#define CORRUPTCHK_PRINT(errlev, what, fmt, ...) do \ -{ \ - bad = max(bad, errlev); \ - if (numcorruptthings>=MAXCORRUPTTHINGS) \ - goto too_many_errors; \ - corruptthings[numcorruptthings++] = (what); \ - if (errlev >= printfromlev) \ - OSD_Printf_nowarn("#%d: " fmt "\n", numcorruptthings, ## __VA_ARGS__); \ -} while (0) -#endif -#ifdef YAX_ENABLE -static int32_t walls_have_equal_endpoints(int32_t w1, int32_t w2) -{ - int32_t n1 = wall[w1].point2, n2 = wall[w2].point2; - - return (wall[w1].x==wall[w2].x && wall[w1].y==wall[w2].y && - wall[n1].x==wall[n2].x && wall[n1].y==wall[n2].y); -} - -static void correct_yax_nextwall(int32_t wallnum, int32_t bunchnum, int32_t cf, int32_t tryfixingp) -{ - int32_t i, j, startwall, endwall; - int32_t nummatching=0, lastwall[2]={-1,-1}; - - for (SECTORS_OF_BUNCH(bunchnum, !cf, i)) - for (WALLS_OF_SECTOR(i, j)) - { - // v v v shouldn't happen, 'stupidity safety' - if (j!=wallnum && walls_have_equal_endpoints(wallnum, j)) - { - lastwall[nummatching++] = j; - if (nummatching==2) - goto outofloop; - } - } -outofloop: - if (nummatching==1) - { - if (!tryfixingp) - { - OSD_Printf(" will set wall %d's %s to %d on tryfix\n", - wallnum, yupdownwall[cf], lastwall[0]); - } - else - { - int32_t setreverse = 0; - yax_setnextwall(wallnum, cf, lastwall[0]); - if (yax_getnextwall(lastwall[0], !cf) < 0) - { - setreverse = 1; - yax_setnextwall(lastwall[0], !cf, wallnum); - } - - OSD_Printf("auto-correction: set wall %d's %s to %d%s\n", - wallnum, yupdownwall[cf], lastwall[0], setreverse?" and its reverse link":""); - } - } - else if (!tryfixingp) - { - if (nummatching > 1) - { - OSD_Printf(" found more than one matching wall: at least %d and %d\n", - lastwall[0], lastwall[1]); - } - else if (nummatching == 0) - { - OSD_Printf(" found no matching walls!\n"); - } - } -} -#endif - -// in reverse orientation -static int32_t walls_are_consistent(int32_t w1, int32_t w2) -{ - return (wall[w2].x==POINT2(w1).x && wall[w2].y==POINT2(w1).y && - wall[w1].x==POINT2(w2).x && wall[w1].y==POINT2(w2).y); -} - -static void suggest_nextsector_correction(int32_t nw, int32_t j) -{ - // wall j's nextsector is inconsistent with its nextwall... what shall we do? - - if (nw>=0 && nw=0 && wall[j].nextsector=0 && nw=0 && wall[j].nextsector>3]; - - csc_s = csc_i = -1; - - if (Numsprites < 0 || Numsprites > MAXSPRITES) - return 1; - - for (i=0; i MAXSTATUS || (sectnum!=MAXSECTORS && (unsigned)sectnum > (unsigned)numsectors)) - return 3; // oob sectnum or statnum - - if (statnum != MAXSTATUS) - ournumsprites++; - } - - if (ournumsprites != Numsprites) - { - initprintf("ournumsprites=%d, Numsprites=%d\n", ournumsprites, Numsprites); - return 4; // counting sprites by statnum!=MAXSTATUS inconsistent with Numsprites - } - - // SECTOR LIST - - Bmemset(havesprite, 0, (Numsprites+7)>>3); - - for (s=0; s=0; i=nextspritesect[i]) - { - csc_i = i; - - if (i >= MAXSPRITES) - return 5; // oob sprite index in list, or Numsprites inconsistent - - if (havesprite[i>>3]&(1<<(i&7))) - return 6; // have a cycle in the list - - havesprite[i>>3] |= (1<<(i&7)); - - if (sprite[i].sectnum != s) - return 7; // .sectnum inconsistent with list - } - - if (i!=-1) - return 8; // various code checks for -1 to break loop - } - - csc_s = -1; - for (i=0; i>3]&(1<<(i&7)))) - return 9; // have a sprite in the world not in sector list - } - - - // STATUS LIST -- we now clear havesprite[] bits - - for (s=0; s=0; i=nextspritestat[i]) - { - csc_i = i; - - if (i >= MAXSPRITES) - return 10; // oob sprite index in list, or Numsprites inconsistent - - // have a cycle in the list, or status list inconsistent with - // sector list (*) - if (!(havesprite[i>>3]&(1<<(i&7)))) - return 11; - - havesprite[i>>3] &= ~(1<<(i&7)); - - if (sprite[i].statnum != s) - return 12; // .statnum inconsistent with list - } - - if (i!=-1) - return 13; // various code checks for -1 to break loop - } - - csc_s = -1; - for (i=0; i>3]&(1<<(i&7))) - return 14; - } - - return 0; -} - -#define TRYFIX_NONE() (tryfixing == 0ull) -#define TRYFIX_CNUM(onumct) (onumct < MAXCORRUPTTHINGS && (tryfixing & (1ull<MAXSECTORS) - CORRUPTCHK_PRINT(5, 0, CCHK_PANIC "SECTOR LIMIT EXCEEDED (MAXSECTORS=%d)!!!", MAXSECTORS); - - if (numwalls>MAXWALLS) - CORRUPTCHK_PRINT(5, 0, CCHK_PANIC "WALL LIMIT EXCEEDED (MAXWALLS=%d)!!!", MAXWALLS); - - if (numsectors>MAXSECTORS || numwalls>MAXWALLS) - { - corruptlevel = bad; - return bad; - } - - if (numsectors==0 || numwalls==0) - { - if (numsectors>0) - CORRUPTCHK_PRINT(5, 0, CCHK_PANIC " Have sectors but no walls!"); - if (numwalls>0) - CORRUPTCHK_PRINT(5, 0, CCHK_PANIC " Have walls but no sectors!"); - return bad; - } - - if (!corruptcheck_noalreadyrefd) - { - seen_nextwalls = (uint8_t *)Xcalloc((numwalls+7)>>3,1); - lastnextwallsource = (int16_t *)Xmalloc(numwalls*sizeof(lastnextwallsource[0])); - } - - for (i=0; i numwalls) - { - if (w0 < 0 || w0 >= MAXWALLS) - CORRUPTCHK_PRINT(5, CORRUPT_SECTOR|i, "SECTOR[%d].WALLPTR=%d INVALID!!!", i, w0); - else - CORRUPTCHK_PRINT(5, CORRUPT_SECTOR|i, "SECTOR[%d].WALLPTR=%d out of range (numwalls=%d)", i, w0, numw); - } - - if (w0 != ewall) - 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, 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); - - ewall += numw; - - endwall = w0 + numw; - if (endwall > numwalls) - CORRUPTCHK_PRINT(5, CORRUPT_SECTOR|i, "SECTOR[%d]: wallptr+wallnum=%d out of range: numwalls=%d", i, endwall, numwalls); - - // inconsistent cstat&2 and heinum checker - { - const char *cflabel[2] = {"ceiling", "floor"}; - - for (j=0; j<2; j++) - { - const int32_t cs = !!(SECTORFLD(i,stat, j)&2); - const int32_t hn = !!SECTORFLD(i,heinum, j); - - if (cs != hn && heinumcheckstat <= 1) - { - if (numcorruptthings < MAXCORRUPTTHINGS && - (heinumcheckstat==1 || (heinumcheckstat==0 && (tryfixing & (1ull< endwall) - { - if (wall[j].point2 < 0 || wall[j].point2 >= MAXWALLS) - CORRUPTCHK_PRINT(5, CORRUPT_WALL|j, CCHK_PANIC "WALL[%d].POINT2=%d INVALID!!!", - j, TrackerCast(wall[j].point2)); - else - CORRUPTCHK_PRINT(4, CORRUPT_WALL|j, "WALL[%d].POINT2=%d out of range [%d, %d]", - j, TrackerCast(wall[j].point2), w0, endwall); - } - - nw = wall[j].nextwall; - - if (nw >= numwalls) - { - int32_t onumct = numcorruptthings; - - if (TRYFIX_NONE()) - { - if (nw >= MAXWALLS) - CORRUPTCHK_PRINT(5, CORRUPT_WALL|j, "WALL[%d].NEXTWALL=%d INVALID!!!", - j, nw); - else - CORRUPTCHK_PRINT(4, CORRUPT_WALL|j, "WALL[%d].NEXTWALL=%d out of range: numwalls=%d", - j, nw, numwalls); - OSD_Printf(" will make wall %d white on tryfix\n", j); - } - else if (TRYFIX_CNUM(onumct)) // CODEDUP MAKE_WALL_WHITE - { - wall[j].nextwall = wall[j].nextsector = -1; - OSD_Printf(CCHK_CORRECTED "auto-correction: made wall %d white\n", j); - } - } - - ns = wall[j].nextsector; - - if (ns >= numsectors) - { - int32_t onumct = numcorruptthings; - - if (TRYFIX_NONE()) - { - if (ns >= MAXSECTORS) - CORRUPTCHK_PRINT(5, CORRUPT_WALL|j, "WALL[%d].NEXTSECTOR=%d INVALID!!!", - j, ns); - else - CORRUPTCHK_PRINT(4, CORRUPT_WALL|j, "WALL[%d].NEXTSECTOR=%d out of range: numsectors=%d", - j, ns, numsectors); - OSD_Printf(" will make wall %d white on tryfix\n", j); - } - else if (TRYFIX_CNUM(onumct)) // CODEDUP MAKE_WALL_WHITE - { - wall[j].nextwall = wall[j].nextsector = -1; - OSD_Printf(CCHK_CORRECTED "auto-correction: made wall %d white\n", j); - } - } - - if (nw>=w0 && nw<=endwall) - CORRUPTCHK_PRINT(4, CORRUPT_WALL|j, "WALL[%d].NEXTWALL is its own sector's wall", j); - - if (wall[j].x==POINT2(j).x && wall[j].y==POINT2(j).y) - CORRUPTCHK_PRINT(3, CORRUPT_WALL|j, "WALL[%d] has length 0", j); - -#ifdef YAX_ENABLE - { - int32_t cf, ynw, ynwp2; - - for (cf=0; cf<2; cf++) - { - ynw = yax_getnextwall(j, cf); - if (ynw >= 0) - { - if (ynw >= numwalls) - CORRUPTCHK_PRINT(4, CORRUPT_WALL|j, "WALL %d's %s=%d out of range: numwalls=%d", - j, YUPDOWNWALL[cf], ynw, numwalls); - else - { - int32_t ynextwallok = 1; - - if (j == ynw) - { - CORRUPTCHK_PRINT(4, CORRUPT_WALL|j, "WALL %d's %s is itself", - j, YUPDOWNWALL[cf]); - ynextwallok = 0; - } - else if (!walls_have_equal_endpoints(j, ynw)) - { - CORRUPTCHK_PRINT(4, CORRUPT_WALL|j, "WALL %d's and its %s=%d's " - "endpoints are inconsistent", j, YUPDOWNWALL[cf], ynw); - ynextwallok = 0; - } - - { - int16_t bunchnum = yax_getbunch(i, cf); - int32_t onumct = numcorruptthings; - - if (bunchnum < 0 || bunchnum >= numyaxbunches) - { - if (tryfixing == 0ull) - { - CORRUPTCHK_PRINT(4, CORRUPT_WALL|j, "WALL %d has %s=%d, " - "but its %s bunchnum=%d is invalid", - j, YUPDOWNWALL[cf], ynw, - cf==YAX_CEILING? "ceiling":"floor", bunchnum); - OSD_Printf(" will clear wall %d's %s to -1 on tryfix\n", - j, yupdownwall[cf]); - - } - else if (tryfixing & (1ull<=printfromlev) - correct_yax_nextwall(j, bunchnum, cf, tryfixing!=0ull); - } - } - - if (ynextwallok) - { - int32_t onumct = numcorruptthings; - - ynwp2 = yax_getnextwall(ynw, !cf); - if (ynwp2 != j) - { - CORRUPTCHK_PRINT(4, CORRUPT_WALL|j, "WALL %d's %s=%d's reverse link wrong" - " (expected %d, have %d)", j, YUPDOWNWALL[cf], ynw, j, ynwp2); - if (onumct < MAXCORRUPTTHINGS) - { - if (tryfixing & (1ull<=printfromlev) - { - OSD_Printf(" will set wall %d's %s=%d's %s to %d on tryfix\n", - j, yupdownwall[cf], ynw, yupdownwall[!cf], j); - } - } - } - } // woot! - } - } - } - } -#endif - if (ns == i) - { - if (!bad) - { - int32_t onumct = numcorruptthings; - int32_t safetoclear = (nw==j || (wall[nw].nextwall==-1 && wall[nw].nextsector==-1)); - - CORRUPTCHK_PRINT(4, CORRUPT_WALL|j, "WALL[%d].NEXTSECTOR is its own sector", j); - if (onumct < MAXCORRUPTTHINGS) - { - if (tryfixing & (1ull<=printfromlev) - { - if (safetoclear) - OSD_Printf(" will clear wall %d's nextwall and nextsector on tryfix\n", j); - else - suggest_nextsector_correction(nw, j); - } - } - } - } - - if (!corruptcheck_noalreadyrefd && nw>=0 && nw>3]&(1<<(nw&7))) - { - int16_t nwnw, lnws; - int32_t onumct = numcorruptthings; - - 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 (onumct < MAXCORRUPTTHINGS && (nwnw==j || nwnw==lnws)) - { - int32_t walltoclear = nwnw==j ? lnws : j; - if (tryfixing & (1ull<= 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) - { - int32_t onumct = numcorruptthings; - 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 (onumct < MAXCORRUPTTHINGS) - { - if (tryfixing & (1ull<=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 [%d .. %d]", - j, nw, ns, TrackerCast(sector[ns].wallptr), sector[ns].wallptr+sector[ns].wallnum-1); - if (onumct < MAXCORRUPTTHINGS) - { - if (tryfixing & (1ull<= printfromlev) - suggest_nextsector_correction(nw, j); - } - } -#if 0 - // this one usually appears together with the "already referenced" corruption - else if (wall[nw].nextsector != i || wall[nw].nextwall != j) - { - CORRUPTCHK_PRINT(4, CORRUPT_WALL|nw, "WALL %d nextwall's backreferences inconsistent. Expected nw=%d, ns=%d; got nw=%d, ns=%d", - nw, i, j, wall[nw].nextsector, wall[nw].nextwall); - } -#endif - } - } - - errlevel = max(errlevel, bad); - } - } - } - - bad = 0; - for (i=0; i=numsectors) - CORRUPTCHK_PRINT(4, CORRUPT_SPRITE|i, "SPRITE[%d].SECTNUM=%d. Expect problems!", i, TrackerCast(sprite[i].sectnum)); - - if (sprite[i].statnum<0 || sprite[i].statnum>MAXSTATUS) - CORRUPTCHK_PRINT(4, CORRUPT_SPRITE|i, "SPRITE[%d].STATNUM=%d. Expect problems!", i, TrackerCast(sprite[i].statnum)); - - if (sprite[i].picnum<0 || sprite[i].picnum>=MAXTILES) - { - sprite[i].picnum = 0; - CORRUPTCHK_PRINT(0, CORRUPT_SPRITE|i, "SPRITE[%d].PICNUM=%d out of range, resetting to 0", i, TrackerCast(sprite[i].picnum)); - } - - if (klabs(sprite[i].x) > BXY_MAX || klabs(sprite[i].y) > BXY_MAX) - { - int32_t onumct = numcorruptthings; - - CORRUPTCHK_PRINT(3, CORRUPT_SPRITE|i, "SPRITE %d at [%d, %d] is outside the maximal grid range [%d, %d]", - i, TrackerCast(sprite[i].x), TrackerCast(sprite[i].y), -BXY_MAX, BXY_MAX); - - if (onumct < MAXCORRUPTTHINGS) - { - int32_t x=0, y=0, sect=sprite[i].sectnum, ok=0; - - if ((unsigned)sect < (unsigned)numsectors) - { - int32_t firstwall = sector[sect].wallptr; - - if ((unsigned)firstwall < (unsigned)numwalls) - { - x = wall[firstwall].x; - y = wall[firstwall].y; - ok = 1; - } - } - - if (!(tryfixing & (1ull<= printfromlev) - OSD_Printf(" will reposition to its sector's (%d) first" - " point [%d,%d] on tryfix\n", sect, x, y); - } - else - { - if (ok) - { - sprite[i].x = x; - sprite[i].y = y; - OSD_Printf(CCHK_CORRECTED "auto-correction: repositioned sprite %d to " - "its sector's (%d) first point [%d,%d]\n", i, sect, x, y); - } - } - } - } - } - - i = check_spritelist_consistency(); - if (i) - CORRUPTCHK_PRINT(5, i<0?0:(CORRUPT_SPRITE|i), CCHK_PANIC "SPRITE LISTS CORRUPTED: error code %d, s=%d, i=%d!", - i, csc_s, csc_i); - - if (0) - { -too_many_errors: - if (printfromlev<=errlevel) - OSD_Printf("!! too many errors, stopping. !!\n"); - } - - errlevel = max(errlevel, bad); - - if (errlevel) - { - if (printfromlev<=errlevel) - OSD_Printf("-- corruption level: %d\n", errlevel); - if (tryfixing) - OSD_Printf("--\n"); - } - - if (seen_nextwalls) - { - Bfree(seen_nextwalls); - Bfree(lastnextwallsource); - } - - corruptlevel = errlevel; - - return errlevel; -} //// void faketimerhandler(void) @@ -12792,562 +11500,3 @@ static void GenericSpriteSearch(void) keystatus[KEYSC_ESC] = 0; } - -////////// STATUS BAR MENU "class" ////////// - -#define MENU_MAX_ENTRIES (8*3) -#define MENU_ENTRY_SIZE 25 // max. length of label (including terminating NUL) - -#define MENU_Y_SPACING 8 -#define MENU_BASE_Y (ydim-STATUS2DSIZ+32) - -#define MENU_FG_COLOR editorcolors[11] -#define MENU_BG_COLOR editorcolors[0] -#define MENU_BG_COLOR_SEL editorcolors[1] - -#ifdef LUNATIC -# define MENU_HAVE_DESCRIPTION 1 -#else -# define MENU_HAVE_DESCRIPTION 0 -#endif - -typedef struct StatusBarMenu_ { - const char *const menuname; - const int32_t custom_start_index; - int32_t numentries; - - void (*process_func)(const struct StatusBarMenu_ *m, int32_t col, int32_t row); - - intptr_t auxdata[MENU_MAX_ENTRIES]; - char *description[MENU_MAX_ENTRIES]; // strdup'd description string, NULL if non - char name[MENU_MAX_ENTRIES][MENU_ENTRY_SIZE]; -} StatusBarMenu; - -#define MENU_INITIALIZER_EMPTY(MenuName, ProcessFunc) \ - { MenuName, 0, 0, ProcessFunc, {}, {}, {} } -#define MENU_INITIALIZER(MenuName, CustomStartIndex, ProcessFunc, ...) \ - { MenuName, CustomStartIndex, CustomStartIndex, ProcessFunc, {}, {}, ## __VA_ARGS__ } - -#ifdef LUNATIC -static void M_Clear(StatusBarMenu *m) -{ - int32_t i; - - m->numentries = 0; - Bmemset(m->auxdata, 0, sizeof(m->auxdata)); - Bmemset(m->name, 0, sizeof(m->name)); - - for (i=0; idescription[i]); - m->description[i] = NULL; - } -} - -static int32_t M_HaveDescription(StatusBarMenu *m) -{ - int32_t i; - - for (i=0; idescription[i] != NULL) - return 1; - - return 0; -} -#endif - -// NOTE: Does not handle description strings! (Only the Lua menu uses them.) -static void M_UnregisterFunction(StatusBarMenu *m, intptr_t auxdata) -{ - int32_t i, j; - - for (i=m->custom_start_index; inumentries; i++) - if (m->auxdata[i]==auxdata) - { - for (j=i; jnumentries-1; j++) - { - m->auxdata[j] = m->auxdata[j+1]; - Bmemcpy(m->name[j], m->name[j+1], MENU_ENTRY_SIZE); - } - - m->auxdata[j] = 0; - Bmemset(m->name[j], 0, MENU_ENTRY_SIZE); - - m->numentries--; - - break; - } -} - -static void M_RegisterFunction(StatusBarMenu *m, const char *name, intptr_t auxdata, const char *description) -{ - int32_t i; - - for (i=8; inumentries; i++) - { - if (m->auxdata[i]==auxdata) - { - // same auxdata, different name - Bstrncpyz(m->name[i], name, MENU_ENTRY_SIZE); - return; - } - else if (!Bstrncmp(m->name[i], name, MENU_ENTRY_SIZE)) - { - // same name, different auxdata - m->auxdata[i] = auxdata; - return; - } - } - - if (m->numentries == MENU_MAX_ENTRIES) - return; // max reached - - Bstrncpyz(m->name[m->numentries], name, MENU_ENTRY_SIZE); - m->auxdata[m->numentries] = auxdata; - -#if MENU_HAVE_DESCRIPTION - // NOTE: description only handled here (not above). - if (description) - m->description[m->numentries] = Xstrdup(description); -#else - UNREFERENCED_PARAMETER(description); -#endif - - m->numentries++; -} - -static void M_DisplayInitial(const StatusBarMenu *m) -{ - int32_t x = 8, y = MENU_BASE_Y+16; - int32_t i; - - for (i=0; inumentries; i++) - { - if (i==8 || i==16) - { - x += 208; - y = MENU_BASE_Y+16; - } - - printext16(x,y, MENU_FG_COLOR, MENU_BG_COLOR, m->name[i], 0); - y += MENU_Y_SPACING; - } - - printext16(m->numentries>8 ? 216 : 8, MENU_BASE_Y, MENU_FG_COLOR, -1, m->menuname, 0); - - clearkeys(); -} - -static void M_EnterMainLoop(StatusBarMenu *m) -{ - char disptext[80]; - const int32_t dispwidth = MENU_ENTRY_SIZE-1; - - int32_t i, col=0, row=0; - int32_t crowmax[3] = {-1, -1, -1}; - int32_t xpos = 8, ypos = MENU_BASE_Y+16; - - if (m->numentries == 0) - { - printmessage16("%s menu has no entries", m->menuname); - return; - } - - Bmemset(disptext, 0, sizeof(disptext)); - - Bassert((unsigned)m->numentries <= MENU_MAX_ENTRIES); - for (i=0; i<=(m->numentries-1)/8; i++) - crowmax[i] = (m->numentries >= (i+1)*8) ? 7 : (m->numentries-1)&7; - - drawgradient(); - M_DisplayInitial(m); - - while (keystatus[KEYSC_ESC] == 0) - { - idle_waitevent(); - if (handleevents()) - quitevent = 0; - - _printmessage16("Select an option, press to exit"); - - if (PRESSED_KEYSC(DOWN)) - { - if (row < crowmax[col]) - { - printext16(xpos, ypos+row*MENU_Y_SPACING, MENU_FG_COLOR, MENU_BG_COLOR, disptext, 0); - row++; - } - } - else if (PRESSED_KEYSC(UP)) - { - if (row > 0) - { - printext16(xpos, ypos+row*MENU_Y_SPACING, MENU_FG_COLOR, MENU_BG_COLOR, disptext, 0); - row--; - } - } - else if (PRESSED_KEYSC(LEFT)) - { - if (col > 0) - { - printext16(xpos, ypos+row*8, MENU_FG_COLOR, 0, disptext, 0); - col--; - xpos -= 208; - disptext[dispwidth] = 0; - row = min(crowmax[col], row); - } - } - else if (PRESSED_KEYSC(RIGHT)) - { - if (col < 2 && crowmax[col+1]>=0) - { - printext16(xpos, ypos+row*8, MENU_FG_COLOR, 0, disptext, 0); - col++; - xpos += 208; - disptext[dispwidth] = 0; - row = min(crowmax[col], row); - } - } - - for (i=Bsnprintf(disptext, dispwidth, "%s", m->name[col*8 + row]); i < dispwidth; i++) - disptext[i] = ' '; - - if (PRESSED_KEYSC(ENTER)) - { - Bassert(m->process_func != NULL); - m->process_func(m, col, row); - break; - } - -#if MENU_HAVE_DESCRIPTION - if (M_HaveDescription(m)) - { - const int32_t maxrows = 20; - int32_t r; - - for (r=0; rdescription[col*8 + row] != NULL) - printext16(16, 16, MENU_FG_COLOR, MENU_BG_COLOR, m->description[col*8 + row], 0); - } -#endif - printext16(xpos, ypos+row*MENU_Y_SPACING, MENU_FG_COLOR, MENU_BG_COLOR_SEL, disptext, 0); - showframe(1); - } - - printext16(xpos, ypos+row*MENU_Y_SPACING, MENU_FG_COLOR, MENU_BG_COLOR, disptext, 0); - showframe(1); - - keystatus[KEYSC_ESC] = 0; -} - -////////// SPECIAL FUNCTIONS MENU ////////// - -static void FuncMenu_Process(const StatusBarMenu *m, int32_t col, int32_t row); - -static StatusBarMenu g_specialFuncMenu = MENU_INITIALIZER( - "Special functions", 8, FuncMenu_Process, - - { - "Replace invalid tiles", - "Delete all spr of tile #", - "Set map sky shade", - "Set map sky height", - "Global Z coord shift", - "Resize selection", - "Global shade divide", - "Global visibility divide" - } -); - -// "External functions": - -static void FuncMenu(void) -{ - M_EnterMainLoop(&g_specialFuncMenu); -} - -void registerMenuFunction(const char *funcname, int32_t stateidx) -{ - if (funcname) - M_RegisterFunction(&g_specialFuncMenu, funcname, stateidx, NULL); - else - M_UnregisterFunction(&g_specialFuncMenu, stateidx); -} - -// The processing function... - -static int32_t correct_picnum(int16_t *picnumptr) -{ - int32_t picnum = *picnumptr; - - if ((unsigned)picnum >= MAXTILES || tilesizx[picnum] <= 0) - { - *picnumptr = 0; - return 1; - } - - return 0; -} - -static void FuncMenu_Process(const StatusBarMenu *m, int32_t col, int32_t row) -{ - int32_t i, j; - - switch (col) - { - - case 1: - case 2: - { - const int32_t stateidx = (Bassert(m->auxdata[col*8 + row] < g_stateCount), - m->auxdata[col*8 + row]); - - const char *statename = statesinfo[stateidx].name; - int32_t snlen = Bstrlen(statename); - char *tmpscript = (char *)Xmalloc(1+5+1+snlen+1); - - tmpscript[0] = ' '; // don't save in history - Bmemcpy(&tmpscript[1], "state", 5); - tmpscript[1+5] = ' '; - Bmemcpy(&tmpscript[1+5+1], statename, snlen); - tmpscript[1+5+1+snlen] = 0; - - M32RunScript(tmpscript); - Bfree(tmpscript); - - if (vm.flags&VMFLAG_ERROR) - printmessage16("There were errors while executing the menu function"); - else if (lastpm16time != totalclock) - printmessage16("Menu function executed successfully"); - } - break; - - case 0: - { - switch (row) - { - - case 0: - { - j = 0; - - for (i=0; i= 0) - { - int32_t k = 0; - for (j=0; j= 0) - { - sprite[w].x = (int32_t)(sprite[w].x*size); - sprite[w].y = (int32_t)(sprite[w].y*size); - sprite[w].z = (int32_t)(sprite[w].z*size); - sprite[w].xrepeat = min(max((int32_t)(sprite[w].xrepeat*size),1),255); - sprite[w].yrepeat = min(max((int32_t)(sprite[w].yrepeat*size),1),255); - w = nextspritesect[w]; - } - } - printmessage16("Map scaled"); - } - else printmessage16("Aborted"); - } - break; - - case 6: - { - j=getnumber16("Shade divisor: ",1,128,1); - if (j > 1) - { - for (i=0; i 1) - { - for (i=0; i>4)/j; - } - printmessage16("Visibility adjusted"); - } - else printmessage16("Aborted"); - } - break; - - } // switch (row) - } - break; // switch (col) / case 0 - - } // switch (col) -} - -#ifdef LUNATIC -typedef const char *(*luamenufunc_t)(void); - -static int32_t g_numLuaFuncs = 0; -static luamenufunc_t g_LuaFuncPtrs[MENU_MAX_ENTRIES]; - -static void LuaFuncMenu_Process(const StatusBarMenu *m, int32_t col, int32_t row) -{ - luamenufunc_t func = g_LuaFuncPtrs[col*8 + row]; - const char *errmsg; - - Bassert(func != NULL); - errmsg = func(); - - if (errmsg == NULL) - { - printmessage16("Lua function executed successfully"); - } - else - { - printmessage16("There were errors executing the Lua function, see OSD"); - OSD_Printf("Errors executing Lua function \"%s\": %s\n", m->name[col*8 + row], errmsg); - } -} - -static StatusBarMenu g_LuaFuncMenu = MENU_INITIALIZER_EMPTY("Lua functions", LuaFuncMenu_Process); - -static void LuaFuncMenu(void) -{ - M_EnterMainLoop(&g_LuaFuncMenu); -} - -LUNATIC_EXTERN void LM_Register(const char *name, luamenufunc_t funcptr, const char *description) -{ - if (name == NULL || g_numLuaFuncs == MENU_MAX_ENTRIES) - return; - - g_LuaFuncPtrs[g_numLuaFuncs] = funcptr; - M_RegisterFunction(&g_LuaFuncMenu, name, g_numLuaFuncs, description); - g_numLuaFuncs++; -} - -LUNATIC_EXTERN void LM_Clear(void) -{ - M_Clear(&g_LuaFuncMenu); - - g_numLuaFuncs = 0; - Bmemset(g_LuaFuncPtrs, 0, sizeof(g_LuaFuncPtrs)); -} -#endif diff --git a/polymer/eduke32/source/m32common.c b/polymer/eduke32/source/m32common.c new file mode 100644 index 000000000..ef44dc7c9 --- /dev/null +++ b/polymer/eduke32/source/m32common.c @@ -0,0 +1,1877 @@ + +#include "compat.h" +#include "keys.h" +#include "build.h" +#include "cache1d.h" +#include "polymer.h" +#include "editor.h" +#include "renderlayer.h" + +#include "m32script.h" +#include "m32def.h" + +#include "lz4.h" +#include "xxhash.h" + +//////////////////// Key stuff //////////////////// + +#define eitherALT (keystatus[KEYSC_LALT] || keystatus[KEYSC_RALT]) +#define eitherCTRL (keystatus[KEYSC_LCTRL] || keystatus[KEYSC_RCTRL]) +#define eitherSHIFT (keystatus[KEYSC_LSHIFT] || keystatus[KEYSC_RSHIFT]) + +#define PRESSED_KEYSC(Key) (keystatus[KEYSC_##Key] && !(keystatus[KEYSC_##Key]=0)) + +//// + +// All these variables need verification that all relevant editor stubs are actually implementing them correctly. + +char getmessage[162], getmessageleng; +int32_t getmessagetimeoff; //, charsperline; + +int32_t mousxplc, mousyplc; +int32_t mouseaction; + +char *scripthist[SCRIPTHISTSIZ]; +int32_t scripthistend; + +int32_t g_lazy_tileselector; +int32_t fixmaponsave_sprites = 1; + +int32_t showambiencesounds=2; + +int32_t autosave=180; + +int32_t autocorruptcheck; +int32_t corruptcheck_noalreadyrefd; +int32_t corrupt_tryfix_alt; +int32_t corruptlevel, numcorruptthings, corruptthings[MAXCORRUPTTHINGS]; + +//// + +#ifdef YAX_ENABLE +const char *yupdownwall[2] = {"upwall","downwall"}; +const char *YUPDOWNWALL[2] = {"UPWALL","DOWNWALL"}; +#endif + +//// + +void drawgradient(void) +{ + int32_t i, col = whitecol-21; + begindrawing(); + for (i=ydim-STATUS2DSIZ+16; i0; i++,col--) + CLEARLINES2D(i, 1, (col<<24)|(col<<16)|(col<<8)|col); + CLEARLINES2D(i, ydim-i, 0); + enddrawing(); +} + +static void message_common1(const char *tmpstr) +{ + Bstrncpyz(getmessage, tmpstr, sizeof(getmessage)); + + getmessageleng = Bstrlen(getmessage); + getmessagetimeoff = totalclock + 120*2 + getmessageleng*(120/30); +// lastmessagetime = totalclock; +} + +void message(const char *fmt, ...) +{ + char tmpstr[256]; + va_list va; + + va_start(va, fmt); + Bvsnprintf(tmpstr, 256, fmt, va); + va_end(va); + + message_common1(tmpstr); + + if (!mouseaction) + OSD_Printf("%s\n", tmpstr); +} + +void silentmessage(const char *fmt, ...) +{ + char tmpstr[256]; + va_list va; + + va_start(va, fmt); + Bvsnprintf(tmpstr, 256, fmt, va); + va_end(va); + + message_common1(tmpstr); +} + +////////// tag labeling system ////////// + +typedef struct +{ + hashtable_t hashtab; + char *label[32768]; + int32_t numlabels; +} taglab_t; + +static taglab_t g_taglab; + +static void tstrtoupper(char *s) +{ + int32_t i; + for (i=0; s[i]; i++) + s[i] = Btoupper(s[i]); +} + +void taglab_init() +{ + int32_t i; + + g_taglab.numlabels = 0; + g_taglab.hashtab.size = 16384; + hash_init(&g_taglab.hashtab); + + for (i=0; i<32768; i++) + { + if (g_taglab.label[i]) + Bfree(g_taglab.label[i]); + g_taglab.label[i] = NULL; + } +} + +int32_t taglab_load(const char *filename, int32_t flags) +{ + int32_t fil, len, i; + char buf[BMAX_PATH], *dot, *filebuf; + + taglab_init(); + + len = Bstrlen(filename); + if (len >= BMAX_PATH-1) + return -1; + Bmemcpy(buf, filename, len+1); + + // + dot = Bstrrchr(buf, '.'); + if (!dot) + dot = &buf[len]; + + if (dot-buf+8 >= BMAX_PATH) + return -1; + Bmemcpy(dot, ".maptags", 9); + // + + if ((fil = kopen4load(buf,flags)) == -1) + return -1; + + len = kfilelength(fil); + + filebuf = (char *)Xmalloc(len+1); + if (!filebuf) + { + kclose(fil); + return -1; + } + + kread(fil, filebuf, len); + filebuf[len] = 0; + kclose(fil); + + // ---- + + { + int32_t tag; + char *cp=filebuf, *bp, *ep; + + while (1) + { +#define XTAGLAB_STRINGIFY(X) TAGLAB_STRINGIFY(X) +#define TAGLAB_STRINGIFY(X) #X + i = sscanf(cp, "%d %" XTAGLAB_STRINGIFY(TAGLAB_MAX) "s", &tag, buf); +#undef XTAGLAB_STRINGIFY +#undef TAGLAB_STRINGIFY + if (i != 2 || !buf[0] || tag<0 || tag>=32768) + goto nextline; + + buf[TAGLAB_MAX-1] = 0; + + i = Bstrlen(buf); + bp = buf; while (*bp && isspace(*bp)) bp++; + ep = &buf[i-1]; while (ep>buf && isspace(*ep)) ep--; + ep++; + + if (!(ep > bp)) + goto nextline; + *ep = 0; + + taglab_add(bp, tag); +//initprintf("add tag %s:%d\n", bp, tag); +nextline: + while (*cp && *cp!='\n') + cp++; + while (*cp=='\r' || *cp=='\n') + cp++; + if (*cp == 0) + break; + } + } + + // ---- + Bfree(filebuf); + + return 0; +} + +int32_t taglab_save(const char *mapname) +{ + int32_t fil, len, i; + char buf[BMAX_PATH], *dot; + const char *label; + + if (g_taglab.numlabels==0) + return 1; + + Bstrncpyz(buf, mapname, BMAX_PATH); + + len = Bstrlen(buf); + // + dot = Bstrrchr(buf, '.'); + if (!dot) + dot = &buf[len]; + + if (dot-buf+8 >= BMAX_PATH) + return -1; + Bmemcpy(dot, ".maptags", 9); + // + + if ((fil = Bopen(buf,BO_BINARY|BO_TRUNC|BO_CREAT|BO_WRONLY,BS_IREAD|BS_IWRITE)) == -1) + { + initprintf("Couldn't open \"%s\" for writing: %s\n", buf, strerror(errno)); + return -1; + } + + for (i=0; i<32768; i++) + { + label = taglab_getlabel(i); + if (!label) + continue; + + len = Bsprintf(buf, "%d %s" OURNEWL, i, label); + if (Bwrite(fil, buf, len)!=len) + break; + } + + Bclose(fil); + + return (i!=32768); +} + +int32_t taglab_add(const char *label, int16_t tag) +{ + const char *otaglabel; + char buf[TAGLAB_MAX]; + int32_t olabeltag, diddel=0; + + if (tag < 0) + return -1; + + Bstrncpyz(buf, label, sizeof(buf)); + // upcase the tag for storage and comparison + tstrtoupper(buf); + + otaglabel = g_taglab.label[tag]; + if (otaglabel) + { + if (!Bstrcasecmp(otaglabel, buf)) + return 0; + +// hash_delete(&g_taglab.hashtab, g_taglab.label[tag]); + + // a label having the same tag number as 'tag' is deleted + Bfree(g_taglab.label[tag]); + g_taglab.label[tag] = NULL; + diddel |= 1; + } + else + { + olabeltag = hash_findcase(&g_taglab.hashtab, buf); + if (olabeltag==tag) + return 0; + + if (olabeltag>=0) + { + // the label gets assigned to a new tag number ('tag deleted') + Bfree(g_taglab.label[olabeltag]); + g_taglab.label[olabeltag] = NULL; + diddel |= 2; + } + } + + if (!diddel) + g_taglab.numlabels++; + g_taglab.label[tag] = Xstrdup(buf); +//initprintf("added %s %d to hash\n", g_taglab.label[tag], tag); + hash_add(&g_taglab.hashtab, g_taglab.label[tag], tag, 1); + + return diddel; +} + +const char *taglab_getlabel(int16_t tag) +{ + if (tag < 0) // || tag>=32768 implicitly + return NULL; + + return g_taglab.label[tag]; +} + +int32_t taglab_gettag(const char *label) +{ + char buf[TAGLAB_MAX]; + + Bstrncpyz(buf, label, TAGLAB_MAX); + + // need to upcase since hash_findcase doesn't work as expected: + // getting the code is still (necessarily) case-sensitive... + tstrtoupper(buf); + + return hash_findcase(&g_taglab.hashtab, buf); +} +////////// end tag labeling system ////////// + +////////// UNDO/REDO SYSTEM ////////// +#if M32_UNDO +mapundo_t *mapstate = NULL; + +int32_t map_revision = 1; + +#define QADDNSZ 400 + + +static int32_t try_match_with_prev(int32_t idx, int32_t numsthgs, uint32_t crc) +{ + if (mapstate->prev && mapstate->prev->num[idx]==numsthgs && mapstate->prev->crc[idx]==crc) + { + // found match! + mapstate->sws[idx] = mapstate->prev->sws[idx]; + (*(int32_t *)mapstate->sws[idx])++; // increase refcount! + + return 1; + } + + return 0; +} + +static void create_compressed_block(int32_t idx, const void *srcdata, uint32_t size, uint32_t crc) +{ + uint32_t j; + + // allocate + mapstate->sws[idx] = (char *)Xmalloc(4 + size + QADDNSZ); + + // compress & realloc + j = LZ4_compress((const char*)srcdata, mapstate->sws[idx]+4, size); + mapstate->sws[idx] = (char *)Xrealloc(mapstate->sws[idx], 4 + j); + + // write refcount + *(int32_t *)mapstate->sws[idx] = 1; + + mapstate->crc[idx] = crc; +} + +static void free_self_and_successors(mapundo_t *mapst) +{ + mapundo_t *cur = mapst; + + mapst->prev = NULL; // break the back link + + while (cur->next) + cur = cur->next; + + while (1) + { + int32_t i; + mapundo_t *const prev = cur->prev; + + for (i=0; i<3; i++) + { + int32_t *const refcnt = (int32_t *)cur->sws[i]; + + if (refcnt) + { + (*refcnt)--; + if (*refcnt == 0) + Bfree(refcnt); // free the block! + } + } + + Bfree(cur); + + if (!prev) + break; + + cur = prev; + } +} + +// NOTE: only _consecutive_ matching (size+crc) sector/wall/sprite blocks are +// shared! +void create_map_snapshot(void) +{ + if (mapstate == NULL) + { + // create initial mapstate + + map_revision = 1; + + mapstate = (mapundo_t *)Xcalloc(1, sizeof(mapundo_t)); + mapstate->revision = map_revision; + mapstate->prev = mapstate->next = NULL; + } + else + { + if (mapstate->next) + free_self_and_successors(mapstate->next); + // now, have no successors + + // calloc because not everything may be set in the following: + mapstate->next = (mapundo_t *)Xcalloc(1, sizeof(mapundo_t)); + mapstate->next->prev = mapstate; + + mapstate = mapstate->next; + + mapstate->revision = ++map_revision; + } + + + fixspritesectors(); + + mapstate->num[0] = numsectors; + mapstate->num[1] = numwalls; + mapstate->num[2] = Numsprites; + + + if (numsectors) + { + int32_t j; + uint32_t temphash = XXH32((uint8_t *)sector, numsectors*sizeof(sectortype), numsectors*sizeof(sectortype)); + + if (!try_match_with_prev(0, numsectors, temphash)) + create_compressed_block(0, sector, numsectors*sizeof(sectortype), temphash); + + if (numwalls) + { + temphash = XXH32((uint8_t *)wall, numwalls*sizeof(walltype), numwalls*sizeof(walltype)); + + if (!try_match_with_prev(1, numwalls, temphash)) + create_compressed_block(1, wall, numwalls*sizeof(walltype), temphash); + } + + if (Numsprites) + { + temphash = XXH32((uint8_t *)sprite, MAXSPRITES*sizeof(spritetype), MAXSPRITES*sizeof(spritetype)); + + if (!try_match_with_prev(2, Numsprites, temphash)) + { + int32_t i = 0; + spritetype *const tspri = (spritetype *)Xmalloc(Numsprites*sizeof(spritetype) + 4); + spritetype *spri = tspri; + + for (j=0; jnext == NULL || !mapstate->next->num[0]) return 1; + + // while (map_revision+1 != mapstate->revision && mapstate->next) + mapstate = mapstate->next; + } + else + { + if (mapstate->prev == NULL || !mapstate->prev->num[0]) return 1; + + // while (map_revision-1 != mapstate->revision && mapstate->prev) + mapstate = mapstate->prev; + } + + numsectors = mapstate->num[0]; + numwalls = mapstate->num[1]; + map_revision = mapstate->revision; + + Bmemset(show2dsector, 0, sizeof(show2dsector)); + + reset_highlightsector(); + reset_highlight(); + + initspritelists(); + + if (mapstate->num[0]) + { + // restore sector[] + LZ4_decompress_fast(mapstate->sws[0]+4, (char*)sector, numsectors*sizeof(sectortype)); + + if (mapstate->num[1]) // restore wall[] + LZ4_decompress_fast(mapstate->sws[1]+4, (char*)wall, numwalls*sizeof(walltype)); + + if (mapstate->num[2]) // restore sprite[] + LZ4_decompress_fast(mapstate->sws[2]+4, (char*)sprite, (mapstate->num[2])*sizeof(spritetype)); + } + + // insert sprites + for (i=0; inum[2]; i++) + { + if ((sprite[i].cstat & 48) == 48) sprite[i].cstat &= ~48; + Bassert((unsigned)sprite[i].sectnum < (unsigned)numsectors + && (unsigned)sprite[i].statnum < MAXSTATUS); + insertsprite(sprite[i].sectnum, sprite[i].statnum); + } + + Bassert(Numsprites == mapstate->num[2]); + +#ifdef POLYMER + if (in3dmode() && getrendermode() == REND_POLYMER) + polymer_loadboard(); +#endif +#ifdef YAX_ENABLE + yax_update(0); + yax_updategrays(pos.z); +#endif + CheckMapCorruption(4, 0); + + return 0; +} +#endif + +//// + +//// 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 " -> " + +#ifdef _MSC_VER +#define CORRUPTCHK_PRINT(errlev, what, fmt, ...) do \ +{ \ + bad = max(bad, errlev); \ + if (numcorruptthings>=MAXCORRUPTTHINGS) \ + goto too_many_errors; \ + corruptthings[numcorruptthings++] = (what); \ + if (errlev >= printfromlev) \ + OSD_Printf("#%d: " fmt "\n", numcorruptthings, ## __VA_ARGS__); \ +} while (0) +#else +#define CORRUPTCHK_PRINT(errlev, what, fmt, ...) do \ +{ \ + bad = max(bad, errlev); \ + if (numcorruptthings>=MAXCORRUPTTHINGS) \ + goto too_many_errors; \ + corruptthings[numcorruptthings++] = (what); \ + if (errlev >= printfromlev) \ + OSD_Printf_nowarn("#%d: " fmt "\n", numcorruptthings, ## __VA_ARGS__); \ +} while (0) +#endif +#ifdef YAX_ENABLE +static int32_t walls_have_equal_endpoints(int32_t w1, int32_t w2) +{ + int32_t n1 = wall[w1].point2, n2 = wall[w2].point2; + + return (wall[w1].x==wall[w2].x && wall[w1].y==wall[w2].y && + wall[n1].x==wall[n2].x && wall[n1].y==wall[n2].y); +} + +static void correct_yax_nextwall(int32_t wallnum, int32_t bunchnum, int32_t cf, int32_t tryfixingp) +{ + int32_t i, j, startwall, endwall; + int32_t nummatching=0, lastwall[2]={-1,-1}; + + for (SECTORS_OF_BUNCH(bunchnum, !cf, i)) + for (WALLS_OF_SECTOR(i, j)) + { + // v v v shouldn't happen, 'stupidity safety' + if (j!=wallnum && walls_have_equal_endpoints(wallnum, j)) + { + lastwall[nummatching++] = j; + if (nummatching==2) + goto outofloop; + } + } +outofloop: + if (nummatching==1) + { + if (!tryfixingp) + { + OSD_Printf(" will set wall %d's %s to %d on tryfix\n", + wallnum, yupdownwall[cf], lastwall[0]); + } + else + { + int32_t setreverse = 0; + yax_setnextwall(wallnum, cf, lastwall[0]); + if (yax_getnextwall(lastwall[0], !cf) < 0) + { + setreverse = 1; + yax_setnextwall(lastwall[0], !cf, wallnum); + } + + OSD_Printf("auto-correction: set wall %d's %s to %d%s\n", + wallnum, yupdownwall[cf], lastwall[0], setreverse?" and its reverse link":""); + } + } + else if (!tryfixingp) + { + if (nummatching > 1) + { + OSD_Printf(" found more than one matching wall: at least %d and %d\n", + lastwall[0], lastwall[1]); + } + else if (nummatching == 0) + { + OSD_Printf(" found no matching walls!\n"); + } + } +} +#endif + +// in reverse orientation +static int32_t walls_are_consistent(int32_t w1, int32_t w2) +{ + return (wall[w2].x==POINT2(w1).x && wall[w2].y==POINT2(w1).y && + wall[w1].x==POINT2(w2).x && wall[w1].y==POINT2(w2).y); +} + +static void suggest_nextsector_correction(int32_t nw, int32_t j) +{ + // wall j's nextsector is inconsistent with its nextwall... what shall we do? + + if (nw>=0 && nw=0 && wall[j].nextsector=0 && nw=0 && wall[j].nextsector>3]; + + csc_s = csc_i = -1; + + if (Numsprites < 0 || Numsprites > MAXSPRITES) + return 1; + + for (i=0; i MAXSTATUS || (sectnum!=MAXSECTORS && (unsigned)sectnum > (unsigned)numsectors)) + return 3; // oob sectnum or statnum + + if (statnum != MAXSTATUS) + ournumsprites++; + } + + if (ournumsprites != Numsprites) + { + initprintf("ournumsprites=%d, Numsprites=%d\n", ournumsprites, Numsprites); + return 4; // counting sprites by statnum!=MAXSTATUS inconsistent with Numsprites + } + + // SECTOR LIST + + Bmemset(havesprite, 0, (Numsprites+7)>>3); + + for (s=0; s=0; i=nextspritesect[i]) + { + csc_i = i; + + if (i >= MAXSPRITES) + return 5; // oob sprite index in list, or Numsprites inconsistent + + if (havesprite[i>>3]&(1<<(i&7))) + return 6; // have a cycle in the list + + havesprite[i>>3] |= (1<<(i&7)); + + if (sprite[i].sectnum != s) + return 7; // .sectnum inconsistent with list + } + + if (i!=-1) + return 8; // various code checks for -1 to break loop + } + + csc_s = -1; + for (i=0; i>3]&(1<<(i&7)))) + return 9; // have a sprite in the world not in sector list + } + + + // STATUS LIST -- we now clear havesprite[] bits + + for (s=0; s=0; i=nextspritestat[i]) + { + csc_i = i; + + if (i >= MAXSPRITES) + return 10; // oob sprite index in list, or Numsprites inconsistent + + // have a cycle in the list, or status list inconsistent with + // sector list (*) + if (!(havesprite[i>>3]&(1<<(i&7)))) + return 11; + + havesprite[i>>3] &= ~(1<<(i&7)); + + if (sprite[i].statnum != s) + return 12; // .statnum inconsistent with list + } + + if (i!=-1) + return 13; // various code checks for -1 to break loop + } + + csc_s = -1; + for (i=0; i>3]&(1<<(i&7))) + return 14; + } + + return 0; +} + +#define TRYFIX_NONE() (tryfixing == 0ull) +#define TRYFIX_CNUM(onumct) (onumct < MAXCORRUPTTHINGS && (tryfixing & (1ull<MAXSECTORS) + CORRUPTCHK_PRINT(5, 0, CCHK_PANIC "SECTOR LIMIT EXCEEDED (MAXSECTORS=%d)!!!", MAXSECTORS); + + if (numwalls>MAXWALLS) + CORRUPTCHK_PRINT(5, 0, CCHK_PANIC "WALL LIMIT EXCEEDED (MAXWALLS=%d)!!!", MAXWALLS); + + if (numsectors>MAXSECTORS || numwalls>MAXWALLS) + { + corruptlevel = bad; + return bad; + } + + if (numsectors==0 || numwalls==0) + { + if (numsectors>0) + CORRUPTCHK_PRINT(5, 0, CCHK_PANIC " Have sectors but no walls!"); + if (numwalls>0) + CORRUPTCHK_PRINT(5, 0, CCHK_PANIC " Have walls but no sectors!"); + return bad; + } + + if (!corruptcheck_noalreadyrefd) + { + seen_nextwalls = (uint8_t *)Xcalloc((numwalls+7)>>3,1); + lastnextwallsource = (int16_t *)Xmalloc(numwalls*sizeof(lastnextwallsource[0])); + } + + for (i=0; i numwalls) + { + if (w0 < 0 || w0 >= MAXWALLS) + CORRUPTCHK_PRINT(5, CORRUPT_SECTOR|i, "SECTOR[%d].WALLPTR=%d INVALID!!!", i, w0); + else + CORRUPTCHK_PRINT(5, CORRUPT_SECTOR|i, "SECTOR[%d].WALLPTR=%d out of range (numwalls=%d)", i, w0, numw); + } + + if (w0 != ewall) + 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, 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); + + ewall += numw; + + endwall = w0 + numw; + if (endwall > numwalls) + CORRUPTCHK_PRINT(5, CORRUPT_SECTOR|i, "SECTOR[%d]: wallptr+wallnum=%d out of range: numwalls=%d", i, endwall, numwalls); + + // inconsistent cstat&2 and heinum checker + { + const char *cflabel[2] = {"ceiling", "floor"}; + + for (j=0; j<2; j++) + { + const int32_t cs = !!(SECTORFLD(i,stat, j)&2); + const int32_t hn = !!SECTORFLD(i,heinum, j); + + if (cs != hn && heinumcheckstat <= 1) + { + if (numcorruptthings < MAXCORRUPTTHINGS && + (heinumcheckstat==1 || (heinumcheckstat==0 && (tryfixing & (1ull< endwall) + { + if (wall[j].point2 < 0 || wall[j].point2 >= MAXWALLS) + CORRUPTCHK_PRINT(5, CORRUPT_WALL|j, CCHK_PANIC "WALL[%d].POINT2=%d INVALID!!!", + j, TrackerCast(wall[j].point2)); + else + CORRUPTCHK_PRINT(4, CORRUPT_WALL|j, "WALL[%d].POINT2=%d out of range [%d, %d]", + j, TrackerCast(wall[j].point2), w0, endwall); + } + + nw = wall[j].nextwall; + + if (nw >= numwalls) + { + int32_t onumct = numcorruptthings; + + if (TRYFIX_NONE()) + { + if (nw >= MAXWALLS) + CORRUPTCHK_PRINT(5, CORRUPT_WALL|j, "WALL[%d].NEXTWALL=%d INVALID!!!", + j, nw); + else + CORRUPTCHK_PRINT(4, CORRUPT_WALL|j, "WALL[%d].NEXTWALL=%d out of range: numwalls=%d", + j, nw, numwalls); + OSD_Printf(" will make wall %d white on tryfix\n", j); + } + else if (TRYFIX_CNUM(onumct)) // CODEDUP MAKE_WALL_WHITE + { + wall[j].nextwall = wall[j].nextsector = -1; + OSD_Printf(CCHK_CORRECTED "auto-correction: made wall %d white\n", j); + } + } + + ns = wall[j].nextsector; + + if (ns >= numsectors) + { + int32_t onumct = numcorruptthings; + + if (TRYFIX_NONE()) + { + if (ns >= MAXSECTORS) + CORRUPTCHK_PRINT(5, CORRUPT_WALL|j, "WALL[%d].NEXTSECTOR=%d INVALID!!!", + j, ns); + else + CORRUPTCHK_PRINT(4, CORRUPT_WALL|j, "WALL[%d].NEXTSECTOR=%d out of range: numsectors=%d", + j, ns, numsectors); + OSD_Printf(" will make wall %d white on tryfix\n", j); + } + else if (TRYFIX_CNUM(onumct)) // CODEDUP MAKE_WALL_WHITE + { + wall[j].nextwall = wall[j].nextsector = -1; + OSD_Printf(CCHK_CORRECTED "auto-correction: made wall %d white\n", j); + } + } + + if (nw>=w0 && nw<=endwall) + CORRUPTCHK_PRINT(4, CORRUPT_WALL|j, "WALL[%d].NEXTWALL is its own sector's wall", j); + + if (wall[j].x==POINT2(j).x && wall[j].y==POINT2(j).y) + CORRUPTCHK_PRINT(3, CORRUPT_WALL|j, "WALL[%d] has length 0", j); + +#ifdef YAX_ENABLE + { + int32_t cf, ynw, ynwp2; + + for (cf=0; cf<2; cf++) + { + ynw = yax_getnextwall(j, cf); + if (ynw >= 0) + { + if (ynw >= numwalls) + CORRUPTCHK_PRINT(4, CORRUPT_WALL|j, "WALL %d's %s=%d out of range: numwalls=%d", + j, YUPDOWNWALL[cf], ynw, numwalls); + else + { + int32_t ynextwallok = 1; + + if (j == ynw) + { + CORRUPTCHK_PRINT(4, CORRUPT_WALL|j, "WALL %d's %s is itself", + j, YUPDOWNWALL[cf]); + ynextwallok = 0; + } + else if (!walls_have_equal_endpoints(j, ynw)) + { + CORRUPTCHK_PRINT(4, CORRUPT_WALL|j, "WALL %d's and its %s=%d's " + "endpoints are inconsistent", j, YUPDOWNWALL[cf], ynw); + ynextwallok = 0; + } + + { + int16_t bunchnum = yax_getbunch(i, cf); + int32_t onumct = numcorruptthings; + + if (bunchnum < 0 || bunchnum >= numyaxbunches) + { + if (tryfixing == 0ull) + { + CORRUPTCHK_PRINT(4, CORRUPT_WALL|j, "WALL %d has %s=%d, " + "but its %s bunchnum=%d is invalid", + j, YUPDOWNWALL[cf], ynw, + cf==YAX_CEILING? "ceiling":"floor", bunchnum); + OSD_Printf(" will clear wall %d's %s to -1 on tryfix\n", + j, yupdownwall[cf]); + + } + else if (tryfixing & (1ull<=printfromlev) + correct_yax_nextwall(j, bunchnum, cf, tryfixing!=0ull); + } + } + + if (ynextwallok) + { + int32_t onumct = numcorruptthings; + + ynwp2 = yax_getnextwall(ynw, !cf); + if (ynwp2 != j) + { + CORRUPTCHK_PRINT(4, CORRUPT_WALL|j, "WALL %d's %s=%d's reverse link wrong" + " (expected %d, have %d)", j, YUPDOWNWALL[cf], ynw, j, ynwp2); + if (onumct < MAXCORRUPTTHINGS) + { + if (tryfixing & (1ull<=printfromlev) + { + OSD_Printf(" will set wall %d's %s=%d's %s to %d on tryfix\n", + j, yupdownwall[cf], ynw, yupdownwall[!cf], j); + } + } + } + } // woot! + } + } + } + } +#endif + if (ns == i) + { + if (!bad) + { + int32_t onumct = numcorruptthings; + int32_t safetoclear = (nw==j || (wall[nw].nextwall==-1 && wall[nw].nextsector==-1)); + + CORRUPTCHK_PRINT(4, CORRUPT_WALL|j, "WALL[%d].NEXTSECTOR is its own sector", j); + if (onumct < MAXCORRUPTTHINGS) + { + if (tryfixing & (1ull<=printfromlev) + { + if (safetoclear) + OSD_Printf(" will clear wall %d's nextwall and nextsector on tryfix\n", j); + else + suggest_nextsector_correction(nw, j); + } + } + } + } + + if (!corruptcheck_noalreadyrefd && nw>=0 && nw>3]&(1<<(nw&7))) + { + int16_t nwnw, lnws; + int32_t onumct = numcorruptthings; + + 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 (onumct < MAXCORRUPTTHINGS && (nwnw==j || nwnw==lnws)) + { + int32_t walltoclear = nwnw==j ? lnws : j; + if (tryfixing & (1ull<= 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) + { + int32_t onumct = numcorruptthings; + 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 (onumct < MAXCORRUPTTHINGS) + { + if (tryfixing & (1ull<=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 [%d .. %d]", + j, nw, ns, TrackerCast(sector[ns].wallptr), sector[ns].wallptr+sector[ns].wallnum-1); + if (onumct < MAXCORRUPTTHINGS) + { + if (tryfixing & (1ull<= printfromlev) + suggest_nextsector_correction(nw, j); + } + } +#if 0 + // this one usually appears together with the "already referenced" corruption + else if (wall[nw].nextsector != i || wall[nw].nextwall != j) + { + CORRUPTCHK_PRINT(4, CORRUPT_WALL|nw, "WALL %d nextwall's backreferences inconsistent. Expected nw=%d, ns=%d; got nw=%d, ns=%d", + nw, i, j, wall[nw].nextsector, wall[nw].nextwall); + } +#endif + } + } + + errlevel = max(errlevel, bad); + } + } + } + + bad = 0; + for (i=0; i=numsectors) + CORRUPTCHK_PRINT(4, CORRUPT_SPRITE|i, "SPRITE[%d].SECTNUM=%d. Expect problems!", i, TrackerCast(sprite[i].sectnum)); + + if (sprite[i].statnum<0 || sprite[i].statnum>MAXSTATUS) + CORRUPTCHK_PRINT(4, CORRUPT_SPRITE|i, "SPRITE[%d].STATNUM=%d. Expect problems!", i, TrackerCast(sprite[i].statnum)); + + if (sprite[i].picnum<0 || sprite[i].picnum>=MAXTILES) + { + sprite[i].picnum = 0; + CORRUPTCHK_PRINT(0, CORRUPT_SPRITE|i, "SPRITE[%d].PICNUM=%d out of range, resetting to 0", i, TrackerCast(sprite[i].picnum)); + } + + if (klabs(sprite[i].x) > BXY_MAX || klabs(sprite[i].y) > BXY_MAX) + { + int32_t onumct = numcorruptthings; + + CORRUPTCHK_PRINT(3, CORRUPT_SPRITE|i, "SPRITE %d at [%d, %d] is outside the maximal grid range [%d, %d]", + i, TrackerCast(sprite[i].x), TrackerCast(sprite[i].y), -BXY_MAX, BXY_MAX); + + if (onumct < MAXCORRUPTTHINGS) + { + int32_t x=0, y=0, sect=sprite[i].sectnum, ok=0; + + if ((unsigned)sect < (unsigned)numsectors) + { + int32_t firstwall = sector[sect].wallptr; + + if ((unsigned)firstwall < (unsigned)numwalls) + { + x = wall[firstwall].x; + y = wall[firstwall].y; + ok = 1; + } + } + + if (!(tryfixing & (1ull<= printfromlev) + OSD_Printf(" will reposition to its sector's (%d) first" + " point [%d,%d] on tryfix\n", sect, x, y); + } + else + { + if (ok) + { + sprite[i].x = x; + sprite[i].y = y; + OSD_Printf(CCHK_CORRECTED "auto-correction: repositioned sprite %d to " + "its sector's (%d) first point [%d,%d]\n", i, sect, x, y); + } + } + } + } + } + + i = check_spritelist_consistency(); + if (i) + CORRUPTCHK_PRINT(5, i<0?0:(CORRUPT_SPRITE|i), CCHK_PANIC "SPRITE LISTS CORRUPTED: error code %d, s=%d, i=%d!", + i, csc_s, csc_i); + + if (0) + { +too_many_errors: + if (printfromlev<=errlevel) + OSD_Printf("!! too many errors, stopping. !!\n"); + } + + errlevel = max(errlevel, bad); + + if (errlevel) + { + if (printfromlev<=errlevel) + OSD_Printf("-- corruption level: %d\n", errlevel); + if (tryfixing) + OSD_Printf("--\n"); + } + + if (seen_nextwalls) + { + Bfree(seen_nextwalls); + Bfree(lastnextwallsource); + } + + corruptlevel = errlevel; + + return errlevel; +} +//// + + +////////// STATUS BAR MENU "class" ////////// + +#define MENU_MAX_ENTRIES (8*3) +#define MENU_ENTRY_SIZE 25 // max. length of label (including terminating NUL) + +#define MENU_Y_SPACING 8 +#define MENU_BASE_Y (ydim-STATUS2DSIZ+32) + +#define MENU_FG_COLOR editorcolors[11] +#define MENU_BG_COLOR editorcolors[0] +#define MENU_BG_COLOR_SEL editorcolors[1] + +#ifdef LUNATIC +# define MENU_HAVE_DESCRIPTION 1 +#else +# define MENU_HAVE_DESCRIPTION 0 +#endif + +typedef struct StatusBarMenu_ { + const char *const menuname; + const int32_t custom_start_index; + int32_t numentries; + + void (*process_func)(const struct StatusBarMenu_ *m, int32_t col, int32_t row); + + intptr_t auxdata[MENU_MAX_ENTRIES]; + char *description[MENU_MAX_ENTRIES]; // strdup'd description string, NULL if non + char name[MENU_MAX_ENTRIES][MENU_ENTRY_SIZE]; +} StatusBarMenu; + +#define MENU_INITIALIZER_EMPTY(MenuName, ProcessFunc) \ + { MenuName, 0, 0, ProcessFunc, {}, {}, {} } +#define MENU_INITIALIZER(MenuName, CustomStartIndex, ProcessFunc, ...) \ + { MenuName, CustomStartIndex, CustomStartIndex, ProcessFunc, {}, {}, ## __VA_ARGS__ } + +#ifdef LUNATIC +static void M_Clear(StatusBarMenu *m) +{ + int32_t i; + + m->numentries = 0; + Bmemset(m->auxdata, 0, sizeof(m->auxdata)); + Bmemset(m->name, 0, sizeof(m->name)); + + for (i=0; idescription[i]); + m->description[i] = NULL; + } +} + +static int32_t M_HaveDescription(StatusBarMenu *m) +{ + int32_t i; + + for (i=0; idescription[i] != NULL) + return 1; + + return 0; +} +#endif + +// NOTE: Does not handle description strings! (Only the Lua menu uses them.) +static void M_UnregisterFunction(StatusBarMenu *m, intptr_t auxdata) +{ + int32_t i, j; + + for (i=m->custom_start_index; inumentries; i++) + if (m->auxdata[i]==auxdata) + { + for (j=i; jnumentries-1; j++) + { + m->auxdata[j] = m->auxdata[j+1]; + Bmemcpy(m->name[j], m->name[j+1], MENU_ENTRY_SIZE); + } + + m->auxdata[j] = 0; + Bmemset(m->name[j], 0, MENU_ENTRY_SIZE); + + m->numentries--; + + break; + } +} + +static void M_RegisterFunction(StatusBarMenu *m, const char *name, intptr_t auxdata, const char *description) +{ + int32_t i; + + for (i=8; inumentries; i++) + { + if (m->auxdata[i]==auxdata) + { + // same auxdata, different name + Bstrncpyz(m->name[i], name, MENU_ENTRY_SIZE); + return; + } + else if (!Bstrncmp(m->name[i], name, MENU_ENTRY_SIZE)) + { + // same name, different auxdata + m->auxdata[i] = auxdata; + return; + } + } + + if (m->numentries == MENU_MAX_ENTRIES) + return; // max reached + + Bstrncpyz(m->name[m->numentries], name, MENU_ENTRY_SIZE); + m->auxdata[m->numentries] = auxdata; + +#if MENU_HAVE_DESCRIPTION + // NOTE: description only handled here (not above). + if (description) + m->description[m->numentries] = Xstrdup(description); +#else + UNREFERENCED_PARAMETER(description); +#endif + + m->numentries++; +} + +static void M_DisplayInitial(const StatusBarMenu *m) +{ + int32_t x = 8, y = MENU_BASE_Y+16; + int32_t i; + + for (i=0; inumentries; i++) + { + if (i==8 || i==16) + { + x += 208; + y = MENU_BASE_Y+16; + } + + printext16(x,y, MENU_FG_COLOR, MENU_BG_COLOR, m->name[i], 0); + y += MENU_Y_SPACING; + } + + printext16(m->numentries>8 ? 216 : 8, MENU_BASE_Y, MENU_FG_COLOR, -1, m->menuname, 0); + + clearkeys(); +} + +static void M_EnterMainLoop(StatusBarMenu *m) +{ + char disptext[80]; + const int32_t dispwidth = MENU_ENTRY_SIZE-1; + + int32_t i, col=0, row=0; + int32_t crowmax[3] = {-1, -1, -1}; + int32_t xpos = 8, ypos = MENU_BASE_Y+16; + + if (m->numentries == 0) + { + printmessage16("%s menu has no entries", m->menuname); + return; + } + + Bmemset(disptext, 0, sizeof(disptext)); + + Bassert((unsigned)m->numentries <= MENU_MAX_ENTRIES); + for (i=0; i<=(m->numentries-1)/8; i++) + crowmax[i] = (m->numentries >= (i+1)*8) ? 7 : (m->numentries-1)&7; + + drawgradient(); + M_DisplayInitial(m); + + while (keystatus[KEYSC_ESC] == 0) + { + idle_waitevent(); + if (handleevents()) + quitevent = 0; + + _printmessage16("Select an option, press to exit"); + + if (PRESSED_KEYSC(DOWN)) + { + if (row < crowmax[col]) + { + printext16(xpos, ypos+row*MENU_Y_SPACING, MENU_FG_COLOR, MENU_BG_COLOR, disptext, 0); + row++; + } + } + else if (PRESSED_KEYSC(UP)) + { + if (row > 0) + { + printext16(xpos, ypos+row*MENU_Y_SPACING, MENU_FG_COLOR, MENU_BG_COLOR, disptext, 0); + row--; + } + } + else if (PRESSED_KEYSC(LEFT)) + { + if (col > 0) + { + printext16(xpos, ypos+row*8, MENU_FG_COLOR, 0, disptext, 0); + col--; + xpos -= 208; + disptext[dispwidth] = 0; + row = min(crowmax[col], row); + } + } + else if (PRESSED_KEYSC(RIGHT)) + { + if (col < 2 && crowmax[col+1]>=0) + { + printext16(xpos, ypos+row*8, MENU_FG_COLOR, 0, disptext, 0); + col++; + xpos += 208; + disptext[dispwidth] = 0; + row = min(crowmax[col], row); + } + } + + for (i=Bsnprintf(disptext, dispwidth, "%s", m->name[col*8 + row]); i < dispwidth; i++) + disptext[i] = ' '; + + if (PRESSED_KEYSC(ENTER)) + { + Bassert(m->process_func != NULL); + m->process_func(m, col, row); + break; + } + +#if MENU_HAVE_DESCRIPTION + if (M_HaveDescription(m)) + { + const int32_t maxrows = 20; + int32_t r; + + for (r=0; rdescription[col*8 + row] != NULL) + printext16(16, 16, MENU_FG_COLOR, MENU_BG_COLOR, m->description[col*8 + row], 0); + } +#endif + printext16(xpos, ypos+row*MENU_Y_SPACING, MENU_FG_COLOR, MENU_BG_COLOR_SEL, disptext, 0); + showframe(1); + } + + printext16(xpos, ypos+row*MENU_Y_SPACING, MENU_FG_COLOR, MENU_BG_COLOR, disptext, 0); + showframe(1); + + keystatus[KEYSC_ESC] = 0; +} + +////////// SPECIAL FUNCTIONS MENU ////////// + +static void FuncMenu_Process(const StatusBarMenu *m, int32_t col, int32_t row); + +static StatusBarMenu g_specialFuncMenu = MENU_INITIALIZER( + "Special functions", 8, FuncMenu_Process, + + { + "Replace invalid tiles", + "Delete all spr of tile #", + "Set map sky shade", + "Set map sky height", + "Global Z coord shift", + "Resize selection", + "Global shade divide", + "Global visibility divide" + } +); + +// "External functions": + +void FuncMenu(void) +{ + M_EnterMainLoop(&g_specialFuncMenu); +} + +void registerMenuFunction(const char *funcname, int32_t stateidx) +{ + if (funcname) + M_RegisterFunction(&g_specialFuncMenu, funcname, stateidx, NULL); + else + M_UnregisterFunction(&g_specialFuncMenu, stateidx); +} + +// The processing function... + +static int32_t correct_picnum(int16_t *picnumptr) +{ + int32_t picnum = *picnumptr; + + if ((unsigned)picnum >= MAXTILES || tilesizx[picnum] <= 0) + { + *picnumptr = 0; + return 1; + } + + return 0; +} + +static void FuncMenu_Process(const StatusBarMenu *m, int32_t col, int32_t row) +{ + int32_t i, j; + + switch (col) + { + + case 1: + case 2: + { + const int32_t stateidx = (Bassert(m->auxdata[col*8 + row] < g_stateCount), + m->auxdata[col*8 + row]); + + const char *statename = statesinfo[stateidx].name; + int32_t snlen = Bstrlen(statename); + char *tmpscript = (char *)Xmalloc(1+5+1+snlen+1); + + tmpscript[0] = ' '; // don't save in history + Bmemcpy(&tmpscript[1], "state", 5); + tmpscript[1+5] = ' '; + Bmemcpy(&tmpscript[1+5+1], statename, snlen); + tmpscript[1+5+1+snlen] = 0; + + M32RunScript(tmpscript); + Bfree(tmpscript); + + if (vm.flags&VMFLAG_ERROR) + printmessage16("There were errors while executing the menu function"); + else if (lastpm16time != totalclock) + printmessage16("Menu function executed successfully"); + } + break; + + case 0: + { + switch (row) + { + + case 0: + { + j = 0; + + for (i=0; i= 0) + { + int32_t k = 0; + for (j=0; j= 0) + { + sprite[w].x = (int32_t)(sprite[w].x*size); + sprite[w].y = (int32_t)(sprite[w].y*size); + sprite[w].z = (int32_t)(sprite[w].z*size); + sprite[w].xrepeat = min(max((int32_t)(sprite[w].xrepeat*size),1),255); + sprite[w].yrepeat = min(max((int32_t)(sprite[w].yrepeat*size),1),255); + w = nextspritesect[w]; + } + } + printmessage16("Map scaled"); + } + else printmessage16("Aborted"); + } + break; + + case 6: + { + j=getnumber16("Shade divisor: ",1,128,1); + if (j > 1) + { + for (i=0; i 1) + { + for (i=0; i>4)/j; + } + printmessage16("Visibility adjusted"); + } + else printmessage16("Aborted"); + } + break; + + } // switch (row) + } + break; // switch (col) / case 0 + + } // switch (col) +} + +#ifdef LUNATIC +typedef const char *(*luamenufunc_t)(void); + +static int32_t g_numLuaFuncs = 0; +static luamenufunc_t g_LuaFuncPtrs[MENU_MAX_ENTRIES]; + +static void LuaFuncMenu_Process(const StatusBarMenu *m, int32_t col, int32_t row) +{ + luamenufunc_t func = g_LuaFuncPtrs[col*8 + row]; + const char *errmsg; + + Bassert(func != NULL); + errmsg = func(); + + if (errmsg == NULL) + { + printmessage16("Lua function executed successfully"); + } + else + { + printmessage16("There were errors executing the Lua function, see OSD"); + OSD_Printf("Errors executing Lua function \"%s\": %s\n", m->name[col*8 + row], errmsg); + } +} + +static StatusBarMenu g_LuaFuncMenu = MENU_INITIALIZER_EMPTY("Lua functions", LuaFuncMenu_Process); + +void LuaFuncMenu(void) +{ + M_EnterMainLoop(&g_LuaFuncMenu); +} + +LUNATIC_EXTERN void LM_Register(const char *name, luamenufunc_t funcptr, const char *description) +{ + if (name == NULL || g_numLuaFuncs == MENU_MAX_ENTRIES) + return; + + g_LuaFuncPtrs[g_numLuaFuncs] = funcptr; + M_RegisterFunction(&g_LuaFuncMenu, name, g_numLuaFuncs, description); + g_numLuaFuncs++; +} + +LUNATIC_EXTERN void LM_Clear(void) +{ + M_Clear(&g_LuaFuncMenu); + + g_numLuaFuncs = 0; + Bmemset(g_LuaFuncPtrs, 0, sizeof(g_LuaFuncPtrs)); +} +#endif diff --git a/polymer/eduke32/source/mapster32.h b/polymer/eduke32/source/mapster32.h index 6f441e92e..da0435619 100644 --- a/polymer/eduke32/source/mapster32.h +++ b/polymer/eduke32/source/mapster32.h @@ -57,13 +57,11 @@ static char helpon=0; //static char onwater=0; static uint8_t onnames=4, usedcount=1; static int16_t cursprite; -int32_t mousxplc, mousyplc; static int32_t ppointhighlight; //static int32_t counter=0; static uint8_t nosprites=0,purpleon=0,skill=4; static uint8_t framerateon=1,shadepreview=0; -int32_t autosave=180; static int32_t autosavetimer; static void SearchSectors(int32_t dir); @@ -73,10 +71,6 @@ static inline void SpriteName(int16_t spritenum, char *lo2); static void EditSpriteData(int16_t spritenum); static void EditWallData(int16_t wallnum); static void EditSectorData(int16_t sectnum); -static void FuncMenu(void); -#ifdef LUNATIC -static void LuaFuncMenu(void); -#endif #define BASEPALCOUNT 6 @@ -94,9 +88,6 @@ static int32_t g_firstFogPal; static int32_t updownunits=1024; -static char getmessage[162], getmessageleng; -static int32_t getmessagetimeoff; //, charsperline; - //int32_t intro=0; static int32_t acurpalette=0;