/* Catacomb 3-D Source Code * Copyright (C) 1993-2014 Flat Rock Software * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ // C3_GAME.C #include "C3_DEF.H" #pragma hdrstop #ifdef PROFILE #include "TIME.H" #endif /* ============================================================================= LOCAL CONSTANTS ============================================================================= */ #define NUMLUMPS 25 #define CONTROLSLUMP 0 #define ORCLUMP 1 #define TROLLLUMP 2 #define WARPLUMP 3 #define BOLTLUMP 4 #define NUKELUMP 5 #define POTIONLUMP 6 #define RKEYLUMP 7 #define YKEYLUMP 8 #define GKEYLUMP 9 #define BKEYLUMP 10 #define SCROLLLUMP 11 #define CHESTLUMP 12 #define PLAYERLUMP 13 #define WALL1LUMP 14 #define WALL2LUMP 15 #define BDOORLUMP 16 #define DEMONLUMP 17 #define MAGELUMP 18 #define BATLUMP 19 #define GRELLUMP 20 #define GOALLUMP 21 int lumpstart[NUMLUMPS] = { CONTROLS_LUMP_START, ORC_LUMP_START, TROLL_LUMP_START, WARP_LUMP_START, BOLT_LUMP_START, NUKE_LUMP_START, POTION_LUMP_START, RKEY_LUMP_START, YKEY_LUMP_START, GKEY_LUMP_START, BKEY_LUMP_START, SCROLL_LUMP_START, CHEST_LUMP_START, PLAYER_LUMP_START, WALL1_LUMP_START, WALL2_LUMP_START, BDOOR_LUMP_START, DEMON_LUMP_START, MAGE_LUMP_START, BAT_LUMP_START, GREL_LUMP_START, NEMESISPIC }; int lumpend[NUMLUMPS] = { CONTROLS_LUMP_END, ORC_LUMP_END, TROLL_LUMP_END, WARP_LUMP_END, BOLT_LUMP_END, NUKE_LUMP_END, POTION_LUMP_END, RKEY_LUMP_END, YKEY_LUMP_END, GKEY_LUMP_END, BKEY_LUMP_END, SCROLL_LUMP_END, CHEST_LUMP_END, PLAYER_LUMP_END, WALL1_LUMP_END, WALL2_LUMP_END, BDOOR_LUMP_END, DEMON_LUMP_END, MAGE_LUMP_END, BAT_LUMP_END, GREL_LUMP_END, NEMESISPIC }; /* ============================================================================= GLOBAL VARIABLES ============================================================================= */ unsigned latchpics[NUMLATCHPICS]; unsigned tileoffsets[NUMTILE16]; unsigned textstarts[27]; /* ============================================================================= LOCAL VARIABLES ============================================================================= */ boolean lumpneeded[NUMLUMPS]; //=========================================================================== /* ========================== = = ScanInfoPlane = = Spawn all actors and mark down special places = ========================== */ void ScanInfoPlane (void) { unsigned x,y,i,j; int tile; unsigned far *start; InitObjList(); // start spawning things with a clean slate memset (lumpneeded,0,sizeof(lumpneeded)); start = mapsegs[2]; for (y=0;ywidth; mapheight = mapheaderseg[mapon]->height; // // make a lookup table for the maps left edge // spot = 0; for (y=0;y=EXPWALLSTART && tile0) (unsigned)actorat[x][y] = tile; } } // // decide which graphics are needed and spawn actors // ScanInfoPlane (); // // have the caching manager load and purge stuff to make sure all marks // are in memory // CA_LoadAllSounds (); } //========================================================================== /* ===================== = = LatchDrawPic = ===================== */ void LatchDrawPic (unsigned x, unsigned y, unsigned picnum) { unsigned wide, height, source, dest; wide = pictable[picnum-STARTPICS].width; height = pictable[picnum-STARTPICS].height; dest = bufferofs + ylookup[y]+x; source = latchpics[picnum-FIRSTLATCHPIC]; EGAWRITEMODE(1); EGAMAPMASK(15); asm mov bx,[linewidth] asm sub bx,[wide] asm mov ax,[screenseg] asm mov es,ax asm mov ds,ax asm mov si,[source] asm mov di,[dest] asm mov dx,[height] // scan lines to draw asm mov ax,[wide] lineloop: asm mov cx,ax asm rep movsb asm add di,bx asm dec dx asm jnz lineloop asm mov ax,ss asm mov ds,ax // restore turbo's data segment EGAWRITEMODE(0); } //========================================================================== /* ===================== = = Victory = ===================== */ void Victory (void) { FreeUpMemory (); NormalScreen (); CA_CacheGrChunk (FINALEPIC); VWB_DrawPic (0,0,FINALEPIC); UNMARKGRCHUNK(FINALEPIC); VW_UpdateScreen (); SD_PlaySound (GETBOLTSND); SD_WaitSoundDone (); SD_PlaySound (GETNUKESND); SD_WaitSoundDone (); SD_PlaySound (GETPOTIONSND); SD_WaitSoundDone (); SD_PlaySound (GETKEYSND); SD_WaitSoundDone (); SD_PlaySound (GETSCROLLSND); SD_WaitSoundDone (); SD_PlaySound (GETPOINTSSND); SD_WaitSoundDone (); IN_ClearKeysDown (); IN_Ack(); } //========================================================================== /* =================== = = Died = =================== */ void Died (void) { unsigned page1,page2; // // fizzle fade screen to grey // FreeUpMemory (); SD_PlaySound (GAMEOVERSND); bufferofs = screenloc[(screenpage+1)%3]; LatchDrawPic(0,0,DEADPIC); FizzleFade(bufferofs,displayofs,VIEWWIDTH,VIEWHEIGHT,false); IN_ClearKeysDown(); IN_Ack(); VW_SetScreen (bufferofs,0); } //========================================================================== /* =================== = = NormalScreen = =================== */ void NormalScreen (void) { VW_SetSplitScreen (200); bufferofs = displayofs = SCREEN1START; VW_Bar(0,0,320,200,0); bufferofs = SCREEN2START; VW_Bar(0,0,320,200,0); VW_SetScreen (displayofs,0); } //========================================================================== /* =================== = = DrawPlayScreen = =================== */ void DrawPlayScreen (void) { int i,j,p,m; screenpage = 0; bufferofs = 0; VW_Bar (0,0,320,STATUSLINES,7); for (i=0;i<3;i++) { bufferofs = screenloc[i]; VW_Bar (0,0,320,VIEWHEIGHT,7); } VW_SetSplitScreen(144); VW_SetScreen(screenloc[0],0); bufferofs = 0; CA_CacheGrChunk (STATUSPIC); CA_CacheGrChunk (SIDEBARSPIC); VW_DrawPic (0,0,STATUSPIC); for (i=0;i<3;i++) { bufferofs = screenloc[i]; VW_DrawPic (33,0,SIDEBARSPIC); } grneeded[STATUSPIC]&= ~ca_levelbit; grneeded[SIDEBARSPIC]&= ~ca_levelbit; MM_SetPurge(&grsegs[STATUSPIC],3); MM_SetPurge(&grsegs[SIDEBARSPIC],3); RedrawStatusWindow (); bufferofs = displayofs = screenloc[0]; } //========================================================================== /* =================== = = LoadLatchMem = =================== */ void LoadLatchMem (void) { int i,j,p,m; byte far *src, far *dest; unsigned destoff; EGAWRITEMODE(0); // // draw some pics into latch memory // // // tile 8s // latchpics[0] = freelatch; src = (byte _seg *)grsegs[STARTTILE8]; dest = MK_FP(0xa000,freelatch); for (i=0;iwidth || y>height) continue; drawofs = source+ylookup[y]; asm mov cx,[x] asm mov si,cx asm and si,7 asm mov dx,GC_INDEX asm mov al,GC_BITMASK asm mov ah,BYTE PTR [maskb+si] asm out dx,ax asm mov si,[drawofs] asm shr cx,1 asm shr cx,1 asm shr cx,1 asm add si,cx asm mov di,si asm add di,[pagedelta] asm mov dx,GC_INDEX asm mov al,GC_READMAP // leave GC_INDEX set to READMAP asm out dx,al asm mov dx,SC_INDEX+1 asm mov al,1 asm out dx,al asm mov dx,GC_INDEX+1 asm mov al,0 asm out dx,al asm mov bl,[es:si] asm xchg [es:di],bl asm mov dx,SC_INDEX+1 asm mov al,2 asm out dx,al asm mov dx,GC_INDEX+1 asm mov al,1 asm out dx,al asm mov bl,[es:si] asm xchg [es:di],bl asm mov dx,SC_INDEX+1 asm mov al,4 asm out dx,al asm mov dx,GC_INDEX+1 asm mov al,2 asm out dx,al asm mov bl,[es:si] asm xchg [es:di],bl asm mov dx,SC_INDEX+1 asm mov al,8 asm out dx,al asm mov dx,GC_INDEX+1 asm mov al,3 asm out dx,al asm mov bl,[es:si] asm xchg [es:di],bl if (rndval == 1) // entire sequence has been completed { EGABITMASK(255); EGAMAPMASK(15); return; }; } frame++; while (TimeCountname); // // level // ultoa(s->completed,buffer,10); for (str = buffer;*str;str++) *str = *str + (129 - '0'); // Used fixed-width numbers (129...) USL_MeasureString(buffer,&w,&h); PrintX = (25 * 8) - 8 - w; US_Print(buffer); // // score // ultoa(s->score,buffer,10); for (str = buffer;*str;str++) *str = *str + (129 - '0'); // Used fixed-width numbers (129...) USL_MeasureString(buffer,&w,&h); PrintX = (34 * 8) - 8 - w; US_Print(buffer); } fontcolor = F_BLACK; } /* ======================= = = CheckHighScore = ======================= */ void CheckHighScore (long score,word other) { word i,j; int n; HighScore myscore; strcpy(myscore.name,""); myscore.score = score; myscore.completed = other; for (i = 0,n = -1;i < MaxScores;i++) { if ( (myscore.score > Scores[i].score) || ( (myscore.score == Scores[i].score) && (myscore.completed > Scores[i].completed) ) ) { for (j = MaxScores;--j > i;) Scores[j] = Scores[j - 1]; Scores[i] = myscore; n = i; HighScoresDirty = true; break; } } if (n != -1) { // // got a high score // DrawHighScores (); PrintY = 68 + (16 * n); PrintX = 60; US_LineInput(PrintX,PrintY,Scores[n].name,nil,true,MaxHighName,100); } } //========================================================================== /* =================== = = GameLoop = =================== */ void GameLoop (void) { int i,xl,yl,xh,yh; char num[20]; #ifdef PROFILE clock_t start,end; #endif DrawPlayScreen (); restart: if (!loadedgame) { gamestate.difficulty = restartgame; restartgame = gd_Continue; DrawEnterScreen (); } do { playstate = gd_Continue; if (!loadedgame) SetupGameLevel (); else loadedgame = false; CacheScaleds (); #ifdef PROFILE start = clock(); while (start == clock()); start++; #endif PlayLoop (); #ifdef PROFILE end = clock(); itoa(end-start,str,10); Quit (str); #endif switch (playstate) { case ex_died: Died (); NormalScreen (); FreeUpMemory (); CheckHighScore (gamestate.score,gamestate.mapon+1); return; case ex_warped: FizzleOut (true); if (gamestate.mapon >= NUMLEVELS) { Victory (); FreeUpMemory (); CheckHighScore(gamestate.score,gamestate.mapon+1); return; } break; case ex_abort: FreeUpMemory (); return; case ex_resetgame: case ex_loadedgame: goto restart; case ex_victorious: Victory (); FreeUpMemory(); CheckHighScore(gamestate.score,gamestate.mapon+1); return; } } while (1); }