raze/polymer/eduke32/build/src/build.c
helixhorned 06afc4dcc5 * Comment out some practically dead code (rendmode 1 and 2, pcx screenshots), cutting some 8k from the release binary.
* Refactor two nearly identical chunks in polymost.c into one function in the hope of getting some more, but interestingly that did nothing at all. At least it's more readable this way...
* Commit, but don't enable, code for writing PNG screenshots (I'm tired of converting them every time). Requires libpng which in turn requires zlib.

git-svn-id: https://svn.eduke32.com/eduke32@1852 1a8010ca-5511-0410-912e-c29ae57300e0
2011-03-19 18:07:12 +00:00

7598 lines
239 KiB
C

// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
// Ken Silverman's official web site: "http://www.advsys.net/ken"
// See the included license file "BUILDLIC.TXT" for license info.
//
// This file has been modified from Ken Silverman's original release
// by Jonathon Fowler (jonof@edgenetwk.com)
#include "build.h"
#include "compat.h"
#include "pragmas.h"
#include "osd.h"
#include "cache1d.h"
#include "editor.h"
#include "baselayer.h"
#ifdef RENDERTYPEWIN
#include "winlayer.h"
#endif
#include "m32script.h"
#define TIMERINTSPERSECOND 120
#define updatecrc16(crc,dat) (crc = (((crc<<8)&65535)^crctable[((((uint16_t)crc)>>8)&65535)^dat]))
static int32_t crctable[256];
static char kensig[64];
extern const char *ExtGetVer(void);
extern int32_t ExtInit(void);
extern int32_t ExtPreInit(int32_t argc,const char **argv);
extern void ExtUnInit(void);
extern void ExtPreCheckKeys(void);
extern void ExtAnalyzeSprites(void);
extern void ExtCheckKeys(void);
extern void ExtLoadMap(const char *mapname);
extern void ExtSaveMap(const char *mapname);
extern const char *ExtGetSectorCaption(int16_t sectnum);
extern const char *ExtGetWallCaption(int16_t wallnum);
extern const char *ExtGetSpriteCaption(int16_t spritenum);
extern void ExtShowSectorData(int16_t sectnum);
extern void ExtShowWallData(int16_t wallnum);
extern void ExtShowSpriteData(int16_t spritenum);
extern void ExtEditSectorData(int16_t sectnum);
extern void ExtEditWallData(int16_t wallnum);
extern void ExtEditSpriteData(int16_t spritenum);
extern const char *ExtGetSectorType(int32_t lotag);
extern char spritecol2d[MAXTILES][2];
char noclip=0;
int32_t vel, svel, angvel;
// 0 1 2 3 4 5 6 7
// up, down, left, right, lshift, rctrl, lctrl, space
// 8 9 10 11 12 13
// a, z, pgdn, pgup, [,], [.]
// 14 15 16 17 18 19
// kpenter, enter, =, -, tab, `
uint8_t buildkeys[NUMBUILDKEYS] =
{
0xc8,0xd0,0xcb,0xcd,0x2a,0x9d,0x1d,0x39,
0x1e,0x2c,0xd1,0xc9,0x33,0x34,
0x9c,0x1c,0xd,0xc,0xf,0x29
};
vec3_t pos;
int32_t horiz = 100;
static int32_t mousexsurp = 0, mouseysurp = 0;
int16_t ang, cursectnum;
int32_t hvel;
int32_t grponlymode = 0;
extern int32_t editorgridextent; // in engine.c
extern double msens;
int32_t graphicsmode = 0;
extern int32_t xyaspect;
extern int32_t totalclocklock;
int32_t synctics = 0, lockclock = 0;
// those ones save the respective 3d video vars while in 2d mode
// so that exiting from mapster32 in 2d mode saves the correct ones
double vid_gamma_3d=-1, vid_contrast_3d=-1, vid_brightness_3d=-1;
extern char vgacompatible;
extern char picsiz[MAXTILES];
extern int32_t startposx, startposy, startposz;
extern int16_t startang, startsectnum;
extern int32_t ydim16, halfxdim16, midydim16;
extern intptr_t frameplace;
int32_t xdim2d = 640, ydim2d = 480, xdimgame = 640, ydimgame = 480, bppgame = 8;
int32_t forcesetup = 1;
extern int32_t cachesize, artsize;
static int16_t oldmousebstatus = 0;
char game_executable[BMAX_PATH] = DEFAULT_GAME_LOCAL_EXEC;
int32_t zlock = 0x7fffffff, zmode = 0, whitecol, kensplayerheight = 32;
//int16_t defaultspritecstat = 0;
int16_t localartfreq[MAXTILES];
int16_t localartlookup[MAXTILES], localartlookupnum;
char tempbuf[4096];
char names[MAXTILES][25];
const char *g_namesFileName = "NAMES.H";
int16_t asksave = 0;
extern int16_t editstatus, searchit;
extern int32_t searchx, searchy; //search input
extern int16_t searchsector, searchwall, searchstat; //search output
int32_t osearchx, osearchy; //old search input
extern int16_t pointhighlight, linehighlight, highlightcnt;
int32_t grid = 3, autogrid = 0, gridlock = 1, showtags = 1;
int32_t zoom = 768, gettilezoom = 1;
int32_t lastpm16time = 0;
int32_t numsprites;
extern int32_t mapversion;
int16_t highlight[MAXWALLS+MAXSPRITES];
int16_t highlightsector[MAXSECTORS], highlightsectorcnt = -1;
extern char textfont[128][8];
char pskysearch[MAXSECTORS];
int32_t temppicnum, tempcstat, templotag, temphitag, tempextra;
uint32_t temppal, tempvis, tempxrepeat, tempyrepeat;
int32_t tempshade, tempxvel, tempyvel, tempzvel;
char somethingintab = 255;
int32_t mlook = 0, mskip=0;
int32_t revertCTRL=0,scrollamount=3;
int32_t unrealedlook=1, quickmapcycling=1; //PK
char program_origcwd[BMAX_PATH];
char *mapster32_fullpath;
char *testplay_addparam = 0;
static char boardfilename[BMAX_PATH], selectedboardfilename[BMAX_PATH];
static CACHE1D_FIND_REC *finddirs=NULL, *findfiles=NULL, *finddirshigh=NULL, *findfileshigh=NULL;
static int32_t numdirs=0, numfiles=0;
static int32_t currentlist=0;
//static int32_t repeatcountx, repeatcounty;
static int32_t fillist[640];
// used for fillsector and point selection in side-view mode:
static int32_t tempxyar[MAXWALLS][2];
static int32_t mousx, mousy;
int16_t prefixtiles[16] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
uint8_t hlsectorbitmap[MAXSECTORS>>3]; // show2dsector is already taken...
static uint8_t visited[MAXWALLS>>3]; // used for AlignWalls and trace_loop
typedef struct
{
int16_t numsectors, numwalls, numsprites;
sectortype *sector;
walltype *wall;
spritetype *sprite;
} mapinfofull_t;
static int32_t backup_highlighted_map(mapinfofull_t *mapinfo);
static int32_t restore_highlighted_map(mapinfofull_t *mapinfo);
/*
static char scantoasc[128] =
{
0,0,'1','2','3','4','5','6','7','8','9','0','-','=',0,0,
'q','w','e','r','t','y','u','i','o','p','[',']',0,0,'a','s',
'd','f','g','h','j','k','l',';',39,'`',0,92,'z','x','c','v',
'b','n','m',',','.','/',0,'*',0,32,0,0,0,0,0,0,
0,0,0,0,0,0,0,'7','8','9','-','4','5','6','+','1',
'2','3','0','.',0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
};
static char scantoascwithshift[128] =
{
0,0,'!','@','#','$','%','^','&','*','(',')','_','+',0,0,
'Q','W','E','R','T','Y','U','I','O','P','{','}',0,0,'A','S',
'D','F','G','H','J','K','L',':',34,'~',0,'|','Z','X','C','V',
'B','N','M','<','>','?',0,'*',0,32,0,0,0,0,0,0,
0,0,0,0,0,0,0,'7','8','9','-','4','5','6','+','1',
'2','3','0','.',0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
};
*/
#define eitherALT (keystatus[0x38]|keystatus[0xb8])
#define eitherCTRL (keystatus[0x1d]|keystatus[0x9d])
#define eitherSHIFT (keystatus[0x2a]|keystatus[0x36])
#define DOWN_BK(BuildKey) (keystatus[buildkeys[BK_##BuildKey]])
int32_t pk_turnaccel=16;
int32_t pk_turndecel=12;
int32_t pk_uedaccel=3;
int8_t sideview_reversehrot = 0;
char lastpm16buf[156];
//static int32_t checksectorpointer_warn = 0;
char changechar(char dachar, int32_t dadir, char smooshyalign, char boundcheck);
static int32_t adjustmark(int32_t *xplc, int32_t *yplc, int16_t danumwalls);
static void locktogrid(int32_t *dax, int32_t *day);
static int32_t checkautoinsert(int32_t dax, int32_t day, int16_t danumwalls);
void keytimerstuff(void);
static int32_t clockdir(int16_t wallstart);
static void flipwalls(int16_t numwalls, int16_t newnumwalls);
static void insertpoint(int16_t linehighlight, int32_t dax, int32_t day);
static void deletepoint(int16_t point);
static int32_t deletesector(int16_t sucksect);
void fixrepeats(int16_t i);
static int16_t loopinside(int32_t x, int32_t y, int16_t startwall);
int32_t fillsector(int16_t sectnum, char fillcolor);
static int16_t whitelinescan(int16_t sucksect, int16_t dalinehighlight);
void printcoords16(int32_t posxe, int32_t posye, int16_t ange);
static void copysector(int16_t soursector, int16_t destsector, int16_t deststartwall, char copystat, const int16_t *oldtonewsect);
int32_t drawtilescreen(int32_t pictopleft, int32_t picbox);
void overheadeditor(void);
static int32_t getlinehighlight(int32_t xplc, int32_t yplc, int32_t line);
void fixspritesectors(void);
static int32_t movewalls(int32_t start, int32_t offs);
int32_t loadnames(const char *namesfile);
void updatenumsprites(void);
static void getclosestpointonwall(int32_t x, int32_t y, int32_t dawall, int32_t *nx, int32_t *ny);
static void initcrc(void);
int32_t gettile(int32_t tilenum);
static int32_t menuselect(void);
static int32_t menuselect_auto(int32_t); //PK
static int32_t insert_sprite_common(int32_t sucksect, int32_t dax, int32_t day);
static void correct_ornamented_sprite(int32_t i, int32_t hitw);
static int32_t getfilenames(const char *path, const char *kind);
static void clearfilenames(void);
void loadmhk(int32_t domessage);
extern int32_t map_revision;
extern int32_t map_undoredo(int32_t dir);
extern void map_undoredo_free(void);
void clearkeys(void) { Bmemset(keystatus,0,sizeof(keystatus)); }
static inline void bclamp(int32_t *x, int32_t mi, int32_t ma)
{
if (*x>ma) *x=ma;
if (*x<mi) *x=mi;
}
#ifdef USE_OPENGL
static int32_t osdcmd_restartvid(const osdfuncparm_t *parm)
{
extern int32_t qsetmode;
UNREFERENCED_PARAMETER(parm);
if (qsetmode != 200) return OSDCMD_OK;
resetvideomode();
if (setgamemode(fullscreen,xdim,ydim,bpp))
OSD_Printf("restartvid: Reset failed...\n");
return OSDCMD_OK;
}
static int32_t osdcmd_vidmode(const osdfuncparm_t *parm)
{
int32_t newx = xdim, newy = ydim, newbpp = bpp, newfullscreen = fullscreen, tmp;
extern int32_t qsetmode;
switch (parm->numparms)
{
case 1: // bpp switch
tmp = Batol(parm->parms[0]);
if (tmp==8 || tmp==16 || tmp==32)
newbpp = tmp;
break;
case 4: // fs, res, bpp switch
newfullscreen = (Batol(parm->parms[3]) != 0);
case 3: // res & bpp switch
tmp = Batol(parm->parms[2]);
if (tmp==8 || tmp==16 || tmp==32)
newbpp = tmp;
case 2: // res switch
newx = Batol(parm->parms[0]);
newy = Batol(parm->parms[1]);
break;
default:
return OSDCMD_SHOWHELP;
}
if (qsetmode != 200)
{
qsetmodeany(newx,newy);
xdim2d = xdim;
ydim2d = ydim;
begindrawing(); //{{{
CLEARLINES2D(0, ydim16, 0);
enddrawing(); //}}}
ydim16 = ydim-STATUS2DSIZ2;
return OSDCMD_OK;
}
if (setgamemode(newfullscreen,newx,newy,newbpp))
OSD_Printf("vidmode: Mode change failed!\n");
xdimgame = newx;
ydimgame = newy;
bppgame = newbpp;
fullscreen = newfullscreen;
return OSDCMD_OK;
}
#endif
extern int32_t startwin_run(void);
extern char *defsfilename; // set in bstub.c
#ifdef M32_SHOWDEBUG
char m32_debugstr[64][128];
int32_t m32_numdebuglines=0;
static void M32_drawdebug(void)
{
int i;
int x=4, y=8;
#if 0
{
static char tstr[128];
Bsprintf(tstr, "search... stat=%d, sector=%d, wall=%d (%d), isbottom=%d, asksave=%d",
searchstat, searchsector, searchwall, searchbottomwall, searchisbottom, asksave);
printext256(x,y,whitecol,0,tstr,xdimgame>640?0:1);
}
#endif
if (m32_numdebuglines>0)
{
begindrawing();
for (i=0; i<m32_numdebuglines; i++)
{
y+=8;
printext256(x,y,whitecol,0,m32_debugstr[i],xdimgame>640?0:1);
}
enddrawing();
}
m32_numdebuglines=0;
}
#endif
#ifdef YAX_ENABLE
static void yax_resetbunchnums(void)
{
int32_t i;
for (i=0; i<MAXSECTORS; i++)
yax_setbunches(i, -1, -1);
}
#endif
static void reset_default_mapstate(void)
{
pos.x = 32768; //new board!
pos.y = 32768;
pos.z = 0;
ang = 1536;
numsectors = 0;
numwalls = 0;
numsprites = 0;
cursectnum = -1;
initspritelists();
#ifdef YAX_ENABLE
yax_resetbunchnums();
#endif
}
int32_t app_main(int32_t argc, const char **argv)
{
char quitflag, cmdsetup = 0;
int32_t i, j, k;
pathsearchmode = 1; // unrestrict findfrompath so that full access to the filesystem can be had
#ifdef USE_OPENGL
OSD_RegisterFunction("restartvid","restartvid: reinitialize the video mode",osdcmd_restartvid);
OSD_RegisterFunction("vidmode","vidmode <xdim> <ydim> <bpp> <fullscreen>: immediately change the video mode",osdcmd_vidmode);
#endif
wm_setapptitle("Mapster32");
editstatus = 1;
newaspect_enable = 1;
if ((i = ExtPreInit(argc,argv)) < 0) return -1;
#ifdef RENDERTYPEWIN
backgroundidle = 1;
#endif
boardfilename[0] = 0;
for (i=1; i<argc; i++)
{
if (argv[i][0] == '-')
{
if (!Bstrcmp(argv[i], "-setup")) cmdsetup = 1;
else if (!Bstrcmp(argv[i], "-help") || !Bstrcmp(argv[i], "--help") || !Bstrcmp(argv[i], "-?"))
{
char *s =
"Mapster32\n"
"Syntax: mapster32 [options] mapname\n"
"Options:\n"
"\t-grp\tUse an extra GRP or ZIP file.\n"
"\t-g\tSame as above.\n"
#if defined RENDERTYPEWIN || (defined RENDERTYPESDL && !defined __APPLE__ && defined HAVE_GTK2)
"\t-setup\tDisplays the configuration dialogue box before entering the editor.\n"
#endif
;
#if defined RENDERTYPEWIN || (defined RENDERTYPESDL && !defined __APPLE__ && defined HAVE_GTK2)
wm_msgbox("Mapster32","%s",s);
#else
puts(s);
#endif
return 0;
}
continue;
}
if (!boardfilename[0])
{
Bstrncpy(boardfilename, argv[i], BMAX_PATH);
boardfilename[i-BMAX_PATH] = 0;
}
}
if (boardfilename[0] == 0)
{
Bstrcpy(boardfilename,"newboard.map");
}
else if (Bstrchr(boardfilename,'.') == 0)
{
Bstrcat(boardfilename, ".map");
}
//Bcanonicalisefilename(boardfilename,0);
if ((i = ExtInit()) < 0) return -1;
#if defined RENDERTYPEWIN || (defined RENDERTYPESDL && !defined __APPLE__ && defined HAVE_GTK2)
if (i || forcesetup || cmdsetup)
{
if (quitevent || !startwin_run())
{
uninitengine();
exit(0);
}
}
#endif
loadnames(g_namesFileName);
if (initinput()) return -1;
initmouse();
inittimer(TIMERINTSPERSECOND);
installusertimercallback(keytimerstuff);
loadpics("tiles000.art", 1048576*16);
Bstrcpy(kensig,"Uses BUILD technology by Ken Silverman");
initcrc();
if (!loaddefinitionsfile(defsfilename))
initprintf("Definitions file loaded.\n");
k = 0;
for (i=0; i<256; i++)
{
j = ((int32_t)palette[i*3])+((int32_t)palette[i*3+1])+((int32_t)palette[i*3+2]);
if (j > k) { k = j; whitecol = i; }
}
k = clipmapinfo_load("_clipshape0.map");
if (k>0)
initprintf("There was an error loading the sprite clipping map (status %d).\n", k);
if (LoadBoard(boardfilename, 1))
reset_default_mapstate();
totalclock = 0;
updatesector(pos.x,pos.y,&cursectnum);
if (cursectnum == -1)
{
vid_gamma_3d = vid_gamma;
vid_brightness_3d = vid_brightness;
vid_contrast_3d = vid_contrast;
vid_gamma = vid_contrast = 1.0;
vid_brightness = 0.0;
setbrightness(0,0,0);
if (setgamemode(fullscreen, xdim2d, ydim2d, 8) < 0)
{
ExtUnInit();
uninitengine();
Bprintf("%d * %d not supported in this graphics mode\n",xdim2d,ydim2d);
exit(0);
}
// executed once per init, but after setgamemode so that OSD has the right width
OSD_Exec("m32_autoexec.cfg");
overheadeditor();
keystatus[buildkeys[BK_MODE2D_3D]] = 0;
vid_gamma = vid_gamma_3d;
vid_contrast = vid_contrast_3d;
vid_brightness = vid_brightness_3d;
vid_gamma_3d = vid_contrast_3d = vid_brightness_3d = -1;
setbrightness(GAMMA_CALC,0,0);
}
else
{
if (setgamemode(fullscreen, xdimgame, ydimgame, bppgame) < 0)
{
ExtUnInit();
uninitengine();
Bprintf("%d * %d not supported in this graphics mode\n",xdim,ydim);
exit(0);
}
// executed once per init, but after setgamemode so that OSD has the right width
OSD_Exec("m32_autoexec.cfg");
setbrightness(GAMMA_CALC,0,0);
}
CANCEL:
quitflag = 0;
while (quitflag == 0)
{
if (handleevents())
{
if (quitevent)
{
keystatus[1] = 1;
quitevent = 0;
}
}
OSD_DispatchQueued();
ExtPreCheckKeys();
nextpage();
synctics = totalclock-lockclock;
lockclock += synctics;
drawrooms(pos.x,pos.y,pos.z,ang,horiz,cursectnum);
ExtAnalyzeSprites();
drawmasks();
#ifdef POLYMER
if (rendmode == 4 && searchit == 2)
{
polymer_editorpick();
drawrooms(pos.x,pos.y,pos.z,ang,horiz,cursectnum);
ExtAnalyzeSprites();
drawmasks();
}
#endif
#ifdef M32_SHOWDEBUG
if (searchstat>=0 && (searchwall<0 || searchsector<0))
{
Bsprintf(m32_debugstr[m32_numdebuglines++], "inconsistent search variables!");
searchstat = -1;
}
M32_drawdebug();
#endif
ExtCheckKeys();
if (keystatus[1])
{
keystatus[1] = 0;
printext256(0,0,whitecol,0,"Are you sure you want to quit?",0);
showframe(1);
synctics = totalclock-lockclock;
lockclock += synctics;
while ((keystatus[1]|keystatus[0x1c]|keystatus[0x39]|keystatus[0x31]) == 0)
{
idle_waitevent();
if (handleevents())
{
if (quitevent)
{
quitflag = 1;
break;
}
}
if (keystatus[0x15]||keystatus[0x1c]) // Y or ENTER
{
keystatus[0x15] = 0;
keystatus[0x1c] = 0;
quitflag = 1; break;
}
}
while (keystatus[1])
{
keystatus[1] = 0;
quitevent = 0;
goto CANCEL;
}
}
}
if (asksave)
{
i = CheckMapCorruption(4, 0);
printext256(0,8,whitecol,0,i<4?"Save changes?":"Map is heavily corrupt. Save changes?",0);
showframe(1);
while ((keystatus[1]|keystatus[0x1c]|keystatus[0x39]|keystatus[0x31]|keystatus[0x2e]) == 0)
{
idle_waitevent();
if (handleevents()) { if (quitevent) break; } // like saying no
if (keystatus[0x15] || keystatus[0x1c]) // Y or ENTER
{
keystatus[0x15] = keystatus[0x1c] = 0;
SaveBoard(NULL, 0);
break;
}
}
while (keystatus[1]||keystatus[0x2e])
{
keystatus[1] = keystatus[0x2e] = 0;
quitevent = 0;
goto CANCEL;
}
}
// clearfilenames();
ExtUnInit();
// uninitengine();
uninitsystem();
Bprintf("Memory status: %d(%d) bytes\n",cachesize,artsize);
Bprintf("%s\n",kensig);
return(0);
}
/*
void showmouse(void)
{
int32_t i;
for (i=1;i<=4;i++)
{
plotpixel(searchx+i,searchy,whitecol);
plotpixel(searchx-i,searchy,whitecol);
plotpixel(searchx,searchy-i,whitecol);
plotpixel(searchx,searchy+i,whitecol);
}
}
*/
static int32_t mhk=0;
void loadmhk(int32_t domessage)
{
char *p; char levname[BMAX_PATH];
if (!mhk)
return;
Bstrcpy(levname, boardfilename);
p = Bstrrchr(levname,'.');
if (!p)
Bstrcat(levname,".mhk");
else
{
p[1]='m';
p[2]='h';
p[3]='k';
p[4]=0;
}
if (!loadmaphack(levname))
{
if (domessage)
message("Loaded map hack file '%s'",levname);
else
initprintf("Loaded map hack file '%s'\n",levname);
}
else
{
mhk=2;
if (domessage)
message("No maphack found for map '%s'",boardfilename);
}
}
static void move_and_update(int32_t xvect, int32_t yvect, int32_t addshr)
{
if (noclip)
{
pos.x += xvect>>(14+addshr);
pos.y += yvect>>(14+addshr);
updatesector(pos.x,pos.y, &cursectnum);
}
else
clipmove(&pos,&cursectnum, xvect>>addshr,yvect>>addshr,
128,4<<8,4<<8, CLIPMASK0);
}
static void mainloop_move()
{
int32_t xvect, yvect, doubvel;
if (angvel != 0) //ang += angvel * constant
{
//ENGINE calculates angvel for you
//Lt. shift makes turn velocity 50% faster
doubvel = (synctics + DOWN_BK(RUN)*(synctics>>1));
ang += ((angvel*doubvel)>>4);
ang &= 2047;
}
if ((vel|svel) != 0)
{
//Lt. shift doubles forward velocity
doubvel = (1+(DOWN_BK(RUN)))*synctics;
xvect = 0;
yvect = 0;
if (vel != 0)
{
xvect += (vel*doubvel*(int32_t)sintable[(ang+2560)&2047])>>3;
yvect += (vel*doubvel*(int32_t)sintable[(ang+2048)&2047])>>3;
}
if (svel != 0)
{
xvect += (svel*doubvel*(int32_t)sintable[(ang+2048)&2047])>>3;
yvect += (svel*doubvel*(int32_t)sintable[(ang+1536)&2047])>>3;
}
move_and_update(xvect, yvect, 0);
}
}
void editinput(void)
{
int32_t mousz, bstatus;
int32_t i, j, k, tempint=0;
int32_t goalz, xvect, yvect, hiz, loz, oposz;
int32_t dax, day, hihit, lohit, omlook=mlook;
// 3B 3C 3D 3E 3F 40 41 42 43 44 57 58 46
// F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 SCROLL
mousz = 0;
getmousevalues(&mousx,&mousy,&bstatus);
mousx = (mousx<<16) + mousexsurp;
mousy = (mousy<<16) + mouseysurp;
if (unrealedlook && !mskip)
{
if (mlook==0 && (bstatus&(1|2|4))==2)
mlook = 3;
else if ((bstatus&(1|2|4))==1)
mlook = 3;
}
{
ldiv_t ld;
if (mlook)
{
ld = ldiv(mousx, (int32_t)((1<<16)/(msens*0.5f))); mousx = ld.quot; mousexsurp = ld.rem;
ld = ldiv(mousy, (int32_t)((1<<16)/(msens*0.25f))); mousy = ld.quot; mouseysurp = ld.rem;
}
else
{
ld = ldiv(mousx, (int32_t)((1<<16)/msens)); mousx = ld.quot; mousexsurp = ld.rem;
ld = ldiv(mousy, (int32_t)((1<<16)/msens)); mousy = ld.quot; mouseysurp = ld.rem;
}
}
if (mlook == 3)
mlook = omlook;
// UnrealEd:
// rmb: mouselook
// lbm: x:turn y:fwd/back local x
// lmb&rmb: x:strafe y:up/dn (move in local yz plane)
// mmb: fwd/back in viewing vector
if (unrealedlook && !mskip) //PK
{
if ((bstatus&(1|2|4))==1)
{
ang += mousx;
xvect = -((mousy*(int32_t)sintable[(ang+2560)&2047])<<(3+pk_uedaccel));
yvect = -((mousy*(int32_t)sintable[(ang+2048)&2047])<<(3+pk_uedaccel));
move_and_update(xvect, yvect, 0);
}
else if (!mlook && (bstatus&(1|2|4))==2)
{
mlook=2;
}
else if ((bstatus&(1|2|4))==(1|2))
{
zmode = 2;
xvect = -((mousx*(int32_t)sintable[(ang+2048)&2047])<<pk_uedaccel);
yvect = -((mousx*(int32_t)sintable[(ang+1536)&2047])<<pk_uedaccel);
pos.z += mousy<<(4+pk_uedaccel);
move_and_update(xvect, yvect, 0);
}
else if ((bstatus&(1|2|4))==4)
{
zmode = 2;
// horiz-100 of 200 is viewing at 326.4 build angle units (=atan(200/128)) upward
tempint = getangle(128, horiz-100);
xvect = -((mousy*
((int32_t)sintable[(ang+2560)&2047]>>6)*
((int32_t)sintable[(tempint+512)&2047])>>6)
<<pk_uedaccel);
yvect = -((mousy*
((int32_t)sintable[(ang+2048)&2047]>>6)*
((int32_t)sintable[(tempint+512)&2047])>>6)
<<pk_uedaccel);
pos.z += mousy*(((int32_t)sintable[(tempint+2048)&2047])>>(10-pk_uedaccel));
move_and_update(xvect, yvect, 2);
}
}
if (mskip)
{
// mskip was set in astub.c to not trigger UEd mouse movements.
// Reset now.
mskip = 0;
}
else
{
if (mlook && (unrealedlook==0 || (bstatus&(1|4))==0))
{
ang += mousx;
horiz -= mousy;
/*
if (mousy && !(mousy/4))
horiz--;
if (mousx && !(mousx/2))
ang++;
*/
bclamp(&horiz, -99, 299);
if (mlook == 1)
{
searchx = xdim>>1;
searchy = ydim>>1;
}
osearchx = searchx-mousx;
osearchy = searchy-mousy;
}
else if (unrealedlook==0 || (bstatus&(1|2|4))==0)
{
osearchx = searchx;
osearchy = searchy;
searchx += mousx;
searchy += mousy;
bclamp(&searchx, 12, xdim-13);
bclamp(&searchy, 12, ydim-13);
}
}
// showmouse();
if (keystatus[0x43]) // F9
{
if (mhk)
{
Bmemset(spriteext, 0, sizeof(spriteext_t) * MAXSPRITES);
Bmemset(spritesmooth, 0, sizeof(spritesmooth_t) * (MAXSPRITES+MAXUNIQHUDID));
delete_maphack_lights();
mhk = 0;
message("Maphacks disabled");
}
else
{
mhk = 1;
loadmhk(1);
}
keystatus[0x43] = 0;
}
mainloop_move();
getzrange(&pos,cursectnum, &hiz,&hihit, &loz,&lohit, 128,CLIPMASK0);
oposz = pos.z;
if (zmode == 0)
{
goalz = loz-(kensplayerheight<<8); //playerheight pixels above floor
if (goalz < hiz+(16<<8)) //ceiling&floor too close
goalz = (loz+hiz)>>1;
goalz += mousz;
if (DOWN_BK(MOVEUP)) //A (stand high)
{
goalz -= (16<<8);
if (DOWN_BK(RUN))
goalz -= (24<<8);
}
if (DOWN_BK(MOVEDOWN)) //Z (stand low)
{
goalz += (12<<8);
if (DOWN_BK(RUN))
goalz += (12<<8);
}
if (goalz != pos.z)
{
if (pos.z < goalz) hvel += 64;
if (pos.z > goalz) hvel = ((goalz-pos.z)>>3);
pos.z += hvel;
if (pos.z > loz-(4<<8)) pos.z = loz-(4<<8), hvel = 0;
if (pos.z < hiz+(4<<8)) pos.z = hiz+(4<<8), hvel = 0;
}
}
else
{
goalz = pos.z;
if (DOWN_BK(MOVEUP)) //A
{
if (eitherCTRL)
{
horiz = max(-100,horiz-((DOWN_BK(RUN)+1)*synctics*2));
}
else
{
if (zmode != 1)
goalz -= (8<<8);
else
{
zlock += (4<<8);
DOWN_BK(MOVEUP) = 0;
}
}
}
if (DOWN_BK(MOVEDOWN)) //Z (stand low)
{
if (eitherCTRL)
{
horiz = min(300,horiz+((DOWN_BK(RUN)+1)*synctics*2));
}
else
{
if (zmode != 1)
goalz += (8<<8);
else if (zlock > 0)
{
zlock -= (4<<8);
DOWN_BK(MOVEDOWN) = 0;
}
}
}
if (!noclip)
bclamp(&goalz, hiz+(4<<8), loz-(4<<8));
if (zmode == 1) goalz = loz-zlock;
if (!noclip && (goalz < hiz+(4<<8)))
goalz = ((loz+hiz)>>1); //ceiling&floor too close
if (zmode == 1) pos.z = goalz;
if (goalz != pos.z)
{
//if (pos.z < goalz) hvel += (32<<DOWN_BK(RUN));
//if (pos.z > goalz) hvel -= (32<<DOWN_BK(RUN));
if (pos.z < goalz)
hvel = ((192*synctics)<<DOWN_BK(RUN));
else
hvel = -((192*synctics)<<DOWN_BK(RUN));
pos.z += hvel;
if (!noclip)
{
if (pos.z > loz-(4<<8)) pos.z = loz-(4<<8), hvel = 0;
if (pos.z < hiz+(4<<8)) pos.z = hiz+(4<<8), hvel = 0;
}
}
else
hvel = 0;
}
{
int16_t ocursectnum = cursectnum;
updatesectorz(pos.x,pos.y,pos.z, &cursectnum);
if (cursectnum<0)
{
if (zmode != 2)
pos.z = oposz; // don't allow to fall into infinity when in void space
cursectnum = ocursectnum;
}
}
searchit = 2;
if (searchstat >= 0)
{
if ((bstatus&(1|2|4)) || keystatus[0x39]) // SPACE
searchit = 0;
if (keystatus[0x1f]) //S (insert sprite) (3D)
{
hitdata_t hitinfo;
dax = 16384;
day = divscale14(searchx-(xdim>>1), xdim>>1);
rotatepoint(0,0, dax,day, ang, &dax,&day);
hitscan((const vec3_t *)&pos,cursectnum, //Start position
dax,day,(scale(searchy,200,ydim)-horiz)*2000, //vector of 3D ang
&hitinfo,CLIPMASK1);
if (hitinfo.hitsect >= 0)
{
dax = hitinfo.pos.x;
day = hitinfo.pos.y;
if (gridlock && grid > 0)
{
if (searchstat == 0 || searchstat == 4)
hitinfo.pos.z &= 0xfffffc00;
else
locktogrid(&dax, &day);
}
i = insert_sprite_common(hitinfo.hitsect, dax, day);
if (i < 0)
message("Couldn't insert sprite.");
else
{
int32_t cz, fz;
if (somethingintab == 3)
{
sprite[i].picnum = temppicnum;
if (tilesizx[temppicnum] <= 0 || tilesizy[temppicnum] <= 0)
{
j = 0;
for (k=0; k<MAXTILES; k++)
if (tilesizx[k] > 0 && tilesizy[k] > 0)
{
j = k;
break;
}
sprite[i].picnum = j;
}
sprite[i].shade = tempshade;
sprite[i].pal = temppal;
sprite[i].xrepeat = max(tempxrepeat, 1);
sprite[i].yrepeat = max(tempyrepeat, 1);
sprite[i].cstat = tempcstat;
}
getzsofslope(hitinfo.hitsect, hitinfo.pos.x, hitinfo.pos.y, &cz, &fz);
j = spriteheight(i, NULL)>>1;
sprite[i].z = hitinfo.pos.z;
if ((sprite[i].cstat&48)!=32)
{
if ((sprite[i].cstat&128) == 0)
bclamp(&sprite[i].z, cz+(j<<1), fz);
else
bclamp(&sprite[i].z, cz+j, fz-j);
}
if (searchstat == 0 || searchstat == 4)
{
sprite[i].cstat &= ~48;
sprite[i].cstat |= (16+64);
correct_ornamented_sprite(i, hitinfo.hitwall);
}
else
sprite[i].cstat |= (tilesizy[sprite[i].picnum]>=32);
correct_sprite_yoffset(i);
updatenumsprites();
asksave = 1;
VM_OnEvent(EVENT_INSERTSPRITE3D, i);
}
}
keystatus[0x1f] = 0;
}
if (keystatus[0x3f]||keystatus[0x40]) //F5,F6
{
switch (searchstat)
{
case 1:
case 2:
ExtShowSectorData(searchsector); break;
case 0:
case 4:
ExtShowWallData(searchwall); break;
case 3:
ExtShowSpriteData(searchwall); break;
}
keystatus[0x3f] = keystatus[0x40] = 0;
}
if (keystatus[0x41]||keystatus[0x42]) //F7,F8
{
switch (searchstat)
{
case 1:
case 2:
ExtEditSectorData(searchsector); break;
case 0:
case 4:
ExtEditWallData(searchwall); break;
case 3:
ExtEditSpriteData(searchwall); break;
}
keystatus[0x41] = keystatus[0x42] = 0;
}
}
if (keystatus[buildkeys[BK_MODE2D_3D]]) // Enter
{
vid_gamma_3d = vid_gamma;
vid_contrast_3d = vid_contrast;
vid_brightness_3d = vid_brightness;
vid_gamma = vid_contrast = 1.0;
vid_brightness = 0.0;
setbrightness(0,0,0);
keystatus[buildkeys[BK_MODE2D_3D]] = 0;
overheadeditor();
keystatus[buildkeys[BK_MODE2D_3D]] = 0;
vid_gamma = vid_gamma_3d;
vid_contrast = vid_contrast_3d;
vid_brightness = vid_brightness_3d;
vid_gamma_3d = vid_contrast_3d = vid_brightness_3d = -1;
setbrightness(GAMMA_CALC,0,0);
}
}
char changechar(char dachar, int32_t dadir, char smooshyalign, char boundcheck)
{
if (dadir < 0)
{
if ((dachar > 0) || (boundcheck == 0))
{
dachar--;
if (smooshyalign > 0)
dachar = (dachar&0xf8);
}
}
else if (dadir > 0)
{
if ((dachar < 255) || (boundcheck == 0))
{
dachar++;
if (smooshyalign > 0)
{
if (dachar >= 256-8) dachar = 255;
else dachar = ((dachar+7)&0xf8);
}
}
}
return(dachar);
}
////////////////////// OVERHEADEDITOR //////////////////////
int32_t inside_editor(const vec3_t *pos, int32_t searchx, int32_t searchy, int32_t zoom,
int32_t x, int32_t y, int16_t sectnum)
{
if (!m32_sideview)
return inside(x, y, sectnum);
// if in side-view mode, use the screen coords instead
{
int32_t dst = MAXSECTORS+M32_FIXME_SECTORS-1, i, oi;
int32_t srcw=sector[sectnum].wallptr, dstw=MAXWALLS;
int32_t ret;
if (sector[sectnum].wallnum > M32_FIXME_WALLS)
return -1;
Bmemcpy(&sector[dst], &sector[sectnum], sizeof(sectortype));
sector[dst].wallptr = dstw;
Bmemcpy(&wall[dstw], &wall[srcw], sector[dst].wallnum*sizeof(walltype));
for (i=dstw, oi=srcw; i<dstw+sector[dst].wallnum; i++, oi++)
{
wall[i].point2 += dstw-srcw;
screencoords(&wall[i].x, &wall[i].y, wall[i].x-pos->x, wall[i].y-pos->y, zoom);
wall[i].y += getscreenvdisp(getflorzofslope(sectnum,wall[oi].x,wall[oi].y)-pos->z, zoom);
wall[i].x += halfxdim16;
wall[i].y += midydim16;
}
i = numsectors;
numsectors = dst+1;
ret = inside(searchx, searchy, dst);
numsectors = i;
return ret;
}
}
static inline void drawline16base(int32_t bx, int32_t by, int32_t x1, int32_t y1, int32_t x2, int32_t y2, char col)
{
drawline16(bx+x1, by+y1, bx+x2, by+y2, col);
}
void drawsmallabel(const char *text, char col, char backcol, int32_t dax, int32_t day, int32_t daz)
{
int32_t x1, y1, x2, y2;
screencoords(&dax,&day, dax-pos.x,day-pos.y, zoom);
if (m32_sideview)
day += getscreenvdisp(daz-pos.z, zoom);
x1 = halfxdim16+dax-(Bstrlen(text)<<1);
y1 = midydim16+day-4;
x2 = x1 + (Bstrlen(text)<<2)+2;
y2 = y1 + 7;
if ((x1 > 3) && (x2 < xdim) && (y1 > 1) && (y2 < ydim16))
{
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
// -2: out of mem
// 0: ok
static int32_t backup_highlighted_map(mapinfofull_t *mapinfo)
{
int32_t i, j, k, m, tmpnumwalls=0, tmpnumsprites=0;
if (highlightsectorcnt <= 0)
return -1;
// count walls & sprites
for (i=0; i<highlightsectorcnt; i++)
{
tmpnumwalls += sector[highlightsector[i]].wallnum;
m = headspritesect[highlightsector[i]];
while (m != -1)
{
tmpnumsprites++;
m = nextspritesect[m];
}
}
// allocate temp storage
mapinfo->sector = Bmalloc(highlightsectorcnt * sizeof(sectortype));
if (!mapinfo->sector) return -2;
mapinfo->wall = Bmalloc(tmpnumwalls * sizeof(walltype));
if (!mapinfo->wall) { Bfree(mapinfo->sector); return -2; }
if (tmpnumsprites>0)
{
mapinfo->sprite = Bmalloc(tmpnumsprites * sizeof(spritetype));
if (!mapinfo->sprite)
{
Bfree(mapinfo->sector);
Bfree(mapinfo->wall);
return -2;
}
}
// copy everything over
tmpnumwalls = 0;
tmpnumsprites = 0;
for (i=0; i<highlightsectorcnt; i++)
{
k = highlightsector[i];
Bmemcpy(&mapinfo->sector[i], &sector[k], sizeof(sectortype));
mapinfo->sector[i].wallptr = tmpnumwalls;
for (j=0; j<sector[k].wallnum; j++)
{
Bmemcpy(&mapinfo->wall[tmpnumwalls+j], &wall[sector[k].wallptr+j], sizeof(walltype));
mapinfo->wall[tmpnumwalls+j].point2 += (tmpnumwalls-sector[k].wallptr);
mapinfo->wall[tmpnumwalls+j].nextsector = -1;
mapinfo->wall[tmpnumwalls+j].nextwall = -1;
}
tmpnumwalls += j;
m = headspritesect[highlightsector[i]];
while (m != -1)
{
Bmemcpy(&mapinfo->sprite[tmpnumsprites], &sprite[m], sizeof(spritetype));
mapinfo->sprite[tmpnumsprites].sectnum = i;
m = nextspritesect[m];
tmpnumsprites++;
}
}
mapinfo->numsectors = highlightsectorcnt;
mapinfo->numwalls = tmpnumwalls;
mapinfo->numsprites = tmpnumsprites;
return 0;
}
static void mapinfofull_free(mapinfofull_t *mapinfo)
{
Bfree(mapinfo->sector);
Bfree(mapinfo->wall);
if (mapinfo->numsprites>0)
Bfree(mapinfo->sprite);
}
// restore map saved with backup_highlighted_map, also
// frees mapinfo's sector, wall, (sprite) in any case.
// return values:
// -1: limits exceeded
// 0: ok
static int32_t restore_highlighted_map(mapinfofull_t *mapinfo)
{
int32_t i, j, sect, onumsectors=numsectors, newnumsectors, newnumwalls;
updatenumsprites();
if (numsectors+mapinfo->numsectors>MAXSECTORS || numwalls+mapinfo->numwalls>MAXWALLS
|| numsprites+mapinfo->numsprites>MAXSPRITES)
{
mapinfofull_free(mapinfo);
return -1;
}
newnumsectors = numsectors + mapinfo->numsectors;
newnumwalls = numwalls + mapinfo->numwalls;
// copy sectors & walls
Bmemcpy(&sector[numsectors], mapinfo->sector, mapinfo->numsectors*sizeof(sectortype));
Bmemcpy(&wall[numwalls], mapinfo->wall, mapinfo->numwalls*sizeof(walltype));
// tweak index members
for (i=numsectors; i<newnumsectors; i++)
sector[i].wallptr += numwalls;
for (i=numwalls; i<newnumwalls; i++)
{
wall[i].point2 += numwalls;
wall[i].x += BXY_MAX*2;
}
// reconstruct wall connections
numsectors=newnumsectors; // needed now for checksectorpointer
// checksectorpointer_warn = 0;
Bmemset(hlsectorbitmap, 0, sizeof(hlsectorbitmap));
for (i=onumsectors; i<newnumsectors; i++)
{
for (j=sector[i].wallptr; j<sector[i].wallptr+sector[i].wallnum; j++)
checksectorpointer(j, i);
hlsectorbitmap[i>>3] |= (1<<(i&7));
}
for (i=numwalls; i<newnumwalls; i++)
wall[i].x -= BXY_MAX*2;
// checksectorpointer_warn = 1;
// insert sprites
for (i=0; i<mapinfo->numsprites; i++)
{
sect = onumsectors+mapinfo->sprite[i].sectnum;
j = insertsprite(sect, mapinfo->sprite[i].statnum);
Bmemcpy(&sprite[j], &mapinfo->sprite[i], sizeof(spritetype));
sprite[j].sectnum = sect;
}
numwalls = newnumwalls;
updatenumsprites();
update_highlightsector();
mapinfofull_free(mapinfo);
return 0;
}
static int32_t newnumwalls=-1;
static void ovh_whiteoutgrab()
{
int32_t i, j, k, startwall, endwall;
//White out all bordering lines of grab that are
//not highlighted on both sides
for (i=highlightsectorcnt-1; i>=0; i--)
{
startwall = sector[highlightsector[i]].wallptr;
endwall = startwall + sector[highlightsector[i]].wallnum;
for (j=startwall; j<endwall; j++)
{
if (wall[j].nextwall >= 0)
{
// for (k=highlightsectorcnt-1; k>=0; k--)
// if (highlightsector[k] == wall[j].nextsector)
// break;
k = wall[j].nextsector;
if ((hlsectorbitmap[k>>3]&(1<<(k&7)))==0)
// if (k < 0)
{
NEXTWALL(j).nextwall = -1;
NEXTWALL(j).nextsector = -1;
wall[j].nextwall = -1;
wall[j].nextsector = -1;
}
}
}
}
}
static void duplicate_selected_sectors()
{
int32_t i, j, startwall, endwall, newnumsectors, newwalls = 0;
int32_t minx=INT_MAX, maxx=INT_MIN, miny=INT_MAX, maxy=INT_MIN, dx, dy;
for (i=0; i<highlightsectorcnt; i++)
newwalls += sector[highlightsector[i]].wallnum;
if (highlightsectorcnt + numsectors <= MAXSECTORS && numwalls+newwalls <= MAXWALLS)
{
int16_t *oldtonewsect = Bmalloc(numsectors * sizeof(int16_t));
if (oldtonewsect)
{
for (i=0; i<numsectors; i++)
oldtonewsect[i] = -1;
for (i=0; i<highlightsectorcnt; i++)
oldtonewsect[highlightsector[i]] = numsectors+i;
}
else
message("warning: out of memory!");
newnumsectors = numsectors;
newnumwalls = numwalls;
for (i=0; i<highlightsectorcnt; i++)
{
copysector(highlightsector[i], newnumsectors, newnumwalls, 1, oldtonewsect);
newnumsectors++;
newnumwalls += sector[highlightsector[i]].wallnum;
}
if (oldtonewsect)
Bfree(oldtonewsect);
Bmemset(hlsectorbitmap, 0, sizeof(hlsectorbitmap));
for (i=0; i<highlightsectorcnt; i++)
{
// first, make red lines of old selected sectors, effectively
// restoring the original state
for (WALLS_OF_SECTOR(highlightsector[i], j))
{
if (wall[j].nextwall >= 0)
checksectorpointer(wall[j].nextwall,wall[j].nextsector);
checksectorpointer(j, highlightsector[i]);
minx = min(minx, wall[j].x);
maxx = max(maxx, wall[j].x);
miny = min(miny, wall[j].y);
maxy = max(maxy, wall[j].y);
}
// Then, highlight the ones just copied.
// These will have all walls whited out.
j = numsectors + i;
hlsectorbitmap[j>>3] |= (1<<(j&7));
}
// displace walls of new sectors by a small amount
if (grid>0 && grid<9)
dx = max(2048>>grid, 128);
else
dx = 512;
dy = -dx;
if (maxx+dx >= editorgridextent) dx*=-1;
if (minx+dx <= -editorgridextent) dx*=-1;
if (maxy+dy >= editorgridextent) dy*=-1;
if (miny+dy <= -editorgridextent) dy*=-1;
for (i=numsectors; i<newnumsectors; i++)
{
for (j=sector[i].wallptr; j<sector[i].wallptr+sector[i].wallnum; j++)
{
wall[j].x += dx;
wall[j].y += dy;
}
for (j=headspritesect[i]; j>=0; j=nextspritesect[j])
{
sprite[j].x += dx;
sprite[j].y += dy;
}
}
numsectors = newnumsectors;
numwalls = newnumwalls;
update_highlightsector(); // must be after numsectors = newnumsectors
newnumwalls = -1;
newnumsectors = -1;
updatenumsprites();
printmessage16("Sectors duplicated and stamped.");
asksave = 1;
}
else
{
printmessage16("Copying sectors would exceed sector or wall limit.");
}
}
static void duplicate_selected_sprites()
{
int32_t i, j, k=0;
for (i=0; i<highlightcnt; i++)
k += ((highlight[i]&0xc000) == 16384);
if (highlightcnt + k <= MAXSPRITES)
{
for (i=0; i<highlightcnt; i++)
if ((highlight[i]&0xc000) == 16384)
{
//duplicate sprite
k = (highlight[i]&16383);
j = insertsprite(sprite[k].sectnum,sprite[k].statnum);
Bmemcpy(&sprite[j],&sprite[k],sizeof(spritetype));
// sprite[j].sectnum = sprite[k].sectnum; //Don't let memcpy overwrite sector!
// setsprite(j,(vec3_t *)&sprite[j]);
}
updatenumsprites();
printmessage16("Sprites duplicated and stamped.");
asksave = 1;
}
else
{
printmessage16("Copying sprites would exceed sprite limit.");
}
}
static void correct_ornamented_sprite(int32_t i, int32_t hitw)
{
int32_t j;
if (hitw >= 0)
sprite[i].ang = (getangle(POINT2(hitw).x-wall[hitw].x,
POINT2(hitw).y-wall[hitw].y)+512)&2047;
//Make sure sprite's in right sector
if (inside(sprite[i].x, sprite[i].y, sprite[i].sectnum) == 0)
{
j = wall[hitw].point2;
sprite[i].x -= ksgn(wall[j].y-wall[hitw].y);
sprite[i].y += ksgn(wall[j].x-wall[hitw].x);
}
}
void DoSpriteOrnament(int32_t i)
{
hitdata_t hitinfo;
hitscan((const vec3_t *)&sprite[i],sprite[i].sectnum,
sintable[(sprite[i].ang+1536)&2047],
sintable[(sprite[i].ang+1024)&2047],
0,
&hitinfo,CLIPMASK1);
sprite[i].x = hitinfo.pos.x;
sprite[i].y = hitinfo.pos.y;
sprite[i].z = hitinfo.pos.z;
changespritesect(i, hitinfo.hitsect);
correct_ornamented_sprite(i, hitinfo.hitwall);
}
void update_highlight()
{
int32_t i;
highlightcnt = 0;
for (i=0; i<numwalls; i++)
if (show2dwall[i>>3]&(1<<(i&7)))
highlight[highlightcnt++] = i;
for (i=0; i<MAXSPRITES; i++)
if (sprite[i].statnum < MAXSTATUS)
{
if (show2dsprite[i>>3]&(1<<(i&7)))
highlight[highlightcnt++] = i+16384;
}
else
show2dsprite[i>>3] &= ~(1<<(i&7));
if (highlightcnt == 0)
highlightcnt = -1;
}
void update_highlightsector()
{
int32_t i;
highlightsectorcnt = 0;
for (i=0; i<numsectors; i++)
if (hlsectorbitmap[i>>3]&(1<<(i&7)))
highlightsector[highlightsectorcnt++] = i;
if (highlightsectorcnt==0)
highlightsectorcnt = -1;
}
// hook run after handleevents in side view
static void sideview_filter_keys(void)
{
uint32_t i;
for (i=0; i<sizeof(keystatus)/sizeof(keystatus[0]); i++)
{
switch (i)
{
case 0xd2: case 0xd3: // ins, del
case 0x2e: case 0x39: // c, space
// case 0xb8: // ralt
keystatus[i] = 0;
break;
}
}
}
void m32_setkeyfilter(int32_t on)
{
if (m32_sideview && on)
{
after_handleevents_hook = &sideview_filter_keys;
clearkeys();
}
else
after_handleevents_hook = 0;
}
// Get average point of sectors
static void get_sectors_center(const int16_t *sectors, int32_t numsecs, int32_t *cx, int32_t *cy)
{
int32_t i, j, k=0, dax = 0, day = 0;
int32_t startwall, endwall;
for (i=0; i<numsecs; i++)
{
for (WALLS_OF_SECTOR(sectors[i], j))
{
dax += wall[j].x;
day += wall[j].y;
k++;
}
}
if (k > 0)
{
dax /= k;
day /= k;
}
*cx = dax;
*cy = day;
}
static int32_t insert_sprite_common(int32_t sucksect, int32_t dax, int32_t day)
{
int32_t i, j, k;
i = insertsprite(sucksect,0);
if (i < 0)
return -1;
sprite[i].x = dax, sprite[i].y = day;
sprite[i].cstat = DEFAULT_SPRITE_CSTAT;
sprite[i].shade = 0;
sprite[i].pal = 0;
sprite[i].xrepeat = 64, sprite[i].yrepeat = 64;
sprite[i].xoffset = 0, sprite[i].yoffset = 0;
sprite[i].ang = 1536;
sprite[i].xvel = 0; sprite[i].yvel = 0; sprite[i].zvel = 0;
sprite[i].owner = -1;
sprite[i].clipdist = 32;
sprite[i].lotag = 0;
sprite[i].hitag = 0;
sprite[i].extra = -1;
Bmemset(localartfreq, 0, sizeof(localartfreq));
for (k=0; k<MAXSPRITES; k++)
localartfreq[sprite[k].picnum] += (sprite[k].statnum < MAXSTATUS);
j = 0;
for (k=0; k<MAXTILES; k++)
if (localartfreq[k] > localartfreq[j])
j = k;
if (localartfreq[j] > 0)
sprite[i].picnum = j;
else
sprite[i].picnum = 0;
return i;
}
void correct_sprite_yoffset(int32_t i)
{
int32_t tileyofs = (int8_t)((picanm[sprite[i].picnum]>>16)&255);
int32_t tileysiz = tilesizy[sprite[i].picnum];
if (klabs(tileyofs) >= tileysiz)
{
tileyofs *= -1;
if (tileyofs == 128)
tileyofs = 127;
sprite[i].yoffset = tileyofs;
}
else
sprite[i].yoffset = 0;
}
static void fade_screen()
{
char blackcol=editorcolors[0], greycol=whitecol-25, *cp;
int32_t i;
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);
}
static void copy_some_wall_members(int16_t dst, int16_t src)
{
// x y p2 nw ns cs p op sh pl xr yr xp yp lo hi ex
static const walltype nullwall = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, -1 };
walltype *dstwal=&wall[dst];
const walltype *srcwal = src >= 0 ? &wall[src] : &nullwall;
dstwal->cstat = srcwal->cstat;
dstwal->shade = srcwal->shade;
dstwal->yrepeat = srcwal->yrepeat;
fixrepeats(dst); // xrepeat
dstwal->picnum = srcwal->picnum;
dstwal->overpicnum = srcwal->overpicnum;
dstwal->nextwall = -1;
dstwal->nextsector = -1;
dstwal->pal = srcwal->pal;
dstwal->xpanning = srcwal->xpanning;
dstwal->ypanning = srcwal->ypanning;
dstwal->lotag = 0; //srcwal->lotag;
dstwal->hitag = 0; //srcwal->hitag;
dstwal->extra = -1; //srcwal->extra;
}
// helpers for often needed ops:
static int32_t do_while_copyloop1(int16_t startwall, int16_t endwall,
int16_t *danumwalls, int16_t lastpoint2)
{
int32_t m = startwall;
do
{
if (*danumwalls >= MAXWALLS + M32_FIXME_WALLS)
return 1;
Bmemcpy(&wall[*danumwalls], &wall[m], sizeof(walltype));
wall[*danumwalls].point2 = *danumwalls+1;
(*danumwalls)++;
m = wall[m].point2;
}
while (m != endwall);
if (lastpoint2 >= 0)
wall[(*danumwalls)-1].point2 = lastpoint2;
return 0;
}
static void updatesprite1(int16_t i)
{
setsprite(i, (vec3_t *)&sprite[i]);
if (sprite[i].sectnum>=0)
{
int32_t tempint, cz, fz;
tempint = spriteheight(i, NULL);
if (sprite[i].cstat&128)
tempint >>= 1;
getzsofslope(sprite[i].sectnum, sprite[i].x, sprite[i].y, &cz, &fz);
sprite[i].z = max(sprite[i].z, cz+tempint);
sprite[i].z = min(sprite[i].z, fz);
}
}
static int32_t ask_if_sure(const char *query, uint32_t flags);
#ifdef YAX_ENABLE
static int32_t ask_above_or_below();
#endif
// returns:
// 0: continue
// >0: newnumwalls
// <0: error
static int32_t trace_loop(int32_t j, uint8_t *visitedwall, int16_t *ignore_ret, int16_t *refsect_ret)
{
int16_t refsect, ignore;
int32_t k, n, refwall;
if (wall[j].nextwall>=0 || (visitedwall[j>>3]&(1<<(j&7))))
return 0;
n=2*MAXWALLS; // simple inf loop check
refwall = j;
k = numwalls;
ignore = 0;
if (ignore_ret)
{
refsect = -1;
updatesectorexclude(wall[j].x, wall[j].y, &refsect, hlsectorbitmap);
if (refsect<0)
return -1;
}
do
{
if (j!=refwall && visitedwall[j>>3]&(1<<(j&7)))
ignore = 1;
visitedwall[j>>3] |= (1<<(j&7));
if (ignore_ret)
{
if (inside(wall[j].x, wall[j].y, refsect) != 1)
ignore = 1;
}
if (!ignore)
{
if (k>=MAXWALLS)
{
message("Wall limits exceeded while tracing outer loop.");
return -2;
}
Bmemcpy(&wall[k], &wall[j], sizeof(walltype));
wall[k].point2 = k+1;
wall[k].nextsector = wall[k].nextwall = wall[k].extra = -1;
k++;
}
j = wall[j].point2;
n--;
while (wall[j].nextwall>=0 && n>0)
{
j = wall[wall[j].nextwall].point2;
// if (j!=refwall && (visitedwall[j>>3]&(1<<(j&7))))
// ignore = 1;
// visitedwall[j>>3] |= (1<<(j&7));
n--;
}
}
while (j!=refwall && n>0);
if (j!=refwall)
{
message("internal error while tracing outer loop: didn't reach refwall");
return -3;
}
if (ignore_ret)
{
*ignore_ret = ignore;
if (refsect_ret)
*refsect_ret = refsect;
}
return k;
}
static int32_t backup_drawn_walls(int32_t restore)
{
static int32_t wallsdrawn = -1;
static walltype *tmpwall;
// back up
if (restore==0)
{
if (newnumwalls == -1)
{
wallsdrawn = -1;
}
else
{
wallsdrawn = newnumwalls-numwalls;
tmpwall = Bmalloc(wallsdrawn * sizeof(walltype));
if (!tmpwall)
{
wallsdrawn = -1;
return 1;
}
Bmemcpy(tmpwall, &wall[numwalls], wallsdrawn*sizeof(walltype));
newnumwalls = -1;
}
return 0;
}
// restore
if (wallsdrawn != -1)
{
int32_t i;
Bmemcpy(&wall[numwalls], tmpwall, wallsdrawn*sizeof(walltype));
newnumwalls = numwalls + wallsdrawn;
for (i=numwalls; i<newnumwalls; i++)
wall[i].point2 = i+1;
Bfree(tmpwall);
tmpwall = NULL;
}
return 0;
}
#define GETWALCOORD(w) (*(int64_t *)&wall[*(const int32_t *)(w)].x)
static int32_t compare_wall_coords(const void *w1, const void *w2)
{
if (GETWALCOORD(w1) == GETWALCOORD(w2))
return 0;
if (GETWALCOORD(w1) > GETWALCOORD(w2))
return 1;
return -1;
}
#undef GETWALCOORD
#define RESET_EDITOR_VARS() do { \
sectorhighlightstat = -1; \
newnumwalls = -1; \
joinsector[0] = -1; \
circlewall = -1; \
circlepoints = 7; \
} while (0)
void overheadeditor(void)
{
char buffer[80], *dabuffer, ch;
int32_t i, j, k, m=0, mousxplc, mousyplc, firstx=0, firsty=0, oposz, col;
int32_t tempint, tempint1, tempint2;
int32_t startwall=0, endwall, dax, day, x1, y1, x2, y2, x3, y3, x4, y4;
int32_t highlightx1, highlighty1, highlightx2, highlighty2;
int16_t pag, suckwall=0, sucksect, split=0, bad;
int16_t splitsect=0, joinsector[2];
int16_t splitstartwall=0;
int32_t mousx, mousy, bstatus;
int32_t centerx, centery, circlerad;
int16_t circlepoints, circleang1, circleang2, circleangdir;
int32_t sectorhighlightx=0, sectorhighlighty=0;
int16_t cursectorhighlight, sectorhighlightstat;
walltype *wal;
int32_t prefixarg = 0;
int32_t resetsynctics = 0, lasttick=getticks(), waitdelay=totalclock, lastdraw=getticks();
int32_t tsign;
m32_setkeyfilter(1);
//qsetmode640480();
qsetmodeany(xdim2d,ydim2d);
xdim2d = xdim;
ydim2d = ydim;
osearchx = searchx;
osearchy = searchy;
searchx = clamp(scale(searchx,xdim2d,xdimgame), 8, xdim2d-8-1);
searchy = clamp(scale(searchy,ydim2d-STATUS2DSIZ2,ydimgame), 8, ydim2d-STATUS2DSIZ-8-1);
oposz = pos.z;
begindrawing(); //{{{
CLEARLINES2D(0, ydim, 0);
enddrawing(); //}}}
ydim16 = ydim-STATUS2DSIZ2;
pag = 0;
cursectorhighlight = -1;
lastpm16time = -1;
update_highlightsector();
ovh_whiteoutgrab();
highlightcnt = -1;
Bmemset(show2dwall, 0, sizeof(show2dwall)); //Clear all highlights
Bmemset(show2dsprite, 0, sizeof(show2dsprite));
RESET_EDITOR_VARS();
bstatus = 0;
while ((keystatus[buildkeys[BK_MODE2D_3D]]>>1) == 0)
{
if (!((vel|angvel|svel) //DOWN_BK(MOVEFORWARD) || DOWN_BK(MOVEBACKWARD) || DOWN_BK(TURNLEFT) || DOWN_BK(TURNRIGHT)
|| DOWN_BK(MOVEUP) || DOWN_BK(MOVEDOWN) || keystatus[0x10] || keystatus[0x11]
|| keystatus[0x48] || keystatus[0x4b] || keystatus[0x4d] || keystatus[0x50] // keypad keys
|| bstatus || OSD_IsMoving()))
{
if (totalclock > waitdelay)
{
uint32_t ms = (highlightsectorcnt>0) ? 75 : 200;
// wait for event, timeout after 200 ms - (last loop time)
idle_waitevent_timeout(ms - min(getticks()-lasttick, ms));
// have synctics reset to 0 after we've slept to avoid zooming out to the max instantly
resetsynctics = 1;
}
}
else waitdelay = totalclock + 30; // should be 250 ms
lasttick = getticks();
if (handleevents())
{
if (quitevent)
{
keystatus[1] = 1;
quitevent = 0;
}
}
if (resetsynctics)
{
resetsynctics = 0;
lockclock = totalclock;
synctics = 0;
}
OSD_DispatchQueued();
if (totalclock < 120*3)
printmessage16("Uses BUILD technology by Ken Silverman.");
else if (totalclock < 120*6)
{
printmessage16("Press F1 for help. This is a test release; always keep backups of your maps.");
// printext16(8L,ydim-STATUS2DSIZ+32L,editorcolors[9],-1,kensig,0);
}
oldmousebstatus = bstatus;
getmousevalues(&mousx,&mousy,&bstatus);
mousx = (mousx<<16)+mousexsurp;
mousy = (mousy<<16)+mouseysurp;
{
ldiv_t ld;
ld = ldiv(mousx, 1<<16); mousx = ld.quot; mousexsurp = ld.rem;
ld = ldiv(mousy, 1<<16); mousy = ld.quot; mouseysurp = ld.rem;
}
searchx += mousx;
searchy += mousy;
bclamp(&searchx, 8, xdim-8-1);
bclamp(&searchy, 8, ydim-8-1);
mainloop_move();
getpoint(searchx,searchy,&mousxplc,&mousyplc);
linehighlight = getlinehighlight(mousxplc, mousyplc, linehighlight);
if (newnumwalls >= numwalls)
{
// if we're in the process of drawing a wall, set the end point's coordinates
dax = mousxplc;
day = mousyplc;
adjustmark(&dax,&day,newnumwalls);
wall[newnumwalls].x = dax;
wall[newnumwalls].y = day;
}
ydim16 = ydim;// - STATUS2DSIZ2;
midydim16 = ydim>>1;
tempint = numwalls;
numwalls = newnumwalls;
if (numwalls < 0)
numwalls = tempint;
if ((getticks() - lastdraw) >= 5 || (vel|angvel|svel) || DOWN_BK(MOVEUP) || DOWN_BK(MOVEDOWN)
|| mousx || mousy || bstatus || keystatus[0x10] || keystatus[0x11]
|| newnumwalls>=0 || OSD_IsMoving())
{
lastdraw = getticks();
clear2dscreen();
setup_sideview_sincos();
if (graphicsmode && !m32_sideview)
{
Bmemset(show2dsector, 0xff, sizeof(show2dsector));
setview(0, 0, xdim-1, ydim16-1);
if (graphicsmode == 2)
totalclocklock = totalclock;
drawmapview(pos.x, pos.y, zoom, 1536);
}
draw2dgrid(pos.x,pos.y,pos.z,cursectnum,ang,zoom,grid);
ExtPreCheckKeys();
{
int32_t cx, cy;
// Draw brown arrow (start)
screencoords(&x2, &y2, startposx-pos.x,startposy-pos.y, zoom);
if (m32_sideview)
y2 += getscreenvdisp(startposz-pos.z, zoom);
cx = halfxdim16+x2;
cy = midydim16+y2;
if ((cx >= 2 && cx <= xdim-3) && (cy >= 2 && cy <= ydim16-3))
{
int16_t angofs = m32_sideview ? m32_sideang : 0;
x1 = mulscale11(sintable[(startang+angofs+2560)&2047],zoom) / 768;
y1 = mulscale11(sintable[(startang+angofs+2048)&2047],zoom) / 768;
i = scalescreeny(x1);
j = scalescreeny(y1);
begindrawing(); //{{{
drawline16base(cx,cy, x1,j, -x1,-j, editorcolors[2]);
drawline16base(cx,cy, x1,j, +y1,-i, editorcolors[2]);
drawline16base(cx,cy, x1,j, -y1,+i, editorcolors[2]);
enddrawing(); //}}}
}
}
draw2dscreen(&pos,cursectnum,ang,zoom,grid);
begindrawing(); //{{{
if (showtags == 1)
{
if (zoom >= 768)
{
for (i=0; i<numsectors; i++)
{
int16_t secshort = i;
dabuffer = (char *)ExtGetSectorCaption(i);
if (dabuffer[0] == 0)
continue;
get_sectors_center(&secshort, 1, &dax, &day);
drawsmallabel(dabuffer, editorcolors[0], editorcolors[7],
dax, day, getflorzofslope(i,dax,day));
}
}
x3 = pos.x + divscale14(-halfxdim16,zoom);
y3 = pos.y + divscale14(-(midydim16-4),zoom);
x4 = pos.x + divscale14(halfxdim16,zoom);
y4 = pos.y + divscale14(ydim16-(midydim16-4),zoom);
if (newnumwalls >= 0)
{
for (i=newnumwalls; i>=tempint; i--)
wall[i].cstat |= (1<<14);
}
i = numwalls-1;
if (newnumwalls >= 0)
i = newnumwalls-1;
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;
if ((dax > x3) && (dax < x4) && (day > y3) && (day < y4))
{
dabuffer = (char *)ExtGetWallCaption(i);
if (dabuffer[0] == 0)
continue;
drawsmallabel(dabuffer, editorcolors[0], editorcolors[31],
dax, day, getflorzofslope(sectorofwall(i), dax,day));
}
}
i = 0; j = numsprites; k=0;
if (zoom >= 768)
while (j > 0 && i < MAXSPRITES && (!m32_sideview || k<m32_swcnt))
{
if (m32_sideview)
{
i = m32_wallsprite[k++];
if (i<MAXWALLS)
continue;
i = i-MAXWALLS;
}
if (sprite[i].statnum < MAXSTATUS)
{
dabuffer = (char *)ExtGetSpriteCaption(i);
if (dabuffer[0] != 0)
{
int32_t blocking = (sprite[i].cstat&1);
col = 3 + 2*blocking;
if (spritecol2d[sprite[i].picnum][blocking])
col = spritecol2d[sprite[i].picnum][blocking];
if ((i == pointhighlight-16384) && (totalclock & 32))
col += (2<<2);
drawsmallabel(dabuffer, editorcolors[0], editorcolors[col],
sprite[i].x, sprite[i].y, sprite[i].z);
}
j--;
}
i++;
}
}
// stick this event right between begin- end enddrawing()...
// also after the above label stuff so users can redefine them
VM_OnEvent(EVENT_DRAW2DSCREEN, -1);
printcoords16(pos.x,pos.y,ang);
numwalls = tempint;
if (highlightsectorcnt >= 0)
{
int32_t oydim16 = ydim16;
ydim16 = ydim-STATUS2DSIZ2;
for (i=0; i<numsectors; i++)
if (hlsectorbitmap[i>>3]&(1<<(i&7)))
fillsector(i,2);
ydim16 = oydim16;
}
if (keystatus[0x2a]) // FIXME
{
drawlinepat = 0x00ff00ff;
drawline16(searchx,0, searchx,ydim2d-1, editorcolors[15]);
drawline16(0,searchy, xdim2d-1,searchy, editorcolors[15]);
drawlinepat = 0xffffffff;
_printmessage16("(%d,%d)",mousxplc,mousyplc);
#if 0
i = (Bstrlen(tempbuf)<<3)+6;
if ((searchx+i) < (xdim2d-1))
i = 0;
else i = (searchx+i)-(xdim2d-1);
if ((searchy+16) < (ydim2d-STATUS2DSIZ2-1))
j = 0;
else j = (searchy+16)-(ydim2d-STATUS2DSIZ2-1);
printext16(searchx+6-i,searchy+6-j,editorcolors[11],-1,tempbuf,0);
#endif
}
drawline16(searchx,0, searchx,8, editorcolors[15]);
drawline16(0,searchy, 8,searchy, editorcolors[15]);
////// draw mouse pointer
col = editorcolors[15 - 3*gridlock];
if (joinsector[0] >= 0)
col = editorcolors[11];
if (numcorruptthings>0)
{
static char cbuf[64];
if ((pointhighlight&16384)==0)
{
for (i=0; i<numcorruptthings; i++)
if ((corruptthings[i]&CORRUPT_MASK)==CORRUPT_WALL &&
(corruptthings[i]&(MAXWALLS-1))==pointhighlight)
{
col = editorcolors[13];
printext16(searchx+6,searchy-6-8,editorcolors[13],editorcolors[0],"corrupt wall",0);
break;
}
}
Bsprintf(cbuf, "Map corrupt (level %d): %s%d errors", corruptlevel,
numcorruptthings>=MAXCORRUPTTHINGS ? ">=":"", numcorruptthings);
printext16(8,8, editorcolors[13],editorcolors[0],cbuf,0);
}
if (keystatus[0x36] || keystatus[0xb8]) // RSHIFT || RALT
{
if (keystatus[0x27] || keystatus[0x28]) // ' and ;
{
col = editorcolors[14];
drawline16base(searchx+16, searchy-16, -4,0, +4,0, col);
if (keystatus[0x28])
drawline16base(searchx+16, searchy-16, 0,-4, 0,+4, col);
}
if (keystatus[0x36] && eitherCTRL)
printext16(searchx+6,searchy-6-8,editorcolors[12],-1,"S",0);
}
drawline16base(searchx,searchy, +0,-8, +0,-1, col);
drawline16base(searchx,searchy, +1,-8, +1,-1, col);
drawline16base(searchx,searchy, +0,+2, +0,+9, col);
drawline16base(searchx,searchy, +1,+2, +1,+9, col);
drawline16base(searchx,searchy, -8,+0, -1,+0, col);
drawline16base(searchx,searchy, -8,+1, -1,+1, col);
drawline16base(searchx,searchy, +2,+0, +9,+0, col);
drawline16base(searchx,searchy, +2,+1, +9,+1, col);
////// Draw the white pixel closest to mouse cursor on linehighlight
if (linehighlight>=0 && !m32_sideview)
{
getclosestpointonwall(mousxplc,mousyplc, linehighlight, &dax,&day);
x2 = mulscale14(dax-pos.x,zoom);
y2 = mulscale14(day-pos.y,zoom);
drawline16base(halfxdim16+x2,midydim16+y2, 0,0, 0,0,
wall[linehighlight].nextsector >= 0 ? editorcolors[15] : editorcolors[5]);
}
enddrawing(); //}}}
OSD_Draw();
}
VM_OnEvent(EVENT_PREKEYS2D, -1);
ExtCheckKeys(); // TX 20050101, it makes more sense to have this here so keys can be overwritten with new functions in bstub.c
// Flip/mirror sector Ed Coolidge
if (keystatus[0x2d] || keystatus[0x15]) // X or Y (2D)
{
int32_t about_x=keystatus[0x2d];
int32_t doMirror = eitherALT; // mirror walls and wall/floor sprites
if (highlightsectorcnt > 0)
{
keystatus[0x2d] = keystatus[0x15] = 0;
get_sectors_center(highlightsector, highlightsectorcnt, &dax, &day);
if (gridlock && grid > 0)
locktogrid(&dax, &day);
for (i=0; i<highlightsectorcnt; i++)
{
int32_t startofloop, endofloop;
int32_t numtoswap = -1;
int32_t w=0;
walltype tempwall;
startofloop = startwall = sector[highlightsector[i]].wallptr;
endofloop = endwall = startwall+sector[highlightsector[i]].wallnum-1;
#if 0
if (doMirror)
{
//mirror sector textures
sector[highlightsector[i]].ceilingstat ^= 0x10;
sector[highlightsector[i]].floorstat ^= 0x10;
}
#endif
//save position of wall at start of loop
x3 = wall[startofloop].x;
y3 = wall[startofloop].y;
for (j=startwall; j<=endwall; j++)
{
//fix position of walls
if (about_x)
{
wall[j].x = dax-POINT2(j).x+dax; //flip wall.x about dax
wall[j].y = POINT2(j).y;
}
else
{
wall[j].x = POINT2(j).x;
wall[j].y = day-POINT2(j).y+day; //flip wall.y about day
}
if (doMirror)
wall[j].cstat ^= 8; //mirror walls about dax/day
if (wall[j].point2==startofloop) //check if j is end of loop
{
endofloop = j;
if (about_x)
{
wall[endofloop].x = dax-x3+dax; //flip wall.x about dax
wall[endofloop].y = y3;
}
else
{
wall[endofloop].x = x3;
wall[endofloop].y = day-y3+day; //flip wall.y about dax
}
//correct order of walls in loop to maintain player space (right-hand rule)
numtoswap = (endofloop-startofloop)>>1;
for (w=1; w<=numtoswap; w++)
{
Bmemcpy(&tempwall, &wall[startofloop+w], sizeof(walltype));
Bmemcpy(&wall[startofloop+w], &wall[endofloop-w+1], sizeof(walltype));
Bmemcpy(&wall[endofloop-w+1], &tempwall, sizeof(walltype));
}
//make point2 point to next wall in loop
for (w=startofloop; w<endofloop; w++)
wall[w].point2 = w+1;
wall[endofloop].point2 = startofloop;
startofloop = endofloop+1; //set first wall of next loop
//save position of wall at start of loop
x3 = wall[startofloop].x;
y3 = wall[startofloop].y;
}
}
j = headspritesect[highlightsector[i]];
while (j != -1)
{
if (about_x)
{
x3 = sprite[j].x;
sprite[j].x = dax-x3+dax; //flip sprite.x about dax
sprite[j].ang = (1024+2048-sprite[j].ang)&2047; //flip ang about 512
}
else
{
y3 = sprite[j].y;
sprite[j].y = day-y3+day; //flip sprite.y about day
sprite[j].ang = (2048-sprite[j].ang)&2047; //flip ang about 512
}
if (doMirror && (sprite[j].cstat & 0x30))
sprite[j].cstat ^= 4; // mirror sprites about dax/day (don't mirror monsters)
j = nextspritesect[j];
}
}
printmessage16("Selected sector(s) flipped");
asksave = 1;
}
}
// end edit for sector flip
if (keystatus[88]) //F12
{
keystatus[88] = 0;
//__clearscreen_beforecapture__
Bsprintf(tempbuf, "Mapster32 %s", ExtGetVer());
screencapture("captxxxx.tga", eitherSHIFT, tempbuf);
showframe(1);
}
if (keystatus[0x30]) // B (clip Blocking xor) (2D)
{
pointhighlight = getpointhighlight(mousxplc, mousyplc, pointhighlight);
linehighlight = getlinehighlight(mousxplc, mousyplc, linehighlight);
if ((pointhighlight&0xc000) == 16384)
{
sprite[pointhighlight&16383].cstat ^= 1;
sprite[pointhighlight&16383].cstat &= ~256;
sprite[pointhighlight&16383].cstat |= ((sprite[pointhighlight&16383].cstat&1)<<8);
asksave = 1;
}
else if (linehighlight >= 0)
{
wall[linehighlight].cstat ^= 1;
wall[linehighlight].cstat &= ~64;
if ((wall[linehighlight].nextwall >= 0) && !eitherSHIFT)
{
NEXTWALL(linehighlight).cstat &= ~(1+64);
NEXTWALL(linehighlight).cstat |= (wall[linehighlight].cstat&1);
}
asksave = 1;
}
keystatus[0x30] = 0;
}
if (keystatus[0x21]) //F (F alone does nothing in 2D right now)
{
keystatus[0x21] = 0;
if (eitherALT) //ALT-F (relative alignmment flip)
{
linehighlight = getlinehighlight(mousxplc, mousyplc, linehighlight);
if (linehighlight >= 0)
{
int32_t secti = sectorofwall(linehighlight);
setfirstwall(secti, linehighlight);
asksave = 1;
printmessage16("This wall now sector %d's first wall (sector[].wallptr)", secti);
}
}
}
if (keystatus[0x18]) // O (ornament onto wall) (2D)
{
keystatus[0x18] = 0;
if ((pointhighlight&0xc000) == 16384)
{
asksave = 1;
DoSpriteOrnament(pointhighlight&16383);
}
}
tsign = 0;
if (keystatus[0x33] || (bstatus&33)==33) // , (2D)
tsign = +1;
if (keystatus[0x34] || (bstatus&17)==17) // . (2D)
tsign = -1;
if (tsign)
{
if (highlightsectorcnt > 0)
{
int32_t smoothRotation = !eitherSHIFT;
get_sectors_center(highlightsector, highlightsectorcnt, &dax, &day);
if (smoothRotation)
{
if (gridlock && grid > 0)
locktogrid(&dax, &day);
}
for (i=0; i<highlightsectorcnt; i++)
{
for (WALLS_OF_SECTOR(highlightsector[i], j))
{
if (smoothRotation)
{
x3 = wall[j].x;
y3 = wall[j].y;
wall[j].x = dax + tsign*(day-y3);
wall[j].y = day + tsign*(x3-dax);
}
else
rotatepoint(dax,day, wall[j].x,wall[j].y, tsign&2047, &wall[j].x,&wall[j].y);
}
for (j=headspritesect[highlightsector[i]]; j != -1; j=nextspritesect[j])
{
if (smoothRotation)
{
x3 = sprite[j].x;
y3 = sprite[j].y;
sprite[j].x = dax + tsign*(day-y3);
sprite[j].y = day + tsign*(x3-dax);
sprite[j].ang = (sprite[j].ang+tsign*512)&2047;
}
else
{
rotatepoint(dax,day, sprite[j].x,sprite[j].y, tsign&2047, &sprite[j].x,&sprite[j].y);
sprite[j].ang = (sprite[j].ang+tsign)&2047;
}
}
}
if (smoothRotation)
keystatus[0x33] = keystatus[0x34] = 0;
mouseb &= ~(16|32);
bstatus &= ~(16|32);
asksave = 1;
}
else
{
if (pointhighlight >= 16384)
{
i = pointhighlight-16384;
if (eitherSHIFT)
sprite[i].ang = (sprite[i].ang-tsign)&2047;
else
{
sprite[i].ang = (sprite[i].ang-128*tsign)&2047;
keystatus[0x33] = keystatus[0x34] = 0;
}
mouseb &= ~(16|32);
bstatus &= ~(16|32);
}
}
}
if (keystatus[0x46]) //Scroll lock (set starting position)
{
startposx = pos.x;
startposy = pos.y;
startposz = pos.z;
startang = ang;
startsectnum = cursectnum;
keystatus[0x46] = 0;
asksave = 1;
}
#if 1
if (keystatus[0x3f]) //F5
{
ExtShowSectorData(0);
}
if (keystatus[0x40]) //F6
{
if (pointhighlight >= 16384)
ExtShowSpriteData(pointhighlight-16384);
else if (linehighlight >= 0)
ExtShowWallData(linehighlight);
else
ExtShowWallData(0);
}
if (keystatus[0x41]) //F7
{
keystatus[0x41] = 0;
for (i=0; i<numsectors; i++)
if (inside_editor(&pos, searchx,searchy, zoom, mousxplc,mousyplc,i) == 1)
{
ExtEditSectorData(i);
break;
}
}
if (keystatus[0x42]) //F8
{
keystatus[0x42] = 0;
if (pointhighlight >= 16384)
ExtEditSpriteData(pointhighlight-16384);
else if (linehighlight >= 0)
ExtEditWallData(linehighlight);
}
#endif
if (keystatus[0x23]) //H (Hi 16 bits of tag)
{
keystatus[0x23] = 0;
if (eitherCTRL) //Ctrl-H
{
pointhighlight = getpointhighlight(mousxplc, mousyplc, pointhighlight);
linehighlight = getlinehighlight(mousxplc, mousyplc, linehighlight);
if ((pointhighlight&0xc000) == 16384)
{
sprite[pointhighlight&16383].cstat ^= 256;
asksave = 1;
}
else if (linehighlight >= 0)
{
wall[linehighlight].cstat ^= 64;
if ((wall[linehighlight].nextwall >= 0) && !eitherSHIFT)
{
NEXTWALL(linehighlight).cstat &= ~64;
NEXTWALL(linehighlight).cstat |= (wall[linehighlight].cstat&64);
}
asksave = 1;
}
}
else if (eitherALT) //ALT
{
if (pointhighlight >= 16384)
{
i = pointhighlight-16384;
Bsprintf(buffer, "Sprite (%d) Hi-tag: ", i);
sprite[i].hitag = getnumber16(buffer, sprite[i].hitag, BTAG_MAX, 0);
}
else if (linehighlight >= 0)
{
i = linehighlight;
Bsprintf(buffer, "Wall (%d) Hi-tag: ", i);
wall[i].hitag = getnumber16(buffer, wall[i].hitag, BTAG_MAX, 0);
}
}
else
{
for (i=0; i<numsectors; i++)
if (inside_editor(&pos, searchx,searchy, zoom, mousxplc,mousyplc,i) == 1)
{
Bsprintf(buffer, "Sector (%d) Hi-tag: ", i);
sector[i].hitag = getnumber16(buffer, sector[i].hitag, BTAG_MAX, 0);
break;
}
}
// printmessage16("");
}
if (keystatus[0x19]) // P (palookup #)
{
keystatus[0x19] = 0;
for (i=0; i<numsectors; i++)
if (inside_editor(&pos, searchx,searchy, zoom, mousxplc,mousyplc,i) == 1)
{
Bsprintf(buffer, "Sector (%d) Ceilingpal: ", i);
sector[i].ceilingpal = getnumber16(buffer, sector[i].ceilingpal, M32_MAXPALOOKUPS, 0);
Bsprintf(buffer, "Sector (%d) Floorpal: ", i);
sector[i].floorpal = getnumber16(buffer, sector[i].floorpal, M32_MAXPALOOKUPS, 0);
break;
}
}
if (keystatus[0x12]) // E (status list)
{
keystatus[0x12] = 0;
if (!eitherCTRL)
{
if (pointhighlight >= 16384)
{
i = pointhighlight-16384;
Bsprintf(buffer, "Sprite (%d) Status list: ", i);
changespritestat(i, getnumber16(buffer, sprite[i].statnum, MAXSTATUS-1, 0));
}
}
#ifdef YAX_ENABLE
else if (highlightsectorcnt > 0 && newnumwalls < 0)
{
////////// YAX //////////
static const char *cfs[2] = {"ceiling", "floor"};
int32_t cf, thez;
cf = ask_above_or_below();
if (cf==-1)
goto end_yax;
thez = YAX_SECTORFLD(highlightsector[0],z, cf);
for (i=0; i<highlightsectorcnt; i++)
{
if (yax_getbunch(highlightsector[i], cf) >= 0)
{
message("Sector %d's %s is already extended", highlightsector[i], cfs[cf]);
goto end_yax;
}
if (i==0)
continue;
if (YAX_SECTORFLD(highlightsector[i],z, cf) != thez)
{
message("All sectors must have the same %s height", cfs[cf]);
goto end_yax;
}
if ((YAX_SECTORFLD(highlightsector[i],stat, cf)&2)!=0)
{
message("Sector %ss must not be sloped", cfs[cf]);
goto end_yax;
}
}
m = numwalls;
Bmemset(visited, 0, sizeof(visited));
// construct!
for (i=0; i<highlightsectorcnt; i++)
for (WALLS_OF_SECTOR(highlightsector[i], j))
{
k = trace_loop(j, visited, NULL, NULL);
if (k == 0)
continue;
else if (k < 0)
{
numwalls = m;
goto end_yax;
}
//message("loop");
wall[k-1].point2 = numwalls;
numwalls = k;
}
i = highlightsector[0];
Bmemcpy(&sector[numsectors], &sector[i], sizeof(sectortype));
sector[numsectors].wallptr = m;
sector[numsectors].wallnum = numwalls-m;
if (YAX_SECTORFLD(i,stat, cf)&2)
{
YAX_SECTORFLD(numsectors,stat, !cf) |= 2;
YAX_SECTORFLD(numsectors,heinum, !cf) = YAX_SECTORFLD(i,heinum, cf);
}
YAX_SECTORFLD(numsectors,z, !cf) = YAX_SECTORFLD(i,z, cf);
YAX_SECTORFLD(numsectors,z, cf) = YAX_SECTORFLD(i,z, cf) - (1-2*cf)*16384;
k = -1; // nextbunchnum
for (i=0; i<numsectors; i++)
{
j = yax_getbunch(i,YAX_CEILING);
k = max(k, j);
j = yax_getbunch(i,YAX_FLOOR);
k = max(k, j);
}
k++;
newnumwalls = numwalls;
numwalls = m;
// restore red walls of the selected sectors
for (i=0; i<highlightsectorcnt; i++)
{
for (WALLS_OF_SECTOR(highlightsector[i], j))
if (wall[j].nextwall < 0)
checksectorpointer(j, highlightsector[i]);
}
// link
yax_setbunch(numsectors, !cf, k);
for (i=0; i<highlightsectorcnt; i++)
yax_setbunch(highlightsector[i], cf, k);
numwalls = newnumwalls;
newnumwalls = -1;
numsectors++;
Bmemset(hlsectorbitmap, 0, sizeof(hlsectorbitmap));
update_highlightsector();
message("Extended %ss of highlighted sectors, created new bunch %d", cfs[cf], k);
end_yax: ;
}
#endif
}
if (highlightsectorcnt < 0)
{
if (keystatus[0x36]) //Right shift (point highlighting)
{
if (highlightcnt == 0)
{
int32_t xx[] = { highlightx1, highlightx1, searchx, searchx, highlightx1 };
int32_t yy[] = { highlighty1, searchy, searchy, highlighty1, highlighty1 };
highlightx2 = searchx;
highlighty2 = searchy;
ydim16 = ydim-STATUS2DSIZ2;
plotlines2d(xx, yy, 5, editorcolors[5]);
}
else
{
highlightcnt = 0;
highlightx1 = searchx;
highlighty1 = searchy;
highlightx2 = searchx;
highlighty2 = searchy;
}
}
else
{
if (highlightcnt == 0)
{
if (!m32_sideview)
{
getpoint(highlightx1,highlighty1, &highlightx1,&highlighty1);
getpoint(highlightx2,highlighty2, &highlightx2,&highlighty2);
}
if (highlightx1 > highlightx2)
swaplong(&highlightx1, &highlightx2);
if (highlighty1 > highlighty2)
swaplong(&highlighty1, &highlighty2);
// Ctrl+RShift: select all wall-points of highlighted wall's loop:
if (eitherCTRL && highlightx1==highlightx2 && highlighty1==highlighty2)
{
Bmemset(show2dwall, 0, sizeof(show2dwall));
Bmemset(show2dsprite, 0, sizeof(show2dsprite));
if (linehighlight >= 0 && linehighlight < MAXWALLS)
{
i = linehighlight;
do
{
show2dwall[i>>3] |= (1<<(i&7));
for (j=0; j<numwalls; j++)
if (j!=i && wall[j].x==wall[i].x && wall[j].y==wall[i].y)
show2dwall[j>>3] |= (1<<(j&7));
i = wall[i].point2;
}
while (i != linehighlight);
}
update_highlight();
}
else
{
int32_t add=keystatus[0x28], sub=(!add && keystatus[0x27]), setop=(add||sub);
int32_t tx, ty, onlySprites=eitherCTRL;
if (!setop)
{
Bmemset(show2dwall, 0, sizeof(show2dwall));
Bmemset(show2dsprite, 0, sizeof(show2dsprite));
}
for (i=0; i<numwalls; i++)
{
if (onlySprites)
break;
if (!m32_sideview)
{
tx = wall[i].x;
ty = wall[i].y;
wall[i].cstat &= ~(1<<14);
}
else
{
screencoords(&tx,&ty, wall[i].x-pos.x,wall[i].y-pos.y, zoom);
ty += getscreenvdisp(
getflorzofslope(sectorofwall(i), wall[i].x,wall[i].y)-pos.z, zoom);
tx += halfxdim16;
ty += midydim16;
}
if (tx >= highlightx1 && tx <= highlightx2 &&
ty >= highlighty1 && ty <= highlighty2)
{
if (!sub)
show2dwall[i>>3] |= (1<<(i&7));
else if (sub)
show2dwall[i>>3] &= ~(1<<(i&7));
}
}
if (m32_sideview && numwalls>0 && !onlySprites)
{
int64_t curcoord;
int32_t begwall=0, mustselect=0;
// also select walls that would be dragged but
// maybe were missed
for (i=0; i<numwalls; i++)
tempxyar[i][0] = i;
qsort(tempxyar, numwalls, sizeof(tempxyar[0]), compare_wall_coords);
i = 0;
k = tempxyar[i][0]; // the actual wallnum...
curcoord = *(int64_t *)&wall[k].x;
while (i<numwalls)
{
//OSD_Printf("%5d: wall %5d: %8d,%8d\n", i, k, wall[k].x, wall[k].y);
mustselect |= (show2dwall[k>>3]&(1<<(k&7)));
i++;
if (i==numwalls || ((k=tempxyar[i][0]), (*(int64_t *)&wall[k].x != curcoord)))
{
if (mustselect)
{
// select all from begwall to i-1
for (j=begwall; j<i; j++)
{
//OSD_Printf("sel %5d: wall %5d: %8d,%8d\n", j, tempxyar[j][0],
//wall[tempxyar[j][0]].x, wall[tempxyar[j][0]].y);
show2dwall[tempxyar[j][0]>>3] |= (1<<(tempxyar[j][0]&7));
}
mustselect = 0;
}
if (i==numwalls)
break;
begwall = i;
curcoord = *(int64_t *)&wall[tempxyar[i][0]].x;
}
}
}
for (i=0; i<MAXSPRITES; i++)
{
if (sprite[i].statnum == MAXSTATUS)
continue;
if (!m32_sideview)
{
tx = sprite[i].x;
ty = sprite[i].y;
}
else
{
screencoords(&tx,&ty, sprite[i].x-pos.x,sprite[i].y-pos.y, zoom);
ty += getscreenvdisp(sprite[i].z-pos.z, zoom);
tx += halfxdim16;
ty += midydim16;
}
if (tx >= highlightx1 && tx <= highlightx2 &&
ty >= highlighty1 && ty <= highlighty2)
{
if (!sub)
{
if (sprite[i].sectnum >= 0) // don't allow to select sprites in null space
show2dsprite[i>>3] |= (1<<(i&7));
}
else
show2dsprite[i>>3] &= ~(1<<(i&7));
}
}
update_highlight();
}
}
}
}
if (highlightcnt < 0)
{
if (keystatus[0xb8]) //Right alt (sector highlighting)
{
if (highlightsectorcnt == 0)
{
if (!eitherCTRL)
{
int32_t xx[] = { highlightx1, highlightx1, searchx, searchx, highlightx1 };
int32_t yy[] = { highlighty1, searchy, searchy, highlighty1, highlighty1 };
highlightx2 = searchx;
highlighty2 = searchy;
ydim16 = ydim-STATUS2DSIZ2;
plotlines2d(xx, yy, 5, editorcolors[10]);
}
}
else
{
int32_t didmakered = (highlightsectorcnt<0), hadouterpoint=0;
int16_t tmprefsect;
for (i=0; i<highlightsectorcnt; i++)
{
for (WALLS_OF_SECTOR(highlightsector[i], j))
{
if (wall[j].nextwall >= 0)
checksectorpointer(wall[j].nextwall,wall[j].nextsector);
didmakered |= !!checksectorpointer(j, highlightsector[i]);
if (!didmakered)
{
updatesectorexclude(wall[j].x, wall[j].y, &tmprefsect, hlsectorbitmap);
if (tmprefsect<0)
hadouterpoint = 1;
}
}
}
if (!didmakered && !hadouterpoint && newnumwalls<0)
{
// fade the screen to have the user's attention
fade_screen();
didmakered |= !ask_if_sure("Insert outer loop and make red walls?", 0);
clearkeys();
}
if (!didmakered && !hadouterpoint && newnumwalls<0)
{
int16_t ignore, refsect;
int32_t n;
Bmemset(visited, 0, sizeof(visited));
for (i=0; i<highlightsectorcnt; i++)
{
for (WALLS_OF_SECTOR(highlightsector[i], j))
{
k = trace_loop(j, visited, &ignore, &refsect);
if (k == 0)
continue;
else if (k < 0)
{
i = highlightsectorcnt;
break; // outer loop too
}
if (ignore)
continue;
wall[k-1].point2 = numwalls; // close the loop
newnumwalls = k;
n = (newnumwalls-numwalls); // number of walls in just constructed loop
if (clockdir(numwalls)==0)
{
int16_t begwalltomove = sector[refsect].wallptr+sector[refsect].wallnum;
flipwalls(numwalls, newnumwalls);
sector[refsect].wallnum += n;
if (refsect != numsectors-1)
{
walltype *tmpwall = Bmalloc(n * sizeof(walltype));
if (!tmpwall)
{
message("out of memory!");
ExtUnInit();
uninitsystem();
exit(1);
}
for (m=0; m<numwalls; m++)
{
if (wall[m].nextwall >= begwalltomove)
wall[m].nextwall += n;
}
for (m=refsect+1; m<numsectors; m++)
sector[m].wallptr += n;
for (m=begwalltomove; m<numwalls; m++)
wall[m].point2 += n;
for (m=numwalls; m<newnumwalls; m++)
wall[m].point2 += (begwalltomove-numwalls);
Bmemcpy(tmpwall, &wall[numwalls], n*sizeof(walltype));
Bmemmove(&wall[begwalltomove+n], &wall[begwalltomove], (numwalls-begwalltomove)*sizeof(walltype));
Bmemcpy(&wall[begwalltomove], tmpwall, n*sizeof(walltype));
Bfree(tmpwall);
}
numwalls = newnumwalls;
newnumwalls = -1;
for (m=begwalltomove; m<begwalltomove+n; m++)
checksectorpointer(m, refsect);
message("Attached new inner loop to sector %d", refsect);
}
}
}
newnumwalls = -1;
}
highlightx1 = searchx;
highlighty1 = searchy;
highlightx2 = searchx;
highlighty2 = searchy;
highlightsectorcnt = 0;
}
}
else
{
if (highlightsectorcnt == 0)
{
int32_t add=keystatus[0x28], sub=(!add && keystatus[0x27]), setop=(add||sub);
int32_t tx,ty, pointsel = eitherCTRL;
if (!m32_sideview)
{
getpoint(highlightx1,highlighty1, &highlightx1,&highlighty1);
getpoint(highlightx2,highlighty2, &highlightx2,&highlighty2);
}
if (!pointsel)
{
if (highlightx1 > highlightx2)
swaplong(&highlightx1, &highlightx2);
if (highlighty1 > highlighty2)
swaplong(&highlighty1, &highlighty2);
}
if (!setop)
Bmemset(hlsectorbitmap, 0, sizeof(hlsectorbitmap));
for (i=0; i<numsectors; i++)
{
if (pointsel)
{
bad = (inside_editor(&pos, searchx,searchy, zoom, highlightx2, highlighty2, i)!=1);
}
else
{
bad = 0;
for (WALLS_OF_SECTOR(i, j))
{
if (!m32_sideview)
{
tx = wall[j].x;
ty = wall[j].y;
}
else
{
screencoords(&tx,&ty, wall[j].x-pos.x,wall[j].y-pos.y, zoom);
ty += getscreenvdisp(getflorzofslope(i, wall[j].x,wall[j].y)-pos.z, zoom);
tx += halfxdim16;
ty += midydim16;
}
if (tx < highlightx1 || tx > highlightx2) bad = 1;
if (ty < highlighty1 || ty > highlighty2) bad = 1;
if (bad == 1) break;
}
}
if (bad == 0)
{
if (sub)
{
hlsectorbitmap[i>>3] &= ~(1<<(i&7));
for (j=sector[i].wallptr; j<sector[i].wallptr+sector[i].wallnum; j++)
{
if (wall[j].nextwall >= 0)
checksectorpointer(wall[j].nextwall,wall[j].nextsector);
checksectorpointer(j, i);
}
}
else
hlsectorbitmap[i>>3] |= (1<<(i&7));
}
}
update_highlightsector();
ovh_whiteoutgrab();
}
}
}
if (((bstatus&1) < (oldmousebstatus&1)) && highlightsectorcnt < 0) //after dragging
{
int32_t runi;
if (backup_drawn_walls(0))
goto end_after_dragging;
j = 1;
if (highlightcnt > 0)
for (i=0; i<highlightcnt; i++)
if (pointhighlight == highlight[i])
{
j = 0;
break;
}
if (j == 0)
{
for (i=0; i<highlightcnt; i++)
if ((highlight[i]&0xc000) == 16384)
updatesprite1(highlight[i]&16383);
}
else if ((pointhighlight&0xc000) == 16384)
{
updatesprite1(pointhighlight&16383);
}
if ((pointhighlight&0xc000) == 0)
{
dax = wall[pointhighlight].x;
day = wall[pointhighlight].y;
}
else if ((pointhighlight&0xc000) == 16384)
{
dax = sprite[pointhighlight&16383].x;
day = sprite[pointhighlight&16383].y;
}
for (runi=0; runi<2; runi++)
for (i=numwalls-1; i>=0; i--) //delete points
{
if (wall[i].x == POINT2(i).x && wall[i].y == POINT2(i).y
&& sector[sectorofwall(i)].wallnum > 3
&& sector[sectorofwall(wall[i].point2)].wallnum > 3)
{
int32_t b = (wall[i].nextwall == -1 ||
(sector[sectorofwall(wall[i].nextwall)].wallnum > 3 &&
sector[sectorofwall(NEXTWALL(i).point2)].wallnum > 3));
if (runi==0 && !b)
{
printmessage16("Invalid operation, delete or join sector instead.");
goto end_after_dragging;
}
else if (runi==1 && b)
{
deletepoint(i);
printmessage16("Point deleted.");
asksave = 1;
}
}
}
for (i=0; i<numwalls; i++) //make new red lines?
{
if ((wall[i].x == dax && wall[i].y == day)
|| (POINT2(i).x == dax && POINT2(i).y == day))
{
checksectorpointer(i, sectorofwall(i));
// fixrepeats(i);
asksave = 1;
}
}
backup_drawn_walls(1);
}
end_after_dragging:
if ((bstatus&1) > 0) //drag points
{
if (highlightsectorcnt > 0)
{
if ((bstatus&1) > (oldmousebstatus&1))
{
newnumwalls = -1;
sectorhighlightstat = -1;
// updatesector(mousxplc,mousyplc,&cursectorhighlight);
cursectorhighlight = -1;
for (i=0; i<highlightsectorcnt; i++)
if (inside_editor(&pos, searchx,searchy, zoom, mousxplc, mousyplc, highlightsector[i])==1)
{
cursectorhighlight = highlightsector[i];
break;
}
if (cursectorhighlight >= 0 && cursectorhighlight < numsectors)
{
// for (i=0; i<highlightsectorcnt; i++)
// if (cursectorhighlight == highlightsector[i])
{
//You clicked inside one of the flashing sectors!
sectorhighlightstat = 1;
dax = mousxplc;
day = mousyplc;
if (gridlock && grid > 0)
locktogrid(&dax, &day);
sectorhighlightx = dax;
sectorhighlighty = day;
// break;
}
}
}
else if (sectorhighlightstat == 1)
{
dax = mousxplc;
day = mousyplc;
if (gridlock && grid > 0)
locktogrid(&dax, &day);
dax -= sectorhighlightx;
day -= sectorhighlighty;
sectorhighlightx += dax;
sectorhighlighty += day;
for (i=0; i<highlightsectorcnt; i++)
{
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])
{ sprite[j].x += dax; sprite[j].y += day; }
}
//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)
// checksectorpointer(wall[j].nextwall,wall[j].nextsector);
// checksectorpointer((short)j,highlightsector[i]);
// }
//}
asksave = 1;
}
}
else //if (highlightsectorcnt <= 0)
{
if ((bstatus&1) > (oldmousebstatus&1))
pointhighlight = getpointhighlight(mousxplc, mousyplc, pointhighlight);
if (pointhighlight >= 0 && (!m32_sideview || m32_sideelev>=32))
{
if (m32_sideview)
{
int32_t dz;
if (pointhighlight>=16384)
dz = sprite[pointhighlight&16383].z - pos.z;
else
dz = getflorzofslope(sectorofwall(pointhighlight),
wall[pointhighlight].x, wall[pointhighlight].y) - pos.z;
getinvdisplacement(&dax,&day, -dz);
dax += mousxplc;
day += mousyplc;
}
else
{
dax = mousxplc;
day = mousyplc;
}
if (gridlock && grid > 0)
locktogrid(&dax, &day);
j = 1;
if (highlightcnt > 0)
for (i=0; i<highlightcnt; i++)
if (pointhighlight == highlight[i])
{ j = 0; break; }
if (j == 0)
{
if ((pointhighlight&0xc000) == 0)
{
dax -= wall[pointhighlight].x;
day -= wall[pointhighlight].y;
}
else
{
dax -= sprite[pointhighlight&16383].x;
day -= sprite[pointhighlight&16383].y;
}
for (i=0; i<highlightcnt; i++)
{
if ((highlight[i]&0xc000) == 0)
{
wall[highlight[i]].x += dax;
wall[highlight[i]].y += day;
}
else
{
sprite[highlight[i]&16383].x += dax;
sprite[highlight[i]&16383].y += day;
}
}
}
else
{
if ((pointhighlight&0xc000) == 0)
{
if (newnumwalls >= numwalls &&
wall[pointhighlight].x==firstx && wall[pointhighlight].y==firsty)
{
printmessage16("Can't drag point where drawing started.");
goto end_point_dragging;
}
dragpoint(pointhighlight,dax,day);
}
else if ((pointhighlight&0xc000) == 16384)
{
int32_t daspr=pointhighlight&16383, osec=sprite[daspr].sectnum;
vec3_t vec, ovec;
Bmemcpy(&ovec, (vec3_t *)&sprite[daspr], sizeof(vec3_t));
vec.x = dax;
vec.y = day;
vec.z = sprite[daspr].z;
if (setsprite(daspr, &vec) == -1 && osec>=0)
Bmemcpy(&sprite[daspr], &ovec, sizeof(vec3_t));
#if 0
daz = spriteheight(daspr, NULL);
for (i=0; i<numsectors; i++)
if (inside(dax,day,i) == 1)
if (sprite[daspr].z >= getceilzofslope(i,dax,day))
if (sprite[daspr].z-daz <= getflorzofslope(i,dax,day))
{
sprite[daspr].x = dax;
sprite[daspr].y = day;
if (sprite[daspr].sectnum != i)
changespritesect(daspr,(int16_t)i);
break;
}
#endif
}
}
asksave = 1;
}
}
}
else //if ((bstatus&1) == 0)
{
pointhighlight = getpointhighlight(mousxplc, mousyplc, pointhighlight);
sectorhighlightstat = -1;
}
end_point_dragging:
if (bstatus&(2|4)) // change arrow position
{
if (eitherCTRL)
{
int16_t cursectornum;
for (cursectornum=0; cursectornum<numsectors; cursectornum++)
if (inside_editor(&pos, searchx,searchy, zoom, mousxplc,mousyplc,cursectornum) == 1)
break;
if (cursectornum < numsectors)
{
if (pointhighlight >= 16384)
{
i = pointhighlight-16384;
ExtEditSpriteData((int16_t)i);
}
else if ((linehighlight >= 0) && (bstatus&1 || sectorofwall(linehighlight) == cursectornum))
ExtEditWallData((int16_t)linehighlight);
else if (cursectornum >= 0)
ExtEditSectorData((int16_t)cursectornum);
}
bstatus &= ~6;
}
else
{
if (m32_sideview && (bstatus&4))
{
pos.z += divscale18(searchy-midydim16,zoom);
getpoint(searchx,midydim16, &pos.x, &pos.y);
}
else
{
pos.x = mousxplc;
pos.y = mousyplc;
}
if (m32_sideview)
{
int32_t opat=drawlinepat;
y1 = INT_MAX;
for (i=0; i<numsectors; i++)
{
if (inside(pos.x, pos.y, i)==1)
{
day = getscreenvdisp(getflorzofslope(i, pos.x, pos.y)-pos.z, zoom);
x2 = max(4, mulscale14(64,zoom));
y2 = scalescreeny(x2);
if (klabs(day) < y1)
y1 = day;
drawline16base(halfxdim16, midydim16+day, -x2,-y2, x2,y2, editorcolors[14]);
drawline16base(halfxdim16, midydim16+day, -x2,y2, x2,-y2, editorcolors[14]);
}
}
drawlinepat = 0x11111111;
if (y1 != INT_MAX)
drawline16base(halfxdim16,midydim16, 0,0, 0,y1, editorcolors[14]);
// else
// drawline16base(halfxdim16,midydim16, 0,0, 0,getscreenvdisp(-pos.z, zoom), editorcolors[14]);
drawlinepat = opat;
}
searchx = halfxdim16;
searchy = midydim16;
}
}
else if ((oldmousebstatus&6) > 0)
updatesectorz(pos.x,pos.y,pos.z,&cursectnum);
if (circlewall != -1 && (keystatus[0x4a] || ((bstatus&32) && !eitherCTRL))) // -, mousewheel down
{
if (circlepoints > 1)
circlepoints--;
keystatus[0x4a] = 0;
mouseb &= ~32;
bstatus &= ~32;
}
if (circlewall != -1 && (keystatus[0x4e] || ((bstatus&16) && !eitherCTRL))) // +, mousewheel up
{
if (circlepoints < 63)
circlepoints++;
keystatus[0x4e] = 0;
mouseb &= ~16;
bstatus &= ~16;
}
if (keystatus[0x3d]) // F3
{
keystatus[0x3d]=0;
if (!m32_sideview && (newnumwalls>=0 || joinsector[0]>=0 || circlewall>=0 || (bstatus&1)))
message("Must not be editing map while switching to side view mode.");
else
{
m32_sideview = !m32_sideview;
printmessage16("Side view %s", m32_sideview?"enabled":"disabled");
m32_setkeyfilter(1);
}
}
if (m32_sideview && (keystatus[0x10] || keystatus[0x11]))
{
if (eitherCTRL)
{
if (m32_sideang&63)
{
m32_sideang += (1-2*keystatus[0x10])*(1-2*sideview_reversehrot)*32;
m32_sideang &= (2047&~63);
}
else
{
m32_sideang += (1-2*keystatus[0x10])*(1-2*sideview_reversehrot)*64;
m32_sideang &= 2047;
}
keystatus[0x10] = keystatus[0x11] = 0;
}
else
{
m32_sideang += (1-2*keystatus[0x10])*(1-2*sideview_reversehrot)*synctics<<(eitherSHIFT*2);
m32_sideang &= 2047;
}
_printmessage16("Sideview angle: %d", (int32_t)m32_sideang);
}
if (m32_sideview && (eitherSHIFT || (bstatus&(16|32))))
{
if ((DOWN_BK(MOVEUP) || (bstatus&16)) && m32_sideelev < 512)
{
m32_sideelev += synctics<<(1+!!(bstatus&16));
if (m32_sideelev > 512)
m32_sideelev = 512;
_printmessage16("Sideview elevation: %d", m32_sideelev);
}
if ((DOWN_BK(MOVEDOWN) || (bstatus&32)) && m32_sideelev > 0)
{
m32_sideelev -= synctics<<(1+!!(bstatus&32));
if (m32_sideelev < 0)
m32_sideelev = 0;
_printmessage16("Sideview elevation: %d", m32_sideelev);
}
}
else
{
int32_t didzoom=0;
if ((DOWN_BK(MOVEUP) || (bstatus&16)) && zoom < 65536)
{
zoom += synctics*(zoom>>4);
if (zoom < 24) zoom += 2;
didzoom = 1;
}
if ((DOWN_BK(MOVEDOWN) || (bstatus&32)) && zoom > 8)
{
zoom -= synctics*(zoom>>4);
didzoom = 1;
}
if (didzoom)
{
if (eitherALT)
{
searchx = halfxdim16;
searchy = midydim16;
pos.x = mousxplc;
pos.y = mousyplc;
}
zoom = clamp(zoom, 8, 65536);
_printmessage16("Zoom: %d",zoom);
}
}
if (keystatus[0x22]) // G (grid on/off)
{
keystatus[0x22] = 0;
grid++;
if (grid == 7) grid = 0;
}
if (keystatus[0x26]) // L (grid lock)
{
keystatus[0x26] = 0;
gridlock = !gridlock;
printmessage16("Grid locking %s", gridlock?"on":"off");
}
if (keystatus[0x24]) // J (join sectors)
{
keystatus[0x24] = 0;
if (newnumwalls >= 0)
{
printmessage16("Can't join sectors while editing.");
goto end_join_sectors;
}
if (joinsector[0] < 0)
{
joinsector[0] = -1;
for (i=0; i<numsectors; i++)
if (inside_editor(&pos, searchx,searchy, zoom, mousxplc,mousyplc,i) == 1)
{
joinsector[0] = i;
printmessage16("Join sector - press J again on sector to join with.");
break;
}
goto end_join_sectors;
}
else
{
int16_t joink;
joinsector[1] = -1;
for (i=0; i<numsectors; i++)
{
if (inside_editor(&pos, searchx,searchy, zoom, mousxplc,mousyplc,i) == 1)
{
startwall = sector[i].wallptr;
endwall = startwall + sector[i].wallnum;
for (j=startwall; j<endwall; j++)
if (wall[j].nextsector == joinsector[0])
break;
joinsector[1] = i;
// pressing J into the same sector is the same as saying 'no'
// v----------------v
if (j == endwall && i != joinsector[0])
{
fade_screen();
if (!ask_if_sure("Join non-adjacent sectors? (Y/N)", 0))
joinsector[1] = joinsector[0];
}
break;
}
}
if (joinsector[1] < 0 || joinsector[0] == joinsector[1])
{
printmessage16("No sectors joined.");
joinsector[0] = -1;
goto end_join_sectors;
}
for (i=0; i<numwalls; i++)
wall[i].cstat &= ~(1<<14);
newnumwalls = numwalls;
for (k=0; k<2; k++)
{
for (WALLS_OF_SECTOR(joinsector[k], j))
{
int32_t loopnum=MAXWALLS*2;
if (wall[j].cstat & (1<<14))
continue;
if (wall[j].nextsector == joinsector[1-k])
{
wall[j].cstat |= (1<<14);
continue;
}
i = j;
m = newnumwalls;
joink = k;
do
{
if (newnumwalls >= MAXWALLS + M32_FIXME_WALLS)
{
message("Joining sectors failed: not enough space beyond wall[]");
joinsector[0] = -1;
newnumwalls = -1;
for (i=0; i<numwalls; i++)
wall[i].cstat &= ~(1<<14);
goto end_join_sectors;
}
Bmemcpy(&wall[newnumwalls], &wall[i], sizeof(walltype));
wall[newnumwalls].point2 = newnumwalls+1;
newnumwalls++;
wall[i].cstat |= (1<<14);
i = wall[i].point2;
if (wall[i].nextsector == joinsector[1-joink])
{
i = NEXTWALL(i).point2;
joink = 1 - joink;
}
loopnum--;
}
while (loopnum>0 && ((wall[i].cstat & (1<<14))==0)
&& (wall[i].nextsector != joinsector[1-joink]));
wall[newnumwalls-1].point2 = m;
if (loopnum==0)
{
printmessage16("internal error while joining sectors: infloop!");
newnumwalls = -1;
}
}
}
if (newnumwalls > numwalls)
{
Bmemcpy(&sector[numsectors], &sector[joinsector[0]], sizeof(sectortype));
sector[numsectors].wallptr = numwalls;
sector[numsectors].wallnum = newnumwalls-numwalls;
//fix sprites
for (i=0; i<2; i++)
{
j = headspritesect[joinsector[i]];
while (j != -1)
{
k = nextspritesect[j];
changespritesect(j, numsectors);
j = k;
}
}
numsectors++;
for (i=numwalls; i<newnumwalls; i++)
{
if (wall[i].nextwall >= 0)
{
NEXTWALL(i).nextwall = i;
NEXTWALL(i).nextsector = numsectors-1;
}
}
numwalls = newnumwalls;
newnumwalls = -1;
for (k=0; k<2; k++)
for (WALLS_OF_SECTOR(joinsector[k], j))
wall[j].nextwall = wall[j].nextsector = -1;
deletesector(joinsector[0]);
if (joinsector[0] < joinsector[1])
joinsector[1]--;
deletesector(joinsector[1]);
printmessage16("Sectors joined.");
asksave = 1;
}
joinsector[0] = -1;
}
}
end_join_sectors:
// PK
for (i=0x02; i<=0x0b; i++) // keys '1' to '0' on the upper row
if (keystatus[i])
{
prefixarg = prefixtiles[i-2];
break;
}
if (eitherALT && keystatus[0x1f]) //ALT-S
{
keystatus[0x1f] = 0;
if (linehighlight >= 0 && wall[linehighlight].nextwall == -1)
{
newnumwalls = whitelinescan(sectorofwall(linehighlight), linehighlight);
if (newnumwalls < numwalls)
{
printmessage16("Can't make a sector out there.");
newnumwalls = -1;
}
else if (newnumwalls > MAXWALLS)
{
printmessage16("Making new sector from inner loop would exceed wall limits.");
newnumwalls = -1;
}
else
{
for (i=numwalls; i<newnumwalls; i++)
{
NEXTWALL(i).nextwall = i;
NEXTWALL(i).nextsector = numsectors;
}
numwalls = newnumwalls;
newnumwalls = -1;
numsectors++;
printmessage16("Inner loop made into new sector.");
}
}
}
else if (keystatus[0x1f]) //S
{
keystatus[0x1f] = 0;
sucksect = -1;
for (i=0; i<numsectors; i++)
if (inside_editor(&pos, searchx,searchy, zoom, mousxplc,mousyplc,i) == 1)
{
sucksect = i;
break;
}
if (sucksect >= 0)
{
dax = mousxplc;
day = mousyplc;
if (gridlock && grid > 0)
locktogrid(&dax, &day);
i = insert_sprite_common(sucksect, dax, day);
if (i < 0)
printmessage16("Couldn't insert sprite.");
else
{
sprite[i].z = getflorzofslope(sucksect,dax,day);
// if (sprite[i].cstat&128)
// sprite[i].z -= spriteheight(i, NULL)>>1;
// PK
if (prefixarg)
{
sprite[i].picnum = prefixarg;
sprite[i].xrepeat = sprite[i].yrepeat = 48;
prefixarg = 0;
}
else if (somethingintab == 3)
{
sprite[i].picnum = temppicnum;
if (tilesizx[temppicnum] <= 0 || tilesizy[temppicnum] <= 0)
{
j = 0;
for (k=0; k<MAXTILES; k++)
if (tilesizx[k] > 0 && tilesizy[k] > 0)
{
j = k;
break;
}
sprite[i].picnum = j;
}
sprite[i].shade = tempshade;
sprite[i].pal = temppal;
sprite[i].xrepeat = max(tempxrepeat, 1);
sprite[i].yrepeat = max(tempyrepeat, 1);
sprite[i].cstat = tempcstat;
}
if (tilesizy[sprite[i].picnum] >= 32)
sprite[i].cstat |= 1;
correct_sprite_yoffset(i);
printmessage16("Sprite inserted.");
updatenumsprites();
asksave = 1;
VM_OnEvent(EVENT_INSERTSPRITE2D, i);
}
}
}
if (keystatus[0x2e]) // C (make circle of points)
{
if (highlightsectorcnt >= 0)
duplicate_selected_sectors();
else if (highlightcnt >= 0)
duplicate_selected_sprites();
else if (circlewall >= 0)
{
circlewall = -1;
}
else
{
if (linehighlight >= 0)
circlewall = linehighlight;
}
keystatus[0x2e] = 0;
}
bad = keystatus[0x39]; //Gotta do this to save lots of 3 spaces!
if (circlewall >= 0)
{
x1 = wall[circlewall].x;
y1 = wall[circlewall].y;
x2 = POINT2(circlewall).x;
y2 = POINT2(circlewall).y;
x3 = mousxplc;
y3 = mousyplc;
adjustmark(&x3,&y3,newnumwalls);
tempint1 = dmulscale4(x3-x2,x1-x3, y1-y3,y3-y2);
tempint2 = dmulscale4(y1-y2,x1-x3, y1-y3,x2-x1);
if (tempint2 != 0)
{
int32_t ps = 2, goodtogo; // pointsize
centerx = ((x1+x2) + scale(y1-y2,tempint1,tempint2))>>1;
centery = ((y1+y2) + scale(x2-x1,tempint1,tempint2))>>1;
dax = mulscale14(centerx-pos.x,zoom);
day = mulscale14(centery-pos.y,zoom);
drawline16base(halfxdim16+dax,midydim16+day, -2,-2, +2,+2, editorcolors[14]);
drawline16base(halfxdim16+dax,midydim16+day, -2,+2, +2,-2, editorcolors[14]);
circleang1 = getangle(x1-centerx,y1-centery);
circleang2 = getangle(x2-centerx,y2-centery);
circleangdir = 1;
k = ((circleang2-circleang1)&2047);
if (mulscale4(x3-x1,y2-y1) < mulscale4(x2-x1,y3-y1))
{
circleangdir = -1;
k = -((circleang1-circleang2)&2047);
}
circlerad = ksqrt(dmulscale4(centerx-x1,centerx-x1, centery-y1,centery-y1))<<2;
goodtogo = (numwalls+circlepoints <= MAXWALLS);
for (i=circlepoints; i>0; i--)
{
j = (circleang1 + scale(i,k,circlepoints+1))&2047;
dax = centerx + mulscale14(sintable[(j+512)&2047],circlerad);
day = centery + mulscale14(sintable[j],circlerad);
bclamp(&dax, -editorgridextent, editorgridextent);
bclamp(&day, -editorgridextent, editorgridextent);
if (bad > 0 && goodtogo)
{
insertpoint(circlewall,dax,day);
if (wall[circlewall].nextwall >= 0 && wall[circlewall].nextwall < circlewall)
circlewall++;
}
dax = mulscale14(dax-pos.x,zoom);
day = mulscale14(day-pos.y,zoom);
drawline16base(halfxdim16+dax,midydim16+day, -ps,-ps, +ps,-ps, editorcolors[14]);
drawline16base(halfxdim16+dax,midydim16+day, +ps,-ps, +ps,+ps, editorcolors[14]);
drawline16base(halfxdim16+dax,midydim16+day, +ps,+ps, -ps,+ps, editorcolors[14]);
drawline16base(halfxdim16+dax,midydim16+day, -ps,+ps, -ps,-ps, editorcolors[14]);
// drawcircle16(halfxdim16+dax, midydim16+day, 3, 14);
}
if (bad > 0)
{
bad = 0;
keystatus[0x39] = 0;
if (goodtogo)
{
asksave = 1;
printmessage16("Circle points inserted.");
circlewall = -1;
}
else
printmessage16("Inserting circle points would exceed wall limit.");
}
}
}
if (bad > 0) //Space bar test
{
keystatus[0x39] = 0;
adjustmark(&mousxplc,&mousyplc,newnumwalls);
if (checkautoinsert(mousxplc,mousyplc,newnumwalls) == 1)
{
printmessage16("You must insert a point there first.");
bad = 0;
}
}
if (bad > 0) //Space
{
if (newnumwalls < numwalls) // starting wall drawing
{
if (numwalls >= MAXWALLS-1)
{
// whatever we do, we will need at least two new walls
printmessage16("Can't start sector drawing: wall limit reached.");
goto end_space_handling;
}
if (numsectors >= MAXSECTORS)
{
printmessage16("Can't start sector drawing: sector limit reached.");
goto end_space_handling;
}
firstx = mousxplc;
firsty = mousyplc; //Make first point
newnumwalls = numwalls;
suckwall = -1;
split = 0;
Bmemset(&wall[newnumwalls], 0, sizeof(walltype));
wall[newnumwalls].extra = -1;
wall[newnumwalls].x = mousxplc;
wall[newnumwalls].y = mousyplc;
wall[newnumwalls].nextsector = -1;
wall[newnumwalls].nextwall = -1;
for (i=0; i<numwalls; i++)
if (wall[i].x == mousxplc && wall[i].y == mousyplc)
suckwall = i;
wall[newnumwalls].point2 = newnumwalls+1;
newnumwalls++;
printmessage16("Sector drawing started.");
}
else // 2nd point and up...
{
//if not back to first point
if (firstx != mousxplc || firsty != mousyplc) //nextpoint
{
if (newnumwalls>=MAXWALLS)
{
printmessage16("Inserting another point would exceed wall limit.");
goto end_space_handling;
}
j = 0;
for (i=numwalls; i<newnumwalls; i++)
if (mousxplc == wall[i].x && mousyplc == wall[i].y)
j = 1;
if (j == 0) // if new point is not on a position of already drawn points
{
// on the second point insertion, check if starting to split a sector
if (newnumwalls == numwalls+1)
{
dax = (wall[numwalls].x+mousxplc)>>1;
day = (wall[numwalls].y+mousyplc)>>1;
for (i=0; i<numsectors; i++)
{
if (inside(dax,day,i) != 1)
continue;
//check if first point at point of sector
m = -1;
for (WALLS_OF_SECTOR(i, k))
if (wall[k].x==wall[numwalls].x && wall[k].y==wall[numwalls].y)
{
m = k;
break;
}
// if the second insertion is not on a neighboring point of the first one...
if (m>=0 && (POINT2(k).x != mousxplc || POINT2(k).y != mousyplc))
if (wall[lastwall(k)].x != mousxplc || wall[lastwall(k)].y != mousyplc)
{
split = 1;
splitsect = i;
splitstartwall = m;
break;
}
}
}
//make new point
//make sure not drawing over old red line
bad = 0;
for (i=0; i<numwalls; i++)
{
if (wall[i].nextwall >= 0)
{
int32_t lastwalx = wall[newnumwalls-1].x;
int32_t lastwaly = wall[newnumwalls-1].y;
if (wall[i].x == mousxplc && wall[i].y == mousyplc)
if (POINT2(i).x == lastwalx && POINT2(i).y == lastwaly)
bad = 1;
if (wall[i].x == lastwalx && wall[i].y == lastwaly)
if (POINT2(i).x == mousxplc && POINT2(i).y == mousyplc)
bad = 1;
}
}
if (bad == 0)
{
Bmemset(&wall[newnumwalls], 0, sizeof(walltype));
wall[newnumwalls].extra = -1;
wall[newnumwalls].x = mousxplc;
wall[newnumwalls].y = mousyplc;
wall[newnumwalls].nextsector = -1;
wall[newnumwalls].nextwall = -1;
for (i=0; i<numwalls; i++)
if (wall[i].x == mousxplc && wall[i].y == mousyplc)
suckwall = i;
wall[newnumwalls].point2 = newnumwalls+1;
newnumwalls++;
}
else
{
printmessage16("You can't draw new lines over red lines.");
goto end_space_handling;
}
}
}
////////// newnumwalls is at most MAXWALLS here //////////
//if not split and back to first point
if (!split && newnumwalls >= numwalls+3
&& firstx==mousxplc && firsty==mousyplc)
{
wall[newnumwalls-1].point2 = numwalls;
if (suckwall == -1) //if no connections to other sectors
{
k = -1;
for (i=0; i<numsectors; i++)
{
if (inside(firstx,firsty,i) == 1)
{
// if all points inside that one sector i,
// will add an inner loop
for (j=numwalls+1; j<newnumwalls; j++)
{
if (inside(wall[j].x, wall[j].y, i) == 0)
goto check_next_sector;
}
k = i;
break;
}
check_next_sector: ;
}
if (k == -1) //if not inside another sector either
{
//add island sector
if (clockdir(numwalls) == 1)
flipwalls(numwalls,newnumwalls);
Bmemset(&sector[numsectors], 0, sizeof(sectortype));
sector[numsectors].extra = -1;
sector[numsectors].wallptr = numwalls;
sector[numsectors].wallnum = newnumwalls-numwalls;
sector[numsectors].ceilingz = -(32<<8);
sector[numsectors].floorz = (32<<8);
for (i=numwalls; i<newnumwalls; i++)
copy_some_wall_members(i, -1);
#ifdef YAX_ENABLE
yax_setbunches(numsectors, -1, -1);
#endif
headspritesect[numsectors] = -1;
numsectors++;
numwalls = newnumwalls;
newnumwalls = -1;
printmessage16("Created new sector %d", numsectors-1);
}
else //else add loop to sector
{
#ifdef YAX_ENABLE
int16_t cbunch, fbunch;
int32_t extendedSector, newnumwalls2;
yax_getbunches(k, &cbunch, &fbunch);
extendedSector = (cbunch>=0 || fbunch>=0);
#endif
j = newnumwalls-numwalls;
#ifdef YAX_ENABLE
newnumwalls2 = newnumwalls + j;
if (extendedSector)
{
if ((cbunch>=0 && (sector[k].ceilingstat&2))
|| (fbunch>=0 && (sector[k].floorstat&2)))
{
message("Sloped extended sectors cannot be subdivided.");
newnumwalls--;
goto end_space_handling;
}
if (newnumwalls + j > MAXWALLS || numsectors+1 > MAXSECTORS)
{
message("Automatically adding inner sector to new extended sector would exceed limits!");
newnumwalls--;
goto end_space_handling;
}
}
#endif
if (clockdir(numwalls) == 0)
flipwalls(numwalls,newnumwalls);
sector[k].wallnum += j;
for (i=k+1; i<numsectors; i++)
sector[i].wallptr += j;
suckwall = sector[k].wallptr;
for (i=0; i<numwalls; i++)
{
if (wall[i].nextwall >= suckwall)
wall[i].nextwall += j;
if (wall[i].point2 >= suckwall)
wall[i].point2 += j;
}
Bmemmove(&wall[suckwall+j], &wall[suckwall], (newnumwalls-suckwall)*sizeof(walltype));
Bmemmove(&wall[suckwall], &wall[newnumwalls], j*sizeof(walltype));
for (i=suckwall; i<suckwall+j; i++)
{
wall[i].point2 += (suckwall-numwalls);
copy_some_wall_members(i, suckwall+j);
wall[i].cstat &= ~(1+16+32+64);
}
numwalls = newnumwalls;
newnumwalls = -1;
#ifdef YAX_ENABLE
if (extendedSector)
{
newnumwalls = whitelinescan(k, suckwall);
if (newnumwalls != newnumwalls2)
message("YAX: WTF?");
for (i=numwalls; i<newnumwalls2; i++)
{
NEXTWALL(i).nextwall = i;
NEXTWALL(i).nextsector = numsectors;
}
yax_setbunches(numsectors, cbunch, fbunch);
numwalls = newnumwalls2;
newnumwalls = -1;
numsectors++;
}
#endif
setfirstwall(k, suckwall+j); // restore old first wall
#ifdef YAX_ENABLE
if (extendedSector)
printmessage16("Added inner loop to sector %d and made new inner sector", k);
else
#endif
printmessage16("Added inner loop to sector %d", k);
}
}
else // if connected to at least one other sector
{
//add new sector with connections
if (clockdir(numwalls) == 1)
flipwalls(numwalls,newnumwalls);
sucksect = sectorofwall(suckwall);
if (numsectors != sucksect)
Bmemcpy(&sector[numsectors], &sector[sucksect], sizeof(sectortype));
sector[numsectors].wallptr = numwalls;
sector[numsectors].wallnum = newnumwalls-numwalls;
sector[numsectors].extra = -1;
sector[numsectors].lotag = sector[numsectors].hitag = 0;
sector[numsectors].ceilingstat &= ~2;
sector[numsectors].floorstat &= ~2;
sector[numsectors].ceilingheinum = sector[numsectors].floorheinum = 0;
sector[numsectors].ceilingpal = sector[numsectors].floorpal = 0;
for (i=numwalls; i<newnumwalls; i++)
{
copy_some_wall_members(i, suckwall);
checksectorpointer(i, numsectors);
}
#ifdef YAX_ENABLE
yax_setbunches(numsectors, -1, -1);
#endif
headspritesect[numsectors] = -1;
numsectors++;
numwalls = newnumwalls;
newnumwalls = -1;
printmessage16("Created new sector %d based on sector %d", numsectors-1, sucksect);
}
asksave = 1;
goto end_space_handling;
}
////////// split sector //////////
else if (split == 1)
{
int16_t danumwalls, splitendwall, doSectorSplit;
int16_t secondstartwall=-1; // used only with splitting
int32_t expectedNumwalls = numwalls+2*(newnumwalls-numwalls-1), loopnum;
startwall = sector[splitsect].wallptr;
endwall = startwall + sector[splitsect].wallnum - 1;
// OSD_Printf("numwalls: %d, newnumwalls: %d\n", numwalls, newnumwalls);
i = -1;
for (k=startwall; k<=endwall; k++)
if (wall[k].x == wall[newnumwalls-1].x && wall[k].y == wall[newnumwalls-1].y)
{
i = k;
break;
}
// vvvv shouldn't happen, but you never know...
if (i==-1 || k==splitstartwall)
goto end_space_handling;
splitendwall = k;
doSectorSplit = (loopnumofsector(splitsect,splitstartwall)
== loopnumofsector(splitsect,splitendwall));
if (expectedNumwalls > MAXWALLS)
{
printmessage16("%s would exceed wall limit.", bad==0 ?
"Splitting sector" : "Joining sector loops");
newnumwalls--;
break;
}
////////// common code for splitting/loop joining //////////
newnumwalls--; //first fix up the new walls
for (i=numwalls; i<newnumwalls; i++)
{
copy_some_wall_members(i, startwall);
wall[i].point2 = i+1;
}
danumwalls = newnumwalls; //where to add more walls
if (doSectorSplit)
{
// Copy outer loop of first sector
if (do_while_copyloop1(splitendwall, splitstartwall, &danumwalls, numwalls))
goto split_not_enough_walls;
//Add other loops for 1st sector
i = loopnum = loopnumofsector(splitsect,splitstartwall);
for (j=startwall; j<=endwall; j++)
{
k = loopnumofsector(splitsect,j);
if (k == i)
continue;
if (k == loopnum)
continue;
i = k;
if (loopinside(wall[j].x,wall[j].y, numwalls) != 1)
continue;
if (do_while_copyloop1(j, j, &danumwalls, danumwalls))
goto split_not_enough_walls;
}
secondstartwall = danumwalls;
}
else
{
if (do_while_copyloop1(splitendwall, splitendwall, &danumwalls, -1))
goto split_not_enough_walls;
}
//copy split points for other sector backwards
for (j=newnumwalls; j>numwalls; j--)
{
Bmemcpy(&wall[danumwalls], &wall[j], sizeof(walltype));
wall[danumwalls].nextwall = -1;
wall[danumwalls].nextsector = -1;
wall[danumwalls].point2 = danumwalls+1;
danumwalls++;
}
//copy rest of loop next
if (doSectorSplit)
{
if (do_while_copyloop1(splitstartwall, splitendwall, &danumwalls, secondstartwall))
goto split_not_enough_walls;
}
else
{
if (do_while_copyloop1(splitstartwall, splitstartwall, &danumwalls, numwalls))
goto split_not_enough_walls;
}
//Add other loops for 2nd sector
i = loopnum = loopnumofsector(splitsect,splitstartwall);
for (j=startwall; j<=endwall; j++)
{
k = loopnumofsector(splitsect, j);
if (k==i)
continue;
if (doSectorSplit && k==loopnum)
continue;
if (!doSectorSplit && (k == loopnumofsector(splitsect,splitstartwall) || k == loopnumofsector(splitsect,splitendwall)))
continue;
i = k;
// was loopinside(... , secondstartwall) != 1, but this way there are
// no duplicate or left-out loops (can happen with convoluted geometry)
if (doSectorSplit && (loopinside(wall[j].x,wall[j].y, numwalls) != 0))
continue;
if (do_while_copyloop1(j, j, &danumwalls, danumwalls))
goto split_not_enough_walls;
}
//fix all next pointers on old sector line
for (j=numwalls; j<danumwalls; j++)
{
if (wall[j].nextwall >= 0)
{
NEXTWALL(j).nextwall = j;
if (!doSectorSplit || j < secondstartwall)
NEXTWALL(j).nextsector = numsectors;
else
NEXTWALL(j).nextsector = numsectors+1;
}
}
//copy sector attributes & fix wall pointers
Bmemcpy(&sector[numsectors], &sector[splitsect], sizeof(sectortype));
sector[numsectors].wallptr = numwalls;
sector[numsectors].wallnum = (doSectorSplit?secondstartwall:danumwalls) - numwalls;
if (doSectorSplit)
{
//set all next pointers on split
for (j=numwalls; j<newnumwalls; j++)
{
m = secondstartwall+(newnumwalls-1-j);
wall[j].nextwall = m;
wall[j].nextsector = numsectors+1;
wall[m].nextwall = j;
wall[m].nextsector = numsectors;
}
Bmemcpy(&sector[numsectors+1], &sector[splitsect], sizeof(sectortype));
sector[numsectors+1].wallptr = secondstartwall;
sector[numsectors+1].wallnum = danumwalls-secondstartwall;
}
//fix sprites
j = headspritesect[splitsect];
while (j != -1)
{
k = nextspritesect[j];
if (!doSectorSplit || loopinside(sprite[j].x,sprite[j].y,numwalls) == 1)
changespritesect(j,numsectors);
//else if (loopinside(sprite[j].x,sprite[j].y,secondstartwall) == 1)
else //Make sure no sprites get left out & deleted!
changespritesect(j,numsectors+1);
j = k;
}
numsectors += 1 + doSectorSplit;
k = danumwalls-numwalls; //Back of number of walls of new sector for later
numwalls = danumwalls;
//clear out old sector's next pointers for clean deletesector
for (j=startwall; j<=endwall; j++)
wall[j].nextwall = wall[j].nextsector = -1;
deletesector(splitsect);
//Check pointers
for (j=numwalls-k; j<numwalls; j++)
{
if (wall[j].nextwall >= 0)
checksectorpointer(wall[j].nextwall, wall[j].nextsector);
checksectorpointer(j, sectorofwall(j));
}
//k now safe to use as temp
if (numwalls==expectedNumwalls)
{
message("%s", doSectorSplit ? "Sector split." : "Loops joined.");
}
else
{
message("%s WARNING: CREATED %d MORE WALLS THAN EXPECTED!",
doSectorSplit ? "Sector split." : "Loops joined.",
numwalls-expectedNumwalls);
// this would display 'num* out of bounds' but this corruption
// is almost as bad... (shouldn't happen anymore)
if (numcorruptthings < MAXCORRUPTTHINGS)
corruptthings[numcorruptthings++] = 0;
corruptlevel = 5;
}
if (0)
{
split_not_enough_walls:
message("%s failed: not enough space beyond wall[]",
doSectorSplit ? "Splitting sectors" : "Joining loops");
}
newnumwalls = -1;
}
}
}
end_space_handling:
if (keystatus[0x1c]) //Left Enter
{
keystatus[0x1c] = 0;
if (keystatus[0x2a] && keystatus[0x1d]) // LCtrl+LShift
{
printmessage16("CHECKING ALL POINTERS!");
for (i=0; i<numsectors; i++)
{
startwall = sector[i].wallptr;
for (j=startwall; j<numwalls; j++)
if (wall[j].point2 < startwall) startwall = wall[j].point2;
sector[i].wallptr = startwall;
}
for (i=numsectors-2; i>=0; i--)
sector[i].wallnum = sector[i+1].wallptr-sector[i].wallptr;
sector[numsectors-1].wallnum = numwalls-sector[numsectors-1].wallptr;
for (i=0; i<numwalls; i++)
{
wall[i].nextsector = -1;
wall[i].nextwall = -1;
}
for (i=0; i<numsectors; i++)
{
for (WALLS_OF_SECTOR(i, j))
checksectorpointer(j, i);
}
printmessage16("ALL POINTERS CHECKED!");
asksave = 1;
}
else
{
if (linehighlight >= 0)
{
checksectorpointer(linehighlight,sectorofwall(linehighlight));
printmessage16("Highlighted line pointers checked.");
asksave = 1;
}
}
}
{
static int32_t backspace_last = 0;
if (keystatus[0x0e]) //Backspace
{
keystatus[0x0e] = 0;
if (newnumwalls >= numwalls)
{
backspace_last = 1;
if (newnumwalls == numwalls+1 || keystatus[0x1d]) // LCtrl: delete all newly drawn walls
newnumwalls = -1;
else
newnumwalls--;
}
else if (backspace_last==0)
{
graphicsmode += (1-2*(DOWN_BK(RUN) || keystatus[0x36]))+3;
graphicsmode %= 3;
printmessage16("2D mode textures %s",
(graphicsmode == 2)?"enabled w/ animation":graphicsmode?"enabled":"disabled");
}
}
else
backspace_last = 0;
}
if (keystatus[0xd3] && eitherCTRL && numwalls > 0) //sector delete
{
#ifdef YAX_ENABLE
int16_t cb, fb;
#endif
keystatus[0xd3] = 0;
sucksect = -1;
for (i=0; i<numsectors; i++)
{
if (inside_editor(&pos, searchx,searchy, zoom, mousxplc,mousyplc,i) != 1)
continue;
#ifdef YAX_ENABLE
// used as a bunch bitmap here
Bmemset(hlsectorbitmap, 0, sizeof(hlsectorbitmap));
#endif
k = 0;
if (highlightsectorcnt >= 0)
{
for (j=0; j<highlightsectorcnt; j++)
if (highlightsector[j] == i)
{
for (j=highlightsectorcnt-1; j>=0; j--)
{
#ifdef YAX_ENABLE
yax_getbunches(highlightsector[j], &cb, &fb);
if (cb>=0) hlsectorbitmap[cb>>3] |= (1<<(cb&7));
if (fb>=0) hlsectorbitmap[fb>>3] |= (1<<(fb&7));
#endif
deletesector(highlightsector[j]);
for (k=j-1; k>=0; k--)
if (highlightsector[k] >= highlightsector[j])
highlightsector[k]--;
}
printmessage16("Highlighted sectors deleted.");
k = 1;
break;
}
}
if (k == 0)
{
#ifdef YAX_ENABLE
yax_getbunches(i, &cb, &fb);
if (cb>=0) hlsectorbitmap[cb>>3] |= (1<<(cb&7));
if (fb>=0) hlsectorbitmap[fb>>3] |= (1<<(fb&7));
#endif
deletesector(i);
printmessage16("Sector deleted.");
}
#ifdef YAX_ENABLE
for (j=0; j<numsectors; j++)
{
yax_getbunches(j, &cb, &fb);
if (hlsectorbitmap[cb>>3] & (1<<(cb&7)))
yax_setbunch(j, YAX_CEILING, -1);
if (hlsectorbitmap[fb>>3] & (1<<(fb&7)))
yax_setbunch(j, YAX_FLOOR, -1);
}
#endif
Bmemset(hlsectorbitmap, 0, sizeof(hlsectorbitmap));
highlightsectorcnt = -1;
Bmemset(show2dwall, 0, sizeof(show2dwall));
update_highlight();
newnumwalls = -1;
asksave = 1;
break;
}
}
if (keystatus[0xd3] && (pointhighlight >= 0))
{
if ((pointhighlight&0xc000) == 16384) //Sprite Delete
{
deletesprite(pointhighlight&16383);
printmessage16("Sprite deleted.");
updatenumsprites();
update_highlight();
asksave = 1;
}
keystatus[0xd3] = 0;
}
if (keystatus[0xd2] || keystatus[0x17]) //InsertPoint
{
if (highlightsectorcnt >= 0)
duplicate_selected_sectors();
else if (highlightcnt >= 0)
duplicate_selected_sprites();
else if (linehighlight >= 0)
{
int32_t onewnumwalls = newnumwalls;
int32_t wallis2sided = (wall[linehighlight].nextwall>=0);
if (backup_drawn_walls(0))
{
message("OUT OF MEMORY!");
}
else if (max(numwalls,onewnumwalls) >= MAXWALLS-wallis2sided)
{
printmessage16("Inserting point would exceed wall limit.");
}
else
{
getclosestpointonwall(mousxplc,mousyplc, linehighlight, &dax,&day);
adjustmark(&dax,&day, newnumwalls);
i = linehighlight;
if ((wall[i].x == dax && wall[i].y == day) || (POINT2(i).x == dax && POINT2(i).y == day))
{
printmessage16("Point not inserted.");
}
else
{
insertpoint(linehighlight, dax,day);
printmessage16("Point inserted.");
}
}
backup_drawn_walls(1);
asksave = 1;
}
keystatus[0xd2] = keystatus[0x17] = 0;
}
/*j = 0;
for(i=22-1;i>=0;i--) updatecrc16(j,kensig[i]);
if ((j&0xffff) != 0xebf)
{
printf("Don't screw with my name.\n");
exit(0);
}*/
//printext16(9L,336+9L,4,-1,kensig,0);
//printext16(8L,336+8L,12,-1,kensig,0);
showframe(1);
synctics = totalclock-lockclock;
lockclock += synctics;
if (keystatus[buildkeys[BK_MODE2D_3D]])
{
updatesector(pos.x,pos.y,&cursectnum);
if (cursectnum >= 0)
keystatus[buildkeys[BK_MODE2D_3D]] = 2;
else
printmessage16("Arrow must be inside a sector before entering 3D mode.");
}
// vvv PK ------------------------------------ (LShift) Ctrl-X: (prev) next map
// this is copied from 'L' (load map), but without copying the highlighted sectors
if (quickmapcycling && keystatus[0x2d]) //X
{
if (eitherCTRL) //Ctrl
{
nextmap:
// bad = 0;
i = menuselect_auto(keystatus[0x2a] ? 0:1); // Left Shift: prev map
if (i < 0)
{
if (i == -1)
message("No more map files.");
else if (i == -2)
message("No .MAP files found.");
else if (i == -3)
message("Load map first!");
}
else
{
if (LoadBoard(NULL, 4))
goto nextmap;
RESET_EDITOR_VARS();
oposz = pos.z;
}
showframe(1);
keystatus[0x1c] = 0;
keystatus[0x2d]=keystatus[0x13]=0;
}
}
// ^^^ PK ------------------------------------
if (keystatus[1] && joinsector[0] >= 0)
{
keystatus[1]=0;
joinsector[0]=-1;
printmessage16("No sectors joined.");
}
CANCEL:
if (keystatus[1])
{
m32_setkeyfilter(0);
keystatus[1] = 0;
_printmessage16("(N)ew, (L)oad, (S)ave, save (A)s, (T)est map, (U)ndo, (R)edo, (Q)uit");
showframe(1);
bflushchars();
bad = 1;
while (bad == 1)
{
if (handleevents())
{
if (quitevent)
quitevent = 0;
}
idle();
ch = bgetchar();
if (keystatus[1])
{
keystatus[1] = 0;
bad = 0;
// printmessage16("");
}
else if (ch == 'n' || ch == 'N') //N
{
bad = 0;
if (!ask_if_sure("Are you sure you want to start a new board? (Y/N)", 0))
break;
else
{
int32_t bakstat=-1;
mapinfofull_t bakmap;
if (highlightsectorcnt > 0)
bakstat = backup_highlighted_map(&bakmap);
// Bmemset(hlsectorbitmap, 0, sizeof(hlsectorbitmap));
// highlightsectorcnt = -1;
highlightcnt = -1;
//Clear all highlights
Bmemset(show2dwall, 0, sizeof(show2dwall));
Bmemset(show2dsprite, 0, sizeof(show2dsprite));
for (i=0; i<MAXSECTORS; i++) sector[i].extra = -1;
for (i=0; i<MAXWALLS; i++) wall[i].extra = -1;
for (i=0; i<MAXSPRITES; i++) sprite[i].extra = -1;
RESET_EDITOR_VARS();
reset_default_mapstate();
Bstrcpy(boardfilename,"newboard.map");
map_undoredo_free();
if (bakstat==0)
{
bakstat = restore_highlighted_map(&bakmap);
if (bakstat == -1)
message("Can't copy highlighted portion of old map: limits exceeded.");
}
break;
}
// printmessage16("");
showframe(1);
}
else if (ch == 'l' || ch == 'L') //L
{
bad = 0;
i = menuselect();
if (i < 0)
{
if (i == -2)
printmessage16("No .MAP files found.");
}
else
{
int32_t bakstat=-1;
mapinfofull_t bakmap;
if (highlightsectorcnt > 0)
bakstat = backup_highlighted_map(&bakmap);
// __old_mapcopy_2__
if (LoadBoard(NULL, 4))
{
printmessage16("Invalid map format.");
if (bakstat==0)
mapinfofull_free(&bakmap);
}
else
{
RESET_EDITOR_VARS();
oposz = pos.z;
if (bakstat==0)
{
bakstat = restore_highlighted_map(&bakmap);
if (bakstat == -1)
message("Can't copy highlighted portion of old map: limits exceeded.");
}
}
}
showframe(1);
keystatus[0x1c] = 0;
}
else if (ch == 'a' || ch == 'A') //A
{
int32_t corrupt = CheckMapCorruption(4, 0);
bad = 0;
Bstrcpy(selectedboardfilename, boardfilename);
if (Bstrrchr(boardfilename, '/'))
Bstrcpy(boardfilename, Bstrrchr(boardfilename, '/')+1);
i = 0;
while ((boardfilename[i] != 0) && (i < 64))
i++;
if (boardfilename[i-4] == '.')
i -= 4;
boardfilename[i] = 0;
bflushchars();
while (bad == 0)
{
_printmessage16("%sSave as: ^011%s%s", corrupt>=4?"(map corrupt) ":"",
boardfilename, (totalclock&32)?"_":"");
showframe(1);
if (handleevents())
quitevent = 0;
idle();
ch = bgetchar();
if (keystatus[1]) bad = 1;
else if (ch == 13) bad = 2;
else if (ch > 0)
{
if (i > 0 && (ch == 8 || ch == 127))
{
i--;
boardfilename[i] = 0;
}
else if (i < 40 && ch > 32 && ch < 128)
{
boardfilename[i++] = ch;
boardfilename[i] = 0;
}
}
}
if (bad == 1)
{
Bstrcpy(boardfilename, selectedboardfilename);
keystatus[1] = 0;
printmessage16("Operation cancelled");
showframe(1);
}
else if (bad == 2)
{
const char *f;
char *slash;
keystatus[0x1c] = 0;
Bstrcpy(&boardfilename[i], ".map");
slash = Bstrrchr(selectedboardfilename,'/');
Bstrcpy(slash ? slash+1 : selectedboardfilename, boardfilename);
_printmessage16("Saving board...");
showframe(1);
f = SaveBoard(selectedboardfilename, 0);
if (f)
printmessage16("Saved board to %s.", f);
else
printmessage16("Saving board failed.");
Bstrcpy(boardfilename, selectedboardfilename);
}
bad = 0;
}
else if (ch == 's' || ch == 'S') //S
{
const char *f;
bad = 0;
if (CheckMapCorruption(4, 0)>=4)
if (!ask_if_sure("Map is corrupt. Are you sure you want to save?", 0))
break;
_printmessage16("Saving board...");
showframe(1);
f = SaveBoard(NULL, 0);
if (f)
printmessage16("Saved board to %s.", f);
else
printmessage16("Saving board failed.");
showframe(1);
}
else if (ch == 't' || ch == 'T')
{
test_map(0);
}
else if (ch == 'u' || ch == 'U')
{
bad = 0;
if (map_undoredo(0)) printmessage16("Nothing to undo!");
else printmessage16("Revision %d undone",map_revision);
}
else if (ch == 'r' || ch == 'R')
{
bad = 0;
if (map_undoredo(1)) printmessage16("Nothing to redo!");
else printmessage16("Restored revision %d",map_revision-1);
}
else if (ch == 'q' || ch == 'Q') //Q
{
bad = 0;
if (ask_if_sure("Are you sure you want to quit?", 0))
{
//QUIT!
int32_t corrupt = CheckMapCorruption(4, 0);
if (ask_if_sure(corrupt<4?"Save changes?":"Map corrupt. Save changes?", 2+(corrupt>=4)))
SaveBoard(NULL, 0);
while (keystatus[1] || keystatus[0x2e])
{
keystatus[1] = 0;
keystatus[0x2e] = 0;
quitevent = 0;
printmessage16("Operation cancelled");
showframe(1);
goto CANCEL;
}
ExtUnInit();
// clearfilenames();
uninittimer();
uninitinput();
// uninitengine();
uninitsystem();
exit(0);
}
// printmessage16("");
showframe(1);
}
}
clearkeys();
m32_setkeyfilter(1);
}
VM_OnEvent(EVENT_KEYS2D, -1);
//nextpage();
}
for (i=0; i<highlightsectorcnt; i++)
{
for (WALLS_OF_SECTOR(highlightsector[i], j))
{
if (wall[j].nextwall >= 0)
checksectorpointer(wall[j].nextwall, wall[j].nextsector);
checksectorpointer(j, highlightsector[i]);
}
}
fixspritesectors();
if (setgamemode(fullscreen,xdimgame,ydimgame,bppgame) < 0)
{
initprintf("%d * %d not supported in this graphics mode\n",xdim,ydim);
ExtUnInit();
uninitinput();
uninittimer();
uninitsystem();
// clearfilenames();
exit(1);
}
setbrightness(GAMMA_CALC,0,0);
pos.z = oposz;
searchx = clamp(scale(searchx,xdimgame,xdim2d), 8, xdimgame-8-1);
searchy = clamp(scale(searchy,ydimgame,ydim2d-STATUS2DSIZ), 8, ydimgame-8-1);
m32_setkeyfilter(0);
VM_OnEvent(EVENT_ENTER3DMODE, -1);
}
// flags:
// 1: quit_is_yes
// 2: don't clear keys on return
static int32_t ask_if_sure(const char *query, uint32_t flags)
{
char ch;
int32_t ret=-1;
if (!query)
_printmessage16("Are you sure?");
else
_printmessage16("%s", query);
showframe(1);
bflushchars();
while ((keystatus[1]|keystatus[0x2e]) == 0 && ret==-1)
{
if (handleevents())
{
if (quitevent)
{
if (flags&1)
return 1;
else
quitevent = 0;
}
}
idle();
ch = bgetchar();
if (ch == 'y' || ch == 'Y')
ret = 1;
else if (ch == 'n' || ch == 'N' || ch == 13 || ch == ' ')
ret = 0;
}
if ((flags&2)==0)
clearkeys();
if (ret >= 0)
return ret;
return 0;
}
#ifdef YAX_ENABLE
static int32_t ask_above_or_below()
{
char ch;
int32_t ret=-1;
_printmessage16("Extend above (a) or below (z)?");
showframe(1);
bflushchars();
while ((keystatus[1]|keystatus[0x2e]) == 0 && ret==-1)
{
if (handleevents())
quitevent = 0;
idle();
ch = bgetchar();
if (ch == 'a' || ch == 'A')
ret = 0;
else if (ch == 'z' || ch == 'Z')
ret = 1;
}
clearkeys();
return ret;
}
#endif
// flags: 1:no ExSaveMap (backup.map)
const char *SaveBoard(const char *fn, uint32_t flags)
{
const char *f;
int32_t ret;
if (!fn)
fn = boardfilename;
if (pathsearchmode)
f = fn;
else
{
// virtual filesystem mode can't save to directories so drop the file into
// the current directory
f = Bstrrchr(fn, '/');
if (!f)
f = fn;
else
f++;
}
fixspritesectors(); //Do this before saving!
updatesector(startposx,startposy,&startsectnum);
ExtPreSaveMap();
ret = saveboard(f,&startposx,&startposy,&startposz,&startang,&startsectnum);
if ((flags&1)==0)
ExtSaveMap(f);
if (!ret)
return f;
else
return NULL;
}
// flags: 1: for running on Mapster32 init
// 4: passed to loadboard flags (no polymer_loadboard); implies no maphack loading
int32_t LoadBoard(const char *filename, uint32_t flags)
{
int32_t i;
if (!filename)
filename = selectedboardfilename;
if (filename != boardfilename)
Bstrcpy(boardfilename, filename);
if ((flags&1)==0)
{
highlightcnt = -1;
Bmemset(show2dwall, 0, sizeof(show2dwall)); //Clear all highlights
Bmemset(show2dsprite, 0, sizeof(show2dsprite));
}
for (i=0; i<MAXSECTORS; i++) sector[i].extra = -1;
for (i=0; i<MAXWALLS; i++) wall[i].extra = -1;
for (i=0; i<MAXSPRITES; i++) sprite[i].extra = -1;
ExtPreLoadMap();
i = loadboard(boardfilename,(flags&4)|(!pathsearchmode&&grponlymode?2:0),
&pos.x,&pos.y,&pos.z,&ang,&cursectnum);
if (i == -2) i = loadoldboard(boardfilename,(!pathsearchmode&&grponlymode?2:0),
&pos.x,&pos.y,&pos.z,&ang,&cursectnum);
if (i < 0)
{
// printmessage16("Invalid map format.");
return i;
}
else
{
if ((flags&4)==0)
loadmhk(0);
ExtLoadMap(boardfilename);
if (mapversion < 7) message("Map %s loaded successfully and autoconverted to V7!",boardfilename);
else
{
i = CheckMapCorruption(4, 0);
message("Loaded map %s %s",boardfilename, i==0?"successfully":
(i<4 ? "(moderate corruption)" : "(HEAVY corruption)"));
}
}
updatenumsprites();
startposx = pos.x; //this is same
startposy = pos.y;
startposz = pos.z;
startang = ang;
startsectnum = cursectnum;
#ifdef YAX_ENABLE
yax_resetbunchnums();
#endif
return 0;
}
void getpoint(int32_t searchxe, int32_t searchye, int32_t *x, int32_t *y)
{
bclamp(&pos.x, -editorgridextent, editorgridextent);
bclamp(&pos.y, -editorgridextent, editorgridextent);
searchxe -= halfxdim16;
searchye -= midydim16;
if (m32_sideview)
{
if (m32_sidesin!=0)
searchye = divscale14(searchye, m32_sidesin);
rotatepoint(0,0, searchxe,searchye, -m32_sideang, &searchxe,&searchye);
}
*x = pos.x + divscale14(searchxe,zoom);
*y = pos.y + divscale14(searchye,zoom);
bclamp(x, -editorgridextent, editorgridextent);
bclamp(y, -editorgridextent, editorgridextent);
}
static int32_t getlinehighlight(int32_t xplc, int32_t yplc, int32_t line)
{
int32_t i, dst, dist, closest, x1, y1, x2, y2, nx, ny;
if (numwalls == 0)
return -1;
if (mouseb & 1)
return line;
if ((pointhighlight&0xc000) == 16384)
return -1;
dist = 1024;
closest = -1;
for (i=0; i<numwalls; i++)
{
getclosestpointonwall(xplc,yplc, i, &nx,&ny);
dst = klabs(xplc-nx) + klabs(yplc-ny);
if (dst <= dist)
{
dist = dst;
closest = i;
}
}
if (closest>=0 && wall[closest].nextwall >= 0)
{
//if red line, allow highlighting of both sides
x1 = wall[closest].x;
y1 = wall[closest].y;
x2 = POINT2(closest).x;
y2 = POINT2(closest).y;
if (dmulscale32(xplc-x1,y2-y1,-(x2-x1),yplc-y1) >= 0)
closest = wall[closest].nextwall;
}
return closest;
}
int32_t getpointhighlight(int32_t xplc, int32_t yplc, int32_t point)
{
int32_t i, j, dst, dist = 512, closest = -1;
int32_t dax,day;
if (numwalls == 0)
return -1;
if (mouseb & 1)
return point;
if (grid < 1)
dist = 0;
for (i=0; i<numsectors; i++)
for (j=sector[i].wallptr; j<sector[i].wallptr+sector[i].wallnum; j++)
{
if (!m32_sideview)
dst = klabs(xplc-wall[j].x) + klabs(yplc-wall[j].y);
else
{
screencoords(&dax,&day, wall[j].x-pos.x,wall[j].y-pos.y, zoom);
day += getscreenvdisp(getflorzofslope(i, wall[j].x,wall[j].y)-pos.z, zoom);
if (halfxdim16+dax < 0 || halfxdim16+dax >= xdim || midydim16+day < 0 || midydim16+day >= ydim)
continue;
dst = klabs(halfxdim16+dax-searchx) + klabs(midydim16+day-searchy);
}
if (dst <= dist)
{
// prefer white walls
if (dst<dist || closest==-1 || (wall[j].nextwall>=0)-(wall[closest].nextwall>=0) <= 0)
dist = dst, closest = j;
}
}
if (zoom >= 256)
for (i=0; i<MAXSPRITES; i++)
if (sprite[i].statnum < MAXSTATUS)
{
if (!m32_sideview)
dst = klabs(xplc-sprite[i].x) + klabs(yplc-sprite[i].y);
else
{
screencoords(&dax,&day, sprite[i].x-pos.x,sprite[i].y-pos.y, zoom);
day += getscreenvdisp(sprite[i].z-pos.z, zoom);
if (halfxdim16+dax < 0 || halfxdim16+dax >= xdim || midydim16+day < 0 || midydim16+day >= ydim)
continue;
dst = klabs(halfxdim16+dax-searchx) + klabs(midydim16+day-searchy);
}
// was (dst <= dist), but this way, when duplicating sprites,
// the selected ones are dragged first
if (dst < dist || (dst == dist && (show2dsprite[i>>3]&(1<<(i&7)))))
dist = dst, closest = i+16384;
}
return closest;
}
static void locktogrid(int32_t *dax, int32_t *day)
{
*dax = ((*dax+(1024>>grid))&(0xffffffff<<(11-grid)));
*day = ((*day+(1024>>grid))&(0xffffffff<<(11-grid)));
}
static int32_t adjustmark(int32_t *xplc, int32_t *yplc, int16_t danumwalls)
{
int32_t i, dst, dist, dax, day, pointlockdist;
if (danumwalls < 0)
danumwalls = numwalls;
pointlockdist = 0;
if (grid > 0 && gridlock)
pointlockdist = (128>>grid);
dist = pointlockdist;
dax = *xplc;
day = *yplc;
for (i=0; i<danumwalls; i++)
{
dst = klabs((*xplc)-wall[i].x) + klabs((*yplc)-wall[i].y);
if (dst < dist)
{
dist = dst;
dax = wall[i].x;
day = wall[i].y;
}
}
if (dist == pointlockdist)
if (gridlock && grid > 0)
locktogrid(&dax, &day);
*xplc = dax;
*yplc = day;
return(0);
}
static int32_t checkautoinsert(int32_t dax, int32_t day, int16_t danumwalls)
{
int32_t i, x1, y1, x2, y2;
if (danumwalls < 0)
danumwalls = numwalls;
for (i=0; i<danumwalls; i++) // Check if a point should be inserted
{
x1 = wall[i].x;
y1 = wall[i].y;
x2 = POINT2(i).x;
y2 = POINT2(i).y;
if ((x1 != dax || y1 != day) && (x2 != dax || y2 != day))
if ((x1 <= dax && dax <= x2) || (x2 <= dax && dax <= x1))
if ((y1 <= day && day <= y2) || (y2 <= day && day <= y1))
if ((dax-x1)*(y2-y1) == (day-y1)*(x2-x1))
return(1); //insertpoint((short)i,dax,day);
}
return(0);
}
static int32_t clockdir(int16_t wallstart) //Returns: 0 is CW, 1 is CCW
{
int16_t i, themin;
int32_t minx, tempint, x0, x1, x2, y0, y1, y2;
minx = 0x7fffffff;
themin = -1;
i = wallstart-1;
do
{
i++;
if (POINT2(i).x < minx)
{
minx = POINT2(i).x;
themin = i;
}
}
while ((wall[i].point2 != wallstart) && (i < MAXWALLS));
x0 = wall[themin].x;
y0 = wall[themin].y;
x1 = POINT2(themin).x;
y1 = POINT2(themin).y;
x2 = POINT2(wall[themin].point2).x;
y2 = POINT2(wall[themin].point2).y;
if (y1 >= y2 && y1 <= y0) return(0);
if (y1 >= y0 && y1 <= y2) return(1);
tempint = (x0-x1)*(y2-y1) - (x2-x1)*(y0-y1);
if (tempint < 0)
return(0);
else
return(1);
}
static void flipwalls(int16_t numwalls, int16_t newnumwalls)
{
int32_t i, j, nume, tempint;
nume = newnumwalls-numwalls;
for (i=numwalls; i<numwalls+(nume>>1); i++)
{
j = numwalls+newnumwalls-i-1;
tempint = wall[i].x; wall[i].x = wall[j].x; wall[j].x = tempint;
tempint = wall[i].y; wall[i].y = wall[j].y; wall[j].y = tempint;
}
}
static void insertpoint(int16_t linehighlight, int32_t dax, int32_t day)
{
int16_t sucksect;
int32_t i, j, k;
uint32_t templenrepquot;
j = linehighlight;
sucksect = sectorofwall(j);
templenrepquot = divscale12(wallength(j), wall[j].xrepeat);
sector[sucksect].wallnum++;
for (i=sucksect+1; i<numsectors; i++)
sector[i].wallptr++;
movewalls(j+1, +1);
Bmemcpy(&wall[j+1], &wall[j], sizeof(walltype));
wall[j].point2 = j+1;
wall[j+1].x = dax;
wall[j+1].y = day;
fixxrepeat(j, templenrepquot);
AlignWallPoint2(j);
fixxrepeat(j+1, templenrepquot);
if (wall[j].nextwall >= 0)
{
k = wall[j].nextwall;
templenrepquot = divscale12(wallength(k), wall[k].xrepeat);
sucksect = sectorofwall(k);
sector[sucksect].wallnum++;
for (i=sucksect+1; i<numsectors; i++)
sector[i].wallptr++;
movewalls(k+1, +1);
Bmemcpy(&wall[k+1], &wall[k], sizeof(walltype));
wall[k].point2 = k+1;
wall[k+1].x = dax;
wall[k+1].y = day;
fixxrepeat(k, templenrepquot);
AlignWallPoint2(k);
fixxrepeat(k+1, templenrepquot);
j = wall[k].nextwall;
wall[j].nextwall = k+1;
wall[j+1].nextwall = k;
wall[k].nextwall = j+1;
wall[k+1].nextwall = j;
}
}
static void deletepoint(int16_t point)
{
int32_t i, j, k, sucksect;
sucksect = sectorofwall(point);
sector[sucksect].wallnum--;
for (i=sucksect+1; i<numsectors; i++)
sector[i].wallptr--;
j = lastwall(point);
k = wall[point].point2;
wall[j].point2 = k;
if (wall[j].nextwall >= 0)
{
NEXTWALL(j).nextwall = -1;
NEXTWALL(j).nextsector = -1;
}
if (wall[point].nextwall >= 0)
{
NEXTWALL(point).nextwall = -1;
NEXTWALL(point).nextsector = -1;
}
movewalls(point, -1);
checksectorpointer(j, sucksect);
}
static int32_t deletesector(int16_t sucksect)
{
int32_t i, j, k, nextk, startwall, endwall;
while (headspritesect[sucksect] >= 0)
deletesprite(headspritesect[sucksect]);
updatenumsprites();
startwall = sector[sucksect].wallptr;
endwall = startwall + sector[sucksect].wallnum - 1;
j = sector[sucksect].wallnum;
for (i=sucksect; i<numsectors-1; i++)
{
k = headspritesect[i+1];
while (k != -1)
{
nextk = nextspritesect[k];
changespritesect(k, i);
k = nextk;
}
Bmemcpy(&sector[i], &sector[i+1], sizeof(sectortype));
sector[i].wallptr -= j;
}
numsectors--;
for (i=startwall; i<=endwall; i++)
if (wall[i].nextwall >= 0)
{
NEXTWALL(i).nextwall = -1;
NEXTWALL(i).nextsector = -1;
}
movewalls(startwall, -j);
for (i=0; i<numwalls; i++)
if (wall[i].nextwall >= startwall)
wall[i].nextsector--;
return(0);
}
void fixspritesectors(void)
{
int32_t i, j, dax, day, daz;
for (i=numsectors-1; i>=0; i--)
if (sector[i].wallnum <= 0 || sector[i].wallptr >= numwalls)
deletesector(i);
if (m32_script_expertmode)
return;
for (i=0; i<MAXSPRITES; i++)
if (sprite[i].statnum < MAXSTATUS)
{
dax = sprite[i].x;
day = sprite[i].y;
if (inside(dax,day,sprite[i].sectnum) != 1)
{
daz = spriteheight(i, NULL);
for (j=0; j<numsectors; j++)
if (inside(dax,day, j) == 1
&& sprite[i].z >= getceilzofslope(j,dax,day)
&& sprite[i].z-daz <= getflorzofslope(j,dax,day))
{
changespritesect(i, j);
break;
}
}
}
}
static int32_t movewalls(int32_t start, int32_t offs)
{
int32_t i;
if (offs < 0) //Delete
{
for (i=start; i<numwalls+offs; i++)
Bmemcpy(&wall[i], &wall[i-offs], sizeof(walltype));
}
else if (offs > 0) //Insert
{
for (i=numwalls+offs-1; i>=start+offs; i--)
Bmemcpy(&wall[i], &wall[i-offs], sizeof(walltype));
}
numwalls += offs;
for (i=0; i<numwalls; i++)
{
if (wall[i].nextwall >= start) wall[i].nextwall += offs;
if (wall[i].point2 >= start) wall[i].point2 += offs;
}
return(0);
}
int32_t wallength(int16_t i)
{
int64_t dax = POINT2(i).x - wall[i].x;
int64_t day = POINT2(i).y - wall[i].y;
#if 1 //def POLYMOST
int64_t hypsq = dax*dax + day*day;
if (hypsq > (int64_t)INT_MAX)
return (int32_t)sqrt((double)hypsq);
else
return ksqrt((int32_t)hypsq);
#else
return ksqrt(dax*dax + day*day);
#endif
}
void fixrepeats(int16_t i)
{
int32_t dist = wallength(i);
int32_t day = wall[i].yrepeat;
wall[i].xrepeat = clamp(mulscale10(dist,day), 1, 255);
}
void fixxrepeat(int16_t i, uint32_t lenrepquot) // lenrepquot: divscale12(wallength,xrepeat)
{
if (lenrepquot != 0)
{
uint32_t res = (((wallength(i)<<12)+(1<<11))/lenrepquot);
wall[i].xrepeat = clamp(res, 1, 255);
}
}
int32_t overridepm16y = -1;
void clearmidstatbar16(void)
{
int32_t y = overridepm16y<0 ? STATUS2DSIZ : overridepm16y;
begindrawing();
CLEARLINES2D(ydim-y+25, STATUS2DSIZ+2-(25<<1), 0);
enddrawing();
}
static void clearministatbar16(void)
{
int32_t i, col = whitecol - 21;
// static const char *tempbuf = "Mapster32" " " VERSION;
char tempbuf[16];
begindrawing();
for (i=ydim-STATUS2DSIZ2; i<ydim; i++)
{
// drawline256(0, i<<12, xdim<<12, i<<12, col);
CLEARLINES2D(i, 1, (col<<24)|(col<<16)|(col<<8)|col);
col--;
if (col <= 0) break;
}
CLEARLINES2D(i, ydim-i, 0);
Bsprintf(tempbuf, "Mapster32 %s", ExtGetVer());
printext16(xdim2d-(Bstrlen(tempbuf)<<3)-3, ydim2d-STATUS2DSIZ2+10, editorcolors[4],-1, tempbuf, 0);
printext16(xdim2d-(Bstrlen(tempbuf)<<3)-2, ydim2d-STATUS2DSIZ2+9, editorcolors[12],-1, tempbuf, 0);
enddrawing();
}
static int16_t loopinside(int32_t x, int32_t y, int16_t startwall)
{
int32_t x1, y1, x2, y2;
int16_t i, cnt;
cnt = clockdir(startwall);
i = startwall;
do
{
x1 = wall[i].x;
x2 = POINT2(i).x;
if (x1 >= x || x2 >= x)
{
y1 = wall[i].y;
y2 = POINT2(i).y;
if (y1 > y2)
{
swaplong(&x1, &x2);
swaplong(&y1, &y2);
}
if (y1 <= y && y2 > y)
if (x1*(y-y2)+x2*(y1-y) <= x*(y1-y2))
cnt ^= 1;
}
i = wall[i].point2;
}
while (i != startwall);
return(cnt);
}
#if 0
static int32_t numloopsofsector(int16_t sectnum)
{
int32_t i, numloops, startwall, endwall;
numloops = 0;
startwall = sector[sectnum].wallptr;
endwall = startwall + sector[sectnum].wallnum;
for (i=startwall; i<endwall; i++)
if (wall[i].point2 < i) numloops++;
return(numloops);
}
#endif
static int32_t getnumber_internal1(char ch, const char *buffer, int32_t *danumptr, int32_t *oldnum, int32_t maxnumber, char sign)
{
int32_t danum = *danumptr;
if (ch >= '0' && ch <= '9')
{
int64_t nbig;
if (danum >= 0)
{
nbig = ((int64_t)danum*10)+(ch-'0');
if (nbig <= (int64_t)maxnumber) danum = nbig;
}
else if (sign) // this extra check isn't hurting anything
{
nbig = ((int64_t)danum*10)-(ch-'0');
if (nbig >= (int64_t)(-maxnumber)) danum = nbig;
}
}
else if (ch == 8 || ch == 127) // backspace
{
danum /= 10;
}
else if (ch == 13)
{
*oldnum = danum;
asksave = 1;
if (qsetmode!=200)
printmessage16("%s", buffer);
return 1;
}
else if (ch == '-' && sign) // negate
{
danum = -danum;
}
*danumptr = danum;
return 0;
}
int32_t _getnumber16(const char *namestart, int32_t num, int32_t maxnumber, char sign, void *(func)(int32_t))
{
char buffer[80], ch;
int32_t n, danum, oldnum;
danum = num;
oldnum = danum;
bflushchars();
while (keystatus[0x1] == 0)
{
if (handleevents())
quitevent = 0;
idle();
ch = bgetchar();
Bsprintf(buffer,"%s^011%d", namestart, danum);
n = Bstrlen(buffer);
if (totalclock & 32) Bstrcat(buffer,"_ ");
_printmessage16("%s", buffer);
if (func != NULL)
{
Bsprintf(buffer, "^011%s", (char *)func(danum));
// printext16(200L-24, ydim-STATUS2DSIZ+20L, editorcolors[9], editorcolors[0], buffer, 0);
printext16(n<<3, ydim-STATUS2DSIZ+128, editorcolors[9], -1, buffer,0);
}
showframe(1);
if (getnumber_internal1(ch, buffer, &danum, &oldnum, maxnumber, sign))
break;
}
clearkeys();
return oldnum;
}
int32_t _getnumber256(const char *namestart, int32_t num, int32_t maxnumber, char sign, void *(func)(int32_t))
{
char buffer[80], ch;
int32_t danum, oldnum;
danum = num;
oldnum = danum;
bflushchars();
while (keystatus[0x1] == 0)
{
if (handleevents())
quitevent = 0;
drawrooms(pos.x,pos.y,pos.z,ang,horiz,cursectnum);
ExtAnalyzeSprites();
drawmasks();
#ifdef POLYMER
if (rendmode == 4 && searchit == 2)
{
polymer_editorpick();
drawrooms(pos.x,pos.y,pos.z,ang,horiz,cursectnum);
ExtAnalyzeSprites();
drawmasks();
}
#endif
ch = bgetchar();
if (keystatus[0x1])
break;
clearkeys();
mouseb = 0;
searchx = osearchx;
searchy = osearchy;
ExtCheckKeys();
Bsprintf(buffer,"%s%d",namestart,danum);
if (totalclock & 32) Bstrcat(buffer,"_ ");
printmessage256(0, 0, buffer);
if (func != NULL)
{
Bsprintf(buffer, "%s", (char *)func(danum));
printmessage256(0, 9, buffer);
}
showframe(1);
if (getnumber_internal1(ch, buffer, &danum, &oldnum, maxnumber, sign))
break;
}
clearkeys();
lockclock = totalclock; //Reset timing
return oldnum;
}
// querystr: e.g. "Name: ", must be !=NULL
// defaultstr: can be NULL
// NO overflow checks are done when copying them!
// maxlen: maximum length of entry string, if ==1, enter single char
const char *getstring_simple(const char *querystr, const char *defaultstr, int32_t maxlen)
{
static char buf[128];
int32_t ei=0, qrylen=0;
char ch;
bflushchars();
clearkeys();
if (maxlen==0)
maxlen = 1000;
Bmemset(buf, 0, sizeof(buf));
qrylen = Bstrlen(querystr);
Bmemcpy(buf, querystr, qrylen);
ei = qrylen;
if (defaultstr)
{
int32_t deflen = Bstrlen(defaultstr);
Bmemcpy(&buf[ei], defaultstr, deflen);
ei += deflen;
}
buf[ei] = 0;
if (maxlen==1)
{
ei = qrylen;
buf[ei] = '_';
buf[ei+1] = 0;
}
while (1)
{
printext256(0, 0, whitecol, 0, buf, 0);
showframe(1);
if (handleevents())
quitevent = 0;
idle_waitevent();
ch = bgetchar();
if (ch==13)
{
if (maxlen != 1)
buf[ei] = 0;
break;
}
else if (keystatus[1])
{
clearkeys();
return defaultstr;
}
if (maxlen!=1)
{
if (ei>qrylen && (ch==8 || ch==127))
{
buf[ei] = ' ';
buf[--ei] = '_';
}
else if ((unsigned)ei<sizeof(buf)-2 && ei-qrylen<maxlen && isprint(ch))
{
buf[ei++] = ch;
buf[ei] = '_';
buf[ei+1] = 0;
}
}
else
{
if (isalnum(ch) || ch==' ')
buf[ei] = Btoupper(ch);
}
}
clearkeys();
return buf+qrylen;
}
static void clearfilenames(void)
{
klistfree(finddirs);
klistfree(findfiles);
finddirs = findfiles = NULL;
numfiles = numdirs = 0;
}
static int32_t getfilenames(const char *path, const char *kind)
{
CACHE1D_FIND_REC *r;
clearfilenames();
finddirs = klistpath(path,"*",CACHE1D_FIND_DIR|CACHE1D_FIND_DRIVE|(!pathsearchmode&&grponlymode?CACHE1D_OPT_NOSTACK:0));
findfiles = klistpath(path,kind,CACHE1D_FIND_FILE|(!pathsearchmode&&grponlymode?CACHE1D_OPT_NOSTACK:0));
for (r = finddirs; r; r=r->next) numdirs++;
for (r = findfiles; r; r=r->next) numfiles++;
finddirshigh = finddirs;
findfileshigh = findfiles;
currentlist = 0;
if (findfileshigh) currentlist = 1;
return(0);
}
// vvv PK ------------------------------------
// copied off menuselect
static const char *g_oldpath=NULL;
static int32_t menuselect_auto(int32_t direction) // 20080104: jump to next (direction!=0) or prev (direction==0) file
{
const char *boardbasename;
if (!g_oldpath)
return -3; // not inited
else
Bmemcpy(selectedboardfilename, g_oldpath, BMAX_PATH);
if (pathsearchmode)
Bcanonicalisefilename(selectedboardfilename, 1); // clips off the last token and compresses relative path
else
Bcorrectfilename(selectedboardfilename, 1);
getfilenames(selectedboardfilename, "*.map");
if (numfiles==0)
return -2;
boardbasename = Bstrrchr(boardfilename,'/'); // PK
if (!boardbasename)
boardbasename=boardfilename;
else
boardbasename++;
for (; findfileshigh; findfileshigh=findfileshigh->next)
if (!Bstrcmp(findfileshigh->name,boardbasename))
break;
if (!findfileshigh)
findfileshigh=findfiles;
if (direction)
{
if (findfileshigh->next)
findfileshigh=findfileshigh->next;
else
return -1;
}
else
{
if (findfileshigh->prev)
findfileshigh=findfileshigh->prev;
else
return -1;
}
Bstrcat(selectedboardfilename, findfileshigh->name);
return(0);
}
// ^^^ PK ------------------------------------
static int32_t menuselect(void)
{
int32_t listsize;
int32_t i;
char ch, buffer[96], /*PK*/ *boardbasename;
static char oldpath[BMAX_PATH];
CACHE1D_FIND_REC *dir;
int32_t bakpathsearchmode = pathsearchmode;
g_oldpath=oldpath; //PK: need it in menuselect_auto
Bstrcpy(selectedboardfilename, oldpath);
if (pathsearchmode)
Bcanonicalisefilename(selectedboardfilename, 1); // clips off the last token and compresses relative path
else
Bcorrectfilename(selectedboardfilename, 1);
getfilenames(selectedboardfilename, "*.map");
// PK 20080103: start with last selected map
boardbasename = Bstrrchr(boardfilename,'/');
if (!boardbasename)
boardbasename=boardfilename;
else
boardbasename++;
for (; findfileshigh; findfileshigh=findfileshigh->next)
if (!Bstrcmp(findfileshigh->name,boardbasename))
break;
if (!findfileshigh)
findfileshigh=findfiles;
_printmessage16("Select map file with arrow keys and enter.");
ydim16 = ydim-STATUS2DSIZ2;
listsize = (ydim16-32)/9;
do
{
begindrawing(); //{{{
CLEARLINES2D(0, ydim16, 0);
if (pathsearchmode)
Bstrcpy(buffer,"Local filesystem mode. Ctrl-F: game filesystem");
else
Bsprintf(buffer,"Game filesystem %smode. Ctrl-F: local filesystem, Ctrl-G: %s",
grponlymode?"GRP-only ":"", grponlymode?"all files":"GRP contents only");
printext16(halfxdim16-(8*Bstrlen(buffer)/2), 4, editorcolors[12],editorcolors[0],buffer,0);
Bsnprintf(buffer,sizeof(buffer)-1,"(%d dirs, %d files) %s",numdirs,numfiles,selectedboardfilename);
buffer[sizeof(buffer)-1] = 0;
printext16(8,ydim16-8-1,editorcolors[8],editorcolors[0],buffer,0);
if (finddirshigh)
{
dir = finddirshigh;
for (i=(listsize/2)-1; i>=0; i--)
{
if (!dir->prev) break;
else dir=dir->prev;
}
for (i=0; ((i<listsize) && dir); i++, dir=dir->next)
{
int32_t c = (dir->type == CACHE1D_FIND_DIR ? 2 : 3); //PK
Bmemset(buffer,0,sizeof(buffer));
Bstrncpy(buffer,dir->name,25);
if (Bstrlen(buffer) == 25)
buffer[21] = buffer[22] = buffer[23] = '.', buffer[24] = 0;
if (dir == finddirshigh)
{
if (currentlist == 0) printext16(8,16+9*i,editorcolors[c|8],editorcolors[0],"->",0);
printext16(32,16+9*i,editorcolors[c|8],editorcolors[0],buffer,0);
}
else
{
printext16(32,16+9*i,editorcolors[c],editorcolors[0],buffer,0);
}
}
}
if (findfileshigh)
{
dir = findfileshigh;
for (i=(listsize/2)-1; i>=0; i--)
{
if (!dir->prev) break;
else dir=dir->prev;
}
for (i=0; ((i<listsize) && dir); i++, dir=dir->next)
{
if (dir == findfileshigh)
{
if (currentlist == 1) printext16(240,16+9*i,editorcolors[7|8],editorcolors[0],"->",0);
printext16(240+24,16+9*i,editorcolors[7|8],editorcolors[0],dir->name,0);
}
else
{
printext16(240+24,16+9*i,editorcolors[7],editorcolors[0],dir->name,0);
}
}
}
enddrawing(); //}}}
showframe(1);
keystatus[0xcb] = 0;
keystatus[0xcd] = 0;
keystatus[0xc8] = 0;
keystatus[0xd0] = 0;
keystatus[0x1c] = 0; //enter
keystatus[0xf] = 0; //tab
keystatus[1] = 0; //esc
ch = 0; //Interesting fakery of ch = getch()
while (ch == 0)
{
if (handleevents())
if (quitevent)
{
keystatus[1] = 1;
quitevent = 0;
}
idle();
ch = bgetchar();
{
// JBF 20040208: seek to first name matching pressed character
CACHE1D_FIND_REC *seeker = currentlist ? findfiles : finddirs;
if (keystatus[0xc7]||keystatus[0xcf]) // home/end
{
while (keystatus[0xcf]?seeker->next:seeker->prev)
seeker = keystatus[0xcf]?seeker->next:seeker->prev;
if (seeker)
{
if (currentlist) findfileshigh = seeker;
else finddirshigh = seeker;
}
ch = keystatus[0xcf]?80:72;
keystatus[0xc7] = keystatus[0xcf] = 0;
}
else if (keystatus[0xc9]|keystatus[0xd1]) // page up/down
{
seeker = currentlist?findfileshigh:finddirshigh;
i = (ydim2d-STATUS2DSIZ2-48)>>5/*3*/; //PK
while (i>0)
{
if (keystatus[0xd1]?seeker->next:seeker->prev)
seeker = keystatus[0xd1]?seeker->next:seeker->prev;
i--;
}
if (seeker)
{
if (currentlist) findfileshigh = seeker;
else finddirshigh = seeker;
}
ch = keystatus[0xd1]?80:72;
keystatus[0xc9] = keystatus[0xd1] = 0;
}
else
{
char ch2;
if (ch > 0 && ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') ||
(ch >= '0' && ch <= '9') || (ch=='_')))
{
#ifdef _WIN32
if (ch >= 'a') ch -= ('a'-'A');
#endif
while (seeker)
{
ch2 = seeker->name[0];
#ifdef _WIN32
if (ch2 >= 'a' && ch2 <= 'z') ch2 -= ('a'-'A');
#endif
if (ch2 == ch) break;
seeker = seeker->next;
}
if (seeker)
{
if (currentlist) findfileshigh = seeker;
else finddirshigh = seeker;
continue;
}
}
}
}
if (keystatus[0xcb]) ch = 9; // left arr
if (keystatus[0xcd]) ch = 9; // right arr
if (keystatus[0xc8]) ch = 72; // up arr
if (keystatus[0xd0]) ch = 80; // down arr
}
if (ch==6) // Ctrl-F
{
currentlist = 0;
pathsearchmode = 1-pathsearchmode;
if (pathsearchmode)
{
Bstrcpy(selectedboardfilename, "");
Bcanonicalisefilename(selectedboardfilename, 0);
}
else Bstrcpy(selectedboardfilename, "/");
getfilenames(selectedboardfilename, "*.map");
Bstrcpy(oldpath,selectedboardfilename);
}
else if (ch==7) // Ctrl-G
{
if (!pathsearchmode)
{
grponlymode = 1-grponlymode;
getfilenames(selectedboardfilename, "*.map");
Bstrcpy(oldpath,selectedboardfilename);
}
}
else if (ch == 9)
{
if ((currentlist == 0 && findfiles) || (currentlist == 1 && finddirs))
currentlist = 1-currentlist;
}
else if (keystatus[0xc8] /*(ch == 75) || (ch == 72)*/)
{
if (currentlist == 0)
{
if (finddirshigh && finddirshigh->prev)
finddirshigh = finddirshigh->prev;
}
else
{
if (findfileshigh && findfileshigh->prev)
findfileshigh = findfileshigh->prev;
}
}
else if (keystatus[0xd0] /*(ch == 77) || (ch == 80)*/)
{
if (currentlist == 0)
{
if (finddirshigh && finddirshigh->next)
finddirshigh = finddirshigh->next;
}
else
{
if (findfileshigh && findfileshigh->next)
findfileshigh = findfileshigh->next;
}
}
else if ((ch == 13) && (currentlist == 0))
{
if (finddirshigh->type == CACHE1D_FIND_DRIVE)
Bstrcpy(selectedboardfilename, finddirshigh->name);
else
Bstrcat(selectedboardfilename, finddirshigh->name);
Bstrcat(selectedboardfilename, "/");
if (pathsearchmode)
Bcanonicalisefilename(selectedboardfilename, 1);
else
Bcorrectfilename(selectedboardfilename, 1);
Bstrcpy(oldpath,selectedboardfilename);
//printf("Changing directories to: %s\n", selectedboardfilename);
getfilenames(selectedboardfilename, "*.map");
ch = 0;
begindrawing();
CLEARLINES2D(0, ydim16, 0);
enddrawing();
showframe(1);
}
if (ch == 13 && !findfileshigh) ch = 0;
}
while ((ch != 13) && (ch != 27));
if (ch == 13)
{
Bstrcat(selectedboardfilename, findfileshigh->name);
//printf("Selected file: %s\n", selectedboardfilename);
return(0);
}
pathsearchmode = bakpathsearchmode;
return(-1);
}
int32_t fillsector(int16_t sectnum, char fillcolor)
{
int32_t x1, x2, y1, y2, sy, y;
int32_t lborder, rborder, uborder, dborder, miny, maxy, dax;
int16_t z, zz, startwall, endwall, fillcnt;
UNREFERENCED_PARAMETER(fillcolor);
lborder = 0; rborder = xdim;
uborder = 0; dborder = ydim16;
if (sectnum == -1)
return 0;
miny = dborder-1;
maxy = uborder;
startwall = sector[sectnum].wallptr;
endwall = startwall + sector[sectnum].wallnum - 1;
for (z=startwall; z<=endwall; z++)
{
screencoords(&x1,&y1, wall[z].x-pos.x,wall[z].y-pos.y, zoom);
if (m32_sideview)
y1 += getscreenvdisp(getflorzofslope(sectnum,wall[z].x,wall[z].y)-pos.z, zoom);
x1 += halfxdim16;
y1 += midydim16;
if (m32_sideview)
{
tempxyar[z][0] = x1;
tempxyar[z][1] = y1;
}
miny = min(miny, y1);
maxy = max(maxy, y1);
}
if (miny < uborder) miny = uborder;
if (maxy >= dborder) maxy = dborder-1;
//+((totalclock>>2)&3)
for (sy=miny; sy<=maxy; sy+=3) // JBF 20040116: numframes%3 -> (totalclock>>2)&3
{
y = pos.y + ((sy-midydim16)<<14)/zoom;
fillist[0] = lborder; fillcnt = 1;
for (z=startwall; z<=endwall; z++)
{
if (m32_sideview)
{
x1 = tempxyar[z][0];
y1 = tempxyar[z][1];
x2 = tempxyar[wall[z].point2][0];
y2 = tempxyar[wall[z].point2][1];
if (y1 > y2)
{
swaplong(&x1, &x2);
swaplong(&y1, &y2);
}
if (y1 <= sy && sy < y2)
{
if (fillcnt == sizeof(fillist)/sizeof(fillist[0]))
break;
x1 += scale(sy-y1, x2-x1, y2-y1);
fillist[fillcnt++] = x1;
}
}
else
{
x1 = wall[z].x; x2 = POINT2(z).x;
y1 = wall[z].y; y2 = POINT2(z).y;
if (y1 > y2)
{
swaplong(&x1, &x2);
swaplong(&y1, &y2);
}
if (y1 <= y && y < y2)
//if (x1*(y-y2) + x2*(y1-y) <= 0)
{
dax = x1 + scale(y-y1, x2-x1, y2-y1);
dax = halfxdim16 + (((dax-pos.x)*zoom)>>14);
if (dax >= lborder)
{
if (fillcnt == sizeof(fillist)/sizeof(fillist[0]))
break;
fillist[fillcnt++] = dax;
}
}
}
}
if (fillcnt > 0)
{
for (z=1; z<fillcnt; z++)
for (zz=0; zz<z; zz++)
if (fillist[z] < fillist[zz])
swaplong(&fillist[z], &fillist[zz]);
for (z=(fillcnt&1); z<fillcnt-1; z+=2)
{
if (fillist[z] > rborder)
break;
if (fillist[z+1] > rborder)
fillist[z+1] = rborder;
drawline16(fillist[z],sy, fillist[z+1],sy, 159 //editorcolors[fillcolor]
-klabs(sintable[((totalclock<<3)&2047)]>>11));
}
}
}
return(0);
}
static int16_t whitelinescan(int16_t sucksect, int16_t dalinehighlight)
{
int32_t i, j, k;
int16_t tnewnumwalls;
if (numsectors >= MAXSECTORS)
return MAXWALLS+1;
Bmemcpy(&sector[numsectors], &sector[sucksect], sizeof(sectortype));
sector[numsectors].wallptr = numwalls;
sector[numsectors].wallnum = 0;
i = dalinehighlight;
tnewnumwalls = numwalls;
do
{
if (tnewnumwalls >= MAXWALLS)
return MAXWALLS+1;
j = lastwall(i);
if (wall[j].nextwall >= 0)
{
j = wall[j].point2;
for (k=0; k<numwalls; k++)
{
if (POINT2(k).x == wall[j].x && POINT2(k).y == wall[j].y)
if (wall[k].nextwall == -1)
{
j = k;
break;
}
}
}
Bmemcpy(&wall[tnewnumwalls], &wall[i], sizeof(walltype));
wall[tnewnumwalls].nextwall = j;
wall[tnewnumwalls].nextsector = sectorofwall(j);
tnewnumwalls++;
sector[numsectors].wallnum++;
i = j;
}
while (i != dalinehighlight);
for (i=numwalls; i<tnewnumwalls-1; i++)
wall[i].point2 = i+1;
wall[tnewnumwalls-1].point2 = numwalls;
if (clockdir(numwalls) == 1)
return(-1);
else
return(tnewnumwalls);
}
int32_t loadnames(const char *namesfile)
{
char buffer[1024], *p, *name, *number, *endptr;
int32_t num, syms=0, line=0, a, comment=0;
BFILE *fp;
Bstrncpy(buffer, namesfile, sizeof(buffer));
buffer[sizeof(buffer)-1] = 0;
p = buffer;
while (*p)
{
*p = Btoupper(*p);
p++;
}
fp = fopenfrompath(buffer,"r");
if (!fp)
{
p = buffer;
while (*p)
{
*p = Btolower(*p);
p++;
}
if ((fp = fopenfrompath(buffer,"r")) == NULL)
{
initprintf("Failed to open %s\n", buffer);
return -1;
}
}
//clearbufbyte(names, sizeof(names), 0);
Bmemset(names,0,sizeof(names));
initprintf("Loading %s\n", buffer);
while (Bfgets(buffer, 1024, fp))
{
a = Bstrlen(buffer);
if (a >= 1)
{
if (a > 1)
if (buffer[a-2] == '\r') buffer[a-2] = 0;
if (buffer[a-1] == '\n') buffer[a-1] = 0;
}
p = buffer;
line++;
while (*p == 32) p++;
if (*p == 0) continue; // blank line
if (*p == '#' && !comment)
{
p++;
while (*p == 32) p++;
if (*p == 0) continue; // null directive
if (!Bstrncmp(p, "define ", 7))
{
// #define_...
p += 7;
while (*p == 32) p++;
if (*p == 0)
{
initprintf("Error: Malformed #define at line %d\n", line-1);
continue;
}
name = p;
while (*p != 32 && *p != 0) p++;
if (*p == 32)
{
*(p++) = 0;
while (*p == 32) p++;
if (*p == 0) // #define_NAME with no number
{
initprintf("Error: No number given for name \"%s\" (line %d)\n", name, line-1);
continue;
}
number = p;
while (*p != 0) p++;
if (*p != 0) *p = 0;
// add to list
num = Bstrtol(number, &endptr, 10);
if (*endptr != 0)
{
p = endptr;
goto badline;
}
//printf("Grokked \"%s\" -> \"%d\"\n", name, num);
if (num < 0 || num >= MAXTILES)
{
initprintf("Error: Constant %d for name \"%s\" out of range (line %d)\n", num, name, line-1);
continue;
}
if (Bstrlen(name) > 24)
initprintf("Warning: Name \"%s\" longer than 24 characters (line %d). Truncating.\n", name, line-1);
Bstrncpy(names[num], name, 24);
names[num][24] = 0;
syms++;
continue;
}
else // #define_NAME with no number
{
initprintf("Error: No number given for name \"%s\" (line %d)\n", name, line-1);
continue;
}
}
else goto badline;
}
else if (*p == '/')
{
if (*(p+1) == '*') {comment++; continue;}
if (*(p+1) == '/') continue; // comment
}
else if (*p == '*' && p[1] == '/')
{
comment--; continue;
}
else if (comment)continue;
badline:
initprintf("Error: Invalid statement found at character %d on line %d\n", (int32_t)(p-buffer), line-1);
}
initprintf("Read %d lines, loaded %d names.\n", line, syms);
Bfclose(fp);
return 0;
}
void printcoords16(int32_t posxe, int32_t posye, int16_t ange)
{
char snotbuf[80];
int32_t i, m;
int32_t v8 = (numsectors > MAXSECTORSV7 || numwalls > MAXWALLSV7 || numsprites > MAXSPRITESV7);
Bsprintf(snotbuf,"x:%d y:%d ang:%d r%d",posxe,posye,ange,map_revision-1);
i = 0;
while ((snotbuf[i] != 0) && (i < 33))
i++;
while (i < 33)
{
snotbuf[i] = 32;
i++;
}
snotbuf[33] = 0;
clearministatbar16();
printext16(8, ydim-STATUS2DSIZ+128, whitecol, -1, snotbuf,0);
if (highlightcnt<=0 && highlightsectorcnt<=0)
{
Bsprintf(snotbuf,"%d/%d sect. %d/%d walls %d/%d spri.",
numsectors, v8?MAXSECTORSV8:MAXSECTORSV7,
numwalls, v8?MAXWALLSV8:MAXWALLSV7,
numsprites, v8?MAXSPRITESV8:MAXSPRITESV7);
}
else
{
if (highlightcnt>0)
{
m = 0;
for (i=0; i<highlightcnt; i++)
m += !!(highlight[i]&16384);
Bsprintf(snotbuf, "%d sprites, %d walls selected", m, highlightcnt-m);
}
else if (highlightsectorcnt>0)
Bsprintf(snotbuf, "%d sectors selected", highlightsectorcnt);
else
snotbuf[0] = 0;
v8 = 1;
}
m = xdim/8 - 264/8;
m = clamp(m, 1, (signed)sizeof(snotbuf)-1);
i = 0;
while (snotbuf[i] && i < m)
i++;
while (i < m)
{
snotbuf[i] = 32;
i++;
}
snotbuf[m] = 0;
printext16(264, ydim-STATUS2DSIZ+128, v8?editorcolors[10]:whitecol, -1, snotbuf,0);
}
void updatenumsprites(void)
{
int32_t i;
numsprites = 0;
for (i=0; i<MAXSPRITES; i++)
numsprites += (sprite[i].statnum != MAXSTATUS);
}
static void copysector(int16_t soursector, int16_t destsector, int16_t deststartwall, char copystat,
const int16_t *oldtonewsect)
{
int16_t i, j, k, m, newnumwalls, startwall, endwall;
newnumwalls = deststartwall; //erase existing sector fragments
//duplicate walls
startwall = sector[soursector].wallptr;
endwall = startwall + sector[soursector].wallnum;
for (j=startwall; j<endwall; j++)
{
Bmemcpy(&wall[newnumwalls], &wall[j], sizeof(walltype));
wall[newnumwalls].point2 += deststartwall-startwall;
if (wall[newnumwalls].nextwall >= 0)
{
k = wall[newnumwalls].nextsector;
if (oldtonewsect && oldtonewsect[k]>=0)
{
wall[newnumwalls].nextsector = oldtonewsect[k];
m = 0;
for (i=0; i<highlightsectorcnt; i++)
{
if (highlightsector[i]==k)
break;
m += sector[highlightsector[i]].wallnum;
}
if (i==highlightsectorcnt)
{
message("internal error in copysector(): i==highlightsectorcnt");
goto nonextsector;
}
else if (highlightsector[i]==soursector)
{
message("internal error in copysector(): highlightsector[i]==soursector");
goto nonextsector;
}
wall[newnumwalls].nextwall = numwalls + m + (wall[j].nextwall-sector[k].wallptr);
}
else
{
nonextsector:
wall[newnumwalls].nextsector = -1;
wall[newnumwalls].nextwall = -1;
}
// the below code is incorrect in the general case since, in a set of
// selected sectors, the order may not be the same as the destination ones
// wall[newnumwalls].nextwall += deststartwall-startwall;
// wall[newnumwalls].nextsector += destsector-soursector;
}
newnumwalls++;
}
//for(j=deststartwall;j<newnumwalls;j++)
//{
// if (wall[j].nextwall >= 0)
// checksectorpointer(wall[j].nextwall,wall[j].nextsector);
// checksectorpointer((short)j,destsector);
//}
if (newnumwalls > deststartwall)
{
//duplicate sectors
Bmemcpy(&sector[destsector],&sector[soursector],sizeof(sectortype));
sector[destsector].wallptr = deststartwall;
sector[destsector].wallnum = newnumwalls-deststartwall;
if (copystat == 1)
{
//duplicate sprites
j = headspritesect[soursector];
while (j >= 0)
{
m = insertsprite(destsector,sprite[j].statnum);
if (m<0)
{
message("Some sprites not duplicated because limit was reached.");
break;
}
Bmemcpy(&sprite[m],&sprite[j],sizeof(spritetype));
sprite[m].sectnum = destsector; //Don't let memcpy overwrite sector!
j = nextspritesect[j];
}
}
}
}
#define DOPRINT(Yofs, fmt, ...) \
Bsprintf(snotbuf, fmt, ## __VA_ARGS__); \
printext16(8+col*200, ydim/*-(row*96)*/-STATUS2DSIZ+Yofs, color, -1, snotbuf, 0);
void showsectordata(int16_t sectnum, int16_t small)
{
sectortype *sec;
char snotbuf[80];
int32_t col=0; //,row = 0;
int32_t color = small ? whitecol : editorcolors[11];
sec = &sector[sectnum];
if (small)
{
_printmessage16("^10Sector %d %s ^O(F7 to edit)", sectnum, ExtGetSectorCaption(sectnum));
return;
}
DOPRINT(32, "^10Sector %d", sectnum);
DOPRINT(48, "Firstwall: %d", sec->wallptr);
DOPRINT(56, "Numberofwalls: %d", sec->wallnum);
DOPRINT(64, "Firstsprite: %d", headspritesect[sectnum]);
DOPRINT(72, "Tags: %d, %d", sec->hitag, sec->lotag);
DOPRINT(80, " (0x%x), (0x%x)", sec->hitag, sec->lotag);
DOPRINT(88, "Extra: %d", sec->extra);
DOPRINT(96, "Visibility: %d", sec->visibility);
DOPRINT(104, "Pixel height: %d", (sec->floorz-sec->ceilingz)>>8);
col++;
DOPRINT(32, "^10CEILING:^O");
DOPRINT(48, "Flags (hex): %x", sec->ceilingstat);
DOPRINT(56, "(X,Y)pan: %d, %d", sec->ceilingxpanning, sec->ceilingypanning);
DOPRINT(64, "Shade byte: %d", sec->ceilingshade);
DOPRINT(72, "Z-coordinate: %d", sec->ceilingz);
DOPRINT(80, "Tile number: %d", sec->ceilingpicnum);
DOPRINT(88, "Ceiling heinum: %d", sec->ceilingheinum);
DOPRINT(96, "Palookup number: %d", sec->ceilingpal);
col++;
DOPRINT(32, "^10FLOOR:^O");
DOPRINT(48, "Flags (hex): %x", sec->floorstat);
DOPRINT(56, "(X,Y)pan: %d, %d", sec->floorxpanning, sec->floorypanning);
DOPRINT(64, "Shade byte: %d", sec->floorshade);
DOPRINT(72, "Z-coordinate: %d", sec->floorz);
DOPRINT(80, "Tile number: %d", sec->floorpicnum);
DOPRINT(88, "Floor heinum: %d", sec->floorheinum);
DOPRINT(96, "Palookup number: %d", sec->floorpal);
}
void showwalldata(int16_t wallnum, int16_t small)
{
walltype *wal;
int32_t sec;
char snotbuf[80];
int32_t col=0; //, row = 0;
int32_t color = small ? whitecol : editorcolors[11];
wal = &wall[wallnum];
if (small)
{
_printmessage16("^10Wall %d %s ^O(F8 to edit)", wallnum, ExtGetWallCaption(wallnum));
return;
}
DOPRINT(32, "^10Wall %d", wallnum);
DOPRINT(48, "X-coordinate: %d", wal->x);
DOPRINT(56, "Y-coordinate: %d", wal->y);
DOPRINT(64, "Point2: %d", wal->point2);
DOPRINT(72, "Sector: ^010%d", sectorofwall(wallnum));
DOPRINT(88, "Tags: %d, %d", wal->hitag, wal->lotag);
DOPRINT(96, " (0x%x), (0x%x)", wal->hitag, wal->lotag);
col++;
DOPRINT(32, "^10%s^O", (wal->picnum>=0 && wal->picnum<MAXTILES) ? names[wal->picnum] : "!INVALID!");
DOPRINT(48, "Flags (hex): %x", wal->cstat);
DOPRINT(56, "Shade: %d", wal->shade);
DOPRINT(64, "Pal: %d", wal->pal);
DOPRINT(72, "(X,Y)repeat: %d, %d", wal->xrepeat, wal->yrepeat);
DOPRINT(80, "(X,Y)pan: %d, %d", wal->xpanning, wal->ypanning);
DOPRINT(88, "Tile number: %d", wal->picnum);
DOPRINT(96, "OverTile number: %d", wal->overpicnum);
col++;
DOPRINT(48-(small?16:0), "nextsector: %d", wal->nextsector);
DOPRINT(56-(small?16:0), "nextwall: %d", wal->nextwall);
DOPRINT(72-(small?16:0), "Extra: %d", wal->extra);
// TX 20050102 I'm not sure what unit dist<<4 is supposed to be, but dist itself is correct in terms of game coordinates as one would expect
DOPRINT(96-(small?16:0), "Wall length: %d", wallength(wallnum));
sec = sectorofwall(wallnum);
DOPRINT(104-(small?16:0), "Pixel height: %d", (sector[sec].floorz-sector[sec].ceilingz)>>8);
}
void showspritedata(int16_t spritenum, int16_t small)
{
spritetype *spr;
char snotbuf[80];
int32_t col=0; //, row = 0;
int32_t color = small ? whitecol : editorcolors[11];
spr = &sprite[spritenum];
if (small)
{
_printmessage16("^10Sprite %d %s ^O(F8 to edit)",spritenum, ExtGetSpriteCaption(spritenum));
return;
}
DOPRINT(32, "^10Sprite %d", spritenum);
DOPRINT(48, "X-coordinate: %d", spr->x);
DOPRINT(56, "Y-coordinate: %d", spr->y);
DOPRINT(64, "Z-coordinate: %d", spr->z);
DOPRINT(72, "Sectnum: ^010%d", spr->sectnum);
DOPRINT(80, "Statnum: %d", spr->statnum);
DOPRINT(96, "Tags: %d, %d", spr->hitag, spr->lotag);
DOPRINT(104, " (0x%x), (0x%x)", spr->hitag, spr->lotag);
col++;
DOPRINT(32, "^10%s^O", (spr->picnum>=0 && spr->picnum<MAXTILES) ? names[spr->picnum] : "!INVALID!");
DOPRINT(48, "Flags (hex): %x", spr->cstat);
DOPRINT(56, "Shade: %d", spr->shade);
DOPRINT(64, "Pal: %d", spr->pal);
DOPRINT(72, "(X,Y)repeat: %d, %d", spr->xrepeat, spr->yrepeat);
DOPRINT(80, "(X,Y)offset: %d, %d", spr->xoffset, spr->yoffset);
DOPRINT(88, "Tile number: %d", spr->picnum);
col++;
DOPRINT(48, "Angle (2048 degrees): %d", spr->ang);
DOPRINT(56, "X-Velocity: %d", spr->xvel);
DOPRINT(64, "Y-Velocity: %d", spr->yvel);
DOPRINT(72, "Z-Velocity: %d", spr->zvel);
DOPRINT(80, "Owner: %d", spr->owner);
DOPRINT(88, "Clipdist: %d", spr->clipdist);
DOPRINT(96, "Extra: %d", spr->extra);
}
#undef DOPRINT
// gets called once per totalclock increment since last call
void keytimerstuff(void)
{
if (DOWN_BK(STRAFE) == 0)
{
if (DOWN_BK(TURNLEFT)) angvel = max(angvel-pk_turnaccel, -128);
if (DOWN_BK(TURNRIGHT)) angvel = min(angvel+pk_turnaccel, 127);
}
else
{
if (DOWN_BK(TURNLEFT)) svel = min(svel+16, 255); // svel and vel aren't even chars...
if (DOWN_BK(TURNRIGHT)) svel = max(svel-16, -256);
}
if (DOWN_BK(MOVEFORWARD)) vel = min(vel+16, 255);
if (DOWN_BK(MOVEBACKWARD)) vel = max(vel-16, -256);
/* if (DOWN_BK(STRAFELEFT)) svel = min(svel+8, 127);
if (DOWN_BK(STRAFERIGHT)) svel = max(svel-8, -128); */
if (angvel < 0) angvel = min(angvel+pk_turndecel, 0);
if (angvel > 0) angvel = max(angvel-pk_turndecel, 0);
if (svel < 0) svel = min(svel+6, 0);
if (svel > 0) svel = max(svel-6, 0);
if (vel < 0) vel = min(vel+6, 0);
if (vel > 0) vel = max(vel-6, 0);
/* if(mlook) pos.z -= (horiz-101)*(vel/40); */
}
#if 0
int32_t snfillprintf(char *outbuf, size_t bufsiz, int32_t fill, const char *fmt, ...)
{
char tmpstr[256];
int32_t nwritten, ofs;
va_list va;
va_start(va, fmt);
nwritten = Bvsnprintf(tmpstr, bufsiz, fmt, va);
va_end(va);
ofs = min(nwritten, (signed)bufsiz-1);
Bmemset(outbuf, fill, bufsiz-ofs);
return ofs;
}
#endif
void _printmessage16(const char *fmt, ...)
{
int32_t i, ybase;
char snotbuf[156];
char tmpstr[160];
va_list va;
va_start(va, fmt);
Bvsnprintf(tmpstr, 156, fmt, va);
va_end(va);
i = 0;
while (tmpstr[i] && i < 146)
{
snotbuf[i] = tmpstr[i];
i++;
}
snotbuf[i] = 0;
if (lastpm16time == totalclock)
Bstrcpy(lastpm16buf, snotbuf);
clearministatbar16();
ybase = ydim-STATUS2DSIZ+128-8;
printext16(8, ybase+8, whitecol, -1, snotbuf, 0);
}
void printmessage256(int32_t x, int32_t y, const char *name)
{
char snotbuf[80];
int32_t i;
i = 0;
while (name[i] && i < 62)
{
snotbuf[i] = name[i];
i++;
}
while (i < 62)
{
snotbuf[i] = 32;
i++;
}
snotbuf[62] = 0;
printext256(x+2,y+2,0,-1,snotbuf,0);
printext256(x,y,whitecol,-1,snotbuf,0);
}
//Find closest point (*dax, *day) on wall (dawall) to (x, y)
static void getclosestpointonwall(int32_t x, int32_t y, int32_t dawall, int32_t *nx, int32_t *ny)
{
walltype *wal;
int64_t i, j, dx, dy;
wal = &wall[dawall];
dx = wall[wal->point2].x - wal->x;
dy = wall[wal->point2].y - wal->y;
i = dx*(x-wal->x) + dy*(y-wal->y);
if (i <= 0) { *nx = wal->x; *ny = wal->y; return; }
j = dx*dx+dy*dy;
if (i >= j) { *nx = wal->x+dx; *ny = wal->y+dy; return; }
i=((i<<15)/j)<<15;
*nx = wal->x + ((dx*i)>>30);
*ny = wal->y + ((dy*i)>>30);
}
static void initcrc(void)
{
int32_t i, j, k, a;
for (j=0; j<256; j++) //Calculate CRC table
{
k = (j<<8); a = 0;
for (i=7; i>=0; i--)
{
if (((k^a)&0x8000) > 0)
a = ((a<<1)&65535) ^ 0x1021; //0x1021 = genpoly
else
a = ((a<<1)&65535);
k = ((k<<1)&65535);
}
crctable[j] = (a&65535);
}
}
static int32_t GetWallBaseZ(int32_t wallnum)
{
int32_t z=0, sectnum, nextsec;
sectnum = sectorofwall(wallnum);
nextsec = wall[wallnum].nextsector;
if (nextsec == -1) //1-sided wall
{
if (wall[wallnum].cstat&4) // floor-aligned
z = sector[sectnum].floorz;
else
z = sector[sectnum].ceilingz;
}
else //2-sided wall
{
if (wall[wallnum].cstat&4)
z = sector[sectnum].ceilingz;
else
{
if (sector[nextsec].ceilingz > sector[sectnum].ceilingz)
z = sector[nextsec].ceilingz; //top step
if (sector[nextsec].floorz < sector[sectnum].floorz)
z = sector[nextsec].floorz; //bottom step
}
}
return(z);
}
static void AlignWalls(int32_t w0, int32_t z0, int32_t w1, int32_t z1, int32_t tilenum)
{
int32_t n;
//do the x alignment
wall[w1].cstat &= ~0x0108; //Set to non-flip
wall[w1].xpanning = (uint8_t)((wall[w0].xpanning + (wall[w0].xrepeat<<3))%tilesizx[tilenum]);
for (n=picsiz[tilenum]>>4; (1<<n)<tilesizy[tilenum]; n++);
wall[w1].yrepeat = wall[w0].yrepeat;
wall[w1].ypanning = (uint8_t)(wall[w0].ypanning + (((z1-z0)*wall[w0].yrepeat)>>(n+3)));
}
void AlignWallPoint2(int32_t w0)
{
int32_t w1 = wall[w0].point2;
AlignWalls(w0,GetWallBaseZ(w0), w1,GetWallBaseZ(w1), wall[w0].picnum);
}
// pass maxrecurs=0 for unconstrained recursion
int32_t AutoAlignWalls(int32_t w0, int32_t dorecurse, int32_t nrecurs)
{
int32_t z0, z1, tilenum, w1, visible, nextsec, sectnum;
static int32_t numaligned;
tilenum = wall[w0].picnum;
if (nrecurs == 0)
{
//clear visited bits
Bmemset(visited, 0, sizeof(visited));
visited[w0>>3] |= (1<<(w0&7));
numaligned = 0;
}
z0 = GetWallBaseZ(w0);
w1 = wall[w0].point2;
//loop through walls at this vertex in CCW order
while (1)
{
//break if this wall would connect us in a loop
if (visited[w1>>3]&(1<<(w1&7)))
break;
visited[w1>>3] |= (1<<(w1&7));
//break if reached back of left wall
if (wall[w1].nextwall == w0)
break;
if (wall[w1].picnum == tilenum)
{
z1 = GetWallBaseZ(w1);
visible = 0;
nextsec = wall[w1].nextsector;
if (nextsec < 0)
visible = 1;
else
{
int32_t cz,fz, czn,fzn;
//ignore two sided walls that have no visible face
sectnum = NEXTWALL(w1).nextsector;
getzsofslope(sectnum, wall[w1].x,wall[w1].y, &cz, &fz);
getzsofslope(nextsec, wall[w1].x,wall[w1].y, &czn, &fzn);
if (cz < czn || fz > fzn)
visible = 1;
}
if (visible)
{
numaligned++;
AlignWalls(w0,z0, w1,z1, tilenum);
//if wall was 1-sided, no need to recurse
if (wall[w1].nextwall < 0)
{
w0 = w1;
z0 = GetWallBaseZ(w0);
w1 = wall[w0].point2;
continue;
}
else if (dorecurse)
AutoAlignWalls(w1, 1, nrecurs+1);
}
}
if (wall[w1].nextwall < 0) break;
w1 = NEXTWALL(w1).point2;
}
return numaligned;
}
#define PLAYTEST_MAPNAME "autosave_playtest.map"
void test_map(int32_t mode)
{
if (!mode)
updatesector(pos.x, pos.y, &cursectnum);
else
updatesector(startposx, startposy, &startsectnum);
if ((!mode && cursectnum >= 0) || (mode && startsectnum >= 0))
{
char *param = " -map " PLAYTEST_MAPNAME " -noinstancechecking";
char *fullparam;
char current_cwd[BMAX_PATH];
int32_t slen = 0;
BFILE *fp;
if ((program_origcwd[0] == '\0') || !getcwd(current_cwd, BMAX_PATH))
current_cwd[0] = '\0';
else // Before we check if file exists, for the case there's no absolute path.
chdir(program_origcwd);
fp = fopen(game_executable, "rb"); // File exists?
if (fp != NULL)
fclose(fp);
else
{
#ifdef _WIN32
fullparam = Bstrrchr(mapster32_fullpath, '\\');
#else
fullparam = Bstrrchr(mapster32_fullpath, '/');
#endif
if (fullparam)
{
slen = fullparam-mapster32_fullpath+1;
Bstrncpy(game_executable, mapster32_fullpath, slen);
// game_executable is now expected to not be NULL-terminated!
Bstrcpy(game_executable+slen, DEFAULT_GAME_EXEC);
}
else
Bstrcpy(game_executable, DEFAULT_GAME_LOCAL_EXEC);
}
if (current_cwd[0] != '\0') // Temporarily changing back,
chdir(current_cwd); // after checking if file exists.
if (testplay_addparam)
slen = Bstrlen(testplay_addparam);
// Considering the NULL character, quatation marks
// and a possible extra space not in testplay_addparam,
// the length should be Bstrlen(game_executable)+Bstrlen(param)+(slen+1)+2+1.
fullparam = Bmalloc(Bstrlen(game_executable)+Bstrlen(param)+slen+4);
Bsprintf(fullparam,"\"%s\"",game_executable);
if (testplay_addparam)
{
Bstrcat(fullparam, " ");
Bstrcat(fullparam, testplay_addparam);
}
Bstrcat(fullparam, param);
fixspritesectors(); //Do this before saving!
ExtPreSaveMap();
if (mode)
saveboard(PLAYTEST_MAPNAME,&startposx,&startposy,&startposz,&startang,&startsectnum);
else
saveboard(PLAYTEST_MAPNAME,&pos.x,&pos.y,&pos.z,&ang,&cursectnum);
message("Board saved to " PLAYTEST_MAPNAME ". Starting the game...");
OSD_Printf("...as `%s'\n", fullparam);
showframe(1);
uninitmouse();
#ifdef _WIN32
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si,sizeof(si));
ZeroMemory(&pi,sizeof(pi));
si.cb = sizeof(si);
if (!CreateProcess(NULL,fullparam,NULL,NULL,0,0,NULL,NULL,&si,&pi))
message("Error launching the game!");
else WaitForSingleObject(pi.hProcess,INFINITE);
}
#else
if (current_cwd[0] != '\0')
{
chdir(program_origcwd);
if (system(fullparam))
message("Error launching the game!");
chdir(current_cwd);
}
else system(fullparam);
#endif
printmessage16("Game process exited");
initmouse();
clearkeys();
Bfree(fullparam);
}
else
printmessage16("Position must be in valid player space to test map!");
}