#include "wolfdef.h" #include /********************************** Return the absolute value **********************************/ Word w_abs(int val) { return val>=0 ? val : -val; } /********************************** Return a seeded random number **********************************/ Byte rndtable[256] = { 0, 8, 109, 220, 222, 241, 149, 107, 75, 248, 254, 140, 16, 66, 74, 21, 211, 47, 80, 242, 154, 27, 205, 128, 161, 89, 77, 36, 95,110, 85, 48, 212, 140, 211, 249, 22, 79, 200, 50, 28, 188, 52,140, 202, 120, 68, 145, 62, 70, 184, 190, 91, 197, 152, 224, 149,104, 25, 178, 252, 182, 202, 182, 141, 197, 4, 81, 181, 242, 145, 42, 39, 227, 156, 198, 225, 193, 219, 93, 122, 175, 249, 0, 175,143, 70, 239, 46, 246, 163, 53, 163, 109, 168, 135, 2, 235, 25, 92, 20, 145, 138, 77, 69, 166, 78, 176, 173, 212, 166, 113, 94,161, 41, 50, 239, 49, 111, 164, 70, 60, 2, 37, 171, 75, 136,156, 11, 56, 42, 146, 138, 229, 73, 146, 77, 61, 98, 196, 135,106, 63, 197, 195, 86, 96, 203, 113, 101, 170, 247, 181, 113, 80,250, 108, 7, 255, 237, 129, 226, 79, 107, 112, 166, 103, 241, 24,223, 239, 120, 198, 58, 60, 82, 128, 3, 184, 66, 143, 224, 145,224, 81, 206, 163, 45, 63, 90, 168, 114, 59, 33, 159, 95, 28,139, 123, 98, 125, 196, 15, 70, 194, 253, 54, 14, 109, 226, 71, 17, 161, 93, 186, 87, 244, 138, 20, 52, 123, 251, 26, 36, 17, 46, 52, 231, 232, 76, 31, 221, 84, 37, 216, 165, 212, 106, 197,242, 98, 43, 39, 175, 254, 145, 190, 84, 118, 222, 187, 136, 120,163, 236, 249 }; Word rndindex = 0; Word w_rnd(void) { rndindex = (rndindex+1)&0xff; /* Next index */ return rndtable[rndindex]; /* Return the number */ } /********************************** Return an angle value based on a slope. Assume that x is >= to y. **********************************/ Word AngleFromSlope2(Word y,Word x) { return tantoangle[((LongWord)y<=0) { /* x is positive? */ if (y>=0) { /* y is positive? */ if (x>y) { return AngleFromSlope2(y,x); /* octant 0*/ } else { return ANG90-1-AngleFromSlope2(x,y); /* octant 1 */ } } else { /* y<0 */ y = -y; /* Negate y (Make positive) */ if (x>y) { return -AngleFromSlope2(y,x); /* octant 8 */ } else { return ANG270+AngleFromSlope2 (x,y); /* octant 7 */ } } } else { /* x<0*/ x = -x; /* Force x positive */ if (y>= 0) { /* Is y positive? */ if (x>y) { return ANG180-1-AngleFromSlope2(y,x); /* octant 3 */ } else { return ANG90+AngleFromSlope2(x,y); /* octant 2 */ } } else { /* y<0*/ y = -y; /* Force y positive also */ if (x>y) { return ANG180+AngleFromSlope2 (y,x); /* octant 4 */ } } } return ANG270-1-AngleFromSlope2(x,y); /* octant 5 */ } /********************************** Died() has already spun the view toward the killer GameOver() scales the "game over" sprite in and pulses it until an event **********************************/ void GameOver(void) { topspritenum = S_GAMEOVER; /* Game over words */ topspritescale = 8; /* Start the scale factor */ do { RenderView(); /* Draw the 3-d view */ topspritescale+=8; } while (topspritescale<120); for (;;) { /* Stay here forever */ do { if (WaitTicksEvent(1)) { /* Canceled? */ return; } RenderView(); /* Show the 3-D view */ topspritescale-=2; /* Make smaller */ } while(topspritescale>100); /* Not too small... */ do { if (WaitTicksEvent(1)) { /* Canceled? */ return; } RenderView(); /* Show the 3-D view */ topspritescale+=2; /* Make bigger */ } while (topspritescale<120); /* Not too big... */ } } /********************************** Show the word "Victory" scaling in... **********************************/ void VictoryScale(void) { topspritenum = S_VICTORY; topspritescale = 16; do { RenderView(); topspritescale += 16; } while (topspritescale<240); for (;;) { do { if (WaitTicksEvent(1)) { return; } RenderView(); topspritescale-=4; } while (topspritescale>200); do { if (WaitTicksEvent(1)) { return; } RenderView(); topspritescale+=4; } while (topspritescale<240); } } /********************************** You died... **********************************/ void Died (void) { Word Timer; /* Time mark */ Word Adds; /* Number of tics elapsed */ Word Total; angle_t SrcAngle; /* Angle of view */ angle_t DestAngle; /* Angle of death */ fixed_t Motion; /* Motion constant */ gamestate.attackframe = 0; /* Remove the gun shape */ NoWeaponDraw = TRUE; /* The weapon is not drawn */ PlaySound(SND_PDIE); /* ARRRGGGHHHH!! */ IO_DrawFace(9); /* Show the dead face */ /* find angle to face attacker */ SrcAngle = gamestate.viewangle<=Total) { /* Too much time? */ break; /* Get out now! */ } Total-=Adds; /* Remove elapsed time */ SrcAngle += Motion*Adds; /* Spin */ gamestate.viewangle = SrcAngle>>SHORTTOANGLESHIFT; /* Set the new view angle */ RenderView(); /* Show the view */ } gamestate.viewangle = DestAngle>>SHORTTOANGLESHIFT; /* Finish the motion */ RenderView(); /* Draw the screen */ } /* done */ if (!gamestate.lives) { GameOver(); /* Show Game over... */ } else { WaitEvent(); /* Wait for an event */ gamestate.health = 100; /* Restore health */ if (difficulty) { /* Remove weapons if difficult */ gamestate.weapon = gamestate.pendingweapon = WP_PISTOL; gamestate.machinegun = FALSE; gamestate.chaingun = FALSE; gamestate.missile = FALSE; gamestate.flamethrower = FALSE; gamestate.ammo = STARTAMMO; gamestate.missiles = 0; gamestate.gas = 0; gamestate.maxammo = 99; gamestate.keys = 0; } else { if (gamestate.ammo < STARTAMMO*2) { /* If easy, then reload... */ gamestate.ammo = STARTAMMO*2; } } gamestate.attackframe = 0; /* Reset the attack frame */ gamestate.attackcount = 0; } FadeToBlack(); /* Fade the screen to black */ } /********************************** Calls draw face if time to change **********************************/ void UpdateFace(void) { Word Base; if (facecount>TicCount) { /* Time to change the face? */ facecount-=TicCount; /* Wait a bit */ } else { Base = (gamestate.health <= 25) ? 5 : 0; if (faceframe==Base) { /* Normal frame? */ ++Base; /* Use alternate */ } faceframe=Base; /* Set the new face */ facecount = (w_rnd ()&31)+4; /* Random time */ IO_DrawFace(faceframe); /* Draw the face */ } } /********************************** Prepare for a game loop **********************************/ void PrepPlayLoop (void) { StartSong(SongListPtr[gamestate.mapon+2]); /* start music */ if (!SetupGameLevel()) { /* Load the game map */ ReleaseMap(); /* Release map memory */ ReleaseScalers(); /* Release the compiled scalers */ PlaySong(0); while (!SetupGameLevel()) { /* Try loading it again */ Again: ReleaseMap(); /* Oh oh... */ if (!GameViewSize) { /* Smallest screen? */ BailOut(); /* Leave... */ } --GameViewSize; /* Smaller screen size */ GameViewSize = NewGameWindow(GameViewSize); } } if (!StartupRendering(GameViewSize)) { ReleaseScalers(); goto Again; } topspritescale = 0; /* No overlay sprite */ faceframe = 1; /* First face */ facecount = 1; /* change face next tic */ firstframe = 1; /* Force a fade in */ NoWeaponDraw = 0; /* Allow drawing of weapon */ memset(buttonstate,0,sizeof(buttonstate)); /* Kill the mouse system */ if (playstate!=EX_LOADGAME) { PushWallRec.pwallcount = 0; /* No pushwalls */ gamestate.playtime = 0; /* Game has started */ } else { FinishLoadGame(); /* Finish the load game code */ } RedrawStatusBar(); /* Redraw the main bar */ mousey = 0; /* Reset the mouse y */ playstate = EX_STILLPLAYING; /* Game is in progress */ } /********************************** Play the game **********************************/ void PlayLoop(void) { LongWord Timer; LastTicCount = ReadTick(); do { Timer = ReadTick(); /* How much time has elapsed */ TicCount = (Timer-LastTicCount); gamestate.playtime += TicCount; /* Add the physical time to the elapsed time */ LastTicCount=Timer; if (!SlowDown) { TicCount = 4; /* Adjust from 4 */ } if (TicCount>=5) { TicCount = 4; } IO_CheckInput(); /* Read the controls from the system */ madenoise = FALSE; /* No noise made (Yet) */ MoveDoors(); /* Open and close all doors */ MovePWalls(); /* Move all push walls */ MovePlayer(); /* Move the player */ MoveActors(); /* Move all the bad guys */ MoveMissiles(); /* Move all projectiles */ UpdateFace(); /* Draw BJ's face and animate it */ viewx = actors[0].x; /* Where is the camera? */ viewy = actors[0].y; RenderView(); /* Draw the 3D view */ } while (playstate==EX_STILLPLAYING); StopSong(); } /********************************** Set up new game to start from the beginning **********************************/ void NewGame(void) { nextmap = 0; /* No next map inited */ memset(&gamestate,0,sizeof(gamestate)); /* Zap the game variables */ gamestate.weapon = gamestate.pendingweapon = WP_PISTOL; /* Set the pistol */ gamestate.health = 100; /* Reset the health */ gamestate.ammo = STARTAMMO; /* Reset the ammo */ if (!difficulty) { gamestate.ammo += STARTAMMO; /* Double the ammo if easy */ } gamestate.maxammo = 99; /* Refill the ammo */ gamestate.lives = 3; /* 3 lives */ gamestate.nextextra = EXTRAPOINTS; /* Next free life score needed */ gamestate.godmode = 0; /* Force god mode off */ } /********************************** Redraw the main status bar at the bottom **********************************/ void RedrawStatusBar(void) { IO_DrawStatusBar(); /* Draw the status bar */ IO_DrawFloor(gamestate.mapon); /* Draw the current floor # */ IO_DrawScore(gamestate.score); /* Draw the current score */ IO_DrawTreasure(gamestate.treasure); /* Draw the treasure score */ IO_DrawLives(gamestate.lives); /* Draw the life count */ IO_DrawHealth(gamestate.health); /* Draw the health */ switch (gamestate.weapon) { /* Draw the proper ammo */ case WP_FLAMETHROWER: IO_DrawAmmo(gamestate.gas); break; case WP_MISSILE: IO_DrawAmmo(gamestate.missiles); break; default: IO_DrawAmmo(gamestate.ammo); break; } IO_DrawKeys(gamestate.keys); /* Draw the keys held */ IO_DrawFace(faceframe); /* Draw BJ's face */ } /********************************** Play the game! **********************************/ void GameLoop (void) { for(;;) { skipbrief: ShowGetPsyched(); PrepPlayLoop(); /* Init internal variables */ EndGetPsyched(); PlayLoop(); /* Play the game */ if (playstate == EX_DIED) { /* Did you die? */ --gamestate.lives; /* Remove a life */ Died(); /* Run the death code */ if (!gamestate.lives) { /* No more lives? */ return; /* Exit then */ } goto skipbrief; /* Try again */ } if (playstate == EX_SECRET) { /* Going to the secret level? */ nextmap = MapListPtr->InfoArray[gamestate.mapon].SecretLevel; } else if (playstate != EX_WARPED) { nextmap = MapListPtr->InfoArray[gamestate.mapon].NextLevel; /* Normal warp? */ } /* If warped, then nextmap is preset */ if (nextmap == 0xffff) { /* Last level? */ VictoryScale(); /* You win!! */ ReleaseMap(); /* Unload the map */ Intermission(); /* Display the wrapup... */ ShareWareEnd(); /* End the game for the shareware version */ /* VictoryIntermission(); /* Wrapup for victory! */ return; } ReleaseMap(); /* Unload the game map */ gamestate.keys = 0; /* Zap the keys */ WaitTicks(1); /* Flush the ticker */ WaitTicks(30); /* Wait for the sound to finish */ if (playstate != EX_WARPED) { /* No bonus for warping! */ Intermission(); /* Show the wrap up... */ } gamestate.mapon = nextmap; /* Next level */ } }