// 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 (jf@jonof.id.au) #include "compat.h" #include "build.h" #include "names.h" #include "pragmas.h" #include "cache1d.h" #include "game.h" #include "osd.h" #include "mmulti.h" #include "common.h" #include "renderlayer.h" #include "common_game.h" const char *AppProperName = "KenBuild"; const char *AppTechnicalName = "testgame"; #define SETUPFILENAME "testgame.cfg" char setupfilename[BMAX_PATH] = SETUPFILENAME; #define TIMERINTSPERSECOND 140 //280 #define MOVESPERSECOND 40 #define TICSPERFRAME 3 #define MOVEFIFOSIZ 256 #define EYEHEIGHT (32<<8) //Normally (32<<8), (51<<8) to make mirrors happy #define TILE_TILT (MAXTILES-2) static int32_t setsprite_eyeheight(int16_t spritenum, const vec3_t *pos) ATTRIBUTE((nonnull(2))); static int32_t setsprite_eyeheight(int16_t spritenum, const vec3_t *pos) { vec3_t eyepos = *pos; eyepos.z += EYEHEIGHT; return setsprite(spritenum, &eyepos); } // declared in sound.c void initsb(char,char,int,char,char,char,char); void uninitsb(void); void setears(int,int,int,int); void wsayfollow(char const *,int,int,int *,int *,char); void wsay(char const *,int,int,int); void loadwaves(void); void loadsong(char const *); void musicon(void); void musicoff(void); void refreshaudio(void); // declared in config.c int Ken_loadsetup(const char *); int Ken_writesetup(const char *); /*************************************************************************** KEN'S TAG DEFINITIONS: (Please define your own tags for your games) sector[?].lotag = 0 Normal sector sector[?].lotag = 1 If you are on a sector with this tag, then all sectors with same hi tag as this are operated. Once. sector[?].lotag = 2 Same as sector[?].tag = 1 but this is retriggable. sector[?].lotag = 3 A really stupid sector that really does nothing now. sector[?].lotag = 4 A sector where you are put closer to the floor (such as the slime in DOOM1.DAT) sector[?].lotag = 5 A really stupid sector that really does nothing now. sector[?].lotag = 6 A normal door - instead of pressing D, you tag the sector with a 6. The reason I make you edit doors this way is so that can program the doors yourself. sector[?].lotag = 7 A door the goes down to open. sector[?].lotag = 8 A door that opens horizontally in the middle. sector[?].lotag = 9 A sliding door that opens vertically in the middle. -Example of the advantages of not using BSP tree. sector[?].lotag = 10 A warping sector with floor and walls that shade. sector[?].lotag = 11 A sector with all walls that do X-panning. sector[?].lotag = 12 A sector with walls using the dragging function. sector[?].lotag = 13 A sector with some swinging doors in it. sector[?].lotag = 14 A revolving door sector. sector[?].lotag = 15 A subway track. sector[?].lotag = 16 A true double-sliding door. wall[?].lotag = 0 Normal wall wall[?].lotag = 1 Y-panning wall wall[?].lotag = 2 Switch - If you flip it, then all sectors with same hi tag as this are operated. wall[?].lotag = 3 Marked wall to detemine starting dir. (sector tag 12) wall[?].lotag = 4 Mark on the shorter wall closest to the pivot point of a swinging door. (sector tag 13) wall[?].lotag = 5 Mark where a subway should stop. (sector tag 15) wall[?].lotag = 6 Mark for true double-sliding doors (sector tag 16) wall[?].lotag = 7 Water fountain wall[?].lotag = 8 Bouncy wall! sprite[?].lotag = 0 Normal sprite sprite[?].lotag = 1 If you press space bar on an AL, and the AL is tagged with a 1, he will turn evil. sprite[?].lotag = 2 When this sprite is operated, a bomb is shot at its position. sprite[?].lotag = 3 Rotating sprite. sprite[?].lotag = 4 Sprite switch. sprite[?].lotag = 5 Basketball hoop score. KEN'S STATUS DEFINITIONS: (Please define your own statuses for your games) status = 0 Inactive sprite status = 1 Active monster sprite status = 2 Monster that becomes active only when it sees you status = 3 Smoke on the wall for chainguns status = 4 Splashing sprites (When you shoot slime) status = 5 Explosion! status = 6 Travelling bullet status = 7 Bomb sprial-out explosion status = 8 Player! status = 9 EVILALGRAVE shrinking list status = 10 EVILAL list status = 11 Sprite respawning list status = 12 Sprite which does not respawn (Andy's addition) status = MAXSTATUS Non-existent sprite (this will be true for your code also) **************************************************************************/ typedef struct { signed char fvel, svel, avel; short bits; } input; static int screentilt = 0, oscreentilt = 0; static int fvel, svel, avel; static int fvel2, svel2, avel2; #define NUMOPTIONS 8 #define NUMGAMEKEYS 19 char option[NUMOPTIONS] = {0,0,0,0,0,0,1,0}; unsigned char keys[NUMGAMEKEYS] = { 0xc8,0xd0,0xcb,0xcd,0x2a,0x9d,0x1d,0x39, 0x1e,0x2c,0xd1,0xc9,0x33,0x34, 0x9c,0x1c,0xd,0xc,0xf }; int xdimgame = 320, ydimgame = 200, bppgame = 8, xdim2d = 640, ydim2d = 480; // JBF 20050318: config.c expects to find these int forcesetup = 1; static int digihz[8] = {6000,8000,11025,16000,22050,32000,44100,48000}; static char frame2draw[MAXPLAYERS]; static int frameskipcnt[MAXPLAYERS]; #define LAVASIZ 128 #define LAVALOGSIZ 7 #define LAVAMAXDROPS 32 static char lavabakpic[(LAVASIZ+4)*(LAVASIZ+4)], lavainc[LAVASIZ]; static int lavanumdrops, lavanumframes; static int lavadropx[LAVAMAXDROPS], lavadropy[LAVAMAXDROPS]; static int lavadropsiz[LAVAMAXDROPS], lavadropsizlookup[LAVAMAXDROPS]; static int lavaradx[24][96], lavarady[24][96], lavaradcnt[32]; //Shared player variables static vec3_t pos[MAXPLAYERS]; static int horiz[MAXPLAYERS], zoom[MAXPLAYERS], hvel[MAXPLAYERS]; static short ang[MAXPLAYERS], cursectnum[MAXPLAYERS], ocursectnum[MAXPLAYERS]; static short playersprite[MAXPLAYERS], deaths[MAXPLAYERS]; static int lastchaingun[MAXPLAYERS]; static int health[MAXPLAYERS], flytime[MAXPLAYERS]; static short oflags[MAXPLAYERS]; static short numbombs[MAXPLAYERS]; static short numgrabbers[MAXPLAYERS]; // Andy did this static short nummissiles[MAXPLAYERS]; // Andy did this static char dimensionmode[MAXPLAYERS]; static char revolvedoorstat[MAXPLAYERS]; static short revolvedoorang[MAXPLAYERS], revolvedoorrotang[MAXPLAYERS]; static int revolvedoorx[MAXPLAYERS], revolvedoory[MAXPLAYERS]; static int nummoves; // Bug: NUMSTATS used to be equal to the greatest tag number, // so that the last statrate[] entry was random memory junk // because stats 0-NUMSTATS required NUMSTATS+1 bytes. -Andy #define NUMSTATS 13 static signed char statrate[NUMSTATS] = {-1,0,-1,0,0,0,1,3,0,3,15,-1,-1}; //Input structures static char networkmode; //0 is 2(n-1) mode, 1 is n(n-1) mode static int locselectedgun, locselectedgun2; static input loc, oloc, loc2; static input ffsync[MAXPLAYERS], osync[MAXPLAYERS], ssync[MAXPLAYERS]; //Input faketimerhandler -> movethings fifo static int movefifoplc, movefifoend[MAXPLAYERS]; static input baksync[MOVEFIFOSIZ][MAXPLAYERS]; //Game recording variables static int reccnt, recstat = 1; static input recsync[16384][2]; //static int myminlag[MAXPLAYERS], mymaxlag, otherminlag, bufferjitter = 1; static signed char otherlag[MAXPLAYERS] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; static int averagelag[MAXPLAYERS] = {512,512,512,512,512,512,512,512,512,512,512,512,512,512,512,512}; static int fakemovefifoplc; static vec3_t my, omy; static int myzvel; static int myhoriz, omyhoriz; static short myang, omyang, mycursectnum; static vec3_t mybak[MOVEFIFOSIZ]; static int myhorizbak[MOVEFIFOSIZ]; static short myangbak[MOVEFIFOSIZ]; //GAME.C sync state variables static char syncstat, syncval[MOVEFIFOSIZ], othersyncval[MOVEFIFOSIZ]; static int syncvaltottail, syncvalhead, othersyncvalhead, syncvaltail; static char detailmode = 0, ready2send = 0; static int ototalclock = 0, gotlastpacketclock = 0, smoothratio; static vec3_t opos[MAXPLAYERS]; static int ohoriz[MAXPLAYERS], ozoom[MAXPLAYERS]; static short oang[MAXPLAYERS]; static vec3_t osprite[MAXSPRITES]; #define MAXINTERPOLATIONS 1024 static int numinterpolations = 0, startofdynamicinterpolations = 0; static int oldipos[MAXINTERPOLATIONS]; static int bakipos[MAXINTERPOLATIONS]; static int *curipos[MAXINTERPOLATIONS]; // extern int cachecount; static char playerreadyflag[MAXPLAYERS]; //Miscellaneous variables static unsigned char packbuf[MAXXDIM]; static char tempbuf[MAXXDIM]; static char boardfilename[BMAX_PATH]; static short tempshort[MAXSECTORS]; static short screenpeek = 0, oldmousebstatus = 0; short brightness = 0; static short screensize, screensizeflag = 0; static short neartagsector, neartagwall, neartagsprite; static int lockclock, neartagdist, neartaghitdist; extern int pageoffset, ydim16; static int globhiz, globloz, globhihit, globlohit; //Over the shoulder mode variables static int cameradist = -1, cameraang = 0, cameraclock = 0; //Board animation variables #define MAXMIRRORS 64 static short mirrorwall[MAXMIRRORS], mirrorsector[MAXMIRRORS], mirrorcnt; static short floormirrorsector[64], floormirrorcnt; static short turnspritelist[16], turnspritecnt; static short warpsectorlist[64], warpsectorcnt; static short xpanningsectorlist[16], xpanningsectorcnt; static short ypanningwalllist[64], ypanningwallcnt; static short floorpanninglist[64], floorpanningcnt; static short dragsectorlist[16], dragxdir[16], dragydir[16], dragsectorcnt; static int dragx1[16], dragy1[16], dragx2[16], dragy2[16], dragfloorz[16]; static short swingcnt, swingwall[32][5], swingsector[32]; static short swingangopen[32], swingangclosed[32], swingangopendir[32]; static short swingang[32], swinganginc[32]; static int swingx[32][8], swingy[32][8]; static short revolvesector[4], revolveang[4], revolvecnt; static int revolvex[4][16], revolvey[4][16]; static int revolvepivotx[4], revolvepivoty[4]; static short subwaytracksector[4][128], subwaynumsectors[4], subwaytrackcnt; static int subwaystop[4][8], subwaystopcnt[4]; static int subwaytrackx1[4], subwaytracky1[4]; static int subwaytrackx2[4], subwaytracky2[4]; static int subwayx[4], subwaygoalstop[4], subwayvel[4], subwaypausetime[4]; static short waterfountainwall[MAXPLAYERS], waterfountaincnt[MAXPLAYERS]; static short slimesoundcnt[MAXPLAYERS]; //Variables that let you type messages to other player static char getmessage[162], getmessageleng; static int getmessagetimeoff; static char typemessage[162], typemessageleng = 0, typemode = 0; #if 0 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, }; #endif //These variables are for animating x, y, or z-coordinates of sectors, //walls, or sprites (They are NOT to be used for changing the [].picnum's) //See the setanimation(), and getanimategoal() functions for more details. #define MAXANIMATES 512 static int *animateptr[MAXANIMATES], animategoal[MAXANIMATES]; static int animatevel[MAXANIMATES], animateacc[MAXANIMATES], animatecnt = 0; #if defined USE_OPENGL //These parameters are in exact order of sprite structure in BUILD.H #define spawnsprite(newspriteindex2,x2,y2,z2,cstat2,shade2,pal2, \ clipdist2,xrepeat2,yrepeat2,xoffset2,yoffset2,picnum2,ang2, \ xvel2,yvel2,zvel2,owner2,sectnum2,statnum2,lotag2,hitag2,extra2) \ { \ spritetype *spr2; \ newspriteindex2 = insertsprite(sectnum2,statnum2); \ spr2 = &sprite[newspriteindex2]; \ spr2->x = x2; spr2->y = y2; spr2->z = z2; \ spr2->cstat = cstat2; spr2->shade = shade2; \ spr2->pal = pal2; spr2->clipdist = clipdist2; \ spr2->xrepeat = xrepeat2; spr2->yrepeat = yrepeat2; \ spr2->xoffset = xoffset2; spr2->yoffset = yoffset2; \ spr2->picnum = picnum2; spr2->ang = ang2; \ spr2->xvel = xvel2; spr2->yvel = yvel2; spr2->zvel = zvel2; \ spr2->owner = owner2; \ spr2->lotag = lotag2; spr2->hitag = hitag2; spr2->extra = extra2; \ copybuf(&spr2->x,&osprite[newspriteindex2].x,3); \ show2dsprite[newspriteindex2>>3] &= ~(1<<(newspriteindex2&7)); \ if (show2dsector[sectnum2>>3]&(1<<(sectnum2&7))) \ show2dsprite[newspriteindex2>>3] |= (1<<(newspriteindex2&7)); \ clearbufbyte(&spriteext[newspriteindex2], sizeof(spriteext_t), 0); \ } #else #define spawnsprite(newspriteindex2,x2,y2,z2,cstat2,shade2,pal2, \ clipdist2,xrepeat2,yrepeat2,xoffset2,yoffset2,picnum2,ang2, \ xvel2,yvel2,zvel2,owner2,sectnum2,statnum2,lotag2,hitag2,extra2) \ { \ spritetype *spr2; \ newspriteindex2 = insertsprite(sectnum2,statnum2); \ spr2 = &sprite[newspriteindex2]; \ spr2->x = x2; spr2->y = y2; spr2->z = z2; \ spr2->cstat = cstat2; spr2->shade = shade2; \ spr2->pal = pal2; spr2->clipdist = clipdist2; \ spr2->xrepeat = xrepeat2; spr2->yrepeat = yrepeat2; \ spr2->xoffset = xoffset2; spr2->yoffset = yoffset2; \ spr2->picnum = picnum2; spr2->ang = ang2; \ spr2->xvel = xvel2; spr2->yvel = yvel2; spr2->zvel = zvel2; \ spr2->owner = owner2; \ spr2->lotag = lotag2; spr2->hitag = hitag2; spr2->extra = extra2; \ copybuf(&spr2->x,&osprite[newspriteindex2].x,3); \ show2dsprite[newspriteindex2>>3] &= ~(1<<(newspriteindex2&7)); \ if (show2dsector[sectnum2>>3]&(1<<(sectnum2&7))) \ show2dsprite[newspriteindex2>>3] |= (1<<(newspriteindex2&7)); \ } #endif int nextvoxid = 0; int osdcmd_restartvid(const osdfuncparm_t *parm) { UNREFERENCED_PARAMETER(parm); resetvideomode(); if (setgamemode(fullscreen,xdim,ydim,bpp)) buildputs("restartvid: Reset failed...\n"); return OSDCMD_OK; } static int osdcmd_vidmode(const osdfuncparm_t *parm) { int newx = xdim, newy = ydim, newbpp = bpp, newfullscreen = fullscreen; if (parm->numparms < 1 || parm->numparms > 4) return OSDCMD_SHOWHELP; switch (parm->numparms) { case 1: // bpp switch newbpp = Batol(parm->parms[0]); break; case 2: // res switch newx = Batol(parm->parms[0]); newy = Batol(parm->parms[1]); break; case 3: // res & bpp switch case 4: newx = Batol(parm->parms[0]); newy = Batol(parm->parms[1]); newbpp = Batol(parm->parms[2]); if (parm->numparms == 4) newfullscreen = (Batol(parm->parms[3]) != 0); break; } if (setgamemode(newfullscreen,newx,newy,newbpp)) buildputs("vidmode: Mode change failed!\n"); screensize = xdim+1; return OSDCMD_OK; } static int osdcmd_map(const osdfuncparm_t *parm) { int i; char *dot, namebuf[BMAX_PATH+1]; if (parm->numparms != 1) return OSDCMD_SHOWHELP; strncpy(namebuf, parm->parms[0], BMAX_PATH); namebuf[BMAX_PATH] = 0; dot = strrchr(namebuf, '.'); if ((!dot || Bstrcasecmp(dot, ".map")) && strlen(namebuf) <= BMAX_PATH-4) { strcat(namebuf, ".map"); } prepareboard(namebuf); screenpeek = myconnectindex; reccnt = 0; for (i=connecthead; i>=0; i=connectpoint2[i]) initplayersprite((short)i); waitforeverybody(); totalclock = ototalclock = 0; gotlastpacketclock = 0; nummoves = 0; ready2send = 1; drawscreen(screenpeek,65536L); return OSDCMD_OK; } static void Ken_UninitAll(void) { sendlogoff(); //Signing off musicoff(); uninitmultiplayers(); uninittimer(); uninitinput(); uninitengine(); uninitsb(); uninitgroupfile(); } static void Ken_FatalEngineError(void) { buildprintf("There was a problem initialising the engine: %s.\n", engineerrstr); } int32_t app_main(int32_t argc, char const * const * argv) { #if defined STARTUP_SETUP_WINDOW int cmdsetup = 0; #endif int i, j, k /*, l, fil, waitplayers, x1, y1, x2, y2*/; int /*other, packleng,*/ netparm; OSD_SetFunctions( NULL, NULL, NULL, NULL, NULL, COMMON_clearbackground, BGetTime, NULL ); OSD_SetParameters(0,2, 0,0, 4,0); OSD_SetLogFile("testgame.log"); initprintf("%s %s %s\n", AppProperName, s_buildRev, s_buildInfo); initprintf("Compiled %s\n", s_buildTimestamp); #ifdef USE_OPENGL OSD_RegisterFunction("restartvid","restartvid: reinitialise the video mode",osdcmd_restartvid); OSD_RegisterFunction("vidmode","vidmode [xdim ydim] [bpp] [fullscreen]: immediately change the video mode",osdcmd_vidmode); OSD_RegisterFunction("map", "map [filename]: load a map", osdcmd_map); #endif wm_setapptitle(AppProperName); Bstrcpy(boardfilename, "nukeland.map"); j = 0; netparm = argc; for (i=1; i= 2); loadpics("tiles000.art",1048576); //Load artwork if (!qloadkvx(nextvoxid,"voxel000.kvx")) tiletovox[PLAYER] = nextvoxid++; if (!qloadkvx(nextvoxid,"voxel001.kvx")) tiletovox[BROWNMONSTER] = nextvoxid++; if (!loaddefinitionsfile(G_DefFile())) buildputs("Definitions file loaded.\n"); if (E_PostInit()) { Ken_UninitAll(); Ken_FatalEngineError(); return -1; } //Here's an example of TRUE ornamented walls //The allocatepermanenttile should be called right after loadpics //Since it resets the tile cache for each call. if (allocatepermanenttile(SLIME,128,128) == 0) //If enough memory { buildputs("Not enough memory for slime!\n"); exit(0); } if (allocatepermanenttile(MAXTILES-1,64,64) != 0) //If enough memory { //My face with an explosion written over it copytilepiece(KENPICTURE,0,0,64,64,MAXTILES-1,0,0); copytilepiece(EXPLOSION,0,0,64,64,MAXTILES-1,0,0); } initlava(); for (j=0; j<256; j++) tempbuf[j] = ((j+32)&255); //remap colors for screwy palette sectors makepalookup(16,tempbuf,0,0,0,1); for (j=0; j<256; j++) tempbuf[j] = j; makepalookup(17,tempbuf,96,96,96,1); for (j=0; j<256; j++) tempbuf[j] = j; //(j&31)+32; makepalookup(18,tempbuf,32,32,192,1); fillemptylookups(); prepareboard(boardfilename); //Load board initsb(option[1],option[2],digihz[option[7]>>4],((option[7]&4)>0)+1,((option[7]&2)>0)+1,60,option[7]&1); //if (Bstrcmp(boardfilename,"klab.map") == 0) // loadsong("klabsong.kdm"); //else loadsong("neatsong.kdm"); musicon(); #if 0 if (option[4] > 0) { x1 = ((xdim-screensize)>>1); x2 = x1+screensize-1; y1 = (((ydim-32)-scale(screensize,ydim-32,xdim))>>1); y2 = y1 + scale(screensize,ydim-32,xdim)-1; drawtilebackground(/*0L,0L,*/ BACKGROUND,8,x1,y1,x2,y2,0); sendlogon(); if (option[4] < 5) waitplayers = 2; else waitplayers = option[4]-3; while (numplayers < waitplayers) { sprintf(tempbuf,"%ld of %ld players in...",numplayers,waitplayers); printext256(68L,84L,31,0,tempbuf,0); nextpage(); if (getpacket(&other,packbuf) > 0) if (packbuf[0] == 255) keystatus[1] = 1; if (handleevents()) { if (quitevent) { keystatus[1] = 1; quitevent = 0; } } if (keystatus[1]) { Ken_UninitAll(); return 0; } } screenpeek = myconnectindex; if (numplayers <= 3) networkmode = 1; else networkmode = 0; j = 1; for (i=connecthead; i>=0; i=connectpoint2[i]) { if (myconnectindex == i) break; j++; } sprintf(getmessage,"Player %ld",j); if (networkmode == 0) { if (j == 1) Bstrcat(getmessage," (Master)"); else Bstrcat(getmessage," (Slave)"); } else Bstrcat(getmessage," (Even)"); getmessageleng = Bstrlen(getmessage); getmessagetimeoff = totalclock+120; } #endif screenpeek = myconnectindex; reccnt = 0; for (i=connecthead; i>=0; i=connectpoint2[i]) initplayersprite((short)i); waitforeverybody(); totalclock = ototalclock = 0; gotlastpacketclock = 0; nummoves = 0; ready2send = 1; drawscreen(screenpeek,65536L); while (!keystatus[1]) //Main loop starts here { if (handleevents()) { if (quitevent) { keystatus[1] = 1; quitevent = 0; } } refreshaudio(); OSD_DispatchQueued(); // backslash (useful only with KDM) // if (keystatus[0x2b]) { keystatus[0x2b] = 0; preparesndbuf(); } if ((networkmode == 1) || (myconnectindex != connecthead)) while (fakemovefifoplc != movefifoend[myconnectindex]) fakedomovethings(); getpackets(); if (typemode == 0) //if normal game keys active { if ((keystatus[0x2a]&keystatus[0x36]&keystatus[0x13]) > 0) //Sh.Sh.R (replay) { keystatus[0x13] = 0; playback(); } if (keystatus[0x26]&(keystatus[0x1d]|keystatus[0x9d])) //Load game { keystatus[0x26] = 0; loadgame(); drawstatusbar(screenpeek); // Andy did this } if (keystatus[0x1f]&(keystatus[0x1d]|keystatus[0x9d])) //Save game { keystatus[0x1f] = 0; savegame(); } } if ((networkmode == 0) || (option[4] == 0)) { while (movefifoplc != movefifoend[0]) domovethings(); } else { j = connecthead; if (j == myconnectindex) j = connectpoint2[j]; averagelag[j] = ((averagelag[j]*7+(((movefifoend[myconnectindex]-movefifoend[j]+otherlag[j]+2)&255)<<8))>>3); j = max(averagelag[j]>>9,1); while (((movefifoend[myconnectindex]-movefifoplc)&(MOVEFIFOSIZ-1)) > j) { for (i=connecthead; i>=0; i=connectpoint2[i]) if (movefifoplc == movefifoend[i]) break; if (i >= 0) break; if (myconnectindex != connecthead) { k = ((movefifoend[myconnectindex]-movefifoend[connecthead]-otherlag[connecthead]+128)&255); if (k > 128+1) ototalclock++; if (k < 128-1) ototalclock--; } domovethings(); } } i = (totalclock-gotlastpacketclock)*(65536/(TIMERINTSPERSECOND/MOVESPERSECOND)); drawscreen(screenpeek,i); } Ken_UninitAll(); return 0; } void operatesector(short dasector) { //Door code int i, j, /*k, s, nexti, good, cnt,*/ datag; int /*dax, day,*/ daz, dax2, day2, /*daz2,*/ centx, centy; short startwall, endwall, wallfind[2]; datag = sector[dasector].lotag; startwall = sector[dasector].wallptr; endwall = startwall + sector[dasector].wallnum; centx = 0L, centy = 0L; for (i=startwall; i= 0) //If door already moving, reverse its direction { if (datag == 8) daz = ((sector[dasector].ceilingz+sector[dasector].floorz)>>1); else daz = sector[dasector].floorz; if (animategoal[i] == daz) animategoal[i] = sector[nextsectorneighborz(dasector,sector[dasector].floorz,-1,-1)].ceilingz; else animategoal[i] = daz; animatevel[i] = 0; } else //else insert the door's ceiling on the animation list { if (sector[dasector].ceilingz == sector[dasector].floorz) daz = sector[nextsectorneighborz(dasector,sector[dasector].floorz,-1,-1)].ceilingz; else { if (datag == 8) daz = ((sector[dasector].ceilingz+sector[dasector].floorz)>>1); else daz = sector[dasector].floorz; } if ((j = setanimation(§or[dasector].ceilingz,daz,6L,6L)) >= 0) wsayfollow("updowndr.wav",4096L+(krand()&255)-128,256L,¢x,¢y,0); } } //Simple door that moves down if ((datag == 7) || (datag == 8)) //If the sector in front's elevator { i = getanimationgoal(§or[dasector].floorz); if (i >= 0) //If elevator already moving, reverse its direction { if (datag == 8) daz = ((sector[dasector].ceilingz+sector[dasector].floorz)>>1); else daz = sector[dasector].ceilingz; if (animategoal[i] == daz) animategoal[i] = sector[nextsectorneighborz(dasector,sector[dasector].ceilingz,1,1)].floorz; else animategoal[i] = daz; animatevel[i] = 0; } else //else insert the elevator's ceiling on the animation list { if (sector[dasector].floorz == sector[dasector].ceilingz) daz = sector[nextsectorneighborz(dasector,sector[dasector].ceilingz,1,1)].floorz; else { if (datag == 8) daz = ((sector[dasector].ceilingz+sector[dasector].floorz)>>1); else daz = sector[dasector].ceilingz; } if ((j = setanimation(§or[dasector].floorz,daz,6L,6L)) >= 0) wsayfollow("updowndr.wav",4096L+(krand()&255)-128,256L,¢x,¢y,0); } } if (datag == 9) //Smooshy-wall sideways double-door { //find any points with either same x or same y coordinate // as center (centx, centy) - should be 2 points found. wallfind[0] = -1; wallfind[1] = -1; for (i=startwall; i>1)-wall[wallfind[j]].x; day2 = ((wall[i].y+wall[wall[wallfind[j]].point2].y)>>1)-wall[wallfind[j]].y; if (dax2 != 0) { dax2 = wall[wall[wall[wallfind[j]].point2].point2].x; dax2 -= wall[wall[wallfind[j]].point2].x; setanimation(&wall[wallfind[j]].x,wall[wallfind[j]].x+dax2,4L,0L); setanimation(&wall[i].x,wall[i].x+dax2,4L,0L); setanimation(&wall[wall[wallfind[j]].point2].x,wall[wall[wallfind[j]].point2].x+dax2,4L,0L); } else if (day2 != 0) { day2 = wall[wall[wall[wallfind[j]].point2].point2].y; day2 -= wall[wall[wallfind[j]].point2].y; setanimation(&wall[wallfind[j]].y,wall[wallfind[j]].y+day2,4L,0L); setanimation(&wall[i].y,wall[i].y+day2,4L,0L); setanimation(&wall[wall[wallfind[j]].point2].y,wall[wall[wallfind[j]].point2].y+day2,4L,0L); } } else { i = wallfind[j]-1; if (i < startwall) i = endwall-1; dax2 = ((wall[i].x+wall[wall[wallfind[j]].point2].x)>>1)-wall[wallfind[j]].x; day2 = ((wall[i].y+wall[wall[wallfind[j]].point2].y)>>1)-wall[wallfind[j]].y; if (dax2 != 0) { setanimation(&wall[wallfind[j]].x,centx,4L,0L); setanimation(&wall[i].x,centx+dax2,4L,0L); setanimation(&wall[wall[wallfind[j]].point2].x,centx+dax2,4L,0L); } else if (day2 != 0) { setanimation(&wall[wallfind[j]].y,centy,4L,0L); setanimation(&wall[i].y,centy+day2,4L,0L); setanimation(&wall[wall[wallfind[j]].point2].y,centy+day2,4L,0L); } } } wsayfollow("updowndr.wav",4096L-256L,256L,¢x,¢y,0); wsayfollow("updowndr.wav",4096L+256L,256L,¢x,¢y,0); } if (datag == 13) //Swinging door { for (i=0; i>1) == centx) && (((wall[wallfind[j]].y+wall[wall[wallfind[j]].point2].y)>>1) == centy)) { //door was closed //find what direction door should open i = wallfind[j]-1; if (i < startwall) i = endwall-1; dax2 = wall[i].x-wall[wallfind[j]].x; day2 = wall[i].y-wall[wallfind[j]].y; if (dax2 != 0) { dax2 = wall[wall[wall[wall[wallfind[j]].point2].point2].point2].x; dax2 -= wall[wall[wall[wallfind[j]].point2].point2].x; setanimation(&wall[wallfind[j]].x,wall[wallfind[j]].x+dax2,4L,0L); setanimation(&wall[i].x,wall[i].x+dax2,4L,0L); setanimation(&wall[wall[wallfind[j]].point2].x,wall[wall[wallfind[j]].point2].x+dax2,4L,0L); setanimation(&wall[wall[wall[wallfind[j]].point2].point2].x,wall[wall[wall[wallfind[j]].point2].point2].x+dax2,4L,0L); } else if (day2 != 0) { day2 = wall[wall[wall[wall[wallfind[j]].point2].point2].point2].y; day2 -= wall[wall[wall[wallfind[j]].point2].point2].y; setanimation(&wall[wallfind[j]].y,wall[wallfind[j]].y+day2,4L,0L); setanimation(&wall[i].y,wall[i].y+day2,4L,0L); setanimation(&wall[wall[wallfind[j]].point2].y,wall[wall[wallfind[j]].point2].y+day2,4L,0L); setanimation(&wall[wall[wall[wallfind[j]].point2].point2].y,wall[wall[wall[wallfind[j]].point2].point2].y+day2,4L,0L); } } else { //door was not closed i = wallfind[j]-1; if (i < startwall) i = endwall-1; dax2 = wall[i].x-wall[wallfind[j]].x; day2 = wall[i].y-wall[wallfind[j]].y; if (dax2 != 0) { setanimation(&wall[wallfind[j]].x,centx,4L,0L); setanimation(&wall[i].x,centx+dax2,4L,0L); setanimation(&wall[wall[wallfind[j]].point2].x,centx,4L,0L); setanimation(&wall[wall[wall[wallfind[j]].point2].point2].x,centx+dax2,4L,0L); } else if (day2 != 0) { setanimation(&wall[wallfind[j]].y,centy,4L,0L); setanimation(&wall[i].y,centy+day2,4L,0L); setanimation(&wall[wall[wallfind[j]].point2].y,centy,4L,0L); setanimation(&wall[wall[wall[wallfind[j]].point2].point2].y,centy+day2,4L,0L); } } } wsayfollow("updowndr.wav",4096L-64L,256L,¢x,¢y,0); wsayfollow("updowndr.wav",4096L+64L,256L,¢x,¢y,0); } } void operatesprite(short dasprite) { int datag; datag = sprite[dasprite].lotag; if (datag == 2) //A sprite that shoots a bomb { vec3_t vector = { sprite[dasprite].x,sprite[dasprite].y,sprite[dasprite].z }; shootgun(dasprite, &vector, sprite[dasprite].ang,100L,sprite[dasprite].sectnum,2); } } int changehealth(short snum, short deltahealth) { // int dax, day; // short good, k, startwall, endwall, s; if (health[snum] > 0) { health[snum] += deltahealth; if (health[snum] > 999) health[snum] = 999; if (health[snum] <= 0) { health[snum] = -1; wsayfollow("death.wav",4096L+(krand()&127)-64,256L,&pos[snum].x,&pos[snum].y,1); sprite[playersprite[snum]].picnum = SKELETON; } if ((snum == screenpeek) && (screensize <= xdim)) { if (health[snum] > 0) sprintf((char *)tempbuf,"Health:%3d",health[snum]); else sprintf((char *)tempbuf,"YOU STINK!"); printext((xdim>>1)-(Bstrlen((char *)tempbuf)<<2),ydim-24,(char *)tempbuf,ALPHABET /*,80*/); } } return health[snum] <= 0; //You were just injured } void changenumbombs(short snum, short deltanumbombs) // Andy did this { numbombs[snum] += deltanumbombs; if (numbombs[snum] > 999) numbombs[snum] = 999; if (numbombs[snum] <= 0) { wsayfollow("doh.wav",4096L+(krand()&127)-64,256L,&pos[snum].x,&pos[snum].y,1); numbombs[snum] = 0; } if ((snum == screenpeek) && (screensize <= xdim)) { sprintf((char *)tempbuf,"B:%3d",numbombs[snum]); printext(8L,(ydim - 28L),(char *)tempbuf,ALPHABET /*,80*/); } } void changenummissiles(short snum, short deltanummissiles) // Andy did this { nummissiles[snum] += deltanummissiles; if (nummissiles[snum] > 999) nummissiles[snum] = 999; if (nummissiles[snum] <= 0) { wsayfollow("doh.wav",4096L+(krand()&127)-64,256L,&pos[snum].x,&pos[snum].y,1); nummissiles[snum] = 0; } if ((snum == screenpeek) && (screensize <= xdim)) { sprintf((char *)tempbuf,"M:%3d",nummissiles[snum]); printext(8L,(ydim - 20L),(char *)tempbuf,ALPHABET /*,80*/); } } void changenumgrabbers(short snum, short deltanumgrabbers) // Andy did this { numgrabbers[snum] += deltanumgrabbers; if (numgrabbers[snum] > 999) numgrabbers[snum] = 999; if (numgrabbers[snum] <= 0) { wsayfollow("doh.wav",4096L+(krand()&127)-64,256L,&pos[snum].x,&pos[snum].y,1); numgrabbers[snum] = 0; } if ((snum == screenpeek) && (screensize <= xdim)) { sprintf((char *)tempbuf,"G:%3d",numgrabbers[snum]); printext(8L,(ydim - 12L),(char *)tempbuf,ALPHABET /*,80*/); } } static int ostatusflytime = 0x80000000; void drawstatusflytime(short snum) // Andy did this { int nstatusflytime; if ((snum == screenpeek) && (screensize <= xdim)) { nstatusflytime = (((flytime[snum] + 119) - lockclock) / 120); if (nstatusflytime > 1000) nstatusflytime = 1000; else if (nstatusflytime < 0) nstatusflytime = 0; if (nstatusflytime != ostatusflytime) { if (nstatusflytime > 999) sprintf((char *)tempbuf,"FT:BIG"); else sprintf((char *)tempbuf,"FT:%3d",nstatusflytime); printext((xdim - 56L),(ydim - 20L),(char *)tempbuf,ALPHABET /*,80*/); ostatusflytime = nstatusflytime; } } } void drawstatusbar(short snum) // Andy did this { int nstatusflytime; if ((snum == screenpeek) && (screensize <= xdim)) { sprintf((char *)tempbuf,"Deaths:%d",deaths[snum]); printext((xdim>>1)-(strlen((char *)tempbuf)<<2),ydim-16,(char *)tempbuf,ALPHABET /*,80*/); sprintf((char *)tempbuf,"Health:%3d",health[snum]); printext((xdim>>1)-(strlen((char *)tempbuf)<<2),ydim-24,(char *)tempbuf,ALPHABET /*,80*/); sprintf((char *)tempbuf,"B:%3d",numbombs[snum]); printext(8L,(ydim - 28L),(char *)tempbuf,ALPHABET /*,80*/); sprintf((char *)tempbuf,"M:%3d",nummissiles[snum]); printext(8L,(ydim - 20L),(char *)tempbuf,ALPHABET /*,80*/); sprintf((char *)tempbuf,"G:%3d",numgrabbers[snum]); printext(8L,(ydim - 12L),(char *)tempbuf,ALPHABET /*,80*/); nstatusflytime = (((flytime[snum] + 119) - lockclock) / 120); if (nstatusflytime < 0) { sprintf((char *)tempbuf,"FT: 0"); ostatusflytime = 0; } else if (nstatusflytime > 999) { sprintf((char *)tempbuf,"FT:BIG"); ostatusflytime = 999; } else { sprintf((char *)tempbuf,"FT:%3d",nstatusflytime); ostatusflytime = nstatusflytime; } printext((xdim - 56L),(ydim - 20L),(char *)tempbuf,ALPHABET /*,80*/); } } void prepareboard(char *daboardfilename) { short startwall, endwall, dasector; int i, j, k=0, s, dax, day, /*daz,*/ dax2, day2; getmessageleng = 0; typemessageleng = 0; randomseed = 17L; //Clear (do)animation's list animatecnt = 0; typemode = 0; locselectedgun = 0; locselectedgun2 = 0; if (loadboard(daboardfilename,0,&pos[0],&ang[0],&cursectnum[0]) == -1) { musicoff(); uninitmultiplayers(); uninittimer(); uninitinput(); uninitengine(); uninitsb(); uninitgroupfile(); printf("Board not found\n"); exit(0); } else { char tempfn[BMAX_PATH + 1], *fp; strncpy(tempfn, daboardfilename, BMAX_PATH); tempfn[BMAX_PATH] = 0; fp = strrchr(tempfn,'.'); if (fp) *fp = 0; if (strlen(tempfn) <= BMAX_PATH-4) { strcat(tempfn,".mhk"); loadmaphack(tempfn); } } setup3dscreen(); for (i=0; i dax2) dax2 = wall[j].x; if (wall[j].y > day2) day2 = wall[j].y; if (wall[j].lotag == 3) k = j; } if (wall[k].x == dax) dragxdir[dragsectorcnt] = -16; if (wall[k].y == day) dragydir[dragsectorcnt] = -16; if (wall[k].x == dax2) dragxdir[dragsectorcnt] = 16; if (wall[k].y == day2) dragydir[dragsectorcnt] = 16; dasector = wall[startwall].nextsector; dragx1[dragsectorcnt] = 0x7fffffff; dragy1[dragsectorcnt] = 0x7fffffff; dragx2[dragsectorcnt] = 0x80000000; dragy2[dragsectorcnt] = 0x80000000; startwall = sector[dasector].wallptr; endwall = startwall+sector[dasector].wallnum; for (j=startwall; j dragx2[dragsectorcnt]) dragx2[dragsectorcnt] = wall[j].x; if (wall[j].y > dragy2[dragsectorcnt]) dragy2[dragsectorcnt] = wall[j].y; setinterpolation(§or[dasector].floorz); setinterpolation(&wall[j].x); setinterpolation(&wall[j].y); setinterpolation(&wall[wall[j].nextwall].x); setinterpolation(&wall[wall[j].nextwall].y); } dragx1[dragsectorcnt] += (wall[sector[i].wallptr].x-dax); dragy1[dragsectorcnt] += (wall[sector[i].wallptr].y-day); dragx2[dragsectorcnt] -= (dax2-wall[sector[i].wallptr].x); dragy2[dragsectorcnt] -= (day2-wall[sector[i].wallptr].y); dragfloorz[dragsectorcnt] = sector[i].floorz; dragsectorlist[dragsectorcnt++] = i; break; case 13: startwall = sector[i].wallptr; endwall = startwall+sector[i].wallnum; for (j=startwall; j dax2) dax2 = wall[j].x; if (wall[j].y > day2) day2 = wall[j].y; } for (j=startwall; j dax) && (wall[j].y > day) && (wall[j].x < dax2) && (wall[j].y < day2)) { subwayx[subwaytrackcnt] = wall[j].x; } else { subwaystop[subwaytrackcnt][subwaystopcnt[subwaytrackcnt]] = wall[j].x; subwaystopcnt[subwaytrackcnt]++; } } } for (j=1; j subwaytrackx1[subwaytrackcnt]) if (wall[startwall].y > subwaytracky1[subwaytrackcnt]) if (wall[startwall].x < subwaytrackx2[subwaytrackcnt]) if (wall[startwall].y < subwaytracky2[subwaytrackcnt]) { if (sector[j].floorz != sector[i].floorz) { sector[j].ceilingstat |= 64; sector[j].floorstat |= 64; } subwaytracksector[subwaytrackcnt][subwaynumsectors[subwaytrackcnt]] = j; subwaynumsectors[subwaytrackcnt]++; } } subwayvel[subwaytrackcnt] = 64; subwaypausetime[subwaytrackcnt] = 720; startwall = sector[i].wallptr; endwall = startwall+sector[i].wallnum; for (k=startwall; k subwaytrackx1[subwaytrackcnt]) if (wall[k].y > subwaytracky1[subwaytrackcnt]) if (wall[k].x < subwaytrackx2[subwaytrackcnt]) if (wall[k].y < subwaytracky2[subwaytrackcnt]) setinterpolation(&wall[k].x); for (j=1; j=0; k=nextspritesect[k]) if (statrate[sprite[k].statnum] < 0) setinterpolation(&sprite[k].x); } subwaytrackcnt++; break; } if (sector[i].floorpicnum == FLOORMIRROR) floormirrorsector[mirrorcnt++] = i; //if (sector[i].ceilingpicnum == FLOORMIRROR) floormirrorsector[mirrorcnt++] = i; //SOS } //Scan wall tags mirrorcnt = 0; tilesiz[MIRROR].x = 0; tilesiz[MIRROR].y = 0; for (i=0; i= 0) && (wall[i].overpicnum == MIRROR) && (wall[i].cstat&32)) { if ((sector[s].floorstat&1) == 0) { wall[i].overpicnum = MIRRORLABEL+mirrorcnt; sector[s].ceilingpicnum = MIRRORLABEL+mirrorcnt; sector[s].floorpicnum = MIRRORLABEL+mirrorcnt; sector[s].floorstat |= 1; mirrorwall[mirrorcnt] = i; mirrorsector[mirrorcnt] = s; mirrorcnt++; } else wall[i].overpicnum = sector[s].ceilingpicnum; } } //Invalidate textures in sector behind mirror for (i=0; i=0; i--) copybuf(&sprite[i].x,&osprite[i].x,3); searchmap(cursectnum[connecthead]); lockclock = 0; ototalclock = 0; gotlastpacketclock = 0; screensize = xdim; dax = ((xdim-screensize)>>1); dax2 = dax+screensize-1; day = (((ydim-32)-scale(screensize,ydim-32,xdim))>>1); day2 = day + scale(screensize,ydim-32,xdim)-1; setview(dax,day,dax2,day2); startofdynamicinterpolations = numinterpolations; #if 0 for (i=connecthead; i>=0; i=connectpoint2[i]) myminlag[i] = 0; otherminlag = mymaxlag = 0; #endif } void checktouchsprite(short snum, short sectnum) { int i, nexti; if ((sectnum < 0) || (sectnum >= numsectors)) return; for (i=headspritesect[sectnum]; i>=0; i=nexti) { nexti = nextspritesect[i]; if (sprite[i].cstat&0x8000) continue; if ((klabs(pos[snum].x-sprite[i].x)+klabs(pos[snum].y-sprite[i].y) < 512) && (klabs((pos[snum].z>>8)-((sprite[i].z>>8)-(tilesiz[sprite[i].picnum].y>>1))) <= 40)) { switch (sprite[i].picnum) { case COIN: wsayfollow("getstuff.wav",4096L+(krand()&127)-64,192L,&sprite[i].x,&sprite[i].y,0); changehealth(snum,5); if (sprite[i].statnum == 12) deletesprite((short)i); else { sprite[i].cstat |= 0x8000; sprite[i].extra = 120*60; changespritestat((short)i,11); } break; case DIAMONDS: wsayfollow("getstuff.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); changehealth(snum,15); if (sprite[i].statnum == 12) deletesprite((short)i); else { sprite[i].cstat |= 0x8000; sprite[i].extra = 120*120; changespritestat((short)i,11); } break; case COINSTACK: wsayfollow("getstuff.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); changehealth(snum,25); if (sprite[i].statnum == 12) deletesprite((short)i); else { sprite[i].cstat |= 0x8000; sprite[i].extra = 120*180; changespritestat((short)i,11); } break; case GIFTBOX: wsayfollow("getstuff.wav",4096L+(krand()&127)+256-mulscale4(sprite[i].xrepeat,sprite[i].yrepeat),208L,&sprite[i].x,&sprite[i].y,0); changehealth(snum,max(mulscale8(sprite[i].xrepeat,sprite[i].yrepeat),1)); if (sprite[i].statnum == 12) deletesprite((short)i); else { sprite[i].cstat |= 0x8000; sprite[i].extra = 90*(sprite[i].xrepeat+sprite[i].yrepeat); changespritestat((short)i,11); } break; case CANNON: wsayfollow("getstuff.wav",3584L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); if (snum == myconnectindex) keystatus[4] = 1; changenumbombs(snum,((sprite[i].xrepeat+sprite[i].yrepeat)>>1)); if (sprite[i].statnum == 12) deletesprite((short)i); else { sprite[i].cstat |= 0x8000; sprite[i].extra = 60*(sprite[i].xrepeat+sprite[i].yrepeat); changespritestat((short)i,11); } break; case LAUNCHER: wsayfollow("getstuff.wav",3584L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); if (snum == myconnectindex) keystatus[5] = 1; changenummissiles(snum,((sprite[i].xrepeat+sprite[i].yrepeat)>>1)); if (sprite[i].statnum == 12) deletesprite((short)i); else { sprite[i].cstat |= 0x8000; sprite[i].extra = 90*(sprite[i].xrepeat+sprite[i].yrepeat); changespritestat((short)i,11); } break; case GRABCANNON: wsayfollow("getstuff.wav",3584L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); if (snum == myconnectindex) keystatus[6] = 1; changenumgrabbers(snum,((sprite[i].xrepeat+sprite[i].yrepeat)>>1)); if (sprite[i].statnum == 12) deletesprite((short)i); else { sprite[i].cstat |= 0x8000; sprite[i].extra = 120*(sprite[i].xrepeat+sprite[i].yrepeat); changespritestat((short)i,11); } break; case AIRPLANE: wsayfollow("getstuff.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); if (flytime[snum] < lockclock) flytime[snum] = lockclock; flytime[snum] += 60*(sprite[i].xrepeat+sprite[i].yrepeat); drawstatusflytime(snum); if (sprite[i].statnum == 12) deletesprite((short)i); else { sprite[i].cstat |= 0x8000; sprite[i].extra = 120*(sprite[i].xrepeat+sprite[i].yrepeat); changespritestat((short)i,11); } break; } } } } void checkgrabbertouchsprite(short snum, short sectnum) // Andy did this { int i, nexti; short onum; if ((sectnum < 0) || (sectnum >= numsectors)) return; onum = (sprite[snum].owner & (MAXSPRITES - 1)); for (i=headspritesect[sectnum]; i>=0; i=nexti) { nexti = nextspritesect[i]; if (sprite[i].cstat&0x8000) continue; if ((klabs(sprite[snum].x-sprite[i].x)+klabs(sprite[snum].y-sprite[i].y) < 512) && (klabs((sprite[snum].z>>8)-((sprite[i].z>>8)-(tilesiz[sprite[i].picnum].y>>1))) <= 40)) { switch (sprite[i].picnum) { case COIN: wsayfollow("getstuff.wav",4096L+(krand()&127)-64,192L,&sprite[i].x,&sprite[i].y,0); changehealth(onum,5); if (sprite[i].statnum == 12) deletesprite((short)i); else { sprite[i].cstat |= 0x8000; sprite[i].extra = 120*60; changespritestat((short)i,11); } break; case DIAMONDS: wsayfollow("getstuff.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); changehealth(onum,15); if (sprite[i].statnum == 12) deletesprite((short)i); else { sprite[i].cstat |= 0x8000; sprite[i].extra = 120*120; changespritestat((short)i,11); } break; case COINSTACK: wsayfollow("getstuff.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); changehealth(onum,25); if (sprite[i].statnum == 12) deletesprite((short)i); else { sprite[i].cstat |= 0x8000; sprite[i].extra = 120*180; changespritestat((short)i,11); } break; case GIFTBOX: wsayfollow("getstuff.wav",4096L+(krand()&127)+256-mulscale4(sprite[i].xrepeat,sprite[i].yrepeat),208L,&sprite[i].x,&sprite[i].y,0); changehealth(onum,max(mulscale8(sprite[i].xrepeat,sprite[i].yrepeat),1)); if (sprite[i].statnum == 12) deletesprite((short)i); else { sprite[i].cstat |= 0x8000; sprite[i].extra = 90*(sprite[i].xrepeat+sprite[i].yrepeat); changespritestat((short)i,11); } break; case CANNON: wsayfollow("getstuff.wav",3584L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); if (onum == myconnectindex) keystatus[4] = 1; changenumbombs(onum,((sprite[i].xrepeat+sprite[i].yrepeat)>>1)); if (sprite[i].statnum == 12) deletesprite((short)i); else { sprite[i].cstat |= 0x8000; sprite[i].extra = 60*(sprite[i].xrepeat+sprite[i].yrepeat); changespritestat((short)i,11); } break; case LAUNCHER: wsayfollow("getstuff.wav",3584L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); if (onum == myconnectindex) keystatus[5] = 1; changenummissiles(onum,((sprite[i].xrepeat+sprite[i].yrepeat)>>1)); if (sprite[i].statnum == 12) deletesprite((short)i); else { sprite[i].cstat |= 0x8000; sprite[i].extra = 90*(sprite[i].xrepeat+sprite[i].yrepeat); changespritestat((short)i,11); } break; case GRABCANNON: wsayfollow("getstuff.wav",3584L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); if (onum == myconnectindex) keystatus[6] = 1; changenumgrabbers(onum,((sprite[i].xrepeat+sprite[i].yrepeat)>>1)); if (sprite[i].statnum == 12) deletesprite((short)i); else { sprite[i].cstat |= 0x8000; sprite[i].extra = 120*(sprite[i].xrepeat+sprite[i].yrepeat); changespritestat((short)i,11); } break; case AIRPLANE: wsayfollow("getstuff.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); if (flytime[snum] < lockclock) flytime[snum] = lockclock; flytime[onum] += 60*(sprite[i].xrepeat+sprite[i].yrepeat); drawstatusflytime(onum); if (sprite[i].statnum == 12) deletesprite((short)i); else { sprite[i].cstat |= 0x8000; sprite[i].extra = 120*(sprite[i].xrepeat+sprite[i].yrepeat); changespritestat((short)i,11); } break; } } } } void shootgun(short snum, const vec3_t *vector, short daang, int dahoriz, short dasectnum, char guntype) { short daang2; int /*i,*/ j, daz2; hitdata_t hitinfo; switch (guntype) { case 0: //Shoot chain gun daang2 = ((daang + (krand()&31)-16)&2047); daz2 = ((100-dahoriz)*2000) + ((krand()-32768)>>1); hitscan(vector,dasectnum, //Start position sintable[(daang2+512)&2047], //X vector of 3D ang sintable[daang2&2047], //Y vector of 3D ang daz2, //Z vector of 3D ang &hitinfo,CLIPMASK1); if (wall[hitinfo.wall].picnum == KENPICTURE) { if (waloff[MAXTILES-1] != 0) wall[hitinfo.wall].picnum = MAXTILES-1; wsayfollow("hello.wav",4096L+(krand()&127)-64,256L,&wall[hitinfo.wall].x,&wall[hitinfo.wall].y,0); } else if (((hitinfo.wall < 0) && (hitinfo.sprite < 0) && (hitinfo.pos.z >= vector->z) && ((sector[hitinfo.sect].floorpicnum == SLIME) || (sector[hitinfo.sect].floorpicnum == FLOORMIRROR))) || ((hitinfo.wall >= 0) && (wall[hitinfo.wall].picnum == SLIME))) { //If you shoot slime, make a splash wsayfollow("splash.wav",4096L+(krand()&511)-256,256L,&hitinfo.pos.x,&hitinfo.pos.y,0); spawnsprite(j,hitinfo.pos.x,hitinfo.pos.y,hitinfo.pos.z,2,0,0,32,64,64,0,0,SPLASH,daang, 0,0,0,snum+4096,hitinfo.sect,4,63,0,0); //63=time left for splash } else { wsayfollow("shoot.wav",4096L+(krand()&127)-64,256L,&hitinfo.pos.x,&hitinfo.pos.y,0); if ((hitinfo.sprite >= 0) && (sprite[hitinfo.sprite].statnum < MAXSTATUS)) switch (sprite[hitinfo.sprite].picnum) { case BROWNMONSTER: if (sprite[hitinfo.sprite].lotag > 0) sprite[hitinfo.sprite].lotag -= 10; if (sprite[hitinfo.sprite].lotag > 0) { wsayfollow("hurt.wav",4096L+(krand()&511)-256,256L,&hitinfo.pos.x,&hitinfo.pos.y,0); if (sprite[hitinfo.sprite].lotag <= 25) sprite[hitinfo.sprite].cstat |= 2; } else { wsayfollow("mondie.wav",4096L+(krand()&127)-64,256L,&hitinfo.pos.x,&hitinfo.pos.y,0); sprite[hitinfo.sprite].z += ((tilesiz[sprite[hitinfo.sprite].picnum].y*sprite[hitinfo.sprite].yrepeat)<<1); sprite[hitinfo.sprite].picnum = GIFTBOX; sprite[hitinfo.sprite].cstat &= ~0x83; //Should not clip, foot-z changespritestat(hitinfo.sprite,12); spawnsprite(j,hitinfo.pos.x,hitinfo.pos.y,hitinfo.pos.z+(32<<8),0,-4,0,32,64,64, 0,0,EXPLOSION,daang,0,0,0,snum+4096, hitinfo.sect,5,31,0,0); } break; case EVILAL: wsayfollow("blowup.wav",4096L+(krand()&127)-64,256L,&hitinfo.pos.x,&hitinfo.pos.y,0); sprite[hitinfo.sprite].picnum = EVILALGRAVE; sprite[hitinfo.sprite].cstat = 0; sprite[hitinfo.sprite].xvel = (krand()&255)-128; sprite[hitinfo.sprite].yvel = (krand()&255)-128; sprite[hitinfo.sprite].zvel = (krand()&4095)-3072; changespritestat(hitinfo.sprite,9); spawnsprite(j,hitinfo.pos.x,hitinfo.pos.y,hitinfo.pos.z+(32<<8),0,-4,0,32,64,64,0, 0,EXPLOSION,daang,0,0,0,snum+4096,hitinfo.sect,5,31,0,0); //31=time left for explosion break; case PLAYER: for (j=connecthead; j>=0; j=connectpoint2[j]) if (playersprite[j] == hitinfo.sprite) { wsayfollow("ouch.wav",4096L+(krand()&127)-64,256L,&hitinfo.pos.x,&hitinfo.pos.y,0); changehealth(j,-10); break; } break; } spawnsprite(j,hitinfo.pos.x,hitinfo.pos.y,hitinfo.pos.z+(8<<8),2,-4,0,32,16,16,0,0, EXPLOSION,daang,0,0,0,snum+4096,hitinfo.sect,3,63,0,0); //Sprite starts out with center exactly on wall. //This moves it back enough to see it at all angles. movesprite((short)j,-(((int)sintable[(512+daang)&2047]*TICSPERFRAME)<<4),-(((int)sintable[daang]*TICSPERFRAME)<<4),0L,4L<<8,4L<<8,CLIPMASK1); } break; case 1: //Shoot silver sphere bullet spawnsprite(j,vector->x,vector->y,vector->z,1+128,0,0,16,64,64,0,0,BULLET,daang, sintable[(daang+512)&2047]>>5,sintable[daang&2047]>>5, (100-dahoriz)<<6,snum+4096,dasectnum,6,0,0,0); wsayfollow("shoot2.wav",4096L+(krand()&127)-64,128L,&sprite[j].x,&sprite[j].y,1); break; case 2: //Shoot bomb spawnsprite(j,vector->x,vector->y,vector->z,128,0,0,12,16,16,0,0,BOMB,daang, sintable[(daang+512)&2047]*5>>8,sintable[daang&2047]*5>>8, (80-dahoriz)<<6,snum+4096,dasectnum,6,0,0,0); wsayfollow("shoot3.wav",4096L+(krand()&127)-64,192L,&sprite[j].x,&sprite[j].y,1); break; case 3: //Shoot missile (Andy did this) spawnsprite(j,vector->x,vector->y,vector->z,1+128,0,0,16,32,32,0,0,MISSILE,daang, sintable[(daang+512)&2047]>>4,sintable[daang&2047]>>4, (100-dahoriz)<<7,snum+4096,dasectnum,6,0,0,0); wsayfollow("shoot3.wav",4096L+(krand()&127)-64,192L,&sprite[j].x,&sprite[j].y,1); break; case 4: //Shoot grabber (Andy did this) spawnsprite(j,vector->x,vector->y,vector->z,1+128,0,0,16,64,64,0,0,GRABBER,daang, sintable[(daang+512)&2047]>>5,sintable[daang&2047]>>5, (100-dahoriz)<<6,snum+4096,dasectnum,6,0,0,0); wsayfollow("shoot4.wav",4096L+(krand()&127)-64,128L,&sprite[j].x,&sprite[j].y,1); break; } } #define MAXVOXMIPS 5 extern intptr_t voxoff[][MAXVOXMIPS]; void analyzesprites(int dax, int day) { int i, j=0, k, *intptr; vec3_t *ospr; uspritetype *tspr; //This function is called between drawrooms() and drawmasks() //It has a list of possible sprites that may be drawn on this frame for (i=0,tspr=&tsprite[0]; ipicnum] >= 0) switch (tspr->picnum) { case PLAYER: // //Get which of the 8 angles of the sprite to draw (0-7) // //k ranges from 0-7 //k = getangle(tspr->x-dax,tspr->y-day); //k = (((tspr->ang+3072+128-k)&2047)>>8)&7; // //This guy has only 5 pictures for 8 angles (3 are x-flipped) //if (k <= 4) //{ // tspr->picnum += (k<<2); // tspr->cstat &= ~4; //clear x-flipping bit //} //else //{ // tspr->picnum += ((8-k)<<2); // tspr->cstat |= 4; //set x-flipping bit //} if ((tspr->cstat&2) == 0) { //tspr->cstat |= 48; tspr->picnum = tiletovox[tspr->picnum]; intptr = (int *)voxoff[tiletovox[PLAYER]][0]; tspr->xrepeat = scale(tspr->xrepeat,56,intptr[2]); tspr->yrepeat = scale(tspr->yrepeat,56,intptr[2]); tspr->shade -= 6; } break; case BROWNMONSTER: //tspr->cstat |= 48; tspr->picnum = tiletovox[tspr->picnum]; break; } k = statrate[tspr->statnum]; if (k >= 0) //Interpolate moving sprite { ospr = &osprite[tspr->owner]; switch (k) { case 0: j = smoothratio; break; case 1: j = (smoothratio>>1)+(((nummoves-tspr->owner)&1)<<15); break; case 3: j = (smoothratio>>2)+(((nummoves-tspr->owner)&3)<<14); break; case 7: j = (smoothratio>>3)+(((nummoves-tspr->owner)&7)<<13); break; case 15: j = (smoothratio>>4)+(((nummoves-tspr->owner)&15)<<12); break; } k = tspr->x-ospr->x; tspr->x = ospr->x; if (k != 0) tspr->x += mulscale16(k,j); k = tspr->y-ospr->y; tspr->y = ospr->y; if (k != 0) tspr->y += mulscale16(k,j); k = tspr->z-ospr->z; tspr->z = ospr->z; if (k != 0) tspr->z += mulscale16(k,j); } //Don't allow close explosion sprites to be transluscent k = tspr->statnum; if ((k == 3) || (k == 4) || (k == 5) || (k == 7)) if (klabs(dax-tspr->x) < 256) if (klabs(day-tspr->y) < 256) tspr->cstat &= ~2; tspr->shade += 6; if (sector[tspr->sectnum].ceilingstat&1) tspr->shade += sector[tspr->sectnum].ceilingshade; else tspr->shade += sector[tspr->sectnum].floorshade; } } void tagcode(void) { int i, /*nexti,*/ j, k, l, s, /*daz, dax2, day2,*/ cnt, good; short startwall, endwall, dasector, p, oldang; for (p=connecthead; p>=0; p=connectpoint2[p]) { if (sector[cursectnum[p]].lotag == 1) { activatehitag(sector[cursectnum[p]].hitag); sector[cursectnum[p]].lotag = 0; sector[cursectnum[p]].hitag = 0; } if ((sector[cursectnum[p]].lotag == 2) && (cursectnum[p] != ocursectnum[p])) activatehitag(sector[cursectnum[p]].hitag); } for (i=0; i>2); if (j >= 16) j = 31-j; { sector[dasector].ceilingshade = j; sector[dasector].floorshade = j; startwall = sector[dasector].wallptr; endwall = startwall+sector[dasector].wallnum; for (s=startwall; s=0; p=connectpoint2[p]) if (sector[cursectnum[p]].lotag == 10) //warp sector { if (cursectnum[p] != ocursectnum[p]) { warpsprite(playersprite[p]); pos[p].x = sprite[playersprite[p]].x; pos[p].y = sprite[playersprite[p]].y; pos[p].z = sprite[playersprite[p]].z; ang[p] = sprite[playersprite[p]].ang; cursectnum[p] = sprite[playersprite[p]].sectnum; sprite[playersprite[p]].z += EYEHEIGHT; //warp(&pos[p].x,&pos[p].y,&pos[p].z,&ang[p],&cursectnum[p]); //Update sprite representation of player //setsprite_eyeheight(playersprite[p],&pos[p]); //sprite[playersprite[p]].ang = ang[p]; } } for (i=0; i>2)&255); } for (i=0; i>2)&255); sector[floorpanninglist[i]].floorypanning = ((lockclock>>2)&255); } for (i=0; i dragx2[i]) dragxdir[i] = -16; if (wall[startwall].y+dragydir[i] > dragy2[i]) dragydir[i] = -16; for (j=startwall; j>3); for (p=connecthead; p>=0; p=connectpoint2[p]) if (cursectnum[p] == dasector) { pos[p].x += dragxdir[i]; pos[p].y += dragydir[i]; if (p == myconnectindex) { my.x += dragxdir[i]; my.y += dragydir[i]; } //pos[p].z += (sector[dasector].floorz-j); //Update sprite representation of player setsprite_eyeheight(playersprite[p],&pos[p]); sprite[playersprite[p]].ang = ang[p]; } } for (i=0; i=0; p=connectpoint2[p]) if ((cursectnum[p] == swingsector[i]) || (testneighborsectors(cursectnum[p],swingsector[i]) == 1)) { cnt = 256; do { good = 1; //swingangopendir is -1 if forwards, 1 is backwards l = (swingangopendir[i] > 0); for (k=l+3; k>=l; k--) if (clipinsidebox((vec2_t *)&pos[p],swingwall[i][k],128L) != 0) { good = 0; break; } if (good == 0) { if (cnt == 256) { swinganginc[i] = -swinganginc[i]; swingang[i] = oldang; } else { swingang[i] = ((swingang[i]-swinganginc[i])&2047); } for (k=1; k<=3; k++) { vec2_t const pivot = { swingx[i][0], swingy[i][0] }; vec2_t const p = { swingx[i][k], swingy[i][k] }; rotatepoint(pivot, p, swingang[i], (vec2_t *)&wall[swingwall[i][k]].x); } if (swingang[i] == swingangclosed[i]) { wsayfollow("closdoor.wav",4096L+(krand()&511)-256,256L,&swingx[i][0],&swingy[i][0],0); swinganginc[i] = 0; break; } if (swingang[i] == swingangopen[i]) { swinganginc[i] = 0; break; } cnt--; } } while ((good == 0) && (cnt > 0)); } } } if (swinganginc[i] == 0) for (j=1; j<=3; j++) { stopinterpolation(&wall[swingwall[i][j]].x); stopinterpolation(&wall[swingwall[i][j]].y); } } for (i=0; i 2)) { dasector = subwaytracksector[i][0]; startwall = sector[dasector].wallptr; endwall = startwall+sector[dasector].wallnum; for (k=startwall; k subwaytrackx1[i]) if (wall[k].y > subwaytracky1[i]) if (wall[k].x < subwaytrackx2[i]) if (wall[k].y < subwaytracky2[i]) wall[k].x += subwayvel[i]; for (j=1; j=0; s=nextspritesect[s]) sprite[s].x += subwayvel[i]; } for (p=connecthead; p>=0; p=connectpoint2[p]) if (cursectnum[p] != subwaytracksector[i][0]) if (sector[cursectnum[p]].floorz != sector[subwaytracksector[i][0]].floorz) if (pos[p].x > subwaytrackx1[i]) if (pos[p].y > subwaytracky1[i]) if (pos[p].x < subwaytrackx2[i]) if (pos[p].y < subwaytracky2[i]) { pos[p].x += subwayvel[i]; if (p == myconnectindex) { my.x += subwayvel[i]; } //Update sprite representation of player setsprite_eyeheight(playersprite[p],&pos[p]); sprite[playersprite[p]].ang = ang[p]; } subwayx[i] += subwayvel[i]; } j = subwayvel[i]; k = subwaystop[i][subwaygoalstop[i]] - subwayx[i]; if (k > 0) { if (k > 4096) { if (subwayvel[i] < 256) subwayvel[i]++; } else subwayvel[i] = (k>>4)+1; } else if (k < 0) { if (k < -4096) { if (subwayvel[i] > -256) subwayvel[i]--; } else subwayvel[i] = (k>>4)-1; } if ((j < 0) && (subwayvel[i] >= 0)) subwayvel[i] = -1; if ((j > 0) && (subwayvel[i] <= 0)) subwayvel[i] = 1; if ((subwayvel[i] <= 2) && (subwayvel[i] >= -2) && (klabs(k) < 2048)) { //Open / close doors if ((subwaypausetime[i] == 720) || ((subwaypausetime[i] >= 120) && (subwaypausetime[i]-TICSPERFRAME < 120))) activatehitag(sector[subwaytracksector[i][0]].hitag); subwaypausetime[i] -= TICSPERFRAME; if (subwaypausetime[i] < 0) { subwaypausetime[i] = 720; if (subwayvel[i] < 0) { subwaygoalstop[i]--; if (subwaygoalstop[i] < 0) { subwaygoalstop[i] = 1; subwayvel[i] = 1; } } else if (subwayvel[i] > 0) { subwaygoalstop[i]++; if (subwaygoalstop[i] >= subwaystopcnt[i]) { subwaygoalstop[i] = subwaystopcnt[i]-2; subwayvel[i] = -1; } } } } } } void statuslistcode(void) { short p, target, hitobject, daang, osectnum, movestat; int i, nexti, j, nextj, k, l, dax, day, daz, dist=0, ox, oy, mindist; int doubvel, xvect, yvect; //Go through active BROWNMONSTER list for (i=headspritestat[1]; i>=0; i=nexti) { nexti = nextspritestat[i]; k = krand(); //Choose a target player mindist = 0x7fffffff; target = connecthead; for (p=connecthead; p>=0; p=connectpoint2[p]) { dist = klabs(sprite[i].x-pos[p].x)+klabs(sprite[i].y-pos[p].y); if (dist < mindist) mindist = dist, target = p; } //brown monster decides to shoot bullet if ((k&63) == 23) { if (cansee(sprite[i].x,sprite[i].y,sprite[i].z-(tilesiz[sprite[i].picnum].y<<7),sprite[i].sectnum,pos[target].x,pos[target].y,pos[target].z,cursectnum[target]) == 0) { if ((k&0xf00) == 0xb00) changespritestat(i,2); } else { wsayfollow("monshoot.wav",5144L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,1); doubvel = (TICSPERFRAME<<((ssync[target].bits&256)>0)); xvect = 0, yvect = 0; if (ssync[target].fvel != 0) { xvect += ((((int)ssync[target].fvel)*doubvel*(int)sintable[(ang[target]+512)&2047])>>3); yvect += ((((int)ssync[target].fvel)*doubvel*(int)sintable[ang[target]&2047])>>3); } if (ssync[target].svel != 0) { xvect += ((((int)ssync[target].svel)*doubvel*(int)sintable[ang[target]&2047])>>3); yvect += ((((int)ssync[target].svel)*doubvel*(int)sintable[(ang[target]+1536)&2047])>>3); } ox = pos[target].x; oy = pos[target].y; //distance is j j = ksqrt((ox-sprite[i].x)*(ox-sprite[i].x)+(oy-sprite[i].y)*(oy-sprite[i].y)); switch ((sprite[i].extra>>11)&3) { case 1: j = -(j>>1); break; case 3: j = 0; break; case 0: case 2: break; } sprite[i].extra += 2048; //rate is (TICSPERFRAME<<19) xvect = scale(xvect,j,TICSPERFRAME<<19); yvect = scale(yvect,j,TICSPERFRAME<<19); clipmove_old(&ox,&oy,&pos[target].z,&cursectnum[target],xvect<<14,yvect<<14,128L,4<<8,4<<8,CLIPMASK0); ox -= sprite[i].x; oy -= sprite[i].y; daang = ((getangle(ox,oy)+(krand()&7)-4)&2047); dax = (sintable[(daang+512)&2047]>>6); day = (sintable[daang&2047]>>6); daz = 0; if (ox != 0) daz = scale(dax,pos[target].z+(8<<8)-sprite[i].z,ox); else if (oy != 0) daz = scale(day,pos[target].z+(8<<8)-sprite[i].z,oy); spawnsprite(j,sprite[i].x,sprite[i].y,sprite[i].z,128,0,0, 16,sprite[i].xrepeat,sprite[i].yrepeat,0,0,BULLET,daang,dax,day,daz,i,sprite[i].sectnum,6,0,0,0); sprite[i].extra &= (~2047); } } //Move brown monster dax = sprite[i].x; //Back up old x&y if stepping off cliff day = sprite[i].y; doubvel = max(mulscale7(sprite[i].xrepeat,sprite[i].yrepeat),4); osectnum = sprite[i].sectnum; movestat = movesprite((short)i,(int)sintable[(sprite[i].ang+512)&2047]*doubvel,(int)sintable[sprite[i].ang]*doubvel,0L,4L<<8,4L<<8,CLIPMASK0); if (globloz > sprite[i].z+(48<<8)) { sprite[i].x = dax; sprite[i].y = day; movestat = 1; } else sprite[i].z = globloz-((tilesiz[sprite[i].picnum].y*sprite[i].yrepeat)<<1); if ((sprite[i].sectnum != osectnum) && (sector[sprite[i].sectnum].lotag == 10)) { warpsprite((short)i); movestat = 0; } if ((movestat != 0) || ((k&63) == 1)) { if (sprite[i].ang == (sprite[i].extra&2047)) { daang = (getangle(pos[target].x-sprite[i].x,pos[target].y-sprite[i].y)&2047); daang = ((daang+(krand()&1023)-512)&2047); sprite[i].extra = ((sprite[i].extra&(~2047))|daang); } if ((sprite[i].extra-sprite[i].ang)&1024) { sprite[i].ang = ((sprite[i].ang-32)&2047); if (!((sprite[i].extra-sprite[i].ang)&1024)) sprite[i].ang = (sprite[i].extra&2047); } else { sprite[i].ang = ((sprite[i].ang+32)&2047); if (((sprite[i].extra-sprite[i].ang)&1024)) sprite[i].ang = (sprite[i].extra&2047); } } } for (i=headspritestat[10]; i>=0; i=nexti) //EVILAL list { nexti = nextspritestat[i]; if (sprite[i].yrepeat < 38) continue; if (sprite[i].yrepeat < 64) { sprite[i].xrepeat++; sprite[i].yrepeat++; continue; } if ((nummoves-i)&statrate[10]) continue; //Choose a target player mindist = 0x7fffffff; target = connecthead; for (p=connecthead; p>=0; p=connectpoint2[p]) { dist = klabs(sprite[i].x-pos[p].x)+klabs(sprite[i].y-pos[p].y); if (dist < mindist) mindist = dist, target = p; } k = (krand()&255); if ((sprite[i].lotag&32) && (k < 48)) //Al decides to reproduce { l = 0; if ((sprite[i].lotag&64) && (k < 2)) //Give him a chance to reproduce without seeing you l = 1; else if (cansee(sprite[i].x,sprite[i].y,sprite[i].z-(tilesiz[sprite[i].picnum].y<<7),sprite[i].sectnum,pos[target].x,pos[target].y,pos[target].z,cursectnum[target]) == 1) l = 1; if (l != 0) { spawnsprite(j,sprite[i].x,sprite[i].y,sprite[i].z,sprite[i].cstat,sprite[i].shade,sprite[i].pal, sprite[i].clipdist,38,38,sprite[i].xoffset,sprite[i].yoffset,sprite[i].picnum,krand()&2047,0,0,0,i, sprite[i].sectnum,10,sprite[i].lotag,sprite[i].hitag,sprite[i].extra); switch (krand()&31) //Mutations! { case 0: sprite[i].cstat ^= 2; break; case 1: sprite[i].cstat ^= 512; break; case 2: sprite[i].shade++; break; case 3: sprite[i].shade--; break; case 4: sprite[i].pal ^= 16; break; case 5: case 6: case 7: sprite[i].lotag ^= (1<<(krand()&7)); break; case 8: sprite[i].lotag = (krand()&255); break; } } } if (k >= 208+((sprite[i].lotag&128)>>2)) //Al decides to shoot bullet { if (cansee(sprite[i].x,sprite[i].y,sprite[i].z-(tilesiz[sprite[i].picnum].y<<7),sprite[i].sectnum,pos[target].x,pos[target].y,pos[target].z,cursectnum[target]) == 1) { wsayfollow("zipguns.wav",5144L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,1); spawnsprite(j,sprite[i].x,sprite[i].y, sector[sprite[i].sectnum].floorz-(24<<8), 0,0,0,16,32,32,0,0,BULLET, (getangle(pos[target].x-sprite[j].x, pos[target].y-sprite[j].y)+(krand()&15)-8)&2047, sintable[(sprite[j].ang+512)&2047]>>6, sintable[sprite[j].ang&2047]>>6, ((pos[target].z+(8<<8)-sprite[j].z)<<8) / (ksqrt((pos[target].x-sprite[j].x) * (pos[target].x-sprite[j].x) + (pos[target].y-sprite[j].y) * (pos[target].y-sprite[j].y))+1), i,sprite[i].sectnum,6,0,0,0); } } //Move Al l = (((sprite[i].lotag&3)+2)<<8); if (sprite[i].lotag&4) l = -l; dax = sintable[(sprite[i].ang+512)&2047]*l; day = sintable[sprite[i].ang]*l; osectnum = sprite[i].sectnum; movestat = movesprite((short)i,dax,day,0L,-(8L<<8),-(8L<<8),CLIPMASK0); sprite[i].z = globloz; if ((sprite[i].sectnum != osectnum) && (sector[sprite[i].sectnum].lotag == 10)) { warpsprite((short)i); movestat = 0; } if (sprite[i].lotag&16) { if (((k&124) >= 120) && (cansee(sprite[i].x,sprite[i].y,sprite[i].z-(tilesiz[sprite[i].picnum].y<<7),sprite[i].sectnum,pos[target].x,pos[target].y,pos[target].z,cursectnum[target]) == 1)) sprite[i].ang = getangle(pos[target].x-sprite[i].x,pos[target].y-sprite[i].y); else sprite[i].ang = (krand()&2047); } if (movestat != 0) { if ((k&2) && (cansee(sprite[i].x,sprite[i].y,sprite[i].z-(tilesiz[sprite[i].picnum].y<<7),sprite[i].sectnum,pos[target].x,pos[target].y,pos[target].z,cursectnum[target]) == 1)) sprite[i].ang = getangle(pos[target].x-sprite[i].x,pos[target].y-sprite[i].y); else sprite[i].ang = (krand()&2047); if ((movestat&49152) == 49152) if (sprite[movestat&16383].picnum == EVILAL) if ((k&31) >= 30) { wsayfollow("blowup.wav",5144L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); sprite[i].picnum = EVILALGRAVE; sprite[i].cstat = 0; sprite[i].xvel = (krand()&255)-128; sprite[i].yvel = (krand()&255)-128; sprite[i].zvel = (krand()&4095)-3072; changespritestat(i,9); } if (sprite[i].lotag&8) if ((k&31) >= 30) { wsayfollow("blowup.wav",5144L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); sprite[i].picnum = EVILALGRAVE; sprite[i].cstat = 0; sprite[i].xvel = (krand()&255)-128; sprite[i].yvel = (krand()&255)-128; sprite[i].zvel = (krand()&4095)-3072; changespritestat(i,9); } if (movestat == -1) { wsayfollow("blowup.wav",5144L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); sprite[i].picnum = EVILALGRAVE; sprite[i].cstat = 0; sprite[i].xvel = (krand()&255)-128; sprite[i].yvel = (krand()&255)-128; sprite[i].zvel = (krand()&4095)-3072; changespritestat(i,9); } } } //Go through travelling bullet sprites for (i=headspritestat[6]; i>=0; i=nexti) { nexti = nextspritestat[i]; if ((nummoves-i)&statrate[6]) continue; //If the sprite is a bullet then... if ((sprite[i].picnum == BULLET) || (sprite[i].picnum == GRABBER) || (sprite[i].picnum == MISSILE) || (sprite[i].picnum == BOMB)) { dax = ((((int)sprite[i].xvel)*TICSPERFRAME)<<12); day = ((((int)sprite[i].yvel)*TICSPERFRAME)<<12); daz = ((((int)sprite[i].zvel)*TICSPERFRAME)>>2); if (sprite[i].picnum == BOMB) daz = 0; osectnum = sprite[i].sectnum; hitobject = movesprite((short)i,dax,day,daz,4L<<8,4L<<8,CLIPMASK1); if ((sprite[i].sectnum != osectnum) && (sector[sprite[i].sectnum].lotag == 10)) { warpsprite((short)i); hitobject = 0; } if (sprite[i].picnum == GRABBER) // Andy did this (& Ken) !Homing! { checkgrabbertouchsprite(i,sprite[i].sectnum); l = 0x7fffffff; for (j = connecthead; j >= 0; j = connectpoint2[j]) // Players if (j != (sprite[i].owner & (MAXSPRITES - 1))) if (cansee(sprite[i].x,sprite[i].y,sprite[i].z,sprite[i].sectnum,pos[j].x,pos[j].y,pos[j].z,cursectnum[j])) { k = ksqrt(sqr(pos[j].x - sprite[i].x) + sqr(pos[j].y - sprite[i].y) + (sqr(pos[j].z - sprite[i].z) >> 8)); if (k < l) { l = k; dax = (pos[j].x - sprite[i].x); day = (pos[j].y - sprite[i].y); daz = (pos[j].z - sprite[i].z); } } for (j = headspritestat[1]; j >= 0; j = nextj) // Active monsters { nextj = nextspritestat[j]; if (cansee(sprite[i].x,sprite[i].y,sprite[i].z,sprite[i].sectnum,sprite[j].x,sprite[j].y,sprite[j].z,sprite[j].sectnum)) { k = ksqrt(sqr(sprite[j].x - sprite[i].x) + sqr(sprite[j].y - sprite[i].y) + (sqr(sprite[j].z - sprite[i].z) >> 8)); if (k < l) { l = k; dax = (sprite[j].x - sprite[i].x); day = (sprite[j].y - sprite[i].y); daz = (sprite[j].z - sprite[i].z); } } } for (j = headspritestat[2]; j >= 0; j = nextj) // Inactive monsters { nextj = nextspritestat[j]; if (cansee(sprite[i].x,sprite[i].y,sprite[i].z,sprite[i].sectnum,sprite[j].x,sprite[j].y,sprite[j].z,sprite[j].sectnum)) { k = ksqrt(sqr(sprite[j].x - sprite[i].x) + sqr(sprite[j].y - sprite[i].y) + (sqr(sprite[j].z - sprite[i].z) >> 8)); if (k < l) { l = k; dax = (sprite[j].x - sprite[i].x); day = (sprite[j].y - sprite[i].y); daz = (sprite[j].z - sprite[i].z); } } } if (l != 0x7fffffff) { sprite[i].xvel = (divscale7(dax,l) + sprite[i].xvel); // 1/5 of velocity is homing, 4/5 is momentum sprite[i].yvel = (divscale7(day,l) + sprite[i].yvel); // 1/5 of velocity is homing, 4/5 is momentum sprite[i].zvel = (divscale7(daz,l) + sprite[i].zvel); // 1/5 of velocity is homing, 4/5 is momentum l = ksqrt((sprite[i].xvel * sprite[i].xvel) + (sprite[i].yvel * sprite[i].yvel) + ((sprite[i].zvel * sprite[i].zvel) >> 8)); sprite[i].xvel = divscale9(sprite[i].xvel,l); sprite[i].yvel = divscale9(sprite[i].yvel,l); sprite[i].zvel = divscale9(sprite[i].zvel,l); sprite[i].ang = getangle(sprite[i].xvel,sprite[i].yvel); } } if (sprite[i].picnum == BOMB) { j = sprite[i].sectnum; if ((sector[j].floorstat&2) && (sprite[i].z > globloz-(8<<8))) { k = sector[j].wallptr; daang = getangle(wall[wall[k].point2].x-wall[k].x,wall[wall[k].point2].y-wall[k].y); sprite[i].xvel += mulscale22(sintable[(daang+1024)&2047],sector[j].floorheinum); sprite[i].yvel += mulscale22(sintable[(daang+512)&2047],sector[j].floorheinum); } } if (sprite[i].picnum == BOMB) { sprite[i].z += sprite[i].zvel; sprite[i].zvel += (TICSPERFRAME<<7); if (sprite[i].z < globhiz+(tilesiz[BOMB].y<<6)) { sprite[i].z = globhiz+(tilesiz[BOMB].y<<6); sprite[i].zvel = -(sprite[i].zvel>>1); } if (sprite[i].z > globloz-(tilesiz[BOMB].y<<6)) { sprite[i].z = globloz-(tilesiz[BOMB].y<<6); sprite[i].zvel = -(sprite[i].zvel>>1); } dax = sprite[i].xvel; day = sprite[i].yvel; dist = dax*dax+day*day; if (dist < 512) { bombexplode(i); goto bulletisdeletedskip; } if (dist < 4096) { sprite[i].xrepeat = ((4096+2048)*16) / (dist+2048); sprite[i].yrepeat = sprite[i].xrepeat; sprite[i].xoffset = (krand()&15)-8; sprite[i].yoffset = (krand()&15)-8; } if (mulscale30(krand(),dist) == 0) { sprite[i].xvel -= ksgn(sprite[i].xvel); sprite[i].yvel -= ksgn(sprite[i].yvel); sprite[i].zvel -= ksgn(sprite[i].zvel); } } //Check for bouncy objects before killing bullet if ((hitobject&0xc000) == 16384) //Bullet hit a ceiling/floor { k = sector[hitobject&(MAXSECTORS-1)].wallptr; l = wall[k].point2; daang = getangle(wall[l].x-wall[k].x,wall[l].y-wall[k].y); getzsofslope(hitobject&(MAXSECTORS-1),sprite[i].x,sprite[i].y,&k,&l); if (sprite[i].z < ((k+l)>>1)) k = sector[hitobject&(MAXSECTORS-1)].ceilingheinum; else k = sector[hitobject&(MAXSECTORS-1)].floorheinum; dax = mulscale14(k,sintable[(daang)&2047]); day = mulscale14(k,sintable[(daang+1536)&2047]); daz = 4096; k = sprite[i].xvel*dax+sprite[i].yvel*day+mulscale4(sprite[i].zvel,daz); l = dax*dax+day*day+daz*daz; if ((klabs(k)>>14) < l) { k = divscale17(k,l); sprite[i].xvel -= mulscale16(dax,k); sprite[i].yvel -= mulscale16(day,k); sprite[i].zvel -= mulscale12(daz,k); } wsayfollow("bouncy.wav",4096L+(krand()&127)-64,255,&sprite[i].x,&sprite[i].y,1); hitobject = 0; sprite[i].owner = -1; //Bullet turns evil! } else if ((hitobject&0xc000) == 32768) //Bullet hit a wall { if (wall[hitobject&4095].lotag == 8) { dax = sprite[i].xvel; day = sprite[i].yvel; if ((sprite[i].picnum != BOMB) || (dax*dax+day*day >= 512)) { k = (hitobject&4095); l = wall[k].point2; j = getangle(wall[l].x-wall[k].x,wall[l].y-wall[k].y)+512; //k = cos(ang) * sin(ang) * 2 k = mulscale13(sintable[(j+512)&2047],sintable[j&2047]); //l = cos(ang * 2) l = sintable[((j<<1)+512)&2047]; ox = sprite[i].xvel; oy = sprite[i].yvel; dax = -ox; day = -oy; sprite[i].xvel = dmulscale14(day,k,dax,l); sprite[i].yvel = dmulscale14(dax,k,-day,l); if (sprite[i].picnum == BOMB) { sprite[i].xvel -= (sprite[i].xvel>>3); sprite[i].yvel -= (sprite[i].yvel>>3); sprite[i].zvel -= (sprite[i].zvel>>3); } ox -= sprite[i].xvel; oy -= sprite[i].yvel; dist = ((ox*ox+oy*oy)>>8); wsayfollow("bouncy.wav",4096L+(krand()&127)-64,min(dist,256),&sprite[i].x,&sprite[i].y,1); hitobject = 0; sprite[i].owner = -1; //Bullet turns evil! } } } else if ((hitobject&0xc000) == 49152) //Bullet hit a sprite { if (sprite[hitobject&4095].picnum == BOUNCYMAT) { if ((sprite[hitobject&4095].cstat&48) == 0) { sprite[i].xvel = -sprite[i].xvel; sprite[i].yvel = -sprite[i].yvel; sprite[i].zvel = -sprite[i].zvel; dist = 255; } else if ((sprite[hitobject&4095].cstat&48) == 16) { j = sprite[hitobject&4095].ang; //k = cos(ang) * sin(ang) * 2 k = mulscale13(sintable[(j+512)&2047],sintable[j&2047]); //l = cos(ang * 2) l = sintable[((j<<1)+512)&2047]; ox = sprite[i].xvel; oy = sprite[i].yvel; dax = -ox; day = -oy; sprite[i].xvel = dmulscale14(day,k,dax,l); sprite[i].yvel = dmulscale14(dax,k,-day,l); ox -= sprite[i].xvel; oy -= sprite[i].yvel; dist = ((ox*ox+oy*oy)>>8); } sprite[i].owner = -1; //Bullet turns evil! wsayfollow("bouncy.wav",4096L+(krand()&127)-64,min(dist,256),&sprite[i].x,&sprite[i].y,1); hitobject = 0; } } if (hitobject != 0) { if ((sprite[i].picnum == MISSILE) || (sprite[i].picnum == BOMB)) { if ((hitobject&0xc000) == 49152) if (sprite[hitobject&4095].lotag == 5) //Basketball hoop { wsayfollow("niceshot.wav",3840L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); deletesprite((short)i); goto bulletisdeletedskip; } bombexplode(i); goto bulletisdeletedskip; } if ((hitobject&0xc000) == 16384) //Hits a ceiling / floor { wsayfollow("bullseye.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); deletesprite((short)i); goto bulletisdeletedskip; } else if ((hitobject&0xc000) == 32768) //Bullet hit a wall { if (wall[hitobject&4095].picnum == KENPICTURE) { if (waloff[MAXTILES-1] != 0) wall[hitobject&4095].picnum = MAXTILES-1; wsayfollow("hello.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); //Ken says, "Hello... how are you today!" } else wsayfollow("bullseye.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); deletesprite((short)i); goto bulletisdeletedskip; } else if ((hitobject&0xc000) == 49152) //Bullet hit a sprite { if ((sprite[hitobject&4095].lotag == 5) && (sprite[i].picnum == GRABBER)) // Basketball hoop (Andy's addition) { wsayfollow("niceshot.wav",3840L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); switch (krand() & 63) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: sprite[i].picnum = COIN; break; case 10: case 11: case 12: case 13: case 14: case 15: case 16: sprite[i].picnum = DIAMONDS; break; case 17: case 18: case 19: sprite[i].picnum = COINSTACK; break; case 20: case 21: case 22: case 23: sprite[i].picnum = GIFTBOX; break; case 24: case 25: sprite[i].picnum = GRABCANNON; break; case 26: case 27: sprite[i].picnum = LAUNCHER; break; case 28: case 29: case 30: sprite[i].picnum = CANNON; break; case 31: sprite[i].picnum = AIRPLANE; break; default: deletesprite((short)i); goto bulletisdeletedskip; } sprite[i].xvel = sprite[i].yvel = sprite[i].zvel = 0; sprite[i].cstat &= ~0x83; //Should not clip, foot-z changespritestat(i,12); goto bulletisdeletedskip; } //Check if bullet hit a player & find which player it was... if (sprite[hitobject&4095].picnum == PLAYER) for (j=connecthead; j>=0; j=connectpoint2[j]) if (sprite[i].owner != j+4096) if (playersprite[j] == (hitobject&4095)) { wsayfollow("ouch.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); if (sprite[i].picnum == GRABBER) // Andy did this { k = ((sprite[i].xrepeat * sprite[i].yrepeat) * 3) >> 9; changehealth((sprite[i].owner - 4096),k); changehealth(j,-k); } else changehealth(j,-mulscale8(sprite[i].xrepeat,sprite[i].yrepeat)); deletesprite((short)i); goto bulletisdeletedskip; } //Check if bullet hit any monsters... j = (hitobject&4095); //j is the spritenum that the bullet (spritenum i) hit if (sprite[i].owner != j) { switch (sprite[j].picnum) { case BROWNMONSTER: if (sprite[j].lotag > 0) { if (sprite[i].picnum == GRABBER) // Andy did this { k = ((sprite[i].xrepeat * sprite[i].yrepeat) * 3) >> 9; changehealth((sprite[i].owner - 4096),k); sprite[j].lotag -= k; } sprite[j].lotag -= mulscale8(sprite[i].xrepeat,sprite[i].yrepeat); } if (sprite[j].lotag > 0) { if (sprite[j].lotag <= 25) sprite[j].cstat |= 2; wsayfollow("hurt.wav",4096L+(krand()&511)-256,256L,&sprite[i].x,&sprite[i].y,1); } else { wsayfollow("mondie.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); sprite[j].z += ((tilesiz[sprite[j].picnum].y*sprite[j].yrepeat)<<1); sprite[j].picnum = GIFTBOX; sprite[j].cstat &= ~0x83; //Should not clip, foot-z spawnsprite(k,sprite[j].x,sprite[j].y,sprite[j].z, 0,-4,0,32,64,64,0,0,EXPLOSION,sprite[j].ang, 0,0,0,j,sprite[j].sectnum,5,31,0,0); //31=Time left for explosion to stay changespritestat(j,12); } deletesprite((short)i); goto bulletisdeletedskip; case EVILAL: wsayfollow("blowup.wav",5144L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); sprite[j].picnum = EVILALGRAVE; sprite[j].cstat = 0; sprite[j].xvel = (krand()&255)-128; sprite[j].yvel = (krand()&255)-128; sprite[j].zvel = (krand()&4095)-3072; changespritestat(j,9); deletesprite((short)i); goto bulletisdeletedskip; case AL: wsayfollow("blowup.wav",5144L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); sprite[j].xrepeat += 2; sprite[j].yrepeat += 2; if (sprite[j].yrepeat >= 38) { sprite[j].picnum = EVILAL; //sprite[j].cstat |= 2; //Make him transluscent changespritestat(j,10); } deletesprite((short)i); goto bulletisdeletedskip; default: wsayfollow("bullseye.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); deletesprite((short)i); goto bulletisdeletedskip; } } } } } bulletisdeletedskip: continue; } //Go through monster waiting for you list for (i=headspritestat[2]; i>=0; i=nexti) { nexti = nextspritestat[i]; if ((nummoves-i)&15) continue; //Use dot product to see if monster's angle is towards a player for (p=connecthead; p>=0; p=connectpoint2[p]) if (sintable[(sprite[i].ang+512)&2047]*(pos[p].x-sprite[i].x) + sintable[sprite[i].ang&2047]*(pos[p].y-sprite[i].y) >= 0) if (cansee(sprite[i].x,sprite[i].y,sprite[i].z-(tilesiz[sprite[i].picnum].y<<7),sprite[i].sectnum,pos[p].x,pos[p].y,pos[p].z,cursectnum[p]) == 1) { changespritestat(i,1); //if (sprite[i].lotag == 100) //{ wsayfollow("iseeyou.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,1); // sprite[i].lotag = 99; //} } } //Go through smoke sprites for (i=headspritestat[3]; i>=0; i=nexti) { nexti = nextspritestat[i]; sprite[i].z -= (TICSPERFRAME<<6); sprite[i].lotag -= TICSPERFRAME; if ((int16_t)sprite[i].lotag < 0) deletesprite(i); } //Go through splash sprites for (i=headspritestat[4]; i>=0; i=nexti) { nexti = nextspritestat[i]; sprite[i].lotag -= TICSPERFRAME; sprite[i].picnum = SPLASH + ((63-sprite[i].lotag)>>4); if ((int16_t)sprite[i].lotag < 0) deletesprite(i); } //Go through explosion sprites for (i=headspritestat[5]; i>=0; i=nexti) { nexti = nextspritestat[i]; sprite[i].lotag -= TICSPERFRAME; if ((int16_t)sprite[i].lotag < 0) deletesprite(i); } //Go through bomb spriral-explosion sprites for (i=headspritestat[7]; i>=0; i=nexti) { nexti = nextspritestat[i]; sprite[i].xrepeat = (sprite[i].lotag>>2); sprite[i].yrepeat = (sprite[i].lotag>>2); sprite[i].lotag -= (TICSPERFRAME<<2); if ((int16_t)sprite[i].lotag < 0) { deletesprite(i); continue; } if ((nummoves-i)&statrate[7]) continue; sprite[i].x += ((sprite[i].xvel*TICSPERFRAME)>>2); sprite[i].y += ((sprite[i].yvel*TICSPERFRAME)>>2); sprite[i].z += ((sprite[i].zvel*TICSPERFRAME)>>2); sprite[i].zvel += (TICSPERFRAME<<9); if (sprite[i].z < sector[sprite[i].sectnum].ceilingz+(4<<8)) { sprite[i].z = sector[sprite[i].sectnum].ceilingz+(4<<8); sprite[i].zvel = -(sprite[i].zvel>>1); } if (sprite[i].z > sector[sprite[i].sectnum].floorz-(4<<8)) { sprite[i].z = sector[sprite[i].sectnum].floorz-(4<<8); sprite[i].zvel = -(sprite[i].zvel>>1); } } //EVILALGRAVE shrinking list for (i=headspritestat[9]; i>=0; i=nexti) { nexti = nextspritestat[i]; sprite[i].xrepeat = (sprite[i].lotag>>2); sprite[i].yrepeat = (sprite[i].lotag>>2); sprite[i].lotag -= TICSPERFRAME; if ((int16_t)sprite[i].lotag < 0) { deletesprite(i); continue; } if ((nummoves-i)&statrate[9]) continue; sprite[i].x += (sprite[i].xvel*TICSPERFRAME); sprite[i].y += (sprite[i].yvel*TICSPERFRAME); sprite[i].z += (sprite[i].zvel*TICSPERFRAME); sprite[i].zvel += (TICSPERFRAME<<8); if (sprite[i].z < sector[sprite[i].sectnum].ceilingz) { sprite[i].z = sector[sprite[i].sectnum].ceilingz; sprite[i].xvel -= (sprite[i].xvel>>2); sprite[i].yvel -= (sprite[i].yvel>>2); sprite[i].zvel = -(sprite[i].zvel>>1); } if (sprite[i].z > sector[sprite[i].sectnum].floorz) { sprite[i].z = sector[sprite[i].sectnum].floorz; sprite[i].xvel -= (sprite[i].xvel>>2); sprite[i].yvel -= (sprite[i].yvel>>2); sprite[i].zvel = -(sprite[i].zvel>>1); } } //Re-spawning sprite list for (i=headspritestat[11]; i>=0; i=nexti) { nexti = nextspritestat[i]; sprite[i].extra -= TICSPERFRAME; if (sprite[i].extra < 0) { wsayfollow("warp.wav",6144L+(krand()&127)-64,128L,&sprite[i].x,&sprite[i].y,0); sprite[i].cstat &= (uint16_t) ~0x8000; sprite[i].extra = -1; changespritestat((short)i,0); } } } void activatehitag(short dahitag) { int i, nexti; for (i=0; i=0; i=nexti) { nexti = nextspritestat[i]; if (sprite[i].hitag == dahitag) operatesprite(i); } } void bombexplode(int i) { int j, nextj, k, daang, dax, day, dist; spawnsprite(j,sprite[i].x,sprite[i].y,sprite[i].z,0,-4,0, 32,64,64,0,0,EXPLOSION,sprite[i].ang, 0,0,0,sprite[i].owner,sprite[i].sectnum,5,31,0,0); //31=Time left for explosion to stay for (k=0; k<12; k++) { spawnsprite(j,sprite[i].x,sprite[i].y,sprite[i].z+(8<<8),2,-4,0, 32,24,24,0,0,EXPLOSION,sprite[i].ang, (krand()>>7)-256,(krand()>>7)-256,(krand()>>2)-8192, sprite[i].owner,sprite[i].sectnum,7,96,0,0); //96=Time left for smoke to be alive } for (j=connecthead; j>=0; j=connectpoint2[j]) { dist = (pos[j].x-sprite[i].x)*(pos[j].x-sprite[i].x); dist += (pos[j].y-sprite[i].y)*(pos[j].y-sprite[i].y); dist += ((pos[j].z-sprite[i].z)>>4)*((pos[j].z-sprite[i].z)>>4); if (dist < 4194304) if (cansee(sprite[i].x,sprite[i].y,sprite[i].z-(tilesiz[sprite[i].picnum].y<<7),sprite[i].sectnum,pos[j].x,pos[j].y,pos[j].z,cursectnum[j]) == 1) { k = ((32768/((dist>>16)+4))>>5); if (j == myconnectindex) { daang = getangle(pos[j].x-sprite[i].x,pos[j].y-sprite[i].y); dax = ((k*sintable[(daang+512)&2047])>>14); day = ((k*sintable[daang&2047])>>14); fvel += ((dax*sintable[(ang[j]+512)&2047]+day*sintable[ang[j]&2047])>>14); svel += ((day*sintable[(ang[j]+512)&2047]-dax*sintable[ang[j]&2047])>>14); } changehealth(j,-k); //if changehealth returns 1, you're dead } } for (k=1; k<=2; k++) //Check for hurting monsters { for (j=headspritestat[k]; j>=0; j=nextj) { nextj = nextspritestat[j]; dist = (sprite[j].x-sprite[i].x)*(sprite[j].x-sprite[i].x); dist += (sprite[j].y-sprite[i].y)*(sprite[j].y-sprite[i].y); dist += ((sprite[j].z-sprite[i].z)>>4)*((sprite[j].z-sprite[i].z)>>4); if (dist >= 4194304) continue; if (cansee(sprite[i].x,sprite[i].y,sprite[i].z-(tilesiz[sprite[i].picnum].y<<7),sprite[i].sectnum,sprite[j].x,sprite[j].y,sprite[j].z-(tilesiz[sprite[j].picnum].y<<7),sprite[j].sectnum) == 0) continue; if (sprite[j].picnum == BROWNMONSTER) { sprite[j].z += ((tilesiz[sprite[j].picnum].y*sprite[j].yrepeat)<<1); sprite[j].picnum = GIFTBOX; sprite[j].cstat &= ~0x83; //Should not clip, foot-z changespritestat(j,12); } } } for (j=headspritestat[10]; j>=0; j=nextj) //Check for EVILAL's { nextj = nextspritestat[j]; dist = (sprite[j].x-sprite[i].x)*(sprite[j].x-sprite[i].x); dist += (sprite[j].y-sprite[i].y)*(sprite[j].y-sprite[i].y); dist += ((sprite[j].z-sprite[i].z)>>4)*((sprite[j].z-sprite[i].z)>>4); if (dist >= 4194304) continue; if (cansee(sprite[i].x,sprite[i].y,sprite[i].z-(tilesiz[sprite[i].picnum].y<<7),sprite[i].sectnum,sprite[j].x,sprite[j].y,sprite[j].z-(tilesiz[sprite[j].picnum].y<<7),sprite[j].sectnum) == 0) continue; sprite[j].picnum = EVILALGRAVE; sprite[j].cstat = 0; sprite[j].xvel = (krand()&255)-128; sprite[j].yvel = (krand()&255)-128; sprite[j].zvel = (krand()&4095)-3072; changespritestat(j,9); } wsayfollow("blowup.wav",3840L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,0); deletesprite((short)i); } void processinput(short snum) { // int oldposx, oldposy, nexti; int i, j, k, doubvel, xvect, yvect, goalz; int dax, day /*, dax2, day2, odax, oday, odax2, oday2*/; // short startwall, endwall; // char *ptr; //SHARED KEYS: //Movement code if ((ssync[snum].fvel|ssync[snum].svel) != 0) { doubvel = (TICSPERFRAME<<((ssync[snum].bits&256)>0)); xvect = 0, yvect = 0; if (ssync[snum].fvel != 0) { xvect += ((((int)ssync[snum].fvel)*doubvel*(int)sintable[(ang[snum]+512)&2047])>>3); yvect += ((((int)ssync[snum].fvel)*doubvel*(int)sintable[ang[snum]&2047])>>3); } if (ssync[snum].svel != 0) { xvect += ((((int)ssync[snum].svel)*doubvel*(int)sintable[ang[snum]&2047])>>3); yvect += ((((int)ssync[snum].svel)*doubvel*(int)sintable[(ang[snum]+1536)&2047])>>3); } if (flytime[snum] > lockclock) { xvect += xvect; yvect += yvect; } // DOuble flying speed clipmove(&pos[snum],&cursectnum[snum],xvect,yvect,128L,4<<8,4<<8,CLIPMASK0); revolvedoorstat[snum] = 1; } else { revolvedoorstat[snum] = 0; } sprite[playersprite[snum]].cstat &= ~1; //Push player away from walls if clipmove doesn't work if (pushmove(&pos[snum],&cursectnum[snum],128L,4<<8,4<<8,CLIPMASK0) < 0) changehealth(snum,-1000); //If this screws up, then instant death!!! // Getzrange returns the highest and lowest z's for an entire box, // NOT just a point. This prevents you from falling off cliffs // when you step only slightly over the cliff. getzrange(&pos[snum],cursectnum[snum],&globhiz,&globhihit,&globloz,&globlohit,128L,CLIPMASK0); sprite[playersprite[snum]].cstat |= 1; if (ssync[snum].avel != 0) //ang += avel * constant { //ENGINE calculates avel for you doubvel = TICSPERFRAME; if ((ssync[snum].bits&256) > 0) //Lt. shift makes turn velocity 50% faster doubvel += (TICSPERFRAME>>1); ang[snum] += ((((int)ssync[snum].avel)*doubvel)>>4); ang[snum] &= 2047; } if (health[snum] < 0) { health[snum] -= TICSPERFRAME; if (health[snum] <= -160) { hvel[snum] = 0; if (snum == myconnectindex) fvel = 0, svel = 0, avel = 0, keystatus[3] = 1; deaths[snum]++; health[snum] = 100; numbombs[snum] = 0; numgrabbers[snum] = 0; nummissiles[snum] = 0; flytime[snum] = 0; findrandomspot(&pos[snum].x,&pos[snum].y,&cursectnum[snum]); pos[snum].z = getflorzofslope(cursectnum[snum],pos[snum].x,pos[snum].y)-(1<<8); horiz[snum] = 100; ang[snum] = (krand()&2047); sprite[playersprite[snum]].x = pos[snum].x; sprite[playersprite[snum]].y = pos[snum].y; sprite[playersprite[snum]].z = pos[snum].z+EYEHEIGHT; sprite[playersprite[snum]].picnum = PLAYER; sprite[playersprite[snum]].ang = ang[snum]; sprite[playersprite[snum]].xrepeat = 64; sprite[playersprite[snum]].yrepeat = 64; changespritesect(playersprite[snum],cursectnum[snum]); drawstatusbar(snum); // Andy did this i = playersprite[snum]; wsayfollow("zipguns.wav",4096L+(krand()&127)-64,256L,&sprite[i].x,&sprite[i].y,1); for (k=0; k<16; k++) { spawnsprite(j,sprite[i].x,sprite[i].y,sprite[i].z+(8<<8),2,-4,0, 32,24,24,0,0,EXPLOSION,sprite[i].ang, (krand()&511)-256,(krand()&511)-256,(krand()&16384)-8192, sprite[i].owner,sprite[i].sectnum,7,96,0,0); //96=Time left for smoke to be alive } } else { sprite[playersprite[snum]].xrepeat = max(((128+health[snum])>>1),0); sprite[playersprite[snum]].yrepeat = max(((128+health[snum])>>1),0); hvel[snum] += (TICSPERFRAME<<2); horiz[snum] = max(horiz[snum]-4,0); pos[snum].z += hvel[snum]; if (pos[snum].z > globloz-(4<<8)) { pos[snum].z = globloz-(4<<8); horiz[snum] = min(horiz[snum]+5,200); hvel[snum] = 0; } } } if (((ssync[snum].bits&8) > 0) && (horiz[snum] > 100-(200>>1))) horiz[snum] -= 4; //- if (((ssync[snum].bits&4) > 0) && (horiz[snum] < 100+(200>>1))) horiz[snum] += 4; //+ goalz = globloz-EYEHEIGHT; if (sector[cursectnum[snum]].lotag == 4) //slime sector if ((globlohit&0xc000) != 49152) //You're not on a sprite { goalz = globloz-(8<<8); if (pos[snum].z >= goalz-(2<<8)) { clipmove(&pos[snum],&cursectnum[snum],-(TICSPERFRAME<<14),-(TICSPERFRAME<<14),128L,4<<8,4<<8,CLIPMASK0); if (slimesoundcnt[snum] >= 0) { slimesoundcnt[snum] -= TICSPERFRAME; while (slimesoundcnt[snum] < 0) { slimesoundcnt[snum] += 120; wsayfollow("slime.wav",4096L+(krand()&127)-64,256L,&pos[snum].x,&pos[snum].y,1); } } } } if (goalz < globhiz+(16<<8)) //ceiling&floor too close goalz = ((globloz+globhiz)>>1); //goalz += mousz; if (health[snum] >= 0) { if ((ssync[snum].bits&1) > 0) //A (stand high) { if (flytime[snum] <= lockclock) { if (pos[snum].z >= globloz-(32<<8)) { goalz -= (16<<8); if (ssync[snum].bits&256) goalz -= (24<<8); } } else { hvel[snum] -= 192; if (ssync[snum].bits&256) hvel[snum] -= 192; } } if ((ssync[snum].bits&2) > 0) //Z (stand low) { if (flytime[snum] <= lockclock) { goalz += (12<<8); if (ssync[snum].bits&256) goalz += (12<<8); } else { hvel[snum] += 192; if (ssync[snum].bits&256) hvel[snum] += 192; } } } if (flytime[snum] <= lockclock) { if (pos[snum].z < goalz) hvel[snum] += (TICSPERFRAME<<4); else hvel[snum] = (((goalz-pos[snum].z)*TICSPERFRAME)>>5); } else { hvel[snum] -= (hvel[snum]>>2); hvel[snum] -= ksgn(hvel[snum]); } pos[snum].z += hvel[snum]; if (pos[snum].z > globloz-(4<<8)) pos[snum].z = globloz-(4<<8), hvel[snum] = 0; if (pos[snum].z < globhiz+(4<<8)) pos[snum].z = globhiz+(4<<8), hvel[snum] = 0; if (dimensionmode[snum] != 3) { if (((ssync[snum].bits&32) > 0) && (zoom[snum] > 48)) zoom[snum] -= (zoom[snum]>>4); if (((ssync[snum].bits&16) > 0) && (zoom[snum] < 4096)) zoom[snum] += (zoom[snum]>>4); } //Update sprite representation of player // -should be after movement, but before shooting code setsprite_eyeheight(playersprite[snum],&pos[snum]); sprite[playersprite[snum]].ang = ang[snum]; if (health[snum] >= 0) { if ((cursectnum[snum] < 0) || (cursectnum[snum] >= numsectors)) { //How did you get in the wrong sector? wsayfollow("ouch.wav",4096L+(krand()&127)-64,64L,&pos[snum].x,&pos[snum].y,1); changehealth(snum,-TICSPERFRAME); } else if (globhiz+(8<<8) > globloz) { //Ceiling and floor are smooshing you! wsayfollow("ouch.wav",4096L+(krand()&127)-64,64L,&pos[snum].x,&pos[snum].y,1); changehealth(snum,-TICSPERFRAME); } } if ((waterfountainwall[snum] >= 0) && (health[snum] >= 0)) if ((wall[neartagwall].lotag != 7) || ((ssync[snum].bits&1024) == 0)) { i = waterfountainwall[snum]; if (wall[i].overpicnum == USEWATERFOUNTAIN) wall[i].overpicnum = WATERFOUNTAIN; else if (wall[i].picnum == USEWATERFOUNTAIN) wall[i].picnum = WATERFOUNTAIN; waterfountainwall[snum] = -1; } if ((ssync[snum].bits&1024) > 0) //Space bar { //Continuous triggers... neartag(pos[snum].x,pos[snum].y,pos[snum].z,cursectnum[snum],ang[snum],&neartagsector,&neartagwall,&neartagsprite,&neartaghitdist,1024L,3,NULL); if (neartagsector == -1) { i = cursectnum[snum]; if ((sector[i].lotag|sector[i].hitag) != 0) neartagsector = i; } if (wall[neartagwall].lotag == 7) //Water fountain { if (wall[neartagwall].overpicnum == WATERFOUNTAIN) { wsayfollow("water.wav",4096L+(krand()&127)-64,256L,&pos[snum].x,&pos[snum].y,1); wall[neartagwall].overpicnum = USEWATERFOUNTAIN; waterfountainwall[snum] = neartagwall; } else if (wall[neartagwall].picnum == WATERFOUNTAIN) { wsayfollow("water.wav",4096L+(krand()&127)-64,256L,&pos[snum].x,&pos[snum].y,1); wall[neartagwall].picnum = USEWATERFOUNTAIN; waterfountainwall[snum] = neartagwall; } if (waterfountainwall[snum] >= 0) { waterfountaincnt[snum] -= TICSPERFRAME; while (waterfountaincnt[snum] < 0) { waterfountaincnt[snum] += 120; wsayfollow("water.wav",4096L+(krand()&127)-64,256L,&pos[snum].x,&pos[snum].y,1); changehealth(snum,2); } } } //1-time triggers... if ((oflags[snum]&1024) == 0) { if (neartagsector >= 0) if (sector[neartagsector].hitag == 0) operatesector(neartagsector); if (neartagwall >= 0) if (wall[neartagwall].lotag == 2) //Switch { activatehitag(wall[neartagwall].hitag); j = wall[neartagwall].overpicnum; if (j == SWITCH1ON) //1-time switch { wall[neartagwall].overpicnum = GIFTBOX; wall[neartagwall].lotag = 0; wall[neartagwall].hitag = 0; } if (j == GIFTBOX) //1-time switch { wall[neartagwall].overpicnum = SWITCH1ON; wall[neartagwall].lotag = 0; wall[neartagwall].hitag = 0; } if (j == SWITCH2ON) wall[neartagwall].overpicnum = SWITCH2OFF; if (j == SWITCH2OFF) wall[neartagwall].overpicnum = SWITCH2ON; if (j == SWITCH3ON) wall[neartagwall].overpicnum = SWITCH3OFF; if (j == SWITCH3OFF) wall[neartagwall].overpicnum = SWITCH3ON; i = wall[neartagwall].point2; dax = ((wall[neartagwall].x+wall[i].x)>>1); day = ((wall[neartagwall].y+wall[i].y)>>1); wsayfollow("switch.wav",4096L+(krand()&255)-128,256L,&dax,&day,0); } if (neartagsprite >= 0) { if (sprite[neartagsprite].lotag == 1) { //if you're shoving innocent little AL around, he gets mad! if (sprite[neartagsprite].picnum == AL) { sprite[neartagsprite].picnum = EVILAL; sprite[neartagsprite].cstat |= 2; //Make him transluscent sprite[neartagsprite].xrepeat = 38; sprite[neartagsprite].yrepeat = 38; changespritestat(neartagsprite,10); } } if (sprite[neartagsprite].lotag == 4) { activatehitag(sprite[neartagsprite].hitag); j = sprite[neartagsprite].picnum; if (j == SWITCH1ON) //1-time switch { sprite[neartagsprite].picnum = GIFTBOX; sprite[neartagsprite].lotag = 0; sprite[neartagsprite].hitag = 0; } if (j == GIFTBOX) //1-time switch { sprite[neartagsprite].picnum = SWITCH1ON; sprite[neartagsprite].lotag = 0; sprite[neartagsprite].hitag = 0; } if (j == SWITCH2ON) sprite[neartagsprite].picnum = SWITCH2OFF; if (j == SWITCH2OFF) sprite[neartagsprite].picnum = SWITCH2ON; if (j == SWITCH3ON) sprite[neartagsprite].picnum = SWITCH3OFF; if (j == SWITCH3OFF) sprite[neartagsprite].picnum = SWITCH3ON; dax = sprite[neartagsprite].x; day = sprite[neartagsprite].y; wsayfollow("switch.wav",4096L+(krand()&255)-128,256L,&dax,&day,0); } } } } if ((ssync[snum].bits & 2048) > 0) // Shoot a bullet { if ((numbombs[snum] == 0) && (((ssync[snum].bits >> 13) & 7) == 2) && (myconnectindex == snum)) locselectedgun = 0; if ((nummissiles[snum] == 0) && (((ssync[snum].bits >> 13) & 7) == 3) && (myconnectindex == snum)) locselectedgun = 1; if ((numgrabbers[snum] == 0) && (((ssync[snum].bits >> 13) & 7) == 4) && (myconnectindex == snum)) locselectedgun = 1; if ((health[snum] >= 0) || ((krand() & 127) > -health[snum])) switch ((ssync[snum].bits >> 13) & 7) { case 0: if (lockclock > lastchaingun[snum]+8) { lastchaingun[snum] = lockclock; shootgun(snum,&pos[snum],ang[snum],horiz[snum],cursectnum[snum],0); } break; case 1: if ((oflags[snum] & 2048) == 0) shootgun(snum,&pos[snum],ang[snum],horiz[snum],cursectnum[snum],1); break; case 2: if ((oflags[snum] & 2048) == 0) if (numbombs[snum] > 0) { shootgun(snum,&pos[snum],ang[snum],horiz[snum],cursectnum[snum],2); changenumbombs(snum,-1); } break; case 3: if ((oflags[snum] & 2048) == 0) if (nummissiles[snum] > 0) { shootgun(snum,&pos[snum],ang[snum],horiz[snum],cursectnum[snum],3); changenummissiles(snum,-1); } break; case 4: if ((oflags[snum] & 2048) == 0) if (numgrabbers[snum] > 0) { shootgun(snum,&pos[snum],ang[snum],horiz[snum],cursectnum[snum],4); changenumgrabbers(snum,-1); } break; } } if ((ssync[snum].bits&4096) > (oflags[snum]&4096)) //Keypad enter { dimensionmode[snum]++; if (dimensionmode[snum] > 3) dimensionmode[snum] = 1; } oflags[snum] = ssync[snum].bits; } void view(short snum, vec3_t *v, short *vsectnum, short ang, int horiz) { spritetype *sp; int i, nx, ny, nz, hx, hy /*, hz*/; short bakcstat, daang; hitdata_t hitinfo; nx = (sintable[(ang+1536)&2047]>>4); ny = (sintable[(ang+1024)&2047]>>4); nz = (horiz-100)*128; sp = &sprite[snum]; bakcstat = sp->cstat; sp->cstat &= (short)~0x101; updatesectorz(v->x,v->y,v->z,vsectnum); hitscan(v,*vsectnum,nx,ny,nz,&hitinfo,CLIPMASK1); hx = hitinfo.pos.x-v->x; hy = hitinfo.pos.y-v->y; if (klabs(nx)+klabs(ny) > klabs(hx)+klabs(hy)) { *vsectnum = hitinfo.sect; if (hitinfo.wall >= 0) { daang = getangle(wall[wall[hitinfo.wall].point2].x-wall[hitinfo.wall].x, wall[wall[hitinfo.wall].point2].y-wall[hitinfo.wall].y); i = nx*sintable[daang]+ny*sintable[(daang+1536)&2047]; if (klabs(nx) > klabs(ny)) hx -= mulscale28(nx,i); else hy -= mulscale28(ny,i); } else if (hitinfo.sprite < 0) { if (klabs(nx) > klabs(ny)) hx -= (nx>>5); else hy -= (ny>>5); } if (klabs(nx) > klabs(ny)) i = divscale16(hx,nx); else i = divscale16(hy,ny); if (i < cameradist) cameradist = i; } v->x = v->x+mulscale16(nx,cameradist); v->y = v->y+mulscale16(ny,cameradist); v->z = v->z+mulscale16(nz,cameradist); updatesectorz(v->x,v->y,v->z,vsectnum); sp->cstat = bakcstat; } void drawscreen(short snum, int dasmoothratio) { int i, j, k=0, l, charsperline, tempint; int x1, y1, x2, y2, ox1, oy1, ox2, oy2, dist, maxdist; vec3_t cpos; int choriz, czoom, tposx, tposy; int tiltlock, *intptr, ovisibility, oparallaxvisibility; short cang, tang, csect; char ch, *ptr, *ptr2, *ptr3, *ptr4; uspritetype *tspr; smoothratio = max(min(dasmoothratio,65536),0); dointerpolations(); if ((snum == myconnectindex) && ((networkmode == 1) || (myconnectindex != connecthead))) { cpos.x = omy.x+mulscale16(my.x-omy.x,smoothratio); cpos.y = omy.y+mulscale16(my.y-omy.y,smoothratio); cpos.z = omy.z+mulscale16(my.z-omy.z,smoothratio); choriz = omyhoriz+mulscale16(myhoriz-omyhoriz,smoothratio); cang = omyang+mulscale16((int)(((myang+1024-omyang)&2047)-1024),smoothratio); } else { cpos.x = opos[snum].x+mulscale16(pos[snum].x-opos[snum].x,smoothratio); cpos.y = opos[snum].y+mulscale16(pos[snum].y-opos[snum].y,smoothratio); cpos.z = opos[snum].z+mulscale16(pos[snum].z-opos[snum].z,smoothratio); choriz = ohoriz[snum]+mulscale16(horiz[snum]-ohoriz[snum],smoothratio); cang = oang[snum]+mulscale16(((ang[snum]+1024-oang[snum])&2047)-1024,smoothratio); } czoom = ozoom[snum]+mulscale16(zoom[snum]-ozoom[snum],smoothratio); setears(cpos.x,cpos.y,(int)sintable[(cang+512)&2047]<<14,(int)sintable[cang&2047]<<14); if (dimensionmode[myconnectindex] == 3) { tempint = screensize; if (((loc.bits&32) > (screensizeflag&32)) && (screensize > 64)) { ox1 = ((xdim-screensize)>>1); ox2 = ox1+screensize-1; oy1 = (((ydim-32)-scale(screensize,ydim-32,xdim))>>1); oy2 = oy1 + scale(screensize,ydim-32,xdim)-1; screensize -= (screensize>>3); if (tempint > xdim) { screensize = xdim; flushperms(); rotatesprite((xdim-320)<<15,(ydim-32)<<16,65536L,0,STATUSBAR,0,0,8+16+64+128,0L,0L,xdim-1L,ydim-1L); i = ((xdim-320)>>1); while (i >= 8) i -= 8, rotatesprite(i<<16,(ydim-32)<<16,65536L,0,STATUSBARFILL8,0,0,8+16+64+128,0L,0L,xdim-1L,ydim-1L); if (i >= 4) i -= 4, rotatesprite(i<<16,(ydim-32)<<16,65536L,0,STATUSBARFILL4,0,0,8+16+64+128,0L,0L,xdim-1L,ydim-1L); i = ((xdim-320)>>1)+320; while (i <= xdim-8) rotatesprite(i<<16,(ydim-32)<<16,65536L,0,STATUSBARFILL8,0,0,8+16+64+128,0L,0L,xdim-1L,ydim-1L), i += 8; if (i <= xdim-4) rotatesprite(i<<16,(ydim-32)<<16,65536L,0,STATUSBARFILL4,0,0,8+16+64+128,0L,0L,xdim-1L,ydim-1L), i += 4; drawstatusbar(screenpeek); // Andy did this } x1 = ((xdim-screensize)>>1); x2 = x1+screensize-1; y1 = (((ydim-32)-scale(screensize,ydim-32,xdim))>>1); y2 = y1 + scale(screensize,ydim-32,xdim)-1; setview(x1,y1,x2,y2); // (ox1,oy1)⁄ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒø // ≥ (x1,y1) ≥ // ≥ ⁄ƒƒƒƒƒø ≥ // ≥ ≥ ≥ ≥ // ≥ ¿ƒƒƒƒƒŸ ≥ // ≥ (x2,y2) ≥ // ¿ƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒƒŸ(ox2,oy2) drawtilebackground(/*0L,0L,*/ BACKGROUND,8,ox1,oy1,x1-1,oy2,0); drawtilebackground(/*0L,0L,*/ BACKGROUND,8,x2+1,oy1,ox2,oy2,0); drawtilebackground(/*0L,0L,*/ BACKGROUND,8,x1,oy1,x2,y1-1,0); drawtilebackground(/*0L,0L,*/ BACKGROUND,8,x1,y2+1,x2,oy2,0); } if (((loc.bits&16) > (screensizeflag&16)) && (screensize <= xdim)) { screensize += (screensize>>3); if ((screensize > xdim) && (tempint == xdim)) { screensize = xdim+1; x1 = 0; y1 = 0; x2 = xdim-1; y2 = ydim-1; } else { if (screensize > xdim) screensize = xdim; x1 = ((xdim-screensize)>>1); x2 = x1+screensize-1; y1 = (((ydim-32)-scale(screensize,ydim-32,xdim))>>1); y2 = y1 + scale(screensize,ydim-32,xdim)-1; } setview(x1,y1,x2,y2); } screensizeflag = loc.bits; } if (dimensionmode[snum] != 2) { if ((numplayers > 1) && (option[4] == 0)) { //Do not draw other views constantly if they're staying still //It's a shame this trick will only work in screen-buffer mode //At least screen-buffer mode covers all the HI hi-res modes //if (vidoption == 2) //{ for (i=connecthead; i>=0; i=connectpoint2[i]) frame2draw[i] = 0; frame2draw[snum] = 1; //2-1,3-1,4-2 //5-2,6-2,7-2,8-3,9-3,10-3,11-3,12-4,13-4,14-4,15-4,16-5 x1 = pos[snum].x; y1 = pos[snum].y; for (j=(numplayers>>2)+1; j>0; j--) { maxdist = 0x80000000; for (i=connecthead; i>=0; i=connectpoint2[i]) if (frame2draw[i] == 0) { x2 = pos[i].x-x1; y2 = pos[i].y-y1; dist = dmulscale12(x2,x2,y2,y2); if (dist < 64) dist = 16384; else if (dist > 16384) dist = 64; else dist = 1048576 / dist; dist *= frameskipcnt[i]; //Increase frame rate if screen is moving if ((pos[i].x != opos[i].x) || (pos[i].y != opos[i].y) || (pos[i].z != opos[i].z) || (ang[i] != oang[i]) || (horiz[i] != ohoriz[i])) dist += dist; if (dist > maxdist) maxdist = dist, k = i; } for (i=connecthead; i>=0; i=connectpoint2[i]) frameskipcnt[i] += (frameskipcnt[i]>>3)+1; frameskipcnt[k] = 0; frame2draw[k] = 1; } //} //else //{ // for(i=connecthead;i>=0;i=connectpoint2[i]) frame2draw[i] = 1; //} for (i=connecthead,j=0; i>=0; i=connectpoint2[i],j++) if (frame2draw[i] != 0) { if (numplayers <= 4) { switch (j) { case 0: setview(0,0,(xdim>>1)-1,(ydim>>1)-1); break; case 1: setview((xdim>>1),0,xdim-1,(ydim>>1)-1); break; case 2: setview(0,(ydim>>1),(xdim>>1)-1,ydim-1); break; case 3: setview((xdim>>1),(ydim>>1),xdim-1,ydim-1); break; } } else { switch (j) { case 0: setview(0,0,(xdim>>2)-1,(ydim>>2)-1); break; case 1: setview(xdim>>2,0,(xdim>>1)-1,(ydim>>2)-1); break; case 2: setview(xdim>>1,0,xdim-(xdim>>2)-1,(ydim>>2)-1); break; case 3: setview(xdim-(xdim>>2),0,xdim-1,(ydim>>2)-1); break; case 4: setview(0,ydim>>2,(xdim>>2)-1,(ydim>>1)-1); break; case 5: setview(xdim>>2,ydim>>2,(xdim>>1)-1,(ydim>>1)-1); break; case 6: setview(xdim>>1,ydim>>2,xdim-(xdim>>2)-1,(ydim>>1)-1); break; case 7: setview(xdim-(xdim>>2),ydim>>2,xdim-1,(ydim>>1)-1); break; case 8: setview(0,ydim>>1,(xdim>>2)-1,ydim-(ydim>>2)-1); break; case 9: setview(xdim>>2,ydim>>1,(xdim>>1)-1,ydim-(ydim>>2)-1); break; case 10: setview(xdim>>1,ydim>>1,xdim-(xdim>>2)-1,ydim-(ydim>>2)-1); break; case 11: setview(xdim-(xdim>>2),ydim>>1,xdim-1,ydim-(ydim>>2)-1); break; case 12: setview(0,ydim-(ydim>>2),(xdim>>2)-1,ydim-1); break; case 13: setview(xdim>>2,ydim-(ydim>>2),(xdim>>1)-1,ydim-1); break; case 14: setview(xdim>>1,ydim-(ydim>>2),xdim-(xdim>>2)-1,ydim-1); break; case 15: setview(xdim-(xdim>>2),ydim-(ydim>>2),xdim-1,ydim-1); break; } } if (i == snum) { sprite[playersprite[snum]].cstat |= 0x8000; drawrooms(cpos.x,cpos.y,cpos.z,cang,choriz,cursectnum[i]); sprite[playersprite[snum]].cstat &= (uint16_t) ~0x8000; analyzesprites(cpos.x,cpos.y); } else { sprite[playersprite[i]].cstat |= 0x8000; drawrooms(pos[i].x,pos[i].y,pos[i].z,ang[i],horiz[i],cursectnum[i]); sprite[playersprite[i]].cstat &= (uint16_t) ~0x8000; analyzesprites(pos[i].x,pos[i].y); } drawmasks(); if ((numgrabbers[i] > 0) || (nummissiles[i] > 0) || (numbombs[i] > 0)) rotatesprite(160<<16,184L<<16,65536,0,GUNONBOTTOM,sector[cursectnum[i]].floorshade,0,2,windowxy1.x,windowxy1.y,windowxy2.x,windowxy2.y); if (lockclock < 384) { if (lockclock < 128) rotatesprite(320<<15,200<<15,lockclock<<9,lockclock<<4,DEMOSIGN,(128-lockclock)>>2,0,1+2,windowxy1.x,windowxy1.y,windowxy2.x,windowxy2.y); else if (lockclock < 256) rotatesprite(320<<15,200<<15,65536,0,DEMOSIGN,0,0,2,windowxy1.x,windowxy1.y,windowxy2.x,windowxy2.y); else rotatesprite(320<<15,200<<15,(384-lockclock)<<9,lockclock<<4,DEMOSIGN,(lockclock-256)>>2,0,1+2,windowxy1.x,windowxy1.y,windowxy2.x,windowxy2.y); } if (health[i] <= 0) rotatesprite(320<<15,200<<15,(-health[i])<<11,(-health[i])<<5,NO,0,0,2,windowxy1.x,windowxy1.y,windowxy2.x,windowxy2.y); } } else { //Init for screen rotation if (getrendermode() == 0) // JBF 20031220 { tiltlock = screentilt; if ((tiltlock) || (detailmode)) { walock[TILE_TILT] = 255; if (waloff[TILE_TILT] == 0) allocache(&waloff[TILE_TILT],320L*320L,&walock[TILE_TILT]); if ((tiltlock&1023) == 0) setviewtotile(TILE_TILT,200L>>detailmode,320L>>detailmode); else setviewtotile(TILE_TILT,320L>>detailmode,320L>>detailmode); if ((tiltlock&1023) == 512) { //Block off unscreen section of 90¯ tilted screen j = ((320-60)>>detailmode); for (i=(60>>detailmode)-1; i>=0; i--) { startumost[i] = 1; startumost[i+j] = 1; startdmost[i] = 0; startdmost[i+j] = 0; } } i = (tiltlock&511); if (i > 256) i = 512-i; i = sintable[i+512]*8 + sintable[i]*5L; setaspect(i>>1,yxaspect); } } else { tiltlock = screentilt; // Ken loves to interpolate setrollangle(oscreentilt + mulscale16(((screentilt-oscreentilt+1024)&2047)-1024,smoothratio)); } if ((gotpic[FLOORMIRROR>>3]&(1<<(FLOORMIRROR&7))) > 0) { dist = 0x7fffffff; i = 0; for (k=floormirrorcnt-1; k>=0; k--) { j = klabs(wall[sector[floormirrorsector[k]].wallptr].x-cpos.x); j += klabs(wall[sector[floormirrorsector[k]].wallptr].y-cpos.y); if (j < dist) dist = j, i = k; } //if (cpos.z > sector[floormirrorsector[i]].ceilingz) i = 1-i; //SOS j = floormirrorsector[i]; if (cameradist < 0) sprite[playersprite[snum]].cstat |= 0x8000; drawrooms(cpos.x,cpos.y,(sector[j].floorz<<1)-cpos.z,cang,201-choriz,j); //SOS //drawrooms(cpos.x,cpos.y,cpos.z,cang,choriz,j+MAXSECTORS); //SOS sprite[playersprite[snum]].cstat &= (uint16_t) ~0x8000; analyzesprites(cpos.x,cpos.y); drawmasks(); //Temp horizon if (getrendermode() == 0) { l = scale(choriz-100,windowxy2.x-windowxy1.x,320)+((windowxy1.y+windowxy2.y)>>1); begindrawing(); //{{{ for (y1=windowxy1.y,y2=windowxy2.y; y1>2,31)<<8); ptr4 = palookup[18]; ptr4 += (min(klabs(y2-l)>>2,31)<<8); j = sintable[((y2+totalclock)<<6)&2047]; j += sintable[((y2-totalclock)<<7)&2047]; j >>= 14; //ptr2 += j; //for(x1=windowxy1.x;x1<=windowxy2.x;x1++) // { ch = ptr[x1]; ptr[x1] = ptr3[ptr2[x1]]; ptr2[x1] = ptr4[ch]; } ox1 = windowxy1.x-min(j,0); ox2 = windowxy2.x-max(j,0); for (x1=windowxy1.x; x1>3] &= ~(1<<(FLOORMIRROR&7)); } //Over the shoulder mode csect = cursectnum[snum]; if (cameradist >= 0) { cang += cameraang; view(playersprite[snum],&cpos,&csect,cang,choriz); } //WARNING! Assuming (MIRRORLABEL&31) = 0 and MAXMIRRORS = 64 intptr = (int *)&gotpic[MIRRORLABEL>>3]; // CHECK! if (intptr[0]|intptr[1]) for (i=MAXMIRRORS-1; i>=0; i--) if (gotpic[(i+MIRRORLABEL)>>3]&(1<<(i&7))) { gotpic[(i+MIRRORLABEL)>>3] &= ~(1<<(i&7)); //Prepare drawrooms for drawing mirror and calculate reflected //position into tposx, tposy, and tang (tpos.z == cpos.z) //Must call preparemirror before drawrooms and // completemirror after drawrooms preparemirror(cpos.x,cpos.y,/*cpos.z,*/ cang, /*choriz,*/ mirrorwall[i],/*mirrorsector[i],*/ &tposx,&tposy,&tang); ovisibility = g_visibility; oparallaxvisibility = parallaxvisibility; g_visibility <<= 1; parallaxvisibility <<= 1; ptr = palookup[0]; palookup[0] = palookup[17]; palookup[17] = ptr; drawrooms(tposx,tposy,cpos.z,tang,choriz,mirrorsector[i]|MAXSECTORS); for (j=0,tspr=&tsprite[0]; jcstat&48) == 0) tspr->cstat |= 4; analyzesprites(tposx,tposy); drawmasks(); ptr = palookup[0]; palookup[0] = palookup[17]; palookup[17] = ptr; g_visibility = ovisibility; parallaxvisibility = oparallaxvisibility; completemirror(); //Reverse screen x-wise in this function break; } if (cameradist < 0) sprite[playersprite[snum]].cstat |= 0x8000; drawrooms(cpos.x,cpos.y,cpos.z,cang,choriz,csect); sprite[playersprite[snum]].cstat &= (uint16_t) ~0x8000; analyzesprites(cpos.x,cpos.y); drawmasks(); //Finish for screen rotation if (getrendermode() == 0) // JBF 20031220 { if ((tiltlock) || (detailmode)) { setviewback(); i = (tiltlock&511); if (i > 256) i = 512-i; i = sintable[i+512]*8 + sintable[i]*5L; if (detailmode == 0) i >>= 1; rotatesprite(320<<15,200<<15,i,tiltlock+512,TILE_TILT,0,0,2+4+64,windowxy1.x,windowxy1.y,windowxy2.x,windowxy2.y); walock[TILE_TILT] = 1; } } if (((numgrabbers[screenpeek] > 0) || (nummissiles[screenpeek] > 0) || (numbombs[screenpeek] > 0)) && (cameradist < 0)) { //Reset startdmost to bottom of screen if ((windowxy1.x == 0) && (windowxy2.x == 319) && (yxaspect == 65536) && (tiltlock == 0)) { x1 = 160L-(tilesiz[GUNONBOTTOM].x>>1); y1 = windowxy2.y+1; for (i=0; i>2,0,1+2,windowxy1.x,windowxy1.y,windowxy2.x,windowxy2.y); else if (lockclock < 256) rotatesprite(320<<15,200<<15,65536,0,DEMOSIGN,0,0,2,windowxy1.x,windowxy1.y,windowxy2.x,windowxy2.y); else rotatesprite(320<<15,200<<15,(384-lockclock)<<9,lockclock<<4,DEMOSIGN,(lockclock-256)>>2,0,1+2,windowxy1.x,windowxy1.y,windowxy2.x,windowxy2.y); } if (health[screenpeek] <= 0) rotatesprite(320<<15,200<<15,(-health[screenpeek])<<11,(-health[screenpeek])<<5,NO,0,0,2,windowxy1.x,windowxy1.y,windowxy2.x,windowxy2.y); } } //Only animate lava if its picnum is on screen //gotpic is a bit array where the tile number's bit is set //whenever it is drawn (ceilings, walls, sprites, etc.) if ((gotpic[SLIME>>3]&(1<<(SLIME&7))) > 0) { gotpic[SLIME>>3] &= ~(1<<(SLIME&7)); if (waloff[SLIME] != 0) { movelava((char *)waloff[SLIME]); invalidatetile(SLIME,0,1); // JBF 20031228 } } if ((show2dsector[cursectnum[snum]>>3]&(1<<(cursectnum[snum]&7))) == 0) searchmap(cursectnum[snum]); if (dimensionmode[snum] != 3) { //Move back pivot point i = scale(czoom,screensize,320); if (dimensionmode[snum] == 2) { clearview(0L); //Clear screen to specified color drawmapview(cpos.x,cpos.y,i,cang); } drawoverheadmap(cpos.x,cpos.y,i,cang); } if (typemode != 0) { charsperline = 40; //if (dimensionmode[snum] == 2) charsperline = 80; for (i=0; i<=typemessageleng; i+=charsperline) { for (j=0; j 0) { charsperline = 40; //if (dimensionmode[snum] == 2) charsperline = 80; for (i=0; i<=getmessageleng; i+=charsperline) { for (j=0; j getmessagetimeoff) getmessageleng = 0; } if ((numplayers >= 2) && (screenpeek != myconnectindex)) { j = 1; for (i=connecthead; i>=0; i=connectpoint2[i]) { if (i == screenpeek) break; j++; } Bsprintf((char *)tempbuf,"(Player %d's view)",j); printext256((xdim>>1)-(Bstrlen((char *)tempbuf)<<2),0,24,-1,(char *)tempbuf,0); } if (syncstat != 0) printext256(68L,84L,31,0,"OUT OF SYNC!",0); if (syncstate != 0) printext256(68L,92L,31,0,"Missed Network packet!",0); // //Uncomment this to test cache locks //extern int cacnum; //typedef struct { int *hand, leng; char *lock; } cactype; //extern cactype cac[]; // // j = 0; // for(i=0;i= 200) // { // Bsprintf(tempbuf,"Locked- %ld: Leng:%ld, Lock:%ld",i,cac[i].leng,*cac[i].lock); // printext256(0L,j,31,-1,tempbuf,1); j += 6; // } nextpage(); // send completed frame to display while (totalclock >= ototalclock+(TIMERINTSPERSECOND/MOVESPERSECOND)) faketimerhandler(); if (keystatus[0x3f]) //F5 { keystatus[0x3f] = 0; detailmode ^= 1; //setrendermode(3); } if (keystatus[0x58]) //F12 { keystatus[0x58] = 0; screencapture("captxxxx.tga",keystatus[0x2a]|keystatus[0x36],"EDuke32"); } if (keystatus[0x3e]) //F4 - screen re-size { keystatus[0x3e] = 0; if (keystatus[0x2a]|keystatus[0x36]) { setgamemode(!fullscreen, xdim, ydim, bpp); } else { //cycle through all modes j=-1; // work out a mask to select the mode for (i=0; i 8) brightness = 0; setbrightness(brightness,0,0); } if (option[4] == 0) //Single player only keys { if (keystatus[0xd2]) //Insert - Insert player { keystatus[0xd2] = 0; if (numplayers < MAXPLAYERS) { connectpoint2[numplayers-1] = numplayers; connectpoint2[numplayers] = -1; movefifoend[numplayers] = movefifoend[0]; //HACK 01/05/2000 initplayersprite(numplayers); clearallviews(0L); //Clear screen to specified color numplayers++; } } if (keystatus[0xd3]) //Delete - Delete player { keystatus[0xd3] = 0; if (numplayers > 1) { numplayers--; connectpoint2[numplayers-1] = -1; deletesprite(playersprite[numplayers]); playersprite[numplayers] = -1; if (myconnectindex >= numplayers) myconnectindex = 0; if (screenpeek >= numplayers) screenpeek = 0; if (numplayers < 2) setup3dscreen(); else clearallviews(0L); //Clear screen to specified color } } if (keystatus[0x46]) //Scroll Lock { keystatus[0x46] = 0; myconnectindex = connectpoint2[myconnectindex]; if (myconnectindex < 0) myconnectindex = connecthead; screenpeek = myconnectindex; } } restoreinterpolations(); } void movethings(void) { int i; gotlastpacketclock = totalclock; for (i=connecthead; i>=0; i=connectpoint2[i]) { copybufbyte(&ffsync[i],&baksync[movefifoend[i]][i],sizeof(input)); movefifoend[i] = ((movefifoend[i]+1)&(MOVEFIFOSIZ-1)); } } void fakedomovethings(void) { input *syn; int /*i, j, k,*/ doubvel, xvect, yvect, goalz; short bakcstat; syn = (input *)&baksync[fakemovefifoplc][myconnectindex]; omy = my; omyang = myang; omyhoriz = myhoriz; bakcstat = sprite[playersprite[myconnectindex]].cstat; sprite[playersprite[myconnectindex]].cstat &= ~0x101; if ((syn->fvel|syn->svel) != 0) { doubvel = (TICSPERFRAME<<((syn->bits&256)>0)); xvect = 0, yvect = 0; if (syn->fvel != 0) { xvect += ((((int)syn->fvel)*doubvel*(int)sintable[(myang+512)&2047])>>3); yvect += ((((int)syn->fvel)*doubvel*(int)sintable[myang&2047])>>3); } if (syn->svel != 0) { xvect += ((((int)syn->svel)*doubvel*(int)sintable[myang&2047])>>3); yvect += ((((int)syn->svel)*doubvel*(int)sintable[(myang+1536)&2047])>>3); } if (flytime[myconnectindex] > lockclock) { xvect += xvect; yvect += yvect; } // DOuble flying speed clipmove(&my,&mycursectnum,xvect,yvect,128L,4<<8,4<<8,CLIPMASK0); } pushmove(&my,&mycursectnum,128L,4<<8,4<<8,CLIPMASK0); getzrange(&my,mycursectnum,&globhiz,&globhihit,&globloz,&globlohit,128L,CLIPMASK0); if (syn->avel != 0) //ang += avel * constant { //ENGINE calculates avel for you doubvel = TICSPERFRAME; if ((syn->bits&256) > 0) //Lt. shift makes turn velocity 50% faster doubvel += (TICSPERFRAME>>1); myang += ((((int)syn->avel)*doubvel)>>4); myang &= 2047; } if (((syn->bits&8) > 0) && (myhoriz > 100-(200>>1))) myhoriz -= 4; //- if (((syn->bits&4) > 0) && (myhoriz < 100+(200>>1))) myhoriz += 4; //+ goalz = globloz-EYEHEIGHT; if (sector[mycursectnum].lotag == 4) //slime sector if ((globlohit&0xc000) != 49152) //You're not on a sprite { goalz = globloz-(8<<8); if (my.z >= goalz-(2<<8)) clipmove(&my,&mycursectnum,-(TICSPERFRAME<<14),-(TICSPERFRAME<<14),128L,4<<8,4<<8,CLIPMASK0); } if (goalz < globhiz+(16<<8)) //ceiling&floor too close goalz = ((globloz+globhiz)>>1); if (health[myconnectindex] >= 0) { if ((syn->bits&1) > 0) //A (stand high) { if (flytime[myconnectindex] <= lockclock) { if (my.z >= globloz-(32<<8)) { goalz -= (16<<8); if (syn->bits&256) goalz -= (24<<8); } } else { myzvel -= 192; if (syn->bits&256) myzvel -= 192; } } if ((syn->bits&2) > 0) //Z (stand low) { if (flytime[myconnectindex] <= lockclock) { goalz += (12<<8); if (syn->bits&256) goalz += (12<<8); } else { myzvel += 192; if (syn->bits&256) myzvel += 192; } } } if (flytime[myconnectindex] <= lockclock) { if (my.z < goalz) myzvel += (TICSPERFRAME<<4); else myzvel = (((goalz-my.z)*TICSPERFRAME)>>5); } else { myzvel -= (myzvel>>2); myzvel -= ksgn(myzvel); } my.z += myzvel; if (my.z > globloz-(4<<8)) my.z = globloz-(4<<8), myzvel = 0; if (my.z < globhiz+(4<<8)) my.z = globhiz+(4<<8), myzvel = 0; sprite[playersprite[myconnectindex]].cstat = bakcstat; mybak[fakemovefifoplc] = my; myangbak[fakemovefifoplc] = myang; myhorizbak[fakemovefifoplc] = myhoriz; fakemovefifoplc = (fakemovefifoplc+1)&(MOVEFIFOSIZ-1); } //Prediction correction void fakedomovethingscorrect(void) { int i; if ((networkmode == 0) && (myconnectindex == connecthead)) return; i = ((movefifoplc-1)&(MOVEFIFOSIZ-1)); if ((pos[myconnectindex].x == mybak[i].x) && (pos[myconnectindex].y == mybak[i].y) && (pos[myconnectindex].z == mybak[i].z) && (horiz[myconnectindex] == myhorizbak[i]) && (ang[myconnectindex] == myangbak[i])) return; //Re-start fakedomovethings back to place of error my = omy; myzvel = hvel[myconnectindex]; myang = omyang = ang[myconnectindex]; mycursectnum = cursectnum[myconnectindex]; myhoriz = omyhoriz = horiz[myconnectindex]; fakemovefifoplc = movefifoplc; while (fakemovefifoplc != movefifoend[myconnectindex]) fakedomovethings(); } void domovethings(void) { short i, j, startwall, endwall; // spritetype *spr; walltype *wal; // vec3_t *ospr; nummoves++; for (i=connecthead; i>=0; i=connectpoint2[i]) copybufbyte(&baksync[movefifoplc][i],&ssync[i],sizeof(input)); movefifoplc = ((movefifoplc+1)&(MOVEFIFOSIZ-1)); if (option[4] != 0) { syncval[syncvalhead] = (char)(randomseed&255); syncvalhead = ((syncvalhead+1)&(MOVEFIFOSIZ-1)); } for (i=connecthead; i>=0; i=connectpoint2[i]) { opos[i] = pos[i]; ohoriz[i] = horiz[i]; ozoom[i] = zoom[i]; oang[i] = ang[i]; } for (i=NUMSTATS-1; i>=0; i--) if (statrate[i] >= 0) for (j=headspritestat[i]; j>=0; j=nextspritestat[j]) if (((nummoves-j)&statrate[i]) == 0) copybuf(&sprite[j].x,&osprite[j].x,3); for (i=connecthead; i>=0; i=connectpoint2[i]) ocursectnum[i] = cursectnum[i]; updateinterpolations(); if ((numplayers <= 2) && (recstat == 1)) { j = 0; for (i=connecthead; i>=0; i=connectpoint2[i]) { copybufbyte(&ssync[i],&recsync[reccnt][j],sizeof(input)); j++; } reccnt++; if (reccnt > 16383) reccnt = 16383; } lockclock += TICSPERFRAME; drawstatusflytime(screenpeek); // Andy did this if (cameradist >= 0) { cameradist = min(cameradist+((totalclock-cameraclock)<<10),65536); if (keystatus[0x52]) //0 cameraang -= ((totalclock-cameraclock)<<(2+(keystatus[0x2a]|keystatus[0x36]))); if (keystatus[0x53]) //. cameraang += ((totalclock-cameraclock)<<(2+(keystatus[0x2a]|keystatus[0x36]))); cameraclock = totalclock; } for (i=connecthead; i>=0; i=connectpoint2[i]) { processinput(i); //Move player checktouchsprite(i,cursectnum[i]); //Pick up coins startwall = sector[cursectnum[i]].wallptr; endwall = startwall + sector[cursectnum[i]].wallnum; for (j=startwall,wal=&wall[j]; jnextsector >= 0) checktouchsprite(i,wal->nextsector); } doanimations(); tagcode(); //Door code, moving sector code, other stuff statuslistcode(); //Monster / bullet code / explosions fakedomovethingscorrect(); checkmasterslaveswitch(); } void getinput(void) { char ch /*, keystate, *ptr*/; int i, j /*, k*/; int mousx, mousy, bstatus; if (typemode == 0) //if normal game keys active { if (keystatus[keys[15]]) { keystatus[keys[15]] = 0; screenpeek = connectpoint2[screenpeek]; if (screenpeek < 0) screenpeek = connecthead; drawstatusbar(screenpeek); // Andy did this } for (i=7; i>=0; i--) if (keystatus[i+2]) { keystatus[i+2] = 0; locselectedgun = i; break; } } //KEYTIMERSTUFF if (!keystatus[keys[5]]) { if (keystatus[keys[2]]) avel = max(avel-16*TICSPERFRAME,-128); if (keystatus[keys[3]]) avel = min(avel+16*TICSPERFRAME,127); } else { if (keystatus[keys[2]]) svel = min(svel+8*TICSPERFRAME,127); if (keystatus[keys[3]]) svel = max(svel-8*TICSPERFRAME,-128); } if (keystatus[keys[0]]) fvel = min(fvel+8*TICSPERFRAME,127); if (keystatus[keys[1]]) fvel = max(fvel-8*TICSPERFRAME,-128); if (keystatus[keys[12]]) svel = min(svel+8*TICSPERFRAME,127); if (keystatus[keys[13]]) svel = max(svel-8*TICSPERFRAME,-128); if (avel < 0) avel = min(avel+12*TICSPERFRAME,0); if (avel > 0) avel = max(avel-12*TICSPERFRAME,0); if (svel < 0) svel = min(svel+2*TICSPERFRAME,0); if (svel > 0) svel = max(svel-2*TICSPERFRAME,0); if (fvel < 0) fvel = min(fvel+2*TICSPERFRAME,0); if (fvel > 0) fvel = max(fvel-2*TICSPERFRAME,0); if ((option[4] == 0) && (numplayers >= 2)) { if (!keystatus[0x4f]) { if (keystatus[0x4b]) avel2 = max(avel2-16*TICSPERFRAME,-128); if (keystatus[0x4d]) avel2 = min(avel2+16*TICSPERFRAME,127); } else { if (keystatus[0x4b]) svel2 = min(svel2+8*TICSPERFRAME,127); if (keystatus[0x4d]) svel2 = max(svel2-8*TICSPERFRAME,-128); } if (keystatus[0x48]) fvel2 = min(fvel2+8*TICSPERFRAME,127); if (keystatus[0x4c]) fvel2 = max(fvel2-8*TICSPERFRAME,-128); if (avel2 < 0) avel2 = min(avel2+12*TICSPERFRAME,0); if (avel2 > 0) avel2 = max(avel2-12*TICSPERFRAME,0); if (svel2 < 0) svel2 = min(svel2+2*TICSPERFRAME,0); if (svel2 > 0) svel2 = max(svel2-2*TICSPERFRAME,0); if (fvel2 < 0) fvel2 = min(fvel2+2*TICSPERFRAME,0); if (fvel2 > 0) fvel2 = max(fvel2-2*TICSPERFRAME,0); } oscreentilt = screentilt; if (keystatus[0x1a]) screentilt += ((4*TICSPERFRAME)<<(keystatus[0x2a]|keystatus[0x36])); if (keystatus[0x1b]) screentilt -= ((4*TICSPERFRAME)<<(keystatus[0x2a]|keystatus[0x36])); i = (TICSPERFRAME<<1); while ((screentilt != 0) && (i > 0)) { screentilt = ((screentilt+ksgn(screentilt-1024))&2047); i--; } if (keystatus[0x28]) screentilt = 1536; loc.fvel = min(max(fvel,-128+8),127-8); loc.svel = min(max(svel,-128+8),127-8); loc.avel = min(max(avel,-128+16),127-16); getmousevalues(&mousx,&mousy,&bstatus); loc.avel = min(max(loc.avel+(mousx<<3),-128),127); loc.fvel = min(max(loc.fvel-(mousy<<3),-128),127); loc.bits = (locselectedgun<<13); if (typemode == 0) //if normal game keys active { loc.bits |= (keystatus[0x32]<<9); //M (be master) loc.bits |= ((keystatus[keys[14]]==1)<<12); //Map mode } loc.bits |= keystatus[keys[8]]; //Stand high loc.bits |= (keystatus[keys[9]]<<1); //Stand low loc.bits |= (keystatus[keys[16]]<<4); //Zoom in loc.bits |= (keystatus[keys[17]]<<5); //Zoom out loc.bits |= (keystatus[keys[4]]<<8); //Run loc.bits |= (keystatus[keys[10]]<<2); //Look up loc.bits |= (keystatus[keys[11]]<<3); //Look down loc.bits |= ((keystatus[keys[7]]==1)<<10); //Space loc.bits |= ((keystatus[keys[6]]==1)<<11); //Shoot loc.bits |= (((bstatus&6)>(oldmousebstatus&6))<<10); //Space loc.bits |= (((bstatus&1)>(oldmousebstatus&1))<<11); //Shoot oldmousebstatus = bstatus; if (((loc.bits&2048) > 0) && (locselectedgun == 0)) oldmousebstatus &= ~1; //Allow continous fire with mouse for chain gun //PRIVATE KEYS: #if 0 if (keystatus[0xb7]) //Printscreen { keystatus[0xb7] = 0; printscreeninterrupt(); } #endif if (keystatus[0x2f]) //V { keystatus[0x2f] = 0; if (cameradist < 0) cameradist = 0; else cameradist = -1; cameraang = 0; } if (typemode == 0) //if normal game keys active { if (keystatus[0x19]) //P { keystatus[0x19] = 0; parallaxtype++; if (parallaxtype > 2) parallaxtype = 0; } if (keystatus[0x38]|keystatus[0xb8]) //ALT { if (keystatus[0x4a]) // Keypad - g_visibility = min(g_visibility+(g_visibility>>3),16384); if (keystatus[0x4e]) // Keypad + g_visibility = max(g_visibility-(g_visibility>>3),128); } if (keystatus[keys[18]]) //Typing mode { keystatus[keys[18]] = 0; typemode = 1; bflushchars(); keyfifoplc = keyfifoend; //Reset keyboard fifo } } else { while ((ch = bgetchar())) { if (ch == 8) //Backspace { if (typemessageleng == 0) { typemode = 0; break; } typemessageleng--; } else if (ch == 9) // tab { keystatus[0xf] = 0; typemode = 0; break; } else if (ch == 13) //Either ENTER { keystatus[0x1c] = 0; keystatus[0x9c] = 0; if (typemessageleng > 0) { packbuf[0] = 2; //Sending text is message type 4 for (j=typemessageleng-1; j>=0; j--) packbuf[j+1] = typemessage[j]; for (i=connecthead; i>=0; i=connectpoint2[i]) if (i != myconnectindex) sendpacket(i,packbuf,typemessageleng+1); typemessageleng = 0; } typemode = 0; break; } else if ((typemessageleng < 159) && (ch >= 32) && (ch < 128)) { typemessage[typemessageleng++] = ch; } } } } void initplayersprite(short snum) { int i; if (playersprite[snum] >= 0) return; spawnsprite(playersprite[snum],pos[snum].x,pos[snum].y,pos[snum].z+EYEHEIGHT, 1+256,0,snum,32,64,64,0,0,PLAYER,ang[snum],0,0,0,snum+4096, cursectnum[snum],8,0,0,0); switch (snum) { case 1: for (i=0; i<32; i++) tempbuf[i+192] = i+128; break; //green->red case 2: for (i=0; i<32; i++) tempbuf[i+192] = i+32; break; //green->blue case 3: for (i=0; i<32; i++) tempbuf[i+192] = i+224; break; //green->pink case 4: for (i=0; i<32; i++) tempbuf[i+192] = i+64; break; //green->brown case 5: for (i=0; i<32; i++) tempbuf[i+192] = i+96; break; case 6: for (i=0; i<32; i++) tempbuf[i+192] = i+160; break; case 7: for (i=0; i<32; i++) tempbuf[i+192] = i+192; break; default: for (i=0; i<256; i++) tempbuf[i] = i; break; } makepalookup(snum,tempbuf,0,0,0,1); } void playback(void) { int i, j, k; ready2send = 0; recstat = 0; i = reccnt; while (!keystatus[1]) { if (handleevents()) { if (quitevent) { keystatus[1] = 1; quitevent = 0; } } refreshaudio(); while (totalclock >= lockclock+TICSPERFRAME) { sampletimer(); if (i >= reccnt) { prepareboard(boardfilename); for (i=connecthead; i>=0; i=connectpoint2[i]) initplayersprite((short)i); totalclock = 0; i = 0; } k = 0; for (j=connecthead; j>=0; j=connectpoint2[j]) { copybufbyte(&recsync[i][k],&ffsync[j],sizeof(input)); k++; } movethings(); domovethings(); i++; } drawscreen(screenpeek,(totalclock-gotlastpacketclock)*(65536/(TIMERINTSPERSECOND/MOVESPERSECOND))); if (keystatus[keys[15]]) { keystatus[keys[15]] = 0; screenpeek = connectpoint2[screenpeek]; if (screenpeek < 0) screenpeek = connecthead; drawstatusbar(screenpeek); // Andy did this } if (keystatus[keys[14]]) { keystatus[keys[14]] = 0; dimensionmode[screenpeek]++; if (dimensionmode[screenpeek] > 3) dimensionmode[screenpeek] = 1; } } musicoff(); uninitmultiplayers(); uninittimer(); uninitinput(); uninitengine(); uninitsb(); uninitgroupfile(); exit(0); } void setup3dscreen(void) { int i, dax, day, dax2, day2; i = setgamemode(fullscreen,xdimgame,ydimgame,bppgame); if (i < 0) { printf("Error setting video mode.\n"); sendlogoff(); musicoff(); uninitmultiplayers(); uninittimer(); uninitinput(); uninitengine(); uninitsb(); uninitgroupfile(); exit(0); } #if 0 //Make that ugly pink into black in case it ever shows up! i = 0L; setpalette(255,1,(char *)&i); //outp(0x3c8,255); outp(0x3c9,0); outp(0x3c9,0); outp(0x3c9,0); #endif screensize = xdim; if (screensize > xdim) { dax = 0; day = 0; dax2 = xdim-1; day2 = ydim-1; } else { dax = ((xdim-screensize)>>1); dax2 = dax+screensize-1; day = (((ydim-32)-scale(screensize,ydim-32,xdim))>>1); day2 = day + scale(screensize,ydim-32,xdim)-1; setview(dax,day,dax2,day2); } flushperms(); if (screensize < xdim) drawtilebackground(/*0L,0L,*/ BACKGROUND,8,0L,0L,xdim-1L,ydim-1L,0); //Draw background if (screensize <= xdim) { rotatesprite((xdim-320)<<15,(ydim-32)<<16,65536L,0,STATUSBAR,0,0,8+16+64+128,0L,0L,xdim-1L,ydim-1L); i = ((xdim-320)>>1); while (i >= 8) i -= 8, rotatesprite(i<<16,(ydim-32)<<16,65536L,0,STATUSBARFILL8,0,0,8+16+64+128,0L,0L,xdim-1L,ydim-1L); if (i >= 4) i -= 4, rotatesprite(i<<16,(ydim-32)<<16,65536L,0,STATUSBARFILL4,0,0,8+16+64+128,0L,0L,xdim-1L,ydim-1L); i = ((xdim-320)>>1)+320; while (i <= xdim-8) rotatesprite(i<<16,(ydim-32)<<16,65536L,0,STATUSBARFILL8,0,0,8+16+64+128,0L,0L,xdim-1L,ydim-1L), i += 8; if (i <= xdim-4) rotatesprite(i<<16,(ydim-32)<<16,65536L,0,STATUSBARFILL4,0,0,8+16+64+128,0L,0L,xdim-1L,ydim-1L), i += 4; drawstatusbar(screenpeek); // Andy did this } } void findrandomspot(int *x, int *y, short *sectnum) { short startwall, endwall, s, dasector; vec3_t da = { 0, 0, 0 }; int minx, maxx, miny, maxy, cnt; for (cnt=256; cnt>=0; cnt--) { do { dasector = mulscale16(krand(),numsectors); } while ((sector[dasector].ceilingz+(8<<8) >= sector[dasector].floorz) || ((sector[dasector].lotag|sector[dasector].hitag) != 0) || ((sector[dasector].floorstat&1) != 0)); startwall = sector[dasector].wallptr; endwall = startwall+sector[dasector].wallnum; if (endwall <= startwall) continue; minx = 0x7fffffff; maxx = 0x80000000; miny = 0x7fffffff; maxy = 0x80000000; for (s=startwall; s maxx) maxx = wall[s].x; if (wall[s].y < miny) miny = wall[s].y; if (wall[s].y > maxy) maxy = wall[s].y; } if ((maxx-minx <= 256) || (maxy-miny <= 256)) continue; da.x /= (endwall-startwall); da.y /= (endwall-startwall); if (inside(da.x,da.y,dasector) == 0) continue; da.z = sector[dasector].floorz-(32<<8); if (pushmove(&da,&dasector,128L,4<<8,4<<8,CLIPMASK0) < 0) continue; *x = da.x; *y = da.y; *sectnum = dasector; return; } } void warp(int *x, int *y, int *z, short *daang, short *dasector) { short startwall, endwall, s; int i, j, dax, day, ox, oy; ox = *x; oy = *y; for (i=0; i= warpsectorcnt) i = 0; } while (sector[warpsectorlist[i]].hitag != j); *dasector = warpsectorlist[i]; break; } //Find center of sector startwall = sector[*dasector].wallptr; endwall = startwall+sector[*dasector].wallnum; dax = 0L, day = 0L; for (s=startwall; s= 0) i = s; } *x = dax / (endwall-startwall); *y = day / (endwall-startwall); *z = sector[*dasector].floorz-(32<<8); updatesector(*x,*y,dasector); dax = ((wall[i].x+wall[wall[i].point2].x)>>1); day = ((wall[i].y+wall[wall[i].point2].y)>>1); *daang = getangle(dax-*x,day-*y); wsayfollow("warp.wav",3072L+(krand()&127)-64,192L,&ox,&oy,0); wsayfollow("warp.wav",4096L+(krand()&127)-64,256L,x,y,0); } void warpsprite(short spritenum) { short dasectnum; dasectnum = sprite[spritenum].sectnum; warp(&sprite[spritenum].x,&sprite[spritenum].y,&sprite[spritenum].z, &sprite[spritenum].ang,&dasectnum); copybuf(&sprite[spritenum].x,&osprite[spritenum].x,3); changespritesect(spritenum,dasectnum); show2dsprite[spritenum>>3] &= ~(1<<(spritenum&7)); if (show2dsector[dasectnum>>3]&(1<<(dasectnum&7))) show2dsprite[spritenum>>3] |= (1<<(spritenum&7)); } void initlava(void) { int x, y, z, r; for (z=0; z<32; z++) lavaradcnt[z] = 0; for (x=-16; x<=16; x++) for (y=-16; y<=16; y++) { r = ksqrt(x*x + y*y); lavaradx[r][lavaradcnt[r]] = x; lavarady[r][lavaradcnt[r]] = y; lavaradcnt[r]++; } for (z=0; z<16; z++) lavadropsizlookup[z] = 8 / (ksqrt(z)+1); for (z=0; z>4)&7)-4)+12; lavanumdrops = 0; lavanumframes = 0; } #if defined(__WATCOMC__) && !defined(NOASM) #pragma aux addlava = \ "mov al, byte ptr [ebx-133]", \ "mov dl, byte ptr [ebx-1]", \ "add al, byte ptr [ebx-132]", \ "add dl, byte ptr [ebx+131]", \ "add al, byte ptr [ebx-131]", \ "add dl, byte ptr [ebx+132]", \ "add al, byte ptr [ebx+1]", \ "add al, dl", \ parm [ebx] \ modify exact [eax edx] int addlava(int); #elif defined(_MSC_VER) && !defined(NOASM) int addlava(void *b) { _asm { mov ebx, b mov al, byte ptr [ebx-133] mov dl, byte ptr [ebx-1] add al, byte ptr [ebx-132] add dl, byte ptr [ebx+131] add al, byte ptr [ebx-131] add dl, byte ptr [ebx+132] add al, byte ptr [ebx+1] add al, dl } } #elif defined(__GNUC__) && defined(__i386__) && !defined(NOASM) int addlava(void *b) { int r; __asm__ __volatile__( "movb -133(%%ebx), %%al\n\t" "movb -1(%%ebx), %%dl\n\t" "addb -132(%%ebx), %%al\n\t" "addb 131(%%ebx), %%dl\n\t" "addb -131(%%ebx), %%al\n\t" "addb 132(%%ebx), %%dl\n\t" "addb 1(%%ebx), %%al\n\t" "addb %%dl, %%al" : "=a" (r) : "b" (b) : "dx" ); return r; } #else int addlava(void *bx) { char *b = (char *)bx; return b[-133] + b[-132] + b[-131] + b[1] + b[-1] + b[131] + b[132]; } #endif void movelava(char *dapic) { int i, /*j,*/ x, y, z, zz, dalavadropsiz, dadropsizlookup; int dalavax, dalavay, *ptr, *ptr2; char *pi, *pj, *py; for (z=min(LAVAMAXDROPS-lavanumdrops-1,3); z>=0; z--) { lavadropx[lavanumdrops] = (Brand()&(LAVASIZ-1)); lavadropy[lavanumdrops] = (Brand()&(LAVASIZ-1)); lavadropsiz[lavanumdrops] = 1; lavanumdrops++; } for (z=lavanumdrops-1; z>=0; z--) { dadropsizlookup = lavadropsizlookup[lavadropsiz[z]]*(((z&1)<<1)-1); dalavadropsiz = lavadropsiz[z]; dalavax = lavadropx[z]; dalavay = lavadropy[z]; for (zz=lavaradcnt[lavadropsiz[z]]-1; zz>=0; zz--) { i = (((lavaradx[dalavadropsiz][zz]+dalavax)&(LAVASIZ-1))< 10) { lavanumdrops--; lavadropx[z] = lavadropx[lavanumdrops]; lavadropy[z] = lavadropy[lavanumdrops]; lavadropsiz[z] = lavadropsiz[lavanumdrops]; } } //Back up dapic with 1 pixel extra on each boundary //(to prevent anding for wrap-around) ptr = (int *)dapic; ptr2 = (int *)((LAVASIZ+4)+1+((intptr_t)lavabakpic)); for (x=0; x>2); y>0; y--) *ptr2++ = ((*ptr++)&0x1f1f1f1f); ptr2++; } for (y=0; y>3)+ ((addlava(&py[1])&0xf8)<<5)+ ((addlava(&py[2])&0xf8)<<13)+ ((addlava(&py[3])&0xf8)<<21)+ 0xc2c2c2c2; } } lavanumframes++; } void doanimations(void) { int i, j; for (i=animatecnt-1; i>=0; i--) { j = *animateptr[i]; if (j < animategoal[i]) j = min(j+animatevel[i]*TICSPERFRAME,animategoal[i]); else j = max(j-animatevel[i]*TICSPERFRAME,animategoal[i]); animatevel[i] += animateacc[i]; *animateptr[i] = j; if (j == animategoal[i]) { animatecnt--; if (i != animatecnt) { stopinterpolation(animateptr[i]); animateptr[i] = animateptr[animatecnt]; animategoal[i] = animategoal[animatecnt]; animatevel[i] = animatevel[animatecnt]; animateacc[i] = animateacc[animatecnt]; } } } } int getanimationgoal(int *animptr) { int i; for (i=animatecnt-1; i>=0; i--) if (animptr == animateptr[i]) return i; return -1; } int setanimation(int *animptr, int thegoal, int thevel, int theacc) { int i, j; if (animatecnt >= MAXANIMATES) return -1; j = animatecnt; for (i=animatecnt-1; i>=0; i--) if (animptr == animateptr[i]) { j = i; break; } setinterpolation(animptr); animateptr[j] = animptr; animategoal[j] = thegoal; animatevel[j] = thevel; animateacc[j] = theacc; if (j == animatecnt) animatecnt++; return j; } void checkmasterslaveswitch(void) { int i, j; if (option[4] == 0) return; j = 0; for (i=connecthead; i>=0; i=connectpoint2[i]) if (ssync[i].bits&512) j++; if (j != 1) return; i = connecthead; for (j=connectpoint2[i]; j>=0; j=connectpoint2[j]) { if (ssync[j].bits&512) { connectpoint2[i] = connectpoint2[j]; connectpoint2[j] = connecthead; connecthead = (short)j; oloc.fvel = loc.fvel+1; oloc.svel = loc.svel+1; oloc.avel = loc.avel+1; oloc.bits = loc.bits+1; for (i=0; i=0; i=connectpoint2[i]) { if (myconnectindex == i) break; j++; } if (j == 1) Bstrcpy(getmessage,"Player 1 (Master)"); else Bsprintf(getmessage,"Player %d (Slave)",j); getmessageleng = Bstrlen(getmessage); getmessagetimeoff = totalclock+120; return; } i = j; } } int testneighborsectors(short sect1, short sect2) { short i, startwall, num1, num2; num1 = sector[sect1].wallnum; num2 = sector[sect2].wallnum; if (num1 < num2) //Traverse walls of sector with fewest walls (for speed) { startwall = sector[sect1].wallptr; for (i=num1-1; i>=0; i--) if (wall[i+startwall].nextsector == sect2) return 1; } else { startwall = sector[sect2].wallptr; for (i=num2-1; i>=0; i--) if (wall[i+startwall].nextsector == sect1) return 1; } return 0; } int loadgame(void) { int dummy = 0; int i; int fil; int tmpanimateptr[MAXANIMATES]; if ((fil = kopen4load("save0000.gam",0)) == -1) return -1; kdfread(&numplayers,4,1,fil); kdfread(&myconnectindex,4,1,fil); kdfread(&connecthead,4,1,fil); kdfread(connectpoint2,4,MAXPLAYERS,fil); //Make sure palookups get set, sprites will get overwritten later for (i=connecthead; i>=0; i=connectpoint2[i]) initplayersprite((short)i); for (i = 0; i < MAXPLAYERS; ++i) kdfread(&pos[i].x,4,1,fil); for (i = 0; i < MAXPLAYERS; ++i) kdfread(&pos[i].y,4,1,fil); for (i = 0; i < MAXPLAYERS; ++i) kdfread(&pos[i].z,4,1,fil); kdfread(horiz,4,MAXPLAYERS,fil); kdfread(zoom,4,MAXPLAYERS,fil); kdfread(hvel,4,MAXPLAYERS,fil); kdfread(ang,2,MAXPLAYERS,fil); kdfread(cursectnum,2,MAXPLAYERS,fil); kdfread(ocursectnum,2,MAXPLAYERS,fil); kdfread(playersprite,2,MAXPLAYERS,fil); kdfread(deaths,2,MAXPLAYERS,fil); kdfread(lastchaingun,4,MAXPLAYERS,fil); kdfread(health,4,MAXPLAYERS,fil); kdfread(numgrabbers,2,MAXPLAYERS,fil); kdfread(nummissiles,2,MAXPLAYERS,fil); kdfread(numbombs,2,MAXPLAYERS,fil); kdfread(flytime,4,MAXPLAYERS,fil); kdfread(oflags,2,MAXPLAYERS,fil); kdfread(dimensionmode,1,MAXPLAYERS,fil); kdfread(revolvedoorstat,1,MAXPLAYERS,fil); kdfread(revolvedoorang,2,MAXPLAYERS,fil); kdfread(revolvedoorrotang,2,MAXPLAYERS,fil); kdfread(revolvedoorx,4,MAXPLAYERS,fil); kdfread(revolvedoory,4,MAXPLAYERS,fil); kdfread(&numsectors,2,1,fil); kdfread(sector,sizeof(sectortype),numsectors,fil); kdfread(&numwalls,2,1,fil); kdfread(wall,sizeof(walltype),numwalls,fil); //Store all sprites (even holes) to preserve indeces kdfread(sprite,sizeof(spritetype),MAXSPRITES,fil); kdfread(headspritesect,2,MAXSECTORS+1,fil); kdfread(prevspritesect,2,MAXSPRITES,fil); kdfread(nextspritesect,2,MAXSPRITES,fil); kdfread(headspritestat,2,MAXSTATUS+1,fil); kdfread(prevspritestat,2,MAXSPRITES,fil); kdfread(nextspritestat,2,MAXSPRITES,fil); kdfread(&fvel,4,1,fil); kdfread(&svel,4,1,fil); kdfread(&avel,4,1,fil); kdfread(&locselectedgun,4,1,fil); kdfread(&loc.fvel,1,1,fil); kdfread(&oloc.fvel,1,1,fil); kdfread(&loc.svel,1,1,fil); kdfread(&oloc.svel,1,1,fil); kdfread(&loc.avel,1,1,fil); kdfread(&oloc.avel,1,1,fil); kdfread(&loc.bits,2,1,fil); kdfread(&oloc.bits,2,1,fil); kdfread(&locselectedgun2,4,1,fil); kdfread(&loc2.fvel,sizeof(input),1,fil); kdfread(ssync,sizeof(input),MAXPLAYERS,fil); kdfread(osync,sizeof(input),MAXPLAYERS,fil); kdfread(boardfilename,1,80,fil); kdfread(&screenpeek,2,1,fil); kdfread(&oldmousebstatus,2,1,fil); kdfread(&brightness,2,1,fil); kdfread(&neartagsector,2,1,fil); kdfread(&neartagwall,2,1,fil); kdfread(&neartagsprite,2,1,fil); kdfread(&lockclock,4,1,fil); kdfread(&neartagdist,4,1,fil); kdfread(&neartaghitdist,4,1,fil); kdfread(turnspritelist,2,16,fil); kdfread(&turnspritecnt,2,1,fil); kdfread(warpsectorlist,2,16,fil); kdfread(&warpsectorcnt,2,1,fil); kdfread(xpanningsectorlist,2,16,fil); kdfread(&xpanningsectorcnt,2,1,fil); kdfread(ypanningwalllist,2,64,fil); kdfread(&ypanningwallcnt,2,1,fil); kdfread(floorpanninglist,2,64,fil); kdfread(&floorpanningcnt,2,1,fil); kdfread(dragsectorlist,2,16,fil); kdfread(dragxdir,2,16,fil); kdfread(dragydir,2,16,fil); kdfread(&dragsectorcnt,2,1,fil); kdfread(dragx1,4,16,fil); kdfread(dragy1,4,16,fil); kdfread(dragx2,4,16,fil); kdfread(dragy2,4,16,fil); kdfread(dragfloorz,4,16,fil); kdfread(&swingcnt,2,1,fil); kdfread(swingwall,2,32*5,fil); kdfread(swingsector,2,32,fil); kdfread(swingangopen,2,32,fil); kdfread(swingangclosed,2,32,fil); kdfread(swingangopendir,2,32,fil); kdfread(swingang,2,32,fil); kdfread(swinganginc,2,32,fil); kdfread(swingx,4,32*8,fil); kdfread(swingy,4,32*8,fil); kdfread(revolvesector,2,4,fil); kdfread(revolveang,2,4,fil); kdfread(&revolvecnt,2,1,fil); kdfread(revolvex,4,4*16,fil); kdfread(revolvey,4,4*16,fil); kdfread(revolvepivotx,4,4,fil); kdfread(revolvepivoty,4,4,fil); kdfread(subwaytracksector,2,4*128,fil); kdfread(subwaynumsectors,2,4,fil); kdfread(&subwaytrackcnt,2,1,fil); kdfread(subwaystop,4,4*8,fil); kdfread(subwaystopcnt,4,4,fil); kdfread(subwaytrackx1,4,4,fil); kdfread(subwaytracky1,4,4,fil); kdfread(subwaytrackx2,4,4,fil); kdfread(subwaytracky2,4,4,fil); kdfread(subwayx,4,4,fil); kdfread(subwaygoalstop,4,4,fil); kdfread(subwayvel,4,4,fil); kdfread(subwaypausetime,4,4,fil); kdfread(waterfountainwall,2,MAXPLAYERS,fil); kdfread(waterfountaincnt,2,MAXPLAYERS,fil); kdfread(slimesoundcnt,2,MAXPLAYERS,fil); //Warning: only works if all pointers are in sector structures! kdfread(tmpanimateptr,4,MAXANIMATES,fil); for (i=MAXANIMATES-1; i>=0; i--) animateptr[i] = (int *)(tmpanimateptr[i]+(intptr_t)sector); kdfread(animategoal,4,MAXANIMATES,fil); kdfread(animatevel,4,MAXANIMATES,fil); kdfread(animateacc,4,MAXANIMATES,fil); kdfread(&animatecnt,4,1,fil); kdfread(&totalclock,4,1,fil); kdfread(&numframes,4,1,fil); kdfread(&randomseed,4,1,fil); kdfread(&numshades,2,1,fil); kdfread(&g_visibility,4,1,fil); kdfread(¶llaxvisibility,4,1,fil); kdfread(¶llaxtype,1,1,fil); kdfread(&dummy,4,1,fil); kdfread(&dummy,2,MAXPSKYTILES,fil); kdfread(&dummy,2,1,fil); kdfread(&mirrorcnt,2,1,fil); kdfread(mirrorwall,2,mirrorcnt,fil); kdfread(mirrorsector,2,mirrorcnt,fil); //I should save off interpolation list, but they're pointers :( numinterpolations = 0; startofdynamicinterpolations = 0; kclose(fil); for (i=connecthead; i>=0; i=connectpoint2[i]) initplayersprite((short)i); totalclock = lockclock; ototalclock = lockclock; Bstrcpy(getmessage,"Game loaded."); getmessageleng = Bstrlen(getmessage); getmessagetimeoff = totalclock+360+(getmessageleng<<4); return 0; } int savegame(void) { int dummy = 0; int i; BFILE *fil; int tmpanimateptr[MAXANIMATES]; if ((fil = Bfopen("save0000.gam","wb")) == 0) return -1; dfwrite(&numplayers,4,1,fil); dfwrite(&myconnectindex,4,1,fil); dfwrite(&connecthead,4,1,fil); dfwrite(connectpoint2,4,MAXPLAYERS,fil); for (i = 0; i < MAXPLAYERS; ++i) dfwrite(&pos[i].x,4,1,fil); for (i = 0; i < MAXPLAYERS; ++i) dfwrite(&pos[i].y,4,1,fil); for (i = 0; i < MAXPLAYERS; ++i) dfwrite(&pos[i].z,4,1,fil); dfwrite(horiz,4,MAXPLAYERS,fil); dfwrite(zoom,4,MAXPLAYERS,fil); dfwrite(hvel,4,MAXPLAYERS,fil); dfwrite(ang,2,MAXPLAYERS,fil); dfwrite(cursectnum,2,MAXPLAYERS,fil); dfwrite(ocursectnum,2,MAXPLAYERS,fil); dfwrite(playersprite,2,MAXPLAYERS,fil); dfwrite(deaths,2,MAXPLAYERS,fil); dfwrite(lastchaingun,4,MAXPLAYERS,fil); dfwrite(health,4,MAXPLAYERS,fil); dfwrite(numgrabbers,2,MAXPLAYERS,fil); dfwrite(nummissiles,2,MAXPLAYERS,fil); dfwrite(numbombs,2,MAXPLAYERS,fil); dfwrite(flytime,4,MAXPLAYERS,fil); dfwrite(oflags,2,MAXPLAYERS,fil); dfwrite(dimensionmode,1,MAXPLAYERS,fil); dfwrite(revolvedoorstat,1,MAXPLAYERS,fil); dfwrite(revolvedoorang,2,MAXPLAYERS,fil); dfwrite(revolvedoorrotang,2,MAXPLAYERS,fil); dfwrite(revolvedoorx,4,MAXPLAYERS,fil); dfwrite(revolvedoory,4,MAXPLAYERS,fil); dfwrite(&numsectors,2,1,fil); dfwrite(sector,sizeof(sectortype),numsectors,fil); dfwrite(&numwalls,2,1,fil); dfwrite(wall,sizeof(walltype),numwalls,fil); //Store all sprites (even holes) to preserve indeces dfwrite(sprite,sizeof(spritetype),MAXSPRITES,fil); dfwrite(headspritesect,2,MAXSECTORS+1,fil); dfwrite(prevspritesect,2,MAXSPRITES,fil); dfwrite(nextspritesect,2,MAXSPRITES,fil); dfwrite(headspritestat,2,MAXSTATUS+1,fil); dfwrite(prevspritestat,2,MAXSPRITES,fil); dfwrite(nextspritestat,2,MAXSPRITES,fil); dfwrite(&fvel,4,1,fil); dfwrite(&svel,4,1,fil); dfwrite(&avel,4,1,fil); dfwrite(&locselectedgun,4,1,fil); dfwrite(&loc.fvel,1,1,fil); dfwrite(&oloc.fvel,1,1,fil); dfwrite(&loc.svel,1,1,fil); dfwrite(&oloc.svel,1,1,fil); dfwrite(&loc.avel,1,1,fil); dfwrite(&oloc.avel,1,1,fil); dfwrite(&loc.bits,2,1,fil); dfwrite(&oloc.bits,2,1,fil); dfwrite(&locselectedgun2,4,1,fil); dfwrite(&loc2.fvel,sizeof(input),1,fil); dfwrite(ssync,sizeof(input),MAXPLAYERS,fil); dfwrite(osync,sizeof(input),MAXPLAYERS,fil); dfwrite(boardfilename,1,80,fil); dfwrite(&screenpeek,2,1,fil); dfwrite(&oldmousebstatus,2,1,fil); dfwrite(&brightness,2,1,fil); dfwrite(&neartagsector,2,1,fil); dfwrite(&neartagwall,2,1,fil); dfwrite(&neartagsprite,2,1,fil); dfwrite(&lockclock,4,1,fil); dfwrite(&neartagdist,4,1,fil); dfwrite(&neartaghitdist,4,1,fil); dfwrite(turnspritelist,2,16,fil); dfwrite(&turnspritecnt,2,1,fil); dfwrite(warpsectorlist,2,16,fil); dfwrite(&warpsectorcnt,2,1,fil); dfwrite(xpanningsectorlist,2,16,fil); dfwrite(&xpanningsectorcnt,2,1,fil); dfwrite(ypanningwalllist,2,64,fil); dfwrite(&ypanningwallcnt,2,1,fil); dfwrite(floorpanninglist,2,64,fil); dfwrite(&floorpanningcnt,2,1,fil); dfwrite(dragsectorlist,2,16,fil); dfwrite(dragxdir,2,16,fil); dfwrite(dragydir,2,16,fil); dfwrite(&dragsectorcnt,2,1,fil); dfwrite(dragx1,4,16,fil); dfwrite(dragy1,4,16,fil); dfwrite(dragx2,4,16,fil); dfwrite(dragy2,4,16,fil); dfwrite(dragfloorz,4,16,fil); dfwrite(&swingcnt,2,1,fil); dfwrite(swingwall,2,32*5,fil); dfwrite(swingsector,2,32,fil); dfwrite(swingangopen,2,32,fil); dfwrite(swingangclosed,2,32,fil); dfwrite(swingangopendir,2,32,fil); dfwrite(swingang,2,32,fil); dfwrite(swinganginc,2,32,fil); dfwrite(swingx,4,32*8,fil); dfwrite(swingy,4,32*8,fil); dfwrite(revolvesector,2,4,fil); dfwrite(revolveang,2,4,fil); dfwrite(&revolvecnt,2,1,fil); dfwrite(revolvex,4,4*16,fil); dfwrite(revolvey,4,4*16,fil); dfwrite(revolvepivotx,4,4,fil); dfwrite(revolvepivoty,4,4,fil); dfwrite(subwaytracksector,2,4*128,fil); dfwrite(subwaynumsectors,2,4,fil); dfwrite(&subwaytrackcnt,2,1,fil); dfwrite(subwaystop,4,4*8,fil); dfwrite(subwaystopcnt,4,4,fil); dfwrite(subwaytrackx1,4,4,fil); dfwrite(subwaytracky1,4,4,fil); dfwrite(subwaytrackx2,4,4,fil); dfwrite(subwaytracky2,4,4,fil); dfwrite(subwayx,4,4,fil); dfwrite(subwaygoalstop,4,4,fil); dfwrite(subwayvel,4,4,fil); dfwrite(subwaypausetime,4,4,fil); dfwrite(waterfountainwall,2,MAXPLAYERS,fil); dfwrite(waterfountaincnt,2,MAXPLAYERS,fil); dfwrite(slimesoundcnt,2,MAXPLAYERS,fil); //Warning: only works if all pointers are in sector structures! for (i=MAXANIMATES-1; i>=0; i--) tmpanimateptr[i] = (int)((intptr_t)animateptr[i]-(intptr_t)sector); dfwrite(tmpanimateptr,4,MAXANIMATES,fil); dfwrite(animategoal,4,MAXANIMATES,fil); dfwrite(animatevel,4,MAXANIMATES,fil); dfwrite(animateacc,4,MAXANIMATES,fil); dfwrite(&animatecnt,4,1,fil); dfwrite(&totalclock,4,1,fil); dfwrite(&numframes,4,1,fil); dfwrite(&randomseed,4,1,fil); dfwrite(&numshades,2,1,fil); dfwrite(&g_visibility,4,1,fil); dfwrite(¶llaxvisibility,4,1,fil); dfwrite(¶llaxtype,1,1,fil); dfwrite(&dummy,4,1,fil); dfwrite(&dummy,2,MAXPSKYTILES,fil); dfwrite(&dummy,2,1,fil); dfwrite(&mirrorcnt,2,1,fil); dfwrite(mirrorwall,2,mirrorcnt,fil); dfwrite(mirrorsector,2,mirrorcnt,fil); Bfclose(fil); Bstrcpy(getmessage,"Game saved."); getmessageleng = Bstrlen(getmessage); getmessagetimeoff = totalclock+360+(getmessageleng<<4); return 0; } void faketimerhandler(void) { short other /*, packbufleng*/; int i, j, k, l; sampletimer(); if ((totalclock < ototalclock+(TIMERINTSPERSECOND/MOVESPERSECOND)) || (ready2send == 0)) return; ototalclock += (TIMERINTSPERSECOND/MOVESPERSECOND); getpackets(); if (getoutputcirclesize() >= 16) return; getinput(); #if 0 for (i=connecthead; i>=0; i=connectpoint2[i]) if (i != myconnectindex) { k = (movefifoend[myconnectindex]-1)-movefifoend[i]; myminlag[i] = min(myminlag[i],k); mymaxlag = max(mymaxlag,k); } if (((movefifoend[myconnectindex]-1)&(TIMERUPDATESIZ-1)) == 0) { i = mymaxlag-bufferjitter; mymaxlag = 0; if (i > 0) bufferjitter += ((2+i)>>2); else if (i < 0) bufferjitter -= ((2-i)>>2); } #endif if (networkmode == 1) { packbuf[2] = 0; j = 3; if (loc.fvel != oloc.fvel) packbuf[j++] = loc.fvel, packbuf[2] |= 1; if (loc.svel != oloc.svel) packbuf[j++] = loc.svel, packbuf[2] |= 2; if (loc.avel != oloc.avel) packbuf[j++] = loc.avel, packbuf[2] |= 4; if ((loc.bits^oloc.bits)&0x00ff) packbuf[j++] = (loc.bits&255), packbuf[2] |= 8; if ((loc.bits^oloc.bits)&0xff00) packbuf[j++] = ((loc.bits>>8)&255), packbuf[2] |= 16; copybufbyte(&loc,&oloc,sizeof(input)); copybufbyte(&loc,&baksync[movefifoend[myconnectindex]][myconnectindex],sizeof(input)); movefifoend[myconnectindex] = ((movefifoend[myconnectindex]+1)&(MOVEFIFOSIZ-1)); for (i=connecthead; i>=0; i=connectpoint2[i]) if (i != myconnectindex) { packbuf[0] = 17; packbuf[1] = (char)((movefifoend[myconnectindex]-movefifoend[i])&(MOVEFIFOSIZ-1)); k = j; if ((myconnectindex == connecthead) || ((i == connecthead) && (myconnectindex == connectpoint2[connecthead]))) { while (syncvalhead != syncvaltail) { packbuf[j++] = syncval[syncvaltail]; syncvaltail = ((syncvaltail+1)&(MOVEFIFOSIZ-1)); } } sendpacket(i,packbuf,j); j = k; } gotlastpacketclock = totalclock; return; } //MASTER (or 1 player game) if ((myconnectindex == connecthead) || (option[4] == 0)) { copybufbyte(&loc,&ffsync[myconnectindex],sizeof(input)); if (option[4] != 0) { packbuf[0] = 0; j = ((numplayers+1)>>1)+1; for (k=1; k=0; i=connectpoint2[i]) { l = 0; if (ffsync[i].fvel != osync[i].fvel) packbuf[j++] = ffsync[i].fvel, l |= 1; if (ffsync[i].svel != osync[i].svel) packbuf[j++] = ffsync[i].svel, l |= 2; if (ffsync[i].avel != osync[i].avel) packbuf[j++] = ffsync[i].avel, l |= 4; if (ffsync[i].bits != osync[i].bits) { packbuf[j++] = (ffsync[i].bits&255); packbuf[j++] = ((ffsync[i].bits>>8)&255); l |= 8; } packbuf[k>>3] |= (l<<(k&7)); k += 4; copybufbyte(&ffsync[i],&osync[i],sizeof(input)); } while (syncvalhead != syncvaltail) { packbuf[j++] = syncval[syncvaltail]; syncvaltail = ((syncvaltail+1)&(MOVEFIFOSIZ-1)); } for (i=connectpoint2[connecthead]; i>=0; i=connectpoint2[i]) sendpacket(i,packbuf,j); } else if (numplayers >= 2) { if (keystatus[0xb5]) { keystatus[0xb5] = 0; locselectedgun2++; if (locselectedgun2 >= 3) locselectedgun2 = 0; } //Second player on 1 computer mode loc2.fvel = min(max(fvel2,-128+8),127-8); loc2.svel = min(max(svel2,-128+8),127-8); loc2.avel = min(max(avel2,-128+16),127-16); loc2.bits = (locselectedgun2<<13); loc2.bits |= keystatus[0x45]; //Stand high loc2.bits |= (keystatus[0x47]<<1); //Stand low loc2.bits |= (1<<8); //Run loc2.bits |= (keystatus[0x49]<<2); //Look up loc2.bits |= (keystatus[0x37]<<3); //Look down loc2.bits |= (keystatus[0x50]<<10); //Space loc2.bits |= (keystatus[0x52]<<11); //Shoot other = connectpoint2[myconnectindex]; if (other < 0) other = connecthead; copybufbyte(&loc2,&ffsync[other],sizeof(input)); } movethings(); //Move EVERYTHING (you too!) } else //I am a SLAVE { packbuf[0] = 1; packbuf[1] = 0; j = 2; if (loc.fvel != oloc.fvel) packbuf[j++] = loc.fvel, packbuf[1] |= 1; if (loc.svel != oloc.svel) packbuf[j++] = loc.svel, packbuf[1] |= 2; if (loc.avel != oloc.avel) packbuf[j++] = loc.avel, packbuf[1] |= 4; if ((loc.bits^oloc.bits)&0x00ff) packbuf[j++] = (loc.bits&255), packbuf[1] |= 8; if ((loc.bits^oloc.bits)&0xff00) packbuf[j++] = ((loc.bits>>8)&255), packbuf[1] |= 16; copybufbyte(&loc,&oloc,sizeof(input)); sendpacket(connecthead,packbuf,j); } } void getpackets(void) { int i, j, k, l; int other, packbufleng, movecnt; if (option[4] == 0) return; movecnt = 0; while ((packbufleng = getpacket(&other,packbuf)) > 0) { switch (packbuf[0]) { case 0: //[0] (receive master sync buffer) j = ((numplayers+1)>>1)+1; k = (1<<3); for (i=connecthead; i>=0; i=connectpoint2[i]) { l = (packbuf[k>>3]>>(k&7)); if (l&1) ffsync[i].fvel = packbuf[j++]; if (l&2) ffsync[i].svel = packbuf[j++]; if (l&4) ffsync[i].avel = packbuf[j++]; if (l&8) { ffsync[i].bits = ((short)packbuf[j])+(((short)packbuf[j+1])<<8); j += 2; } k += 4; } while (j != packbufleng) { othersyncval[othersyncvalhead] = packbuf[j++]; othersyncvalhead = ((othersyncvalhead+1)&(MOVEFIFOSIZ-1)); } if ((syncvalhead != syncvaltottail) && (othersyncvalhead != syncvaltottail)) { syncstat = 0; do { syncstat |= (syncval[syncvaltottail]^othersyncval[syncvaltottail]); syncvaltottail = ((syncvaltottail+1)&(MOVEFIFOSIZ-1)); } while ((syncvalhead != syncvaltottail) && (othersyncvalhead != syncvaltottail)); } movethings(); //Move all players and sprites movecnt++; break; case 1: //[1] (receive slave sync buffer) j = 2; k = packbuf[1]; if (k&1) ffsync[other].fvel = packbuf[j++]; if (k&2) ffsync[other].svel = packbuf[j++]; if (k&4) ffsync[other].avel = packbuf[j++]; if (k&8) ffsync[other].bits = ((ffsync[other].bits&0xff00)|((short)packbuf[j++])); if (k&16) ffsync[other].bits = ((ffsync[other].bits&0x00ff)|(((short)packbuf[j++])<<8)); break; case 2: getmessageleng = packbufleng-1; for (j=getmessageleng-1; j>=0; j--) getmessage[j] = packbuf[j+1]; getmessagetimeoff = totalclock+360+(getmessageleng<<4); wsay("getstuff.wav",8192L,63L,63L); //Added 12/2004 break; case 3: wsay("getstuff.wav",4096L,63L,63L); break; #if 0 case 5: playerreadyflag[other] = packbuf[1]; if ((other == connecthead) && (packbuf[1] == 2)) sendpacket(connecthead,packbuf,2); break; #endif case 250: playerreadyflag[other]++; break; case 17: j = 3; k = packbuf[2]; if (k&1) ffsync[other].fvel = packbuf[j++]; if (k&2) ffsync[other].svel = packbuf[j++]; if (k&4) ffsync[other].avel = packbuf[j++]; if (k&8) ffsync[other].bits = ((ffsync[other].bits&0xff00)|((short)packbuf[j++])); if (k&16) ffsync[other].bits = ((ffsync[other].bits&0x00ff)|(((short)packbuf[j++])<<8)); otherlag[other] = packbuf[1]; copybufbyte(&ffsync[other],&baksync[movefifoend[other]][other],sizeof(input)); movefifoend[other] = ((movefifoend[other]+1)&(MOVEFIFOSIZ-1)); while (j != packbufleng) { othersyncval[othersyncvalhead] = packbuf[j++]; othersyncvalhead = ((othersyncvalhead+1)&(MOVEFIFOSIZ-1)); } if ((syncvalhead != syncvaltottail) && (othersyncvalhead != syncvaltottail)) { syncstat = 0; do { syncstat |= (syncval[syncvaltottail]^othersyncval[syncvaltottail]); syncvaltottail = ((syncvaltottail+1)&(MOVEFIFOSIZ-1)); } while ((syncvalhead != syncvaltottail) && (othersyncvalhead != syncvaltottail)); } break; case 255: //[255] (logout) keystatus[1] = 1; break; } } if ((networkmode == 0) && (myconnectindex != connecthead) && ((movecnt&1) == 0)) { if (rand()&1) ototalclock += (TICSPERFRAME>>1); else ototalclock -= (TICSPERFRAME>>1); } } void drawoverheadmap(int cposx, int cposy, int czoom, short cang) { int i, j, k, l=0, x1, y1, x2=0, y2=0, x3, y3, x4, y4, ox, oy, xoff, yoff; int dax, day, cosang, sinang, xspan, yspan, sprx, spry; int xrepeat, yrepeat, z1, z2, startwall, endwall, tilenum, daang; int xvect, yvect, xvect2, yvect2; char col; walltype *wal, *wal2; spritetype *spr; xvect = sintable[(-cang)&2047] * czoom; yvect = sintable[(1536-cang)&2047] * czoom; xvect2 = mulscale16(xvect,yxaspect); yvect2 = mulscale16(yvect,yxaspect); //Draw red lines for (i=0; inextwall; if (k < 0) continue; if ((show2dwall[j>>3]&(1<<(j&7))) == 0) continue; if ((k > j) && ((show2dwall[k>>3]&(1<<(k&7))) > 0)) continue; if (sector[wal->nextsector].ceilingz == z1) if (sector[wal->nextsector].floorz == z2) if (((wal->cstat|wall[wal->nextwall].cstat)&(16+32)) == 0) continue; col = 152; if (dimensionmode[screenpeek] == 2) { if (sector[i].floorz != sector[i].ceilingz) if (sector[wal->nextsector].floorz != sector[wal->nextsector].ceilingz) if (((wal->cstat|wall[wal->nextwall].cstat)&(16+32)) == 0) if (sector[i].floorz == sector[wal->nextsector].floorz) continue; if (sector[i].floorpicnum != sector[wal->nextsector].floorpicnum) continue; if (sector[i].floorshade != sector[wal->nextsector].floorshade) continue; col = 12; } ox = wal->x-cposx; oy = wal->y-cposy; x1 = dmulscale16(ox,xvect,-oy,yvect)+(xdim<<11); y1 = dmulscale16(oy,xvect2,ox,yvect2)+(ydim<<11); wal2 = &wall[wal->point2]; ox = wal2->x-cposx; oy = wal2->y-cposy; x2 = dmulscale16(ox,xvect,-oy,yvect)+(xdim<<11); y2 = dmulscale16(oy,xvect2,ox,yvect2)+(ydim<<11); drawline256(x1,y1,x2,y2,col); } } //Draw sprites k = playersprite[screenpeek]; for (i=0; i=0; j=nextspritesect[j]) if ((show2dsprite[j>>3]&(1<<(j&7))) > 0) { spr = &sprite[j]; if (spr->cstat&0x8000) continue; col = 56; if (spr->cstat&1) col = 248; if (j == k) col = 31; k = statrate[spr->statnum]; sprx = spr->x; spry = spr->y; if (k >= 0) { switch (k) { case 0: l = smoothratio; break; case 1: l = (smoothratio>>1)+(((nummoves-j)&1)<<15); break; case 3: l = (smoothratio>>2)+(((nummoves-j)&3)<<14); break; case 7: l = (smoothratio>>3)+(((nummoves-j)&7)<<13); break; case 15: l = (smoothratio>>4)+(((nummoves-j)&15)<<12); break; } sprx = osprite[j].x+mulscale16(sprx-osprite[j].x,l); spry = osprite[j].y+mulscale16(spry-osprite[j].y,l); } switch (spr->cstat&48) { case 0: ox = sprx-cposx; oy = spry-cposy; x1 = dmulscale16(ox,xvect,-oy,yvect); y1 = dmulscale16(oy,xvect2,ox,yvect2); if (dimensionmode[screenpeek] == 1) { ox = (sintable[(spr->ang+512)&2047]>>7); oy = (sintable[(spr->ang)&2047]>>7); x2 = dmulscale16(ox,xvect,-oy,yvect); y2 = dmulscale16(oy,xvect,ox,yvect); if (j == playersprite[screenpeek]) { x2 = 0L; y2 = -(czoom<<5); } x3 = mulscale16(x2,yxaspect); y3 = mulscale16(y2,yxaspect); drawline256(x1-x2+(xdim<<11),y1-y3+(ydim<<11), x1+x2+(xdim<<11),y1+y3+(ydim<<11),col); drawline256(x1-y2+(xdim<<11),y1+x3+(ydim<<11), x1+x2+(xdim<<11),y1+y3+(ydim<<11),col); drawline256(x1+y2+(xdim<<11),y1-x3+(ydim<<11), x1+x2+(xdim<<11),y1+y3+(ydim<<11),col); } else { if (((gotsector[i>>3]&(1<<(i&7))) > 0) && (czoom > 96)) { daang = (spr->ang-cang)&2047; if (j == playersprite[screenpeek]) { x1 = 0; y1 = 0; daang = 0; } rotatesprite((x1<<4)+(xdim<<15),(y1<<4)+(ydim<<15),mulscale16(czoom*spr->yrepeat,yxaspect),daang,spr->picnum,spr->shade,spr->pal,(spr->cstat&2)>>1,windowxy1.x,windowxy1.y,windowxy2.x,windowxy2.y); } } break; case 16: x1 = sprx; y1 = spry; tilenum = spr->picnum; xoff = (int)picanm[tilenum].xofs+((int)spr->xoffset); if ((spr->cstat&4) > 0) xoff = -xoff; k = spr->ang; l = spr->xrepeat; dax = sintable[k&2047]*l; day = sintable[(k+1536)&2047]*l; l = tilesiz[tilenum].x; k = (l>>1)+xoff; x1 -= mulscale16(dax,k); x2 = x1+mulscale16(dax,l); y1 -= mulscale16(day,k); y2 = y1+mulscale16(day,l); ox = x1-cposx; oy = y1-cposy; x1 = dmulscale16(ox,xvect,-oy,yvect); y1 = dmulscale16(oy,xvect2,ox,yvect2); ox = x2-cposx; oy = y2-cposy; x2 = dmulscale16(ox,xvect,-oy,yvect); y2 = dmulscale16(oy,xvect2,ox,yvect2); drawline256(x1+(xdim<<11),y1+(ydim<<11), x2+(xdim<<11),y2+(ydim<<11),col); break; case 32: if (dimensionmode[screenpeek] == 1) { tilenum = spr->picnum; xoff = (int)picanm[tilenum].xofs+((int)spr->xoffset); yoff = (int)picanm[tilenum].yofs+((int)spr->yoffset); if ((spr->cstat&4) > 0) xoff = -xoff; if ((spr->cstat&8) > 0) yoff = -yoff; k = spr->ang; cosang = sintable[(k+512)&2047]; sinang = sintable[k]; xspan = tilesiz[tilenum].x; xrepeat = spr->xrepeat; yspan = tilesiz[tilenum].y; yrepeat = spr->yrepeat; dax = ((xspan>>1)+xoff)*xrepeat; day = ((yspan>>1)+yoff)*yrepeat; x1 = sprx + dmulscale16(sinang,dax,cosang,day); y1 = spry + dmulscale16(sinang,day,-cosang,dax); l = xspan*xrepeat; x2 = x1 - mulscale16(sinang,l); y2 = y1 + mulscale16(cosang,l); l = yspan*yrepeat; k = -mulscale16(cosang,l); x3 = x2+k; x4 = x1+k; k = -mulscale16(sinang,l); y3 = y2+k; y4 = y1+k; ox = x1-cposx; oy = y1-cposy; x1 = dmulscale16(ox,xvect,-oy,yvect); y1 = dmulscale16(oy,xvect2,ox,yvect2); ox = x2-cposx; oy = y2-cposy; x2 = dmulscale16(ox,xvect,-oy,yvect); y2 = dmulscale16(oy,xvect2,ox,yvect2); ox = x3-cposx; oy = y3-cposy; x3 = dmulscale16(ox,xvect,-oy,yvect); y3 = dmulscale16(oy,xvect2,ox,yvect2); ox = x4-cposx; oy = y4-cposy; x4 = dmulscale16(ox,xvect,-oy,yvect); y4 = dmulscale16(oy,xvect2,ox,yvect2); drawline256(x1+(xdim<<11),y1+(ydim<<11), x2+(xdim<<11),y2+(ydim<<11),col); drawline256(x2+(xdim<<11),y2+(ydim<<11), x3+(xdim<<11),y3+(ydim<<11),col); drawline256(x3+(xdim<<11),y3+(ydim<<11), x4+(xdim<<11),y4+(ydim<<11),col); drawline256(x4+(xdim<<11),y4+(ydim<<11), x1+(xdim<<11),y1+(ydim<<11),col); } break; } } //Draw white lines for (i=0; inextwall >= 0) continue; if ((show2dwall[j>>3]&(1<<(j&7))) == 0) continue; if (tilesiz[wal->picnum].x == 0) continue; if (tilesiz[wal->picnum].y == 0) continue; if (j == k) { x1 = x2; y1 = y2; } else { ox = wal->x-cposx; oy = wal->y-cposy; x1 = dmulscale16(ox,xvect,-oy,yvect)+(xdim<<11); y1 = dmulscale16(oy,xvect2,ox,yvect2)+(ydim<<11); } k = wal->point2; wal2 = &wall[k]; ox = wal2->x-cposx; oy = wal2->y-cposy; x2 = dmulscale16(ox,xvect,-oy,yvect)+(xdim<<11); y2 = dmulscale16(oy,xvect2,ox,yvect2)+(ydim<<11); drawline256(x1,y1,x2,y2,24); } } } //New movesprite using getzrange. Note that I made the getzrange //parameters global (&globhiz,&globhihit,&globloz,&globlohit) so they //don't need to be passed everywhere. Also this should make this //movesprite function compatible with the older movesprite functions. int movesprite(short spritenum, int dx, int dy, int dz, int ceildist, int flordist, int clipmask) { int daz, zoffs /*, tempint*/; short retval, dasectnum, datempshort; spritetype *spr; spr = &sprite[spritenum]; if ((spr->cstat&128) == 0) zoffs = -((tilesiz[spr->picnum].y*spr->yrepeat)<<1); else zoffs = 0; dasectnum = spr->sectnum; //Can't modify sprite sectors directly becuase of linked lists daz = spr->z+zoffs; //Must do this if not using the new centered centering (of course) retval = clipmove_old(&spr->x,&spr->y,&daz,&dasectnum,dx,dy, ((int)spr->clipdist)<<2,ceildist,flordist,clipmask); if (dasectnum < 0) retval = -1; if ((dasectnum != spr->sectnum) && (dasectnum >= 0)) changespritesect(spritenum,dasectnum); //Set the blocking bit to 0 temporarly so getzrange doesn't pick up //its own sprite datempshort = spr->cstat; spr->cstat &= ~1; getzrange_old(spr->x,spr->y,spr->z-1,spr->sectnum, &globhiz,&globhihit,&globloz,&globlohit, ((int)spr->clipdist)<<2,clipmask); spr->cstat = datempshort; daz = spr->z+zoffs + dz; if ((daz <= globhiz) || (daz > globloz)) { if (retval != 0) return retval; return 16384+dasectnum; } spr->z = daz-zoffs; return retval; } void waitforeverybody() { int i; if (numplayers < 2) return; packbuf[0] = 250; for (i=connecthead; i>=0; i=connectpoint2[i]) { if (i != myconnectindex) sendpacket(i,packbuf,1); if ((!networkmode) && (myconnectindex != connecthead)) break; //slaves in M/S mode only send to master } playerreadyflag[myconnectindex]++; while (1) { handleevents(); refreshaudio(); drawrooms(pos[myconnectindex].x,pos[myconnectindex].y,pos[myconnectindex].z,ang[myconnectindex],horiz[myconnectindex],cursectnum[myconnectindex]); if (!networkmode) Bsprintf((char *)tempbuf,"Master/slave mode"); else Bsprintf((char *)tempbuf,"Peer-peer mode"); printext256((xdim>>1)-(strlen((char *)tempbuf)<<2),(ydim>>1)-24,31,0,(char *)tempbuf,0); Bsprintf((char *)tempbuf,"Waiting for players"); printext256((xdim>>1)-(strlen((char *)tempbuf)<<2),(ydim>>1)-16,31,0,(char *)tempbuf,0); for (i=connecthead; i>=0; i=connectpoint2[i]) { if (playerreadyflag[i] < playerreadyflag[myconnectindex]) { //slaves in M/S mode only wait for master if ((!networkmode) && (myconnectindex != connecthead) && (i != connecthead)) { Bsprintf((char *)tempbuf,"Player %d",i); printext256((xdim>>1)-(16<<2),(ydim>>1)+i*8,15,0,(char *)tempbuf,0); } else { Bsprintf((char *)tempbuf,"Player %d NOT ready",i); printext256((xdim>>1)-(16<<2),(ydim>>1)+i*8,127,0,(char *)tempbuf,0); } } else { Bsprintf((char *)tempbuf,"Player %d ready",i); printext256((xdim>>1)-(16<<2),(ydim>>1)+i*8,31,0,(char *)tempbuf,0); } if (i == myconnectindex) { Bsprintf((char *)tempbuf,"You->"); printext256((xdim>>1)-(26<<2),(ydim>>1)+i*8,95,0,(char *)tempbuf,0); } } nextpage(); if (quitevent || keystatus[1]) { sendlogoff(); //Signing off musicoff(); uninitmultiplayers(); uninittimer(); uninitinput(); uninitengine(); uninitsb(); uninitgroupfile(); exit(0); } getpackets(); for (i=connecthead; i>=0; i=connectpoint2[i]) { if (playerreadyflag[i] < playerreadyflag[myconnectindex]) break; if ((!networkmode) && (myconnectindex != connecthead)) { i = -1; break; } //slaves in M/S mode only wait for master } if (i < 0) return; } } void searchmap(short startsector) { int i, j, dasect, splc, send, startwall, endwall; short dapic; walltype *wal; if ((startsector < 0) || (startsector >= numsectors)) return; for (i=0; i<(MAXSECTORS>>3); i++) show2dsector[i] = 0; for (i=0; i<(MAXWALLS>>3); i++) show2dwall[i] = 0; for (i=0; i<(MAXSPRITES>>3); i++) show2dsprite[i] = 0; //Search your area recursively & set all show2dsector/show2dwalls tempshort[0] = startsector; show2dsector[startsector>>3] |= (1<<(startsector&7)); dapic = sector[startsector].ceilingpicnum; if (waloff[dapic] == 0) loadtile(dapic); dapic = sector[startsector].floorpicnum; if (waloff[dapic] == 0) loadtile(dapic); for (splc=0,send=1; splc>3] |= (1<<(i&7)); dapic = wall[i].picnum; if (waloff[dapic] == 0) loadtile(dapic); dapic = wall[i].overpicnum; if (((dapic&0xfffff000) == 0) && (waloff[dapic] == 0)) loadtile(dapic); j = wal->nextsector; if ((j >= 0) && ((show2dsector[j>>3]&(1<<(j&7))) == 0)) { show2dsector[j>>3] |= (1<<(j&7)); dapic = sector[j].ceilingpicnum; if (waloff[dapic] == 0) loadtile(dapic); dapic = sector[j].floorpicnum; if (waloff[dapic] == 0) loadtile(dapic); tempshort[send++] = (short)j; } } for (i=headspritesect[dasect]; i>=0; i=nextspritesect[i]) { show2dsprite[i>>3] |= (1<<(i&7)); dapic = sprite[i].picnum; if (waloff[dapic] == 0) loadtile(dapic); } } } void setinterpolation(int *posptr) { int i; if (numinterpolations >= MAXINTERPOLATIONS) return; for (i=numinterpolations-1; i>=0; i--) if (curipos[i] == posptr) return; curipos[numinterpolations] = posptr; oldipos[numinterpolations] = *posptr; numinterpolations++; } void stopinterpolation(int *posptr) { int i; for (i=numinterpolations-1; i>=startofdynamicinterpolations; i--) if (curipos[i] == posptr) { numinterpolations--; oldipos[i] = oldipos[numinterpolations]; bakipos[i] = bakipos[numinterpolations]; curipos[i] = curipos[numinterpolations]; } } void updateinterpolations(void) //Stick at beginning of domovethings { int i; for (i=numinterpolations-1; i>=0; i--) oldipos[i] = *curipos[i]; } void dointerpolations(void) //Stick at beginning of drawscreen { int i, j, odelta, ndelta; ndelta = 0; j = 0; for (i=numinterpolations-1; i>=0; i--) { bakipos[i] = *curipos[i]; odelta = ndelta; ndelta = (*curipos[i])-oldipos[i]; if (odelta != ndelta) j = mulscale16(ndelta,smoothratio); *curipos[i] = oldipos[i]+j; } } void restoreinterpolations(void) //Stick at end of drawscreen { int i; for (i=numinterpolations-1; i>=0; i--) *curipos[i] = bakipos[i]; } void printext(int x, int y, char *buffer, short tilenum /*, char invisiblecol*/) { int i; char ch; for (i=0; buffer[i]!=0; i++) { ch = (char)buffer[i]; rotatesprite((x-((8&15)<<3))<<16,(y-((8>>4)<<3))<<16,65536L,0,tilenum,0,0,8+16+64+128,x,y,x+7,y+7); rotatesprite((x-((ch&15)<<3))<<16,(y-((ch>>4)<<3))<<16,65536L,0,tilenum,0,0,8+16+128,x,y,x+7,y+7); x += 8; } } void drawtilebackground(/*int thex, int they,*/ short tilenum, signed char shade, int cx1, int cy1, int cx2, int cy2, char dapalnum) { int x, y, xsiz, ysiz, tx1, ty1, tx2, ty2; xsiz = tilesiz[tilenum].x; tx1 = cx1/xsiz; tx2 = cx2/xsiz; ysiz = tilesiz[tilenum].y; ty1 = cy1/ysiz; ty2 = cy2/ysiz; for (x=tx1; x<=tx2; x++) for (y=ty1; y<=ty2; y++) rotatesprite(x*xsiz<<16,y*ysiz<<16,65536L,0,tilenum,shade,dapalnum,8+16+64+128,cx1,cy1,cx2,cy2); } void M32RunScript(const char *s) { UNREFERENCED_PARAMETER(s); } void G_Polymer_UnInit(void) { } void app_crashhandler(void) { } /* * vim:ts=4:sw=4: */