// WL_GAME.C #include "WL_DEF.H" #pragma hdrstop #ifdef MYPROFILE #include #endif /* ============================================================================= LOCAL CONSTANTS ============================================================================= */ /* ============================================================================= GLOBAL VARIABLES ============================================================================= */ boolean ingame,fizzlein; unsigned latchpics[NUMLATCHPICS]; gametype gamestate; long spearx,speary; unsigned spearangle; boolean spearflag; // // ELEVATOR BACK MAPS - REMEMBER (-1)!! // int ElevatorBackTo[]={1,1,7,3,5,3}; void ScanInfoPlane (void); 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 = ========================== */ fixed globalsoundx,globalsoundy; 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 = FixedByFrac(gx,viewcos); yt = FixedByFrac(gy,viewsin); x = (xt - yt) >> TILESHIFT; // // calculate newy // xt = FixedByFrac(gx,viewsin); yt = FixedByFrac(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); if (SD_PlaySound(s)) { globalsoundx = gx; globalsoundy = gy; } } void UpdateSoundLoc(void) { if (SoundPositioned) { SetSoundLoc(globalsoundx,globalsoundy); SD_SetPosition(leftchannel,rightchannel); } } /* ** JAB End */ /* ========================== = = ClearMemory = ========================== */ void ClearMemory (void) { PM_UnlockMainMem(); SD_StopDigitized(); MM_SortMem (); } /* ========================== = = ScanInfoPlane = = Spawn all actors and mark down special places = ========================== */ void ScanInfoPlane (void) { unsigned x,y,i,j; int tile; unsigned far *start; start = mapsegs[1]; for (y=0;ywidth; mapheight = mapheaderseg[mapon]->height; if (mapwidth != 64 || mapheight != 64) Quit ("Map not 64*64!"); // // 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= 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= 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) { int xl,yl; xl = 160-viewwidth/2; yl = (200-STATUSLINES-viewheight)/2; VWB_Bar (0,0,xl-1,200-STATUSLINES,127); VWB_Bar (xl+viewwidth+1,0,xl-2,200-STATUSLINES,127); VWB_Vlin (yl-1,yl+viewheight,xl-1,0); VWB_Vlin (yl-1,yl+viewheight,xl+viewwidth,125); } /* =================== = = DrawAllPlayBorderSides = =================== */ void DrawAllPlayBorderSides (void) { unsigned i,temp; temp = bufferofs; for (i=0;i<3;i++) { bufferofs = screenloc[i]; DrawPlayBorderSides (); } bufferofs = temp; } /* =================== = = DrawPlayBorder = =================== */ void DrawAllPlayBorder (void) { unsigned i,temp; temp = bufferofs; for (i=0;i<3;i++) { bufferofs = screenloc[i]; DrawPlayBorder (); } bufferofs = temp; } /* =================== = = DrawPlayBorder = =================== */ void DrawPlayBorder (void) { int xl,yl; VWB_Bar (0,0,320,200-STATUSLINES,127); xl = 160-viewwidth/2; yl = (200-STATUSLINES-viewheight)/2; VWB_Bar (xl,yl,viewwidth,viewheight,0); VWB_Hlin (xl-1,xl+viewwidth,yl-1,0); VWB_Hlin (xl-1,xl+viewwidth,yl+viewheight,125); VWB_Vlin (yl-1,yl+viewheight,xl-1,0); VWB_Vlin (yl-1,yl+viewheight,xl+viewwidth,125); VWB_Plot (xl-1,yl+viewheight,124); } /* =================== = = DrawPlayScreen = =================== */ void DrawPlayScreen (void) { int i,j,p,m; unsigned temp; VW_FadeOut (); temp = bufferofs; CA_CacheGrChunk (STATUSBARPIC); for (i=0;i<3;i++) { bufferofs = screenloc[i]; DrawPlayBorder (); VWB_DrawPic (0,200-STATUSLINES,STATUSBARPIC); } bufferofs = temp; UNCACHEGRCHUNK (STATUSBARPIC); DrawFace (); DrawHealth (); DrawLives (); DrawLevel (); DrawAmmo (); DrawKeys (); DrawWeapon (); DrawScore (); } //========================================================================== /* ================== = = StartDemoRecord = ================== */ #define MAXDEMOSIZE 8192 void StartDemoRecord (int levelnumber) { MM_GetPtr (&demobuffer,MAXDEMOSIZE); MM_SetLock (&demobuffer,true); demoptr = (char far *)demobuffer; lastdemoptr = demoptr+MAXDEMOSIZE; *demoptr = levelnumber; demoptr += 4; // leave space for length demorecord = true; } /* ================== = = FinishDemoRecord = ================== */ char demoname[13] = "DEMO?."; void FinishDemoRecord (void) { long length,level; demorecord = false; length = demoptr - (char far *)demobuffer; demoptr = ((char far *)demobuffer)+1; *(unsigned far *)demoptr = length; CenterWindow(24,3); PrintY+=6; US_Print(" Demo number (0-9):"); VW_UpdateScreen(); if (US_LineInput (px,py,str,NULL,true,2,0)) { level = atoi (str); if (level>=0 && level<=9) { demoname[4] = '0'+level; CA_WriteFile (demoname,(void far *)demobuffer,length); } } MM_FreePtr (&demobuffer); } //========================================================================== /* ================== = = RecordDemo = = Fades the screen out, then starts a demo. Exits with the screen faded = ================== */ void RecordDemo (void) { int level,esc; CenterWindow(26,3); PrintY+=6; CA_CacheGrChunk(STARTFONT); fontnumber=0; US_Print(" Demo which level(1-10):"); VW_UpdateScreen(); VW_FadeIn (); esc = !US_LineInput (px,py,str,NULL,true,2,0); if (esc) return; level = atoi (str); level--; SETFONTCOLOR(0,15); 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 (); PM_CheckMainMem (); fizzlein = true; PlayLoop (); demoplayback = false; StopMusic (); VW_FadeOut (); ClearMemory (); FinishDemoRecord (); } //========================================================================== /* ================== = = PlayDemo = = Fades the screen out, then starts a demo. Exits with the screen faded = ================== */ 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 = grsegs[dems[demonumber]]; MM_SetLock (&grsegs[dems[demonumber]],true); #else demoname[4] = '0'+demonumber; CA_LoadFile (demoname,&demobuffer); MM_SetLock (&demobuffer,true); demoptr = (char far *)demobuffer; #endif NewGame (1,0); gamestate.mapon = *demoptr++; gamestate.difficulty = gd_hard; length = *((unsigned far *)demoptr)++; demoptr++; lastdemoptr = demoptr-4+length; VW_FadeOut (); SETFONTCOLOR(0,15); DrawPlayScreen (); VW_FadeIn (); startgame = false; demoplayback = true; SetupGameLevel (); StartMusic (); PM_CheckMainMem (); fizzlein = true; PlayLoop (); #ifdef DEMOSEXTERN UNCACHEGRCHUNK(dems[demonumber]); #else MM_FreePtr (&demobuffer); #endif demoplayback = false; StopMusic (); VW_FadeOut (); ClearMemory (); } //========================================================================== /* ================== = = Died = ================== */ #define DEATHROTATE 2 void Died (void) { float fangle; long dx,dy; int iangle,curangle,clockwise,counter,change; gamestate.weapon = -1; // take away weapon SD_PlaySound (PLAYERDEATHSND); // // swing around to face attacker // dx = killerobj->x - player->x; dy = player->y - killerobj->y; fangle = atan2(dy,dx); // returns -pi to pi if (fangle<0) fangle = M_PI*2+fangle; iangle = fangle/(M_PI*2)*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 (clockwiseiangle) 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 (curangleangle += change; if (player->angle < 0) player->angle += ANGLES; ThreeDRefresh (); CalcTics (); } while (curangle != iangle); } // // fade to red // FinishPaletteShifts (); bufferofs += screenofs; VW_Bar (0,0,viewwidth,viewheight,4); IN_ClearKeysDown (); FizzleFade(bufferofs,displayofs+screenofs,viewwidth,viewheight,70,false); bufferofs -= screenofs; IN_UserInput(100); SD_WaitSoundDone (); if (tedlevel == false) // SO'S YA DON'T GET KILLED WHILE LAUNCHING! gamestate.lives--; if (gamestate.lives > -1) { gamestate.health = 100; gamestate.weapon = gamestate.bestweapon = gamestate.chosenweapon = wp_pistol; gamestate.ammo = STARTAMMO; gamestate.keys = 0; gamestate.attackframe = gamestate.attackcount = gamestate.weaponframe = 0; DrawKeys (); DrawWeapon (); DrawAmmo (); DrawHealth (); DrawFace (); DrawLives (); } } //========================================================================== /* =================== = = GameLoop = =================== */ void GameLoop (void) { int i,xl,yl,xh,yh; char num[20]; boolean died; #ifdef MYPROFILE clock_t start,end; #endif restartgame: ClearMemory (); SETFONTCOLOR(0,15); DrawPlayScreen (); died = false; restart: do { if (!loadedgame) gamestate.score = gamestate.oldscore; DrawScore(); startgame = false; if (loadedgame) loadedgame = false; else SetupGameLevel (); #ifdef SPEAR if (gamestate.mapon == 20) // give them the key allways { gamestate.keys |= 1; DrawKeys (); } #endif ingame = true; StartMusic (); PM_CheckMainMem (); if (!died) PreloadGraphics (); else died = false; fizzlein = true; DrawLevel (); startplayloop: PlayLoop (); #ifdef SPEAR if (spearflag) { SD_StopSound(); SD_PlaySound(GETSPEARSND); if (DigiMode != sds_Off) { long lasttimecount = TimeCount; while(TimeCount < lasttimecount+150) //while(DigiPlaying!=false) SD_Poll(); } else SD_WaitSoundDone(); ClearMemory (); gamestate.oldscore = gamestate.score; gamestate.mapon = 20; SetupGameLevel (); StartMusic (); PM_CheckMainMem (); player->x = spearx; player->y = speary; player->angle = 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: gamestate.keys = 0; DrawKeys (); VW_FadeOut (); ClearMemory (); LevelCompleted (); // do the intermission #ifdef SPEARDEMO if (gamestate.mapon == 1) { died = true; // don't "get psyched!" VW_FadeOut (); ClearMemory (); CheckHighScore (gamestate.score,gamestate.mapon+1); #pragma warn -sus #ifndef JAPAN _fstrcpy(MainMenu[viewscores].string,STR_VS); #endif MainMenu[viewscores].routine = CP_ViewScores; #pragma warn +sus return; } #endif #ifdef JAPDEMO if (gamestate.mapon == 3) { died = true; // don't "get psyched!" VW_FadeOut (); ClearMemory (); CheckHighScore (gamestate.score,gamestate.mapon+1); #pragma warn -sus #ifndef JAPAN _fstrcpy(MainMenu[viewscores].string,STR_VS); #endif MainMenu[viewscores].routine = CP_ViewScores; #pragma warn +sus 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 (); ClearMemory (); CheckHighScore (gamestate.score,gamestate.mapon+1); #pragma warn -sus #ifndef JAPAN _fstrcpy(MainMenu[viewscores].string,STR_VS); #endif MainMenu[viewscores].routine = CP_ViewScores; #pragma warn +sus return; case ex_victorious: #ifndef SPEAR VW_FadeOut (); #else VL_FadeOut (0,255,0,17,17,300); #endif ClearMemory (); Victory (); ClearMemory (); CheckHighScore (gamestate.score,gamestate.mapon+1); #pragma warn -sus #ifndef JAPAN _fstrcpy(MainMenu[viewscores].string,STR_VS); #endif MainMenu[viewscores].routine = CP_ViewScores; #pragma warn +sus return; default: ClearMemory (); break; } } while (1); }