1 /* Catacomb 3-D Source Code
\r
2 * Copyright (C) 1993-2014 Flat Rock Software
\r
4 * This program is free software; you can redistribute it and/or modify
\r
5 * it under the terms of the GNU General Public License as published by
\r
6 * the Free Software Foundation; either version 2 of the License, or
\r
7 * (at your option) any later version.
\r
9 * This program is distributed in the hope that it will be useful,
\r
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
12 * GNU General Public License for more details.
\r
14 * You should have received a copy of the GNU General Public License along
\r
15 * with this program; if not, write to the Free Software Foundation, Inc.,
\r
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
\r
30 =============================================================================
\r
34 =============================================================================
\r
39 #define CONTROLSLUMP 0
\r
45 #define POTIONLUMP 6
\r
50 #define SCROLLLUMP 11
\r
51 #define CHESTLUMP 12
\r
52 #define PLAYERLUMP 13
\r
53 #define WALL1LUMP 14
\r
54 #define WALL2LUMP 15
\r
55 #define BDOORLUMP 16
\r
56 #define DEMONLUMP 17
\r
63 int lumpstart[NUMLUMPS] = {
\r
64 CONTROLS_LUMP_START,
\r
89 int lumpend[NUMLUMPS] = {
\r
117 =============================================================================
\r
121 =============================================================================
\r
124 unsigned latchpics[NUMLATCHPICS];
\r
125 unsigned tileoffsets[NUMTILE16];
\r
126 unsigned textstarts[27];
\r
129 =============================================================================
\r
133 =============================================================================
\r
136 boolean lumpneeded[NUMLUMPS];
\r
139 //===========================================================================
\r
143 ==========================
\r
147 = Spawn all actors and mark down special places
\r
149 ==========================
\r
152 void ScanInfoPlane (void)
\r
156 unsigned far *start;
\r
158 InitObjList(); // start spawning things with a clean slate
\r
160 memset (lumpneeded,0,sizeof(lumpneeded));
\r
162 start = mapsegs[2];
\r
163 for (y=0;y<mapheight;y++)
\r
164 for (x=0;x<mapwidth;x++)
\r
176 lumpneeded[PLAYERLUMP] = true;
\r
177 SpawnPlayer(x,y,NORTH+tile-1);
\r
187 lumpneeded[tile-5+BOLTLUMP] = true;
\r
188 SpawnBonus(x,y,tile-5);
\r
199 lumpneeded[SCROLLLUMP] = true;
\r
200 SpawnBonus(x,y,B_SCROLL1+tile-12);
\r
204 lumpneeded[GOALLUMP] = true;
\r
205 SpawnBonus(x,y,B_GOAL);
\r
209 lumpneeded[CHESTLUMP] = true;
\r
210 SpawnBonus(x,y,B_CHEST);
\r
214 lumpneeded[WARPLUMP] = true;
\r
219 if (gamestate.difficulty <gd_Hard)
\r
222 if (gamestate.difficulty <gd_Normal)
\r
225 lumpneeded[TROLLLUMP] = true;
\r
230 if (gamestate.difficulty <gd_Hard)
\r
233 if (gamestate.difficulty <gd_Normal)
\r
236 lumpneeded[ORCLUMP] = true;
\r
241 if (gamestate.difficulty <gd_Hard)
\r
244 if (gamestate.difficulty <gd_Normal)
\r
247 lumpneeded[BATLUMP] = true;
\r
252 if (gamestate.difficulty <gd_Hard)
\r
255 if (gamestate.difficulty <gd_Normal)
\r
258 lumpneeded[DEMONLUMP] = true;
\r
263 if (gamestate.difficulty <gd_Hard)
\r
266 if (gamestate.difficulty <gd_Normal)
\r
269 lumpneeded[MAGELUMP] = true;
\r
274 lumpneeded[GRELLUMP] = true;
\r
275 SpawnNemesis (x,y);
\r
279 SpawnBounce (x,y,0);
\r
283 SpawnBounce (x,y,1);
\r
290 lumpneeded[WARPLUMP] = true;
\r
291 SpawnWarp (x,y,tile-30);
\r
298 //==========================================================================
\r
308 void ScanText (void)
\r
313 text = (char _seg *)grsegs[LEVEL1TEXT+mapon];
\r
317 for (i=1;i<=26;i++)
\r
319 while (*text != '\n')
\r
326 textstarts[i] = FP_OFF(text);
\r
331 //==========================================================================
\r
341 static char *levelnames[] =
\r
358 "The Fens of Insanity",
\r
364 void DrawEnterScreen (void)
\r
368 VW_Bar(0,0,VIEWWIDTH,VIEWHEIGHT,9); // Medium blue
\r
370 x = (VIEWWIDTH - (18 * 8)) / 2 -3;
\r
371 y = (VIEWHEIGHT - (5 * 8)) / 2;
\r
372 VW_DrawPic(x / 8,y,ENTERPLAQUEPIC);
\r
376 PrintY = (VIEWHEIGHT/2) + 3;
\r
377 US_CPrint (levelnames[gamestate.mapon]);
\r
380 //==========================================================================
\r
382 boolean tileneeded[NUMFLOORS];
\r
393 void CacheScaleds (void)
\r
396 unsigned source,dest;
\r
399 CA_CacheGrChunk(LEVEL1TEXT+mapon);
\r
403 // make sure we are displaying screenpage 0
\r
407 source = screenloc[screenpage];
\r
408 dest = screenloc[0];
\r
409 VW_ScreenToScreen (source,dest,40,VIEWHEIGHT);
\r
411 VW_SetScreen (dest,0);
\r
416 // cache wall pictures
\r
418 for (i=1;i<NUMFLOORS;i++)
\r
421 SetupScaleWall (walllight1[i]);
\r
422 SetupScaleWall (walllight2[i]);
\r
423 SetupScaleWall (walldark1[i]);
\r
424 SetupScaleWall (walldark2[i]);
\r
428 // cache the actor pictures
\r
430 for (i=0;i<NUMLUMPS;i++)
\r
432 for (j=lumpstart[i];j<=lumpend[i];j++)
\r
435 source = screenloc[0];
\r
438 dest = screenloc[i];
\r
439 VW_ScreenToScreen (source,dest,40,VIEWHEIGHT);
\r
445 //==========================================================================
\r
455 void SetupGameLevel (void)
\r
458 unsigned far *map,tile,spot;
\r
460 memset (tileneeded,0,sizeof(tileneeded));
\r
462 // randomize if not a demo
\r
466 US_InitRndT(false);
\r
467 gamestate.difficulty = gd_Normal;
\r
475 CA_CacheMap (gamestate.mapon);
\r
477 mapwidth = mapheaderseg[mapon]->width;
\r
478 mapheight = mapheaderseg[mapon]->height;
\r
481 // make a lookup table for the maps left edge
\r
484 for (y=0;y<mapheight;y++)
\r
486 farmapylookup[y] = spot;
\r
491 // copy the wall data to a data segment array
\r
493 memset (tilemap,0,sizeof(tilemap));
\r
494 memset (actorat,0,sizeof(actorat));
\r
496 for (y=0;y<mapheight;y++)
\r
497 for (x=0;x<mapwidth;x++)
\r
500 if (tile<NUMFLOORS)
\r
502 tileneeded[tile] = true;
\r
503 tilemap[x][y] = tile;
\r
504 if (tile>=EXPWALLSTART && tile<EXPWALLSTART+NUMEXPWALLS)
\r
506 tileneeded[WALLEXP] = tileneeded[WALLEXP+1]
\r
507 = tileneeded[WALLEXP+2] = true;
\r
511 (unsigned)actorat[x][y] = tile;
\r
517 // decide which graphics are needed and spawn actors
\r
522 // have the caching manager load and purge stuff to make sure all marks
\r
525 CA_LoadAllSounds ();
\r
530 //==========================================================================
\r
533 =====================
\r
537 =====================
\r
540 void LatchDrawPic (unsigned x, unsigned y, unsigned picnum)
\r
542 unsigned wide, height, source, dest;
\r
544 wide = pictable[picnum-STARTPICS].width;
\r
545 height = pictable[picnum-STARTPICS].height;
\r
546 dest = bufferofs + ylookup[y]+x;
\r
547 source = latchpics[picnum-FIRSTLATCHPIC];
\r
552 asm mov bx,[linewidth]
\r
555 asm mov ax,[screenseg]
\r
559 asm mov si,[source]
\r
561 asm mov dx,[height] // scan lines to draw
\r
573 asm mov ds,ax // restore turbo's data segment
\r
579 //==========================================================================
\r
582 =====================
\r
586 =====================
\r
589 void Victory (void)
\r
593 CA_CacheGrChunk (FINALEPIC);
\r
594 VWB_DrawPic (0,0,FINALEPIC);
\r
595 UNMARKGRCHUNK(FINALEPIC);
\r
596 VW_UpdateScreen ();
\r
597 SD_PlaySound (GETBOLTSND);
\r
598 SD_WaitSoundDone ();
\r
599 SD_PlaySound (GETNUKESND);
\r
600 SD_WaitSoundDone ();
\r
601 SD_PlaySound (GETPOTIONSND);
\r
602 SD_WaitSoundDone ();
\r
603 SD_PlaySound (GETKEYSND);
\r
604 SD_WaitSoundDone ();
\r
605 SD_PlaySound (GETSCROLLSND);
\r
606 SD_WaitSoundDone ();
\r
607 SD_PlaySound (GETPOINTSSND);
\r
608 SD_WaitSoundDone ();
\r
609 IN_ClearKeysDown ();
\r
613 //==========================================================================
\r
616 ===================
\r
620 ===================
\r
625 unsigned page1,page2;
\r
627 // fizzle fade screen to grey
\r
630 SD_PlaySound (GAMEOVERSND);
\r
631 bufferofs = screenloc[(screenpage+1)%3];
\r
632 LatchDrawPic(0,0,DEADPIC);
\r
633 FizzleFade(bufferofs,displayofs,VIEWWIDTH,VIEWHEIGHT,false);
\r
634 IN_ClearKeysDown();
\r
636 VW_SetScreen (bufferofs,0);
\r
639 //==========================================================================
\r
642 ===================
\r
646 ===================
\r
649 void NormalScreen (void)
\r
651 VW_SetSplitScreen (200);
\r
652 bufferofs = displayofs = SCREEN1START;
\r
653 VW_Bar(0,0,320,200,0);
\r
654 bufferofs = SCREEN2START;
\r
655 VW_Bar(0,0,320,200,0);
\r
656 VW_SetScreen (displayofs,0);
\r
659 //==========================================================================
\r
662 ===================
\r
666 ===================
\r
669 void DrawPlayScreen (void)
\r
676 VW_Bar (0,0,320,STATUSLINES,7);
\r
679 bufferofs = screenloc[i];
\r
680 VW_Bar (0,0,320,VIEWHEIGHT,7);
\r
684 VW_SetSplitScreen(144);
\r
685 VW_SetScreen(screenloc[0],0);
\r
688 CA_CacheGrChunk (STATUSPIC);
\r
689 CA_CacheGrChunk (SIDEBARSPIC);
\r
691 VW_DrawPic (0,0,STATUSPIC);
\r
695 bufferofs = screenloc[i];
\r
696 VW_DrawPic (33,0,SIDEBARSPIC);
\r
699 grneeded[STATUSPIC]&= ~ca_levelbit;
\r
700 grneeded[SIDEBARSPIC]&= ~ca_levelbit;
\r
701 MM_SetPurge(&grsegs[STATUSPIC],3);
\r
702 MM_SetPurge(&grsegs[SIDEBARSPIC],3);
\r
704 RedrawStatusWindow ();
\r
705 bufferofs = displayofs = screenloc[0];
\r
709 //==========================================================================
\r
712 ===================
\r
716 ===================
\r
719 void LoadLatchMem (void)
\r
722 byte far *src, far *dest;
\r
728 // draw some pics into latch memory
\r
734 latchpics[0] = freelatch;
\r
735 src = (byte _seg *)grsegs[STARTTILE8];
\r
736 dest = MK_FP(0xa000,freelatch);
\r
738 for (i=0;i<NUMTILE8;i++)
\r
743 asm mov dx,SC_INDEX
\r
744 asm mov al,SC_MAPMASK
\r
745 asm mov ah,[BYTE PTR m]
\r
756 src = (byte _seg *)grsegs[STARTTILE16];
\r
758 for (i=0;i<NUMTILE16;i++)
\r
760 CA_CacheGrChunk (STARTTILE16+i);
\r
761 src = (byte _seg *)grsegs[STARTTILE16+i];
\r
764 tileoffsets[i] = FP_OFF(dest);
\r
768 asm mov dx,SC_INDEX
\r
769 asm mov al,SC_MAPMASK
\r
770 asm mov ah,[BYTE PTR m]
\r
776 MM_FreePtr (&grsegs[STARTTILE16+i]);
\r
777 UNMARKGRCHUNK(STARTTILE16+i);
\r
780 tileoffsets[i] = 0;
\r
787 destoff = FP_OFF(dest);
\r
788 for (i=FIRSTLATCHPIC+1;i<FIRSTSCALEPIC;i++)
\r
790 latchpics[i-FIRSTLATCHPIC] = destoff;
\r
791 CA_CacheGrChunk (i);
\r
792 j = pictable[i-STARTPICS].width * pictable[i-STARTPICS].height;
\r
793 VW_MemToScreen (grsegs[i],destoff,j,1);
\r
795 MM_FreePtr (&grsegs[i]);
\r
802 //==========================================================================
\r
805 ===================
\r
809 ===================
\r
812 #define PIXPERFRAME 1600
\r
814 void FizzleFade (unsigned source, unsigned dest,
\r
815 unsigned width,unsigned height, boolean abortable)
\r
817 unsigned drawofs,pagedelta;
\r
818 unsigned char maskb[8] = {1,2,4,8,16,32,64,128};
\r
819 unsigned x,y,p,frame;
\r
822 pagedelta = dest-source;
\r
823 VW_SetScreen (dest,0);
\r
827 asm mov es,[screenseg]
\r
828 asm mov dx,SC_INDEX
\r
829 asm mov al,SC_MAPMASK
\r
837 IN_ReadControl(0,&c);
\r
838 if (c.button0 || c.button1 || Keyboard[sc_Space]
\r
839 || Keyboard[sc_Enter])
\r
841 VW_ScreenToScreen (source,dest,width/8,height);
\r
846 for (p=0;p<PIXPERFRAME;p++)
\r
849 // seperate random value into x/y pair
\r
851 asm mov ax,[WORD PTR rndval]
\r
852 asm mov dx,[WORD PTR rndval+2]
\r
855 asm mov [BYTE PTR y],bl // low 8 bits - 1 = y xoordinate
\r
867 asm mov [x],bx // next 9 bits = x xoordinate
\r
869 // advance to next random element
\r
877 asm mov [WORD PTR rndval],ax
\r
878 asm mov [WORD PTR rndval+2],dx
\r
880 if (x>width || y>height)
\r
882 drawofs = source+ylookup[y];
\r
887 asm mov dx,GC_INDEX
\r
888 asm mov al,GC_BITMASK
\r
889 asm mov ah,BYTE PTR [maskb+si]
\r
892 asm mov si,[drawofs]
\r
898 asm add di,[pagedelta]
\r
900 asm mov dx,GC_INDEX
\r
901 asm mov al,GC_READMAP // leave GC_INDEX set to READMAP
\r
904 asm mov dx,SC_INDEX+1
\r
907 asm mov dx,GC_INDEX+1
\r
912 asm xchg [es:di],bl
\r
914 asm mov dx,SC_INDEX+1
\r
917 asm mov dx,GC_INDEX+1
\r
922 asm xchg [es:di],bl
\r
924 asm mov dx,SC_INDEX+1
\r
927 asm mov dx,GC_INDEX+1
\r
932 asm xchg [es:di],bl
\r
934 asm mov dx,SC_INDEX+1
\r
937 asm mov dx,GC_INDEX+1
\r
942 asm xchg [es:di],bl
\r
944 if (rndval == 1) // entire sequence has been completed
\r
952 while (TimeCount<frame) // don't go too fast
\r
959 //==========================================================================
\r
962 ===================
\r
966 ===================
\r
969 void FizzleOut (int showlevel)
\r
971 unsigned page1,page2;
\r
973 // fizzle fade screen to grey
\r
975 bufferofs = screenloc[(screenpage+1)%3];
\r
977 DrawEnterScreen ();
\r
978 FizzleFade(bufferofs,displayofs,VIEWWIDTH,VIEWHEIGHT,false);
\r
981 //==========================================================================
\r
984 ====================
\r
988 ====================
\r
991 void FreeUpMemory (void)
\r
995 for (i=0;i<NUMSCALEPICS;i++)
\r
996 if (shapedirectory[i])
\r
997 MM_SetPurge (&(memptr)shapedirectory[i],3);
\r
999 for (i=0;i<NUMSCALEWALLS;i++)
\r
1000 if (walldirectory[i])
\r
1001 MM_SetPurge (&(memptr)walldirectory[i],3);
\r
1004 //==========================================================================
\r
1007 ==================
\r
1011 ==================
\r
1014 void DrawHighScores(void)
\r
1016 char buffer[16],*str;
\r
1023 CA_CacheGrChunk (HIGHSCORESPIC);
\r
1024 VWB_DrawPic (0,0,HIGHSCORESPIC);
\r
1025 MM_SetPurge (&grsegs[HIGHSCORESPIC],3);
\r
1026 UNMARKGRCHUNK(HIGHSCORESPIC);
\r
1028 for (i = 0,s = Scores;i < MaxScores;i++,s++)
\r
1030 PrintY = 68 + (16 * i);
\r
1036 US_Print(s->name);
\r
1041 ultoa(s->completed,buffer,10);
\r
1042 for (str = buffer;*str;str++)
\r
1043 *str = *str + (129 - '0'); // Used fixed-width numbers (129...)
\r
1044 USL_MeasureString(buffer,&w,&h);
\r
1045 PrintX = (25 * 8) - 8 - w;
\r
1051 ultoa(s->score,buffer,10);
\r
1052 for (str = buffer;*str;str++)
\r
1053 *str = *str + (129 - '0'); // Used fixed-width numbers (129...)
\r
1054 USL_MeasureString(buffer,&w,&h);
\r
1055 PrintX = (34 * 8) - 8 - w;
\r
1059 fontcolor = F_BLACK;
\r
1065 =======================
\r
1069 =======================
\r
1072 void CheckHighScore (long score,word other)
\r
1076 HighScore myscore;
\r
1078 strcpy(myscore.name,"");
\r
1079 myscore.score = score;
\r
1080 myscore.completed = other;
\r
1082 for (i = 0,n = -1;i < MaxScores;i++)
\r
1086 (myscore.score > Scores[i].score)
\r
1088 (myscore.score == Scores[i].score)
\r
1089 && (myscore.completed > Scores[i].completed)
\r
1093 for (j = MaxScores;--j > i;)
\r
1094 Scores[j] = Scores[j - 1];
\r
1095 Scores[i] = myscore;
\r
1097 HighScoresDirty = true;
\r
1105 // got a high score
\r
1107 DrawHighScores ();
\r
1108 PrintY = 68 + (16 * n);
\r
1110 US_LineInput(PrintX,PrintY,Scores[n].name,nil,true,MaxHighName,100);
\r
1115 //==========================================================================
\r
1118 ===================
\r
1122 ===================
\r
1125 void GameLoop (void)
\r
1127 int i,xl,yl,xh,yh;
\r
1130 clock_t start,end;
\r
1133 DrawPlayScreen ();
\r
1138 gamestate.difficulty = restartgame;
\r
1139 restartgame = gd_Continue;
\r
1140 DrawEnterScreen ();
\r
1145 playstate = gd_Continue;
\r
1147 SetupGameLevel ();
\r
1149 loadedgame = false;
\r
1155 while (start == clock());
\r
1161 itoa(end-start,str,10);
\r
1166 switch (playstate)
\r
1172 CheckHighScore (gamestate.score,gamestate.mapon+1);
\r
1176 if (gamestate.mapon >= NUMLEVELS)
\r
1180 CheckHighScore(gamestate.score,gamestate.mapon+1);
\r
1187 case ex_resetgame:
\r
1188 case ex_loadedgame:
\r
1190 case ex_victorious:
\r
1193 CheckHighScore(gamestate.score,gamestate.mapon+1);
\r