/* Catacomb Abyss 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 #include "DEF.H" #include "gelib.h" #pragma hdrstop #ifdef PROFILE #include "TIME.H" #endif /* ============================================================================= LOCAL CONSTANTS ============================================================================= */ #define NUMLUMPS 36 #define ORCLUMP 0 #define TROLLLUMP 1 #define BOLTLUMP 2 #define NUKELUMP 3 #define POTIONLUMP 4 #define RKEYLUMP 5 #define YKEYLUMP 6 #define GKEYLUMP 7 #define BKEYLUMP 8 #define SCROLLLUMP 9 #define CHESTLUMP 10 #define PLAYERLUMP 11 #define WALL1LUMP 12 #define WALL2LUMP 13 #define BDOORLUMP 14 #define DEMONLUMP 15 #define MAGELUMP 16 #define BATLUMP 17 #define GRELLUMP 18 #define TOMBSTONESLUMP 19 #define ZOMBIELUMP 20 #define SPOOKLUMP 21 #define SKELETONLUMP 22 #define RGEMLUMP 23 #define GGEMLUMP 24 #define BGEMLUMP 25 #define YGEMLUMP 26 #define PGEMLUMP 27 #define RKEY2LUMP 28 #define WETMANLUMP 29 #define OBJ_WARPLUMP 30 #define EYELUMP 31 #define REDDEMONLUMP 32 #define PITLUMP 33 #define FTIMELUMP 34 #define WATERCHESTLUMP 35 int lumpstart[NUMLUMPS] = { ORC_LUMP_START, TROLL_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, 0,0,0, DEMON_LUMP_START, MAGE_LUMP_START, BAT_LUMP_START, GREL_LUMP_START, TOMBSTONES_LUMP_START, ZOMBIE_LUMP_START, SPOOK_LUMP_START, SKELDUDE_LUMP_START, RGEM_LUMP_START, GGEM_LUMP_START, BGEM_LUMP_START, YGEM_LUMP_START, PGEM_LUMP_START, RKEY2_LUMP_START, WETMAN_LUMP_START, OBJ_WARP_LUMP_START, EYE_LUMP_START, REDDEMON_LUMP_START, PIT_LUMP_START, TIME_LUMP_START, O_WATER_CHEST_LUMP_START, }; int lumpend[NUMLUMPS] = { ORC_LUMP_END, TROLL_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, 0,0,0, DEMON_LUMP_END, MAGE_LUMP_END, BAT_LUMP_END, GREL_LUMP_END, TOMBSTONES_LUMP_END, ZOMBIE_LUMP_END, SPOOK_LUMP_END, SKELDUDE_LUMP_END, RGEM_LUMP_END, GGEM_LUMP_END, BGEM_LUMP_END, YGEM_LUMP_END, PGEM_LUMP_END, RKEY2_LUMP_END, WETMAN_LUMP_END, OBJ_WARP_LUMP_END, EYE_LUMP_END, REDDEMON_LUMP_END, PIT_LUMP_END, TIME_LUMP_END, O_WATER_CHEST_LUMP_END, }; /* ============================================================================= GLOBAL VARIABLES ============================================================================= */ unsigned latchpics[NUMLATCHPICS]; unsigned tileoffsets[NUMTILE16]; unsigned textstarts[27]; boolean splitscreen=false; /* ============================================================================= LOCAL VARIABLES ============================================================================= */ boolean lumpneeded[NUMLUMPS]; //=========================================================================== //========================================================================== // // // LOCAL PROTOTYPES // // //========================================================================== void CashPoints(void); /* ========================== = = ScanInfoPlane = = Spawn all actors and mark down special places = ========================== */ void ScanInfoPlane (void) { extern unsigned gnd_colors[]; char hibyte; 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;y> 8; tile &= 0xff; if (!tile) continue; switch (tile) { case 1: case 2: case 3: case 4: lumpneeded[PLAYERLUMP] = true; SpawnPlayer(x,y,NORTH+tile-1); break; case 5: case 6: case 7: case 8: case 9: case 10: case 11: lumpneeded[tile-5+BOLTLUMP] = true; SpawnBonus(x,y,tile-5); break; case 29: lumpneeded[RKEY2LUMP] = true; SpawnBonus(x,y,B_RKEY2); break; case 58: case 59: case 60: case 61: case 62: lumpneeded[tile-58+RGEMLUMP] = true; SpawnBonus(x,y,tile-58+B_RGEM); break; case 12: case 13: case 14: case 15: case 16: case 17: case 18: case 19: lumpneeded[SCROLLLUMP] = true; SpawnBonus(x,y,B_SCROLL1+tile-12); break; #if 0 case 20: // goal lumpneeded[GOALLUMP] = true; SpawnBonus(x,y,B_GOAL); break; #endif case 21: // chest if (gnd_colors[gamestate.mapon] == 0x0101) lumpneeded[WATERCHESTLUMP] = true; else lumpneeded[CHESTLUMP] = true; SpawnBonus(x,y,B_CHEST); break; case 31: case 32: case 33: case 34: case 35: lumpneeded[OBJ_WARPLUMP] = true; SpawnWarp (x,y,tile-30); break; case 41: if (gamestate.difficulty width; mapheight = mapheaderseg[mapon]->height; // // make a lookup table for the maps left edge // spot = 0; for (y=0;y>8) == EXP_WALL_CODE) { extern unsigned gnd_colors[]; if (gnd_colors[gamestate.mapon] == 0x0101) tileneeded[WATEREXP] = tileneeded[WATEREXP+1] = tileneeded[WATEREXP+2] = true; else tileneeded[WALLEXP] = tileneeded[WALLEXP+1] = tileneeded[WALLEXP+2] = true; } if (tile0) (unsigned)actorat[x][y] = tile; } spotptr++; } // // Mark any gfx chunks needed // // CA_MarkGrChunk(NORTHICONSPR); // CA_CacheMarks(NULL); // // decide which graphics are needed and spawn actors // zombie_base_delay = 0; // (1*60) + random(1*60); 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 (boolean playsounds) { struct Shape shape; if (playsounds) { 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); } FreeUpMemory(); if (!screenfaded) VW_FadeOut(); screenpage = 1; VW_SetScreen (screenloc[screenpage],0); bufferofs = displayofs = screenloc[screenpage]; VW_Bar (0,0,320,120,0); CA_CacheGrChunk (FINALEPIC); UNMARKGRCHUNK(FINALEPIC); VW_DrawPic(0, 0, FINALEPIC); VW_FadeIn(); #if 0 FreeUpMemory(); if (!screenfaded) VW_FadeOut(); screenpage = 1; VW_SetScreen (screenloc[screenpage],0); if (!FindFile("FINALE."EXT,NULL,1)) Quit("Error: Can't find victory screen."); if (LoadShape("FINALE."EXT,&shape)) TrashProg("Can't load FINALE."EXT); bufferofs = displayofs = screenloc[screenpage]; VW_Bar (0,0,320,120,0); UnpackEGAShapeToScreen(&shape,(320-shape.bmHdr.w)/2,0); FreeShape(&shape); VW_FadeIn(); #endif } //========================================================================== #if 0 /* =================== = = Died = =================== */ void Died (void) { unsigned page1,page2; // // fizzle fade screen to grey // FreeUpMemory (); SD_PlaySound (GAMEOVERSND); bufferofs = screenloc[(screenpage+1)%3]; DisplayMsg("Though fallen, your Spirit ...",NULL); // LatchDrawPic(0,0,DEADPIC); // FizzleFade(bufferofs,displayofs,VIEWWIDTH,VIEWHEIGHT,false); IN_ClearKeysDown(); while (!Keyboard[sc_Enter]); // IN_Ack(); VW_SetScreen (bufferofs,0); VW_ColorBorder(0); } #endif //========================================================================== /* =================== = = 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); splitscreen = false; } //========================================================================== /* =================== = = DrawPlayScreen = =================== */ void DrawPlayScreen (void) { int i,j,p,m; screenpage = 0; bufferofs = 0; VW_Bar (0,0,320,STATUSLINES,0); for (i=0;i<3;i++) { bufferofs = screenloc[i]; VW_Bar (0,0,320,VIEWHEIGHT,0); } splitscreen = true; VW_SetSplitScreen(120); VW_SetScreen(screenloc[0],0); CA_CacheGrChunk (STATUSPIC); bufferofs = 0; VW_DrawPic (0,0,STATUSPIC); grneeded[STATUSPIC] &= ~ca_levelbit; MM_SetPurge(&grsegs[STATUSPIC],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;iname); // // 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); } } #endif //========================================================================== /* =================== = = GameLoop = =================== */ void GameLoop (void) { boolean wait = false; int i,xl,yl,xh,yh; char num[20]; #ifdef PROFILE clock_t start,end; #endif DrawPlayScreen (); IN_ClearKeysDown(); restart: if (!loadedgame) { gamestate.difficulty = restartgame; restartgame = gd_Continue; DrawEnterScreen (); if (gamestate.mapon != 8) fizzlein = true; wait = true; } do { playstate = gd_Continue; if (!loadedgame) SetupGameLevel (); else loadedgame = false; FreeUpMemory(); LoadLatchMem(); CacheScaleds (); if (EASYMODEON) DisplaySMsg("*** NOVICE ***", NULL); else DisplaySMsg("*** WARRIOR ***", NULL); status_delay = 250; RedrawStatusWindow(); if (wait) { VW_WaitVBL(120); wait = false; } #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_abort: FreeUpMemory (); return; case ex_resetgame: NewGame(); case ex_loadedgame: case ex_warped: goto restart; break; } } while (1); } #if 0 // // make wall pictures purgable // for (i=0;i