summaryrefslogtreecommitdiffstats
path: root/apps/plugins/sdl/progs/wolf3d/wl_game.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/sdl/progs/wolf3d/wl_game.c')
-rw-r--r--apps/plugins/sdl/progs/wolf3d/wl_game.c1601
1 files changed, 1601 insertions, 0 deletions
diff --git a/apps/plugins/sdl/progs/wolf3d/wl_game.c b/apps/plugins/sdl/progs/wolf3d/wl_game.c
new file mode 100644
index 0000000000..445cf00153
--- /dev/null
+++ b/apps/plugins/sdl/progs/wolf3d/wl_game.c
@@ -0,0 +1,1601 @@
+// WL_GAME.C
+
+#include "wl_def.h"
+#pragma hdrstop
+
+
+/*
+=============================================================================
+
+ LOCAL CONSTANTS
+
+=============================================================================
+*/
+
+
+/*
+=============================================================================
+
+ GLOBAL VARIABLES
+
+=============================================================================
+*/
+
+boolean ingame,fizzlein;
+gametype gamestate;
+byte bordercol=VIEWCOLOR; // color of the Change View/Ingame border
+
+#ifdef SPEAR
+int32_t spearx,speary;
+unsigned spearangle;
+boolean spearflag;
+#endif
+
+#ifdef USE_FEATUREFLAGS
+int ffDataTopLeft, ffDataTopRight, ffDataBottomLeft, ffDataBottomRight;
+#endif
+
+//
+// ELEVATOR BACK MAPS - REMEMBER (-1)!!
+//
+int ElevatorBackTo[]={1,1,7,3,5,3};
+
+void SetupGameLevel (void);
+void DrawPlayScreen (void);
+void LoadLatchMem (void);
+void GameLoop (void);
+
+/*
+=============================================================================
+
+ LOCAL VARIABLES
+
+=============================================================================
+*/
+
+
+
+//===========================================================================
+//===========================================================================
+
+
+/*
+==========================
+=
+= SetSoundLoc - Given the location of an object (in terms of global
+= coordinates, held in globalsoundx and globalsoundy), munges the values
+= for an approximate distance from the left and right ear, and puts
+= those values into leftchannel and rightchannel.
+=
+= JAB
+=
+==========================
+*/
+
+int leftchannel, rightchannel;
+#define ATABLEMAX 15
+byte righttable[ATABLEMAX][ATABLEMAX * 2] = {
+{ 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 0, 0, 0, 0, 0, 1, 3, 5, 8, 8, 8, 8, 8, 8, 8, 8},
+{ 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 6, 4, 0, 0, 0, 0, 0, 2, 4, 6, 8, 8, 8, 8, 8, 8, 8, 8},
+{ 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 6, 6, 4, 1, 0, 0, 0, 1, 2, 4, 6, 8, 8, 8, 8, 8, 8, 8, 8},
+{ 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 6, 5, 4, 2, 1, 0, 1, 2, 3, 5, 7, 8, 8, 8, 8, 8, 8, 8, 8},
+{ 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 6, 5, 4, 3, 2, 2, 3, 3, 5, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8},
+{ 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 6, 6, 5, 4, 4, 4, 4, 5, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8},
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 6, 6, 5, 5, 5, 6, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 6, 6, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}
+};
+byte lefttable[ATABLEMAX][ATABLEMAX * 2] = {
+{ 8, 8, 8, 8, 8, 8, 8, 8, 5, 3, 1, 0, 0, 0, 0, 0, 6, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8},
+{ 8, 8, 8, 8, 8, 8, 8, 8, 6, 4, 2, 0, 0, 0, 0, 0, 4, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8},
+{ 8, 8, 8, 8, 8, 8, 8, 8, 6, 4, 2, 1, 0, 0, 0, 1, 4, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8},
+{ 8, 8, 8, 8, 8, 8, 8, 8, 7, 5, 3, 2, 1, 0, 1, 2, 4, 5, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8},
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 6, 5, 3, 3, 2, 2, 3, 4, 5, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8},
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 6, 5, 4, 4, 4, 4, 5, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8},
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 6, 6, 5, 5, 5, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8},
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 6, 6, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8},
+{ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8}
+};
+
+void
+SetSoundLoc(fixed gx,fixed gy)
+{
+ fixed xt,yt;
+ int x,y;
+
+//
+// translate point to view centered coordinates
+//
+ gx -= viewx;
+ gy -= viewy;
+
+//
+// calculate newx
+//
+ xt = FixedMul(gx,viewcos);
+ yt = FixedMul(gy,viewsin);
+ x = (xt - yt) >> TILESHIFT;
+
+//
+// calculate newy
+//
+ xt = FixedMul(gx,viewsin);
+ yt = FixedMul(gy,viewcos);
+ y = (yt + xt) >> TILESHIFT;
+
+ if (y >= ATABLEMAX)
+ y = ATABLEMAX - 1;
+ else if (y <= -ATABLEMAX)
+ y = -ATABLEMAX;
+ if (x < 0)
+ x = -x;
+ if (x >= ATABLEMAX)
+ x = ATABLEMAX - 1;
+ leftchannel = lefttable[x][y + ATABLEMAX];
+ rightchannel = righttable[x][y + ATABLEMAX];
+
+#if 0
+ CenterWindow(8,1);
+ US_PrintSigned(leftchannel);
+ US_Print(",");
+ US_PrintSigned(rightchannel);
+ VW_UpdateScreen();
+#endif
+}
+
+/*
+==========================
+=
+= SetSoundLocGlobal - Sets up globalsoundx & globalsoundy and then calls
+= UpdateSoundLoc() to transform that into relative channel volumes. Those
+= values are then passed to the Sound Manager so that they'll be used for
+= the next sound played (if possible).
+=
+= JAB
+=
+==========================
+*/
+void PlaySoundLocGlobal(word s,fixed gx,fixed gy)
+{
+ SetSoundLoc(gx, gy);
+ SD_PositionSound(leftchannel, rightchannel);
+
+ int channel = SD_PlaySound((soundnames) s);
+ if(channel)
+ {
+ channelSoundPos[channel - 1].globalsoundx = gx;
+ channelSoundPos[channel - 1].globalsoundy = gy;
+ channelSoundPos[channel - 1].valid = 1;
+ }
+}
+
+void UpdateSoundLoc(void)
+{
+/* if (SoundPositioned)
+ {
+ SetSoundLoc(globalsoundx,globalsoundy);
+ SD_SetPosition(leftchannel,rightchannel);
+ }*/
+
+ for(int i = 0; i < MIX_CHANNELS; i++)
+ {
+ if(channelSoundPos[i].valid)
+ {
+ SetSoundLoc(channelSoundPos[i].globalsoundx,
+ channelSoundPos[i].globalsoundy);
+ SD_SetPosition(i, leftchannel, rightchannel);
+ }
+ }
+}
+
+/*
+** JAB End
+*/
+
+/*
+==========================
+=
+= ScanInfoPlane
+=
+= Spawn all actors and mark down special places
+=
+==========================
+*/
+
+static void ScanInfoPlane(void)
+{
+ unsigned x,y;
+ int tile;
+ word *start;
+
+ start = mapsegs[1];
+ for (y=0;y<mapheight;y++)
+ {
+ for (x=0;x<mapwidth;x++)
+ {
+ tile = *start++;
+ if (!tile)
+ continue;
+
+ switch (tile)
+ {
+ case 19:
+ case 20:
+ case 21:
+ case 22:
+ SpawnPlayer(x,y,NORTH+tile-19);
+ break;
+
+ case 23:
+ case 24:
+ case 25:
+ case 26:
+ case 27:
+ case 28:
+ case 29:
+ case 30:
+
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ case 38:
+
+ case 39:
+ case 40:
+ case 41:
+ case 42:
+ case 43:
+ case 44:
+ case 45:
+ case 46:
+
+ case 47:
+ case 48:
+ case 49:
+ case 50:
+ case 51:
+ case 52:
+ case 53:
+ case 54:
+
+ case 55:
+ case 56:
+ case 57:
+ case 58:
+ case 59:
+ case 60:
+ case 61:
+ case 62:
+
+ case 63:
+ case 64:
+ case 65:
+ case 66:
+ case 67:
+ case 68:
+ case 69:
+ case 70:
+ case 71:
+ case 72:
+#ifdef SPEAR
+ case 73: // TRUCK AND SPEAR!
+ case 74:
+#elif defined(USE_DIR3DSPR) // just for the example
+ case 73:
+#endif
+ SpawnStatic(x,y,tile-23);
+ break;
+
+//
+// P wall
+//
+ case 98:
+ if (!loadedgame)
+ gamestate.secrettotal++;
+ break;
+
+//
+// guard
+//
+ case 180:
+ case 181:
+ case 182:
+ case 183:
+ if (gamestate.difficulty<gd_hard)
+ break;
+ tile -= 36;
+ case 144:
+ case 145:
+ case 146:
+ case 147:
+ if (gamestate.difficulty<gd_medium)
+ break;
+ tile -= 36;
+ case 108:
+ case 109:
+ case 110:
+ case 111:
+ SpawnStand(en_guard,x,y,tile-108);
+ break;
+
+
+ case 184:
+ case 185:
+ case 186:
+ case 187:
+ if (gamestate.difficulty<gd_hard)
+ break;
+ tile -= 36;
+ case 148:
+ case 149:
+ case 150:
+ case 151:
+ if (gamestate.difficulty<gd_medium)
+ break;
+ tile -= 36;
+ case 112:
+ case 113:
+ case 114:
+ case 115:
+ SpawnPatrol(en_guard,x,y,tile-112);
+ break;
+
+ case 124:
+ SpawnDeadGuard (x,y);
+ break;
+//
+// officer
+//
+ case 188:
+ case 189:
+ case 190:
+ case 191:
+ if (gamestate.difficulty<gd_hard)
+ break;
+ tile -= 36;
+ case 152:
+ case 153:
+ case 154:
+ case 155:
+ if (gamestate.difficulty<gd_medium)
+ break;
+ tile -= 36;
+ case 116:
+ case 117:
+ case 118:
+ case 119:
+ SpawnStand(en_officer,x,y,tile-116);
+ break;
+
+
+ case 192:
+ case 193:
+ case 194:
+ case 195:
+ if (gamestate.difficulty<gd_hard)
+ break;
+ tile -= 36;
+ case 156:
+ case 157:
+ case 158:
+ case 159:
+ if (gamestate.difficulty<gd_medium)
+ break;
+ tile -= 36;
+ case 120:
+ case 121:
+ case 122:
+ case 123:
+ SpawnPatrol(en_officer,x,y,tile-120);
+ break;
+
+
+//
+// ss
+//
+ case 198:
+ case 199:
+ case 200:
+ case 201:
+ if (gamestate.difficulty<gd_hard)
+ break;
+ tile -= 36;
+ case 162:
+ case 163:
+ case 164:
+ case 165:
+ if (gamestate.difficulty<gd_medium)
+ break;
+ tile -= 36;
+ case 126:
+ case 127:
+ case 128:
+ case 129:
+ SpawnStand(en_ss,x,y,tile-126);
+ break;
+
+
+ case 202:
+ case 203:
+ case 204:
+ case 205:
+ if (gamestate.difficulty<gd_hard)
+ break;
+ tile -= 36;
+ case 166:
+ case 167:
+ case 168:
+ case 169:
+ if (gamestate.difficulty<gd_medium)
+ break;
+ tile -= 36;
+ case 130:
+ case 131:
+ case 132:
+ case 133:
+ SpawnPatrol(en_ss,x,y,tile-130);
+ break;
+
+//
+// dogs
+//
+ case 206:
+ case 207:
+ case 208:
+ case 209:
+ if (gamestate.difficulty<gd_hard)
+ break;
+ tile -= 36;
+ case 170:
+ case 171:
+ case 172:
+ case 173:
+ if (gamestate.difficulty<gd_medium)
+ break;
+ tile -= 36;
+ case 134:
+ case 135:
+ case 136:
+ case 137:
+ SpawnStand(en_dog,x,y,tile-134);
+ break;
+
+
+ case 210:
+ case 211:
+ case 212:
+ case 213:
+ if (gamestate.difficulty<gd_hard)
+ break;
+ tile -= 36;
+ case 174:
+ case 175:
+ case 176:
+ case 177:
+ if (gamestate.difficulty<gd_medium)
+ break;
+ tile -= 36;
+ case 138:
+ case 139:
+ case 140:
+ case 141:
+ SpawnPatrol(en_dog,x,y,tile-138);
+ break;
+
+//
+// boss
+//
+#ifndef SPEAR
+ case 214:
+ SpawnBoss (x,y);
+ break;
+ case 197:
+ SpawnGretel (x,y);
+ break;
+ case 215:
+ SpawnGift (x,y);
+ break;
+ case 179:
+ SpawnFat (x,y);
+ break;
+ case 196:
+ SpawnSchabbs (x,y);
+ break;
+ case 160:
+ SpawnFakeHitler (x,y);
+ break;
+ case 178:
+ SpawnHitler (x,y);
+ break;
+#else
+ case 106:
+ SpawnSpectre (x,y);
+ break;
+ case 107:
+ SpawnAngel (x,y);
+ break;
+ case 125:
+ SpawnTrans (x,y);
+ break;
+ case 142:
+ SpawnUber (x,y);
+ break;
+ case 143:
+ SpawnWill (x,y);
+ break;
+ case 161:
+ SpawnDeath (x,y);
+ break;
+
+#endif
+
+//
+// mutants
+//
+ case 252:
+ case 253:
+ case 254:
+ case 255:
+ if (gamestate.difficulty<gd_hard)
+ break;
+ tile -= 18;
+ case 234:
+ case 235:
+ case 236:
+ case 237:
+ if (gamestate.difficulty<gd_medium)
+ break;
+ tile -= 18;
+ case 216:
+ case 217:
+ case 218:
+ case 219:
+ SpawnStand(en_mutant,x,y,tile-216);
+ break;
+
+ case 256:
+ case 257:
+ case 258:
+ case 259:
+ if (gamestate.difficulty<gd_hard)
+ break;
+ tile -= 18;
+ case 238:
+ case 239:
+ case 240:
+ case 241:
+ if (gamestate.difficulty<gd_medium)
+ break;
+ tile -= 18;
+ case 220:
+ case 221:
+ case 222:
+ case 223:
+ SpawnPatrol(en_mutant,x,y,tile-220);
+ break;
+
+//
+// ghosts
+//
+#ifndef SPEAR
+ case 224:
+ SpawnGhosts (en_blinky,x,y);
+ break;
+ case 225:
+ SpawnGhosts (en_clyde,x,y);
+ break;
+ case 226:
+ SpawnGhosts (en_pinky,x,y);
+ break;
+ case 227:
+ SpawnGhosts (en_inky,x,y);
+ break;
+#endif
+ }
+ }
+ }
+}
+
+//==========================================================================
+
+/*
+==================
+=
+= SetupGameLevel
+=
+==================
+*/
+
+void SetupGameLevel (void)
+{
+ int x,y;
+ word *map;
+ word tile;
+
+
+ if (!loadedgame)
+ {
+ gamestate.TimeCount
+ = gamestate.secrettotal
+ = gamestate.killtotal
+ = gamestate.treasuretotal
+ = gamestate.secretcount
+ = gamestate.killcount
+ = gamestate.treasurecount
+ = pwallstate = pwallpos = facetimes = 0;
+ LastAttacker = NULL;
+ killerobj = NULL;
+ }
+
+ if (demoplayback || demorecord)
+ US_InitRndT (false);
+ else
+ US_InitRndT (true);
+
+//
+// load the level
+//
+ CA_CacheMap (gamestate.mapon+10*gamestate.episode);
+ mapon-=gamestate.episode*10;
+
+#ifdef USE_FEATUREFLAGS
+ // Temporary definition to make things clearer
+ #define MXX MAPSIZE - 1
+
+ // Read feature flags data from map corners and overwrite corners with adjacent tiles
+ ffDataTopLeft = MAPSPOT(0, 0, 0); MAPSPOT(0, 0, 0) = MAPSPOT(1, 0, 0);
+ ffDataTopRight = MAPSPOT(MXX, 0, 0); MAPSPOT(MXX, 0, 0) = MAPSPOT(MXX, 1, 0);
+ ffDataBottomRight = MAPSPOT(MXX, MXX, 0); MAPSPOT(MXX, MXX, 0) = MAPSPOT(MXX - 1, MXX, 0);
+ ffDataBottomLeft = MAPSPOT(0, MXX, 0); MAPSPOT(0, MXX, 0) = MAPSPOT(0, MXX - 1, 0);
+
+ #undef MXX
+#endif
+
+//
+// copy the wall data to a data segment array
+//
+ memset (tilemap,0,sizeof(tilemap));
+ memset (actorat,0,sizeof(actorat));
+ map = mapsegs[0];
+ for (y=0;y<mapheight;y++)
+ {
+ for (x=0;x<mapwidth;x++)
+ {
+ tile = *map++;
+ if (tile<AREATILE)
+ {
+ // solid wall
+ tilemap[x][y] = (byte) tile;
+ actorat[x][y] = (objtype *)(uintptr_t) tile;
+ }
+ else
+ {
+ // area floor
+ tilemap[x][y] = 0;
+ actorat[x][y] = 0;
+ }
+ }
+ }
+
+//
+// spawn doors
+//
+ InitActorList (); // start spawning things with a clean slate
+ InitDoorList ();
+ InitStaticList ();
+
+ map = mapsegs[0];
+ for (y=0;y<mapheight;y++)
+ {
+ for (x=0;x<mapwidth;x++)
+ {
+ tile = *map++;
+ if (tile >= 90 && tile <= 101)
+ {
+ // door
+ switch (tile)
+ {
+ case 90:
+ case 92:
+ case 94:
+ case 96:
+ case 98:
+ case 100:
+ SpawnDoor (x,y,1,(tile-90)/2);
+ break;
+ case 91:
+ case 93:
+ case 95:
+ case 97:
+ case 99:
+ case 101:
+ SpawnDoor (x,y,0,(tile-91)/2);
+ break;
+ }
+ }
+ }
+ }
+
+//
+// spawn actors
+//
+ ScanInfoPlane ();
+
+
+//
+// take out the ambush markers
+//
+ map = mapsegs[0];
+ for (y=0;y<mapheight;y++)
+ {
+ for (x=0;x<mapwidth;x++)
+ {
+ tile = *map++;
+ if (tile == AMBUSHTILE)
+ {
+ tilemap[x][y] = 0;
+ if ( (unsigned)(uintptr_t)actorat[x][y] == AMBUSHTILE)
+ actorat[x][y] = NULL;
+
+ if (*map >= AREATILE)
+ tile = *map;
+ if (*(map-1-mapwidth) >= AREATILE)
+ tile = *(map-1-mapwidth);
+ if (*(map-1+mapwidth) >= AREATILE)
+ tile = *(map-1+mapwidth);
+ if ( *(map-2) >= AREATILE)
+ tile = *(map-2);
+
+ *(map-1) = tile;
+ }
+ }
+ }
+
+
+//
+// have the caching manager load and purge stuff to make sure all marks
+// are in memory
+//
+ CA_LoadAllSounds ();
+}
+
+
+//==========================================================================
+
+
+/*
+===================
+=
+= DrawPlayBorderSides
+=
+= To fix window overwrites
+=
+===================
+*/
+void DrawPlayBorderSides(void)
+{
+ if(viewsize == 21) return;
+
+ const int sw = screenWidth;
+ const int sh = screenHeight;
+ const int vw = viewwidth;
+ const int vh = viewheight;
+ const int px = scaleFactor; // size of one "pixel"
+
+ const int h = sh - px * STATUSLINES;
+ const int xl = sw / 2 - vw / 2;
+ const int yl = (h - vh) / 2;
+
+ if(xl != 0)
+ {
+ VWB_BarScaledCoord(0, 0, xl - px, h, bordercol); // left side
+ VWB_BarScaledCoord(xl + vw + px, 0, xl - px * 2, h, bordercol); // right side
+ }
+
+ if(yl != 0)
+ {
+ VWB_BarScaledCoord(0, 0, sw, yl - px, bordercol); // upper side
+ VWB_BarScaledCoord(0, yl + vh + px, sw, yl - px, bordercol); // lower side
+ }
+
+ if(xl != 0)
+ {
+ // Paint game view border lines
+ VWB_BarScaledCoord(xl - px, yl - px, vw + px, px, 0); // upper border
+ VWB_BarScaledCoord(xl, yl + vh, vw + px, px, bordercol - 2); // lower border
+ VWB_BarScaledCoord(xl - px, yl - px, px, vh + px, 0); // left border
+ VWB_BarScaledCoord(xl + vw, yl - px, px, vh + px * 2, bordercol - 2); // right border
+ VWB_BarScaledCoord(xl - px, yl + vh, px, px, bordercol - 3); // lower left highlight
+ }
+ else
+ {
+ // Just paint a lower border line
+ VWB_BarScaledCoord(0, yl+vh, vw, px, bordercol-2); // lower border
+ }
+}
+
+
+/*
+===================
+=
+= DrawStatusBorder
+=
+===================
+*/
+
+void DrawStatusBorder (byte color)
+{
+ int statusborderw = (screenWidth-scaleFactor*320)/2;
+
+ VWB_BarScaledCoord (0,0,screenWidth,screenHeight-scaleFactor*(STATUSLINES-3),color);
+ VWB_BarScaledCoord (0,screenHeight-scaleFactor*(STATUSLINES-3),
+ statusborderw+scaleFactor*8,scaleFactor*(STATUSLINES-4),color);
+ VWB_BarScaledCoord (0,screenHeight-scaleFactor*2,screenWidth,scaleFactor*2,color);
+ VWB_BarScaledCoord (screenWidth-statusborderw-scaleFactor*8, screenHeight-scaleFactor*(STATUSLINES-3),
+ statusborderw+scaleFactor*8,scaleFactor*(STATUSLINES-4),color);
+
+ VWB_BarScaledCoord (statusborderw+scaleFactor*9, screenHeight-scaleFactor*3,
+ scaleFactor*97, scaleFactor*1, color-1);
+ VWB_BarScaledCoord (statusborderw+scaleFactor*106, screenHeight-scaleFactor*3,
+ scaleFactor*161, scaleFactor*1, color-2);
+ VWB_BarScaledCoord (statusborderw+scaleFactor*267, screenHeight-scaleFactor*3,
+ scaleFactor*44, scaleFactor*1, color-3);
+ VWB_BarScaledCoord (screenWidth-statusborderw-scaleFactor*9, screenHeight-scaleFactor*(STATUSLINES-4),
+ scaleFactor*1, scaleFactor*20, color-2);
+ VWB_BarScaledCoord (screenWidth-statusborderw-scaleFactor*9, screenHeight-scaleFactor*(STATUSLINES/2-4),
+ scaleFactor*1, scaleFactor*14, color-3);
+}
+
+
+/*
+===================
+=
+= DrawPlayBorder
+=
+===================
+*/
+
+void DrawPlayBorder (void)
+{
+ const int px = scaleFactor; // size of one "pixel"
+
+ if (bordercol != VIEWCOLOR)
+ DrawStatusBorder(bordercol);
+ else
+ {
+ const int statusborderw = (screenWidth-px*320)/2;
+ VWB_BarScaledCoord (0, screenHeight-px*STATUSLINES,
+ statusborderw+px*8, px*STATUSLINES, bordercol);
+ VWB_BarScaledCoord (screenWidth-statusborderw-px*8, screenHeight-px*STATUSLINES,
+ statusborderw+px*8, px*STATUSLINES, bordercol);
+ }
+
+ if((unsigned) viewheight == screenHeight) return;
+
+ VWB_BarScaledCoord (0,0,screenWidth,screenHeight-px*STATUSLINES,bordercol);
+
+ const int xl = screenWidth/2-viewwidth/2;
+ const int yl = (screenHeight-px*STATUSLINES-viewheight)/2;
+ VWB_BarScaledCoord (xl,yl,viewwidth,viewheight,0);
+
+ if(xl != 0)
+ {
+ // Paint game view border lines
+ VWB_BarScaledCoord(xl-px, yl-px, viewwidth+px, px, 0); // upper border
+ VWB_BarScaledCoord(xl, yl+viewheight, viewwidth+px, px, bordercol-2); // lower border
+ VWB_BarScaledCoord(xl-px, yl-px, px, viewheight+px, 0); // left border
+ VWB_BarScaledCoord(xl+viewwidth, yl-px, px, viewheight+2*px, bordercol-2); // right border
+ VWB_BarScaledCoord(xl-px, yl+viewheight, px, px, bordercol-3); // lower left highlight
+ }
+ else
+ {
+ // Just paint a lower border line
+ VWB_BarScaledCoord(0, yl+viewheight, viewwidth, px, bordercol-2); // lower border
+ }
+}
+
+
+/*
+===================
+=
+= DrawPlayScreen
+=
+===================
+*/
+
+void DrawPlayScreen (void)
+{
+ VWB_DrawPicScaledCoord ((screenWidth-scaleFactor*320)/2,screenHeight-scaleFactor*STATUSLINES,STATUSBARPIC);
+ DrawPlayBorder ();
+
+ DrawFace ();
+ DrawHealth ();
+ DrawLives ();
+ DrawLevel ();
+ DrawAmmo ();
+ DrawKeys ();
+ DrawWeapon ();
+ DrawScore ();
+}
+
+// Uses LatchDrawPic instead of StatusDrawPic
+void LatchNumberHERE (int x, int y, unsigned width, int32_t number)
+{
+ unsigned length,c;
+ char str[20];
+
+ ltoa (number,str,10);
+
+ length = (unsigned) strlen (str);
+
+ while (length<width)
+ {
+ LatchDrawPic (x,y,N_BLANKPIC);
+ x++;
+ width--;
+ }
+
+ c = length <= width ? 0 : length-width;
+
+ while (c<length)
+ {
+ LatchDrawPic (x,y,str[c]-'0'+ N_0PIC);
+ x++;
+ c++;
+ }
+}
+
+void ShowActStatus()
+{
+ // Draw status bar without borders
+ byte *source = grsegs[STATUSBARPIC];
+ int picnum = STATUSBARPIC - STARTPICS;
+ int width = pictable[picnum].width;
+ int height = pictable[picnum].height;
+ int destx = (screenWidth-scaleFactor*320)/2 + 9 * scaleFactor;
+ int desty = screenHeight - (height - 4) * scaleFactor;
+ VL_MemToScreenScaledCoord_ex(source, width, height, 9, 4, destx, desty, width - 18, height - 7);
+
+ ingame = false;
+ DrawFace ();
+ DrawHealth ();
+ DrawLives ();
+ DrawLevel ();
+ DrawAmmo ();
+ DrawKeys ();
+ DrawWeapon ();
+ DrawScore ();
+ ingame = true;
+}
+
+
+//==========================================================================
+
+/*
+==================
+=
+= StartDemoRecord
+=
+==================
+*/
+
+char demoname[13] = "DEMO?.";
+
+#ifndef REMDEBUG
+#define MAXDEMOSIZE 8192
+
+void StartDemoRecord (int levelnumber)
+{
+ demobuffer=malloc(MAXDEMOSIZE);
+ CHECKMALLOCRESULT(demobuffer);
+ demoptr = (int8_t *) demobuffer;
+ lastdemoptr = demoptr+MAXDEMOSIZE;
+
+ *demoptr = levelnumber;
+ demoptr += 4; // leave space for length
+ demorecord = true;
+}
+
+
+/*
+==================
+=
+= FinishDemoRecord
+=
+==================
+*/
+
+void FinishDemoRecord (void)
+{
+ int32_t length,level;
+
+ demorecord = false;
+
+ length = (int32_t) (demoptr - (int8_t *)demobuffer);
+
+ demoptr = ((int8_t *)demobuffer)+1;
+ demoptr[0] = (int8_t) length;
+ demoptr[1] = (int8_t) (length >> 8);
+ demoptr[2] = 0;
+
+ VW_FadeIn();
+ CenterWindow(24,3);
+ PrintY+=6;
+ fontnumber=0;
+ SETFONTCOLOR(0,15);
+ US_Print(" Demo number (0-9): ");
+ VW_UpdateScreen();
+
+ if (US_LineInput (px,py,str,NULL,true,1,0))
+ {
+ level = atoi (str);
+ if (level>=0 && level<=9)
+ {
+ demoname[4] = (char)('0'+level);
+ CA_WriteFile (demoname,demobuffer,length);
+ }
+ }
+
+ free(demobuffer);
+}
+
+//==========================================================================
+
+/*
+==================
+=
+= RecordDemo
+=
+= Fades the screen out, then starts a demo. Exits with the screen faded
+=
+==================
+*/
+
+void RecordDemo (void)
+{
+ int level,esc,maps;
+
+ CenterWindow(26,3);
+ PrintY+=6;
+ CA_CacheGrChunk(STARTFONT);
+ fontnumber=0;
+ SETFONTCOLOR(0,15);
+#ifndef SPEAR
+#ifdef UPLOAD
+ US_Print(" Demo which level(1-10): "); maps = 10;
+#else
+ US_Print(" Demo which level(1-60): "); maps = 60;
+#endif
+#else
+ US_Print(" Demo which level(1-21): "); maps = 21;
+#endif
+ VW_UpdateScreen();
+ VW_FadeIn ();
+ esc = !US_LineInput (px,py,str,NULL,true,2,0);
+ if (esc)
+ return;
+
+ level = atoi (str);
+ level--;
+
+ if (level >= maps || level < 0)
+ return;
+
+ VW_FadeOut ();
+
+#ifndef SPEAR
+ NewGame (gd_hard,level/10);
+ gamestate.mapon = level%10;
+#else
+ NewGame (gd_hard,0);
+ gamestate.mapon = level;
+#endif
+
+ StartDemoRecord (level);
+
+ DrawPlayScreen ();
+ VW_FadeIn ();
+
+ startgame = false;
+ demorecord = true;
+
+ SetupGameLevel ();
+ StartMusic ();
+
+ if(usedoublebuffering) VH_UpdateScreen();
+ fizzlein = true;
+
+ PlayLoop ();
+
+ demoplayback = false;
+
+ StopMusic ();
+ VW_FadeOut ();
+ ClearMemory ();
+
+ FinishDemoRecord ();
+}
+#else
+void FinishDemoRecord (void) {return;}
+void RecordDemo (void) {return;}
+#endif
+
+
+
+//==========================================================================
+
+/*
+==================
+=
+= PlayDemo
+=
+= Fades the screen out, then starts a demo. Exits with the screen unfaded
+=
+==================
+*/
+
+void PlayDemo (int demonumber)
+{
+ int length;
+#ifdef DEMOSEXTERN
+// debug: load chunk
+#ifndef SPEARDEMO
+ int dems[4]={T_DEMO0,T_DEMO1,T_DEMO2,T_DEMO3};
+#else
+ int dems[1]={T_DEMO0};
+#endif
+
+ CA_CacheGrChunk(dems[demonumber]);
+ demoptr = (int8_t *) grsegs[dems[demonumber]];
+#else
+ demoname[4] = '0'+demonumber;
+ CA_LoadFile (demoname,&demobuffer);
+ demoptr = (int8_t *)demobuffer;
+#endif
+
+ NewGame (1,0);
+ gamestate.mapon = *demoptr++;
+ LOGF("%d", gamestate.mapon);
+ gamestate.difficulty = gd_hard;
+ /* FIXME POSSIBLE BUG */
+ length = READWORD((uint8_t **)&demoptr);
+ LOGF("%d", length);
+ // TODO: Seems like the original demo format supports 16 MB demos
+ // But T_DEM00 and T_DEM01 of Wolf have a 0xd8 as third length size...
+ demoptr++;
+ lastdemoptr = demoptr-4+length;
+
+ VW_FadeOut ();
+
+ SETFONTCOLOR(0,15);
+ DrawPlayScreen ();
+
+ startgame = false;
+ demoplayback = true;
+
+ SetupGameLevel ();
+ StartMusic ();
+
+ PlayLoop ();
+
+#ifdef DEMOSEXTERN
+ UNCACHEGRCHUNK(dems[demonumber]);
+#else
+ MM_FreePtr (&demobuffer);
+#endif
+
+ demoplayback = false;
+
+ StopMusic ();
+ ClearMemory ();
+}
+
+//==========================================================================
+
+/*
+==================
+=
+= Died
+=
+==================
+*/
+
+#define DEATHROTATE 2
+
+void Died (void)
+{
+ float fangle;
+ int32_t dx,dy;
+ int iangle,curangle,clockwise,counter,change;
+
+ if (screenfaded)
+ {
+ ThreeDRefresh ();
+ VW_FadeIn ();
+ }
+
+ gamestate.weapon = (weapontype) -1; // take away weapon
+ SD_PlaySound (PLAYERDEATHSND);
+
+ //
+ // swing around to face attacker
+ //
+ if(killerobj)
+ {
+ dx = killerobj->x - player->x;
+ dy = player->y - killerobj->y;
+
+ fangle = (float) atan2((float) dy, (float) dx); // returns -pi to pi
+ if (fangle<0)
+ fangle = (float) (M_PI*2+fangle);
+
+ iangle = (int) (fangle/(M_PI*2)*ANGLES);
+ }
+ else
+ {
+ iangle = player->angle + ANGLES / 2;
+ if(iangle >= ANGLES) iangle -= ANGLES;
+ }
+
+ if (player->angle > iangle)
+ {
+ counter = player->angle - iangle;
+ clockwise = ANGLES-player->angle + iangle;
+ }
+ else
+ {
+ clockwise = iangle - player->angle;
+ counter = player->angle + ANGLES-iangle;
+ }
+
+ curangle = player->angle;
+
+ if (clockwise<counter)
+ {
+ //
+ // rotate clockwise
+ //
+ if (curangle>iangle)
+ curangle -= ANGLES;
+ do
+ {
+ change = tics*DEATHROTATE;
+ if (curangle + change > iangle)
+ change = iangle-curangle;
+
+ curangle += change;
+ player->angle += change;
+ if (player->angle >= ANGLES)
+ player->angle -= ANGLES;
+
+ ThreeDRefresh ();
+ CalcTics ();
+ } while (curangle != iangle);
+ }
+ else
+ {
+ //
+ // rotate counterclockwise
+ //
+ if (curangle<iangle)
+ curangle += ANGLES;
+ do
+ {
+ change = -(int)tics*DEATHROTATE;
+ if (curangle + change < iangle)
+ change = iangle-curangle;
+
+ curangle += change;
+ player->angle += change;
+ if (player->angle < 0)
+ player->angle += ANGLES;
+
+ ThreeDRefresh ();
+ CalcTics ();
+ } while (curangle != iangle);
+ }
+
+ //
+ // fade to red
+ //
+ FinishPaletteShifts ();
+
+ if(usedoublebuffering) VH_UpdateScreen();
+
+ VL_BarScaledCoord (viewscreenx,viewscreeny,viewwidth,viewheight,4);
+
+ IN_ClearKeysDown ();
+
+ FizzleFade(screenBuffer,viewscreenx,viewscreeny,viewwidth,viewheight,70,false);
+
+ IN_UserInput(100);
+ SD_WaitSoundDone ();
+ ClearMemory();
+
+ gamestate.lives--;
+
+ if (gamestate.lives > -1)
+ {
+ gamestate.health = 100;
+ gamestate.weapon = gamestate.bestweapon
+ = gamestate.chosenweapon = wp_pistol;
+ gamestate.ammo = STARTAMMO;
+ gamestate.keys = 0;
+ pwallstate = pwallpos = 0;
+ gamestate.attackframe = gamestate.attackcount =
+ gamestate.weaponframe = 0;
+
+ if(viewsize != 21)
+ {
+ DrawKeys ();
+ DrawWeapon ();
+ DrawAmmo ();
+ DrawHealth ();
+ DrawFace ();
+ DrawLives ();
+ }
+ }
+}
+
+//==========================================================================
+
+/*
+===================
+=
+= GameLoop
+=
+===================
+*/
+
+void GameLoop (void)
+{
+ boolean died;
+#ifdef MYPROFILE
+ clock_t start,end;
+#endif
+
+restartgame:
+ ClearMemory ();
+ SETFONTCOLOR(0,15);
+ VW_FadeOut();
+ DrawPlayScreen ();
+ died = false;
+ do
+ {
+ if (!loadedgame)
+ gamestate.score = gamestate.oldscore;
+ if(!died || viewsize != 21) DrawScore();
+
+ startgame = false;
+ if (!loadedgame)
+ SetupGameLevel ();
+
+#ifdef SPEAR
+ if (gamestate.mapon == 20) // give them the key allways
+ {
+ gamestate.keys |= 1;
+ DrawKeys ();
+ }
+#endif
+
+ ingame = true;
+ if(loadedgame)
+ {
+ ContinueMusic(lastgamemusicoffset);
+ loadedgame = false;
+ }
+ else StartMusic ();
+
+ if (!died)
+ PreloadGraphics (); // TODO: Let this do something useful!
+ else
+ {
+ died = false;
+ fizzlein = true;
+ }
+
+ DrawLevel ();
+
+#ifdef SPEAR
+startplayloop:
+#endif
+ PlayLoop ();
+
+#ifdef SPEAR
+ if (spearflag)
+ {
+ SD_StopSound();
+ SD_PlaySound(GETSPEARSND);
+ if (DigiMode != sds_Off)
+ {
+ Delay(150);
+ }
+ else
+ SD_WaitSoundDone();
+
+ ClearMemory ();
+ gamestate.oldscore = gamestate.score;
+ gamestate.mapon = 20;
+ SetupGameLevel ();
+ StartMusic ();
+ player->x = spearx;
+ player->y = speary;
+ player->angle = (short)spearangle;
+ spearflag = false;
+ Thrust (0,0);
+ goto startplayloop;
+ }
+#endif
+
+ StopMusic ();
+ ingame = false;
+
+ if (demorecord && playstate != ex_warped)
+ FinishDemoRecord ();
+
+ if (startgame || loadedgame)
+ goto restartgame;
+
+ switch (playstate)
+ {
+ case ex_completed:
+ case ex_secretlevel:
+ if(viewsize == 21) DrawPlayScreen();
+ gamestate.keys = 0;
+ DrawKeys ();
+ VW_FadeOut ();
+
+ ClearMemory ();
+
+ LevelCompleted (); // do the intermission
+ if(viewsize == 21) DrawPlayScreen();
+
+#ifdef SPEARDEMO
+ if (gamestate.mapon == 1)
+ {
+ died = true; // don't "get psyched!"
+
+ VW_FadeOut ();
+
+ ClearMemory ();
+
+ CheckHighScore (gamestate.score,gamestate.mapon+1);
+#ifndef JAPAN
+ strcpy(MainMenu[viewscores].string,STR_VS);
+#endif
+ MainMenu[viewscores].routine = CP_ViewScores;
+ return;
+ }
+#endif
+
+#ifdef JAPDEMO
+ if (gamestate.mapon == 3)
+ {
+ died = true; // don't "get psyched!"
+
+ VW_FadeOut ();
+
+ ClearMemory ();
+
+ CheckHighScore (gamestate.score,gamestate.mapon+1);
+#ifndef JAPAN
+ strcpy(MainMenu[viewscores].string,STR_VS);
+#endif
+ MainMenu[viewscores].routine = CP_ViewScores;
+ return;
+ }
+#endif
+
+ gamestate.oldscore = gamestate.score;
+
+#ifndef SPEAR
+ //
+ // COMING BACK FROM SECRET LEVEL
+ //
+ if (gamestate.mapon == 9)
+ gamestate.mapon = ElevatorBackTo[gamestate.episode]; // back from secret
+ else
+ //
+ // GOING TO SECRET LEVEL
+ //
+ if (playstate == ex_secretlevel)
+ gamestate.mapon = 9;
+#else
+
+#define FROMSECRET1 3
+#define FROMSECRET2 11
+
+ //
+ // GOING TO SECRET LEVEL
+ //
+ if (playstate == ex_secretlevel)
+ switch(gamestate.mapon)
+ {
+ case FROMSECRET1: gamestate.mapon = 18; break;
+ case FROMSECRET2: gamestate.mapon = 19; break;
+ }
+ else
+ //
+ // COMING BACK FROM SECRET LEVEL
+ //
+ if (gamestate.mapon == 18 || gamestate.mapon == 19)
+ switch(gamestate.mapon)
+ {
+ case 18: gamestate.mapon = FROMSECRET1+1; break;
+ case 19: gamestate.mapon = FROMSECRET2+1; break;
+ }
+#endif
+ else
+ //
+ // GOING TO NEXT LEVEL
+ //
+ gamestate.mapon++;
+ break;
+
+ case ex_died:
+ Died ();
+ died = true; // don't "get psyched!"
+
+ if (gamestate.lives > -1)
+ break; // more lives left
+
+ VW_FadeOut ();
+ if(screenHeight % 200 != 0)
+ VL_ClearScreen(0);
+
+#ifdef _arch_dreamcast
+ DC_StatusClearLCD();
+#endif
+
+ ClearMemory ();
+
+ CheckHighScore (gamestate.score,gamestate.mapon+1);
+#ifndef JAPAN
+ strcpy(MainMenu[viewscores].string,STR_VS);
+#endif
+ MainMenu[viewscores].routine = CP_ViewScores;
+ return;
+
+ case ex_victorious:
+ if(viewsize == 21) DrawPlayScreen();
+#ifndef SPEAR
+ VW_FadeOut ();
+#else
+ VL_FadeOut (0,255,0,17,17,300);
+#endif
+ ClearMemory ();
+
+ Victory ();
+
+ ClearMemory ();
+
+ CheckHighScore (gamestate.score,gamestate.mapon+1);
+#ifndef JAPAN
+ strcpy(MainMenu[viewscores].string,STR_VS);
+#endif
+ MainMenu[viewscores].routine = CP_ViewScores;
+ return;
+
+ default:
+ if(viewsize == 21) DrawPlayScreen();
+ ClearMemory ();
+ break;
+ }
+ } while (1);
+}