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
25 =============================================================================
\r
29 =============================================================================
\r
32 #define NUMSCROLLS 8
\r
40 #define STATUSCOLOR 4
\r
41 #define TEXTCOLOR 14
\r
43 #define SIDEBARWIDTH 5
\r
46 #define POWERLINE 80
\r
48 #define SPECTILESTART 18
\r
51 #define SHOTDAMAGE 1
\r
52 #define BIGSHOTDAMAGE 3
\r
55 #define PLAYERSPEED 5120
\r
56 #define RUNSPEED 8192
\r
58 #define SHOTSPEED 10000
\r
60 #define LASTWALLTILE 17
\r
61 #define LASTSPECIALTILE 37
\r
63 #define FIRETIME 4 // DEBUG 60
\r
65 #define HANDPAUSE 60
\r
71 =============================================================================
\r
75 =============================================================================
\r
78 long lastnuke,lasthand;
\r
83 =============================================================================
\r
87 =============================================================================
\r
90 int lasttext,lastcompass;
\r
92 unsigned lastfiretime;
\r
94 int strafeangle[9] = {0,90,180,270,45,135,225,315,0};
\r
97 //===========================================================================
\r
99 void DrawChar (unsigned x, unsigned y, unsigned tile);
\r
100 void RedrawStatusWindow (void);
\r
101 void GiveBolt (void);
\r
102 void TakeBolt (void);
\r
103 void GiveNuke (void);
\r
104 void TakeNuke (void);
\r
105 void GivePotion (void);
\r
106 void TakePotion (void);
\r
107 void GiveKey (int keytype);
\r
108 void TakeKey (int keytype);
\r
109 void GiveScroll (int scrolltype,boolean show);
\r
110 void ReadScroll (int scroll);
\r
111 void GivePoints (int points);
\r
112 void DrawLevelNumber (int number);
\r
113 void DrawText (void);
\r
114 void DrawBars (void);
\r
119 void BigShoot (void);
\r
120 void CastBolt (void);
\r
121 void CastNuke (void);
\r
122 void DrinkPotion (void);
\r
126 void SpawnPlayer (int tilex, int tiley, int dir);
\r
127 void Thrust (int angle, unsigned speed);
\r
128 void T_Player (objtype *ob);
\r
130 void AddPoints (int points);
\r
132 void ClipMove (objtype *ob, long xmove, long ymove);
\r
133 boolean ShotClipMove (objtype *ob, long xmove, long ymove);
\r
135 //===========================================================================
\r
146 void DrawChar (unsigned x, unsigned y, unsigned tile)
\r
148 unsigned junk = latchpics[0];
\r
153 asm mov di,[WORD PTR ylookup+bx]
\r
159 asm add si,[junk] // the damn inline assembler won't reference latchpics
\r
160 asm mov ax,[screenseg]
\r
163 asm mov dx,SCREENWIDTH-1
\r
186 //===========================================================================
\r
191 = RedrawStatusWindow
\r
196 void RedrawStatusWindow (void)
\r
200 DrawLevelNumber (gamestate.mapon);
\r
204 j = gamestate.bolts < SHOWITEMS ? gamestate.bolts : SHOWITEMS;
\r
206 DrawChar(7+i,20,BOLTCHAR);
\r
207 j = gamestate.nukes < SHOWITEMS ? gamestate.nukes : SHOWITEMS;
\r
209 DrawChar(7+i,30,NUKECHAR);
\r
210 j = gamestate.potions < SHOWITEMS ? gamestate.potions : SHOWITEMS;
\r
212 DrawChar(7+i,40,POTIONCHAR);
\r
216 for (j=0;j<gamestate.keys[i];j++)
\r
217 DrawChar(x++,20,KEYCHARS+i);
\r
221 if (gamestate.scrolls[i])
\r
222 DrawChar(x++,30,SCROLLCHARS+i);
\r
230 //===========================================================================
\r
240 void GiveBolt (void)
\r
242 SD_PlaySound (GETBOLTSND);
\r
243 if (++gamestate.bolts<=9)
\r
244 DrawChar(6+gamestate.bolts,20,BOLTCHAR);
\r
256 void TakeBolt (void)
\r
258 SD_PlaySound (USEBOLTSND);
\r
259 if (--gamestate.bolts<=9)
\r
260 DrawChar(7+gamestate.bolts,20,BLANKCHAR);
\r
263 //===========================================================================
\r
273 void GiveNuke (void)
\r
275 SD_PlaySound (GETNUKESND);
\r
276 if (++gamestate.nukes<=9)
\r
277 DrawChar(6+gamestate.nukes,30,NUKECHAR);
\r
289 void TakeNuke (void)
\r
291 SD_PlaySound (USENUKESND);
\r
292 if (--gamestate.nukes<=9)
\r
293 DrawChar(7+gamestate.nukes,30,BLANKCHAR);
\r
296 //===========================================================================
\r
306 void GivePotion (void)
\r
308 SD_PlaySound (GETPOTIONSND);
\r
309 if (++gamestate.potions<=9)
\r
310 DrawChar(6+gamestate.potions,40,POTIONCHAR);
\r
322 void TakePotion (void)
\r
324 SD_PlaySound (USEPOTIONSND);
\r
325 if (--gamestate.potions<=9)
\r
326 DrawChar(7+gamestate.potions,40,BLANKCHAR);
\r
329 //===========================================================================
\r
339 void GiveKey (int keytype)
\r
343 SD_PlaySound (GETKEYSND);
\r
344 gamestate.keys[keytype]++;
\r
348 for (j=0;j<gamestate.keys[i];j++)
\r
349 DrawChar(x++,20,KEYCHARS+i);
\r
362 void TakeKey (int keytype)
\r
366 SD_PlaySound (USEKEYSND);
\r
367 gamestate.keys[keytype]--;
\r
371 for (j=0;j<gamestate.keys[i];j++)
\r
372 DrawChar(x++,20,KEYCHARS+i);
\r
374 DrawChar(x,20,BLANKCHAR);
\r
377 //===========================================================================
\r
387 void GiveScroll (int scrolltype,boolean show)
\r
391 SD_PlaySound (GETSCROLLSND);
\r
392 gamestate.scrolls[scrolltype] = true;
\r
396 if (gamestate.scrolls[i])
\r
397 DrawChar(x++,30,SCROLLCHARS+i);
\r
399 ReadScroll(scrolltype);
\r
402 //===========================================================================
\r
412 void GivePoints (int points)
\r
415 pointsleft += points;
\r
419 //===========================================================================
\r
429 void AddPoints (int points)
\r
434 gamestate.score += points;
\r
436 ltoa (gamestate.score,str,10);
\r
437 len = strlen (str);
\r
440 for (i=0;i<len;i++)
\r
441 DrawChar(x++,40,NUMBERCHARS+str[i]-'0');
\r
445 //===========================================================================
\r
455 void GiveChest (void)
\r
457 SD_PlaySound (GETPOINTSSND);
\r
458 GivePoints ((gamestate.mapon+1)*100);
\r
462 //===========================================================================
\r
472 void GiveGoal (void)
\r
474 SD_PlaySound (GETPOINTSSND);
\r
475 GivePoints (100000);
\r
476 playstate = ex_victorious;
\r
480 //===========================================================================
\r
490 void DrawLevelNumber (int number)
\r
502 VW_Bar (5,4,16,9,STATUSCOLOR);
\r
504 fontcolor = TEXTCOLOR^STATUSCOLOR;
\r
505 US_PrintUnsigned (number+1);
\r
510 //===========================================================================
\r
520 void DrawText (void)
\r
528 // draw a new text description if needed
\r
530 number = *(mapsegs[0]+farmapylookup[player->tiley]+player->tilex)-NAMESTART;
\r
535 if (number == lasttext)
\r
545 text = (char _seg *)grsegs[LEVEL1TEXT+mapon]+textstarts[number];
\r
547 _fmemcpy (str,text,80);
\r
549 VW_Bar (26,4,232,9,STATUSCOLOR);
\r
551 fontcolor = TEXTCOLOR^STATUSCOLOR;
\r
552 US_CPrintLine (str);
\r
556 //===========================================================================
\r
566 void DrawCompass (void)
\r
571 // draw the compass if needed
\r
573 angle = player->angle-ANGLES/4;
\r
574 angle -= ANGLES/32;
\r
577 number = angle/(ANGLES/16);
\r
578 if (number>15) // because 360 angles doesn't divide by 16
\r
581 if (number == lastcompass)
\r
584 lastcompass = number;
\r
587 LatchDrawPic (COMPASSX,COMPASSY,COMPAS1PIC+15-number);
\r
590 //===========================================================================
\r
601 void DrawBars (void)
\r
604 unsigned source,dest,topline;
\r
608 bufferofs = screenloc[i];
\r
609 VW_Bar (34*8,POWERLINE,40,MAXSHOTPOWER,1);
\r
612 asm mov es,[screenseg]
\r
617 if (gamestate.shotpower)
\r
619 topline = MAXSHOTPOWER - gamestate.shotpower;
\r
621 source = latchpics[SHOTPOWERPIC-FIRSTLATCHPIC]+topline*SIDEBARWIDTH;
\r
622 dest = (POWERLINE+topline)*SCREENWIDTH+34;
\r
624 asm mov si,[source]
\r
627 asm mov cx,[WORD PTR gamestate.shotpower]
\r
630 asm mov [es:di+PAGE1START],al
\r
631 asm mov [es:di+PAGE2START],al
\r
632 asm mov [es:di+PAGE3START],al
\r
633 asm mov al,[es:si+1]
\r
634 asm mov [es:di+1+PAGE1START],al
\r
635 asm mov [es:di+1+PAGE2START],al
\r
636 asm mov [es:di+1+PAGE3START],al
\r
637 asm mov al,[es:si+2]
\r
638 asm mov [es:di+2+PAGE1START],al
\r
639 asm mov [es:di+2+PAGE2START],al
\r
640 asm mov [es:di+2+PAGE3START],al
\r
641 asm mov al,[es:si+3]
\r
642 asm mov [es:di+3+PAGE1START],al
\r
643 asm mov [es:di+3+PAGE2START],al
\r
644 asm mov [es:di+3+PAGE3START],al
\r
645 asm mov al,[es:si+4]
\r
646 asm mov [es:di+4+PAGE1START],al
\r
647 asm mov [es:di+4+PAGE2START],al
\r
648 asm mov [es:di+4+PAGE3START],al
\r
650 asm add di,SCREENWIDTH
\r
659 if (gamestate.body)
\r
661 source = latchpics[BODYPIC-FIRSTLATCHPIC];
\r
662 dest = BODYLINE*SCREENWIDTH+34;
\r
664 asm mov si,[source]
\r
667 asm mov cx,[WORD PTR gamestate.body]
\r
670 asm mov [es:di+PAGE1START],al
\r
671 asm mov [es:di+PAGE2START],al
\r
672 asm mov [es:di+PAGE3START],al
\r
673 asm mov al,[es:si+1]
\r
674 asm mov [es:di+1+PAGE1START],al
\r
675 asm mov [es:di+1+PAGE2START],al
\r
676 asm mov [es:di+1+PAGE3START],al
\r
677 asm mov al,[es:si+2]
\r
678 asm mov [es:di+2+PAGE1START],al
\r
679 asm mov [es:di+2+PAGE2START],al
\r
680 asm mov [es:di+2+PAGE3START],al
\r
681 asm mov al,[es:si+3]
\r
682 asm mov [es:di+3+PAGE1START],al
\r
683 asm mov [es:di+3+PAGE2START],al
\r
684 asm mov [es:di+3+PAGE3START],al
\r
685 asm mov al,[es:si+4]
\r
686 asm mov [es:di+4+PAGE1START],al
\r
687 asm mov [es:di+4+PAGE2START],al
\r
688 asm mov [es:di+4+PAGE3START],al
\r
690 asm add di,SCREENWIDTH
\r
696 if (gamestate.body != MAXBODY)
\r
698 source = latchpics[NOBODYPIC-FIRSTLATCHPIC]+gamestate.body*SIDEBARWIDTH;
\r
699 dest = (BODYLINE+gamestate.body)*SCREENWIDTH+34;
\r
700 topline = MAXBODY-gamestate.body;
\r
702 asm mov si,[source]
\r
705 asm mov cx,[WORD PTR topline]
\r
708 asm mov [es:di+PAGE1START],al
\r
709 asm mov [es:di+PAGE2START],al
\r
710 asm mov [es:di+PAGE3START],al
\r
711 asm mov al,[es:si+1]
\r
712 asm mov [es:di+1+PAGE1START],al
\r
713 asm mov [es:di+1+PAGE2START],al
\r
714 asm mov [es:di+1+PAGE3START],al
\r
715 asm mov al,[es:si+2]
\r
716 asm mov [es:di+2+PAGE1START],al
\r
717 asm mov [es:di+2+PAGE2START],al
\r
718 asm mov [es:di+2+PAGE3START],al
\r
719 asm mov al,[es:si+3]
\r
720 asm mov [es:di+3+PAGE1START],al
\r
721 asm mov [es:di+3+PAGE2START],al
\r
722 asm mov [es:di+3+PAGE3START],al
\r
723 asm mov al,[es:si+4]
\r
724 asm mov [es:di+4+PAGE1START],al
\r
725 asm mov [es:di+4+PAGE2START],al
\r
726 asm mov [es:di+4+PAGE3START],al
\r
728 asm add di,SCREENWIDTH
\r
739 =============================================================================
\r
743 =============================================================================
\r
746 void T_Pshot (objtype *ob);
\r
749 extern statetype s_pshot1;
\r
750 extern statetype s_pshot2;
\r
752 extern statetype s_bigpshot1;
\r
753 extern statetype s_bigpshot2;
\r
756 statetype s_pshot1 = {PSHOT1PIC,8,&T_Pshot,&s_pshot2};
\r
757 statetype s_pshot2 = {PSHOT2PIC,8,&T_Pshot,&s_pshot1};
\r
759 statetype s_shotexplode = {PSHOT2PIC,8,NULL,NULL};
\r
761 statetype s_bigpshot1 = {BIGPSHOT1PIC,8,&T_Pshot,&s_bigpshot2};
\r
762 statetype s_bigpshot2 = {BIGPSHOT2PIC,8,&T_Pshot,&s_bigpshot1};
\r
766 ===================
\r
770 ===================
\r
773 void SpawnPShot (void)
\r
775 SpawnNewObjFrac (player->x,player->y,&s_pshot1,PIXRADIUS*14);
\r
776 new->obclass = pshotobj;
\r
777 new->speed = SHOTSPEED;
\r
778 new->angle = player->angle;
\r
781 void SpawnBigPShot (void)
\r
783 SpawnNewObjFrac (player->x,player->y,&s_bigpshot1,24*PIXRADIUS);
\r
784 new->obclass = bigpshotobj;
\r
785 new->speed = SHOTSPEED;
\r
786 new->angle = player->angle;
\r
798 void T_Pshot (objtype *ob)
\r
801 long xmove,ymove,speed;
\r
804 // check current position for monsters having moved into it
\r
806 for (check = player->next; check; check=check->next)
\r
807 if (check->shootable
\r
808 && ob->xl <= check->xh
\r
809 && ob->xh >= check->xl
\r
810 && ob->yl <= check->yh
\r
811 && ob->yh >= check->yl)
\r
813 SD_PlaySound (SHOOTMONSTERSND);
\r
814 if (ob->obclass == bigpshotobj)
\r
815 ShootActor (check,BIGSHOTDAMAGE);
\r
817 ShootActor (check,SHOTDAMAGE);
\r
818 ob->state = &s_shotexplode;
\r
819 ob->ticcount = ob->state->tictime;
\r
825 // move ahead, possibly hitting a wall
\r
827 speed = ob->speed*tics;
\r
829 xmove = FixedByFrac(speed,costable[ob->angle]);
\r
830 ymove = -FixedByFrac(speed,sintable[ob->angle]);
\r
832 if (ShotClipMove(ob,xmove,ymove))
\r
834 ob->state = &s_shotexplode;
\r
835 ob->ticcount = ob->state->tictime;
\r
839 ob->tilex = ob->x >> TILESHIFT;
\r
840 ob->tiley = ob->y >> TILESHIFT;
\r
843 // check final position for monsters hit
\r
845 for (check = player->next; check; check=check->next)
\r
847 && ob->xl <= check->xh
\r
848 && ob->xh >= check->xl
\r
849 && ob->yl <= check->yh
\r
850 && ob->yh >= check->yl)
\r
852 ShootActor (check,SHOTDAMAGE);
\r
853 ob->state = &s_shotexplode;
\r
854 ob->ticcount = ob->state->tictime;
\r
863 =============================================================================
\r
867 =============================================================================
\r
879 void BuildShotPower (void)
\r
881 int newlines,topline;
\r
883 unsigned source,dest;
\r
885 if (gamestate.shotpower == MAXSHOTPOWER)
\r
889 for (i=lasttimecount-tics;i<lasttimecount;i++)
\r
892 gamestate.shotpower += newlines;
\r
894 if (gamestate.shotpower > MAXSHOTPOWER)
\r
896 newlines -= (gamestate.shotpower - MAXSHOTPOWER);
\r
897 gamestate.shotpower = MAXSHOTPOWER;
\r
900 topline = MAXSHOTPOWER - gamestate.shotpower;
\r
902 source = latchpics[L_SHOTBAR]+topline*SIDEBARWIDTH;
\r
903 dest = (POWERLINE+topline)*SCREENWIDTH+34;
\r
905 asm mov es,[screenseg]
\r
906 asm mov si,[source]
\r
913 asm mov cx,[newlines]
\r
916 asm mov [es:di+PAGE1START],al
\r
917 asm mov [es:di+PAGE2START],al
\r
918 asm mov [es:di+PAGE3START],al
\r
919 asm mov al,[es:si+1]
\r
920 asm mov [es:di+1+PAGE1START],al
\r
921 asm mov [es:di+1+PAGE2START],al
\r
922 asm mov [es:di+1+PAGE3START],al
\r
923 asm mov al,[es:si+2]
\r
924 asm mov [es:di+2+PAGE1START],al
\r
925 asm mov [es:di+2+PAGE2START],al
\r
926 asm mov [es:di+2+PAGE3START],al
\r
927 asm mov al,[es:si+3]
\r
928 asm mov [es:di+3+PAGE1START],al
\r
929 asm mov [es:di+3+PAGE2START],al
\r
930 asm mov [es:di+3+PAGE3START],al
\r
931 asm mov al,[es:si+4]
\r
932 asm mov [es:di+4+PAGE1START],al
\r
933 asm mov [es:di+4+PAGE2START],al
\r
934 asm mov [es:di+4+PAGE3START],al
\r
936 asm add di,SCREENWIDTH
\r
946 //===========================================================================
\r
956 void ClearShotPower (void)
\r
958 unsigned source,dest,topline;
\r
960 topline = MAXSHOTPOWER - gamestate.shotpower;
\r
962 source = latchpics[L_NOSHOT]+topline*SIDEBARWIDTH;
\r
963 dest = (POWERLINE+topline)*SCREENWIDTH+34;
\r
965 asm mov es,[screenseg]
\r
966 asm mov si,[source]
\r
969 if (!gamestate.shotpower)
\r
974 asm mov cx,[WORD PTR gamestate.shotpower]
\r
977 asm mov [es:di+PAGE1START],al
\r
978 asm mov [es:di+PAGE2START],al
\r
979 asm mov [es:di+PAGE3START],al
\r
980 asm mov al,[es:si+1]
\r
981 asm mov [es:di+1+PAGE1START],al
\r
982 asm mov [es:di+1+PAGE2START],al
\r
983 asm mov [es:di+1+PAGE3START],al
\r
984 asm mov al,[es:si+2]
\r
985 asm mov [es:di+2+PAGE1START],al
\r
986 asm mov [es:di+2+PAGE2START],al
\r
987 asm mov [es:di+2+PAGE3START],al
\r
988 asm mov al,[es:si+3]
\r
989 asm mov [es:di+3+PAGE1START],al
\r
990 asm mov [es:di+3+PAGE2START],al
\r
991 asm mov [es:di+3+PAGE3START],al
\r
992 asm mov al,[es:si+4]
\r
993 asm mov [es:di+4+PAGE1START],al
\r
994 asm mov [es:di+4+PAGE2START],al
\r
995 asm mov [es:di+4+PAGE3START],al
\r
997 asm add di,SCREENWIDTH
\r
1004 gamestate.shotpower = 0;
\r
1007 //===========================================================================
\r
1019 ClearShotPower ();
\r
1020 SD_PlaySound (SHOOTSND);
\r
1024 //===========================================================================
\r
1034 void BigShoot (void)
\r
1036 ClearShotPower ();
\r
1037 SD_PlaySound (BIGSHOOTSND);
\r
1041 //===========================================================================
\r
1051 void CastBolt (void)
\r
1053 if (!gamestate.bolts)
\r
1055 SD_PlaySound (NOITEMSND);
\r
1060 boltsleft = NUMBOLTS;
\r
1061 bolttimer = BOLTTICS;
\r
1074 void ContinueBolt (void)
\r
1080 bolttimer = BOLTTICS;
\r
1086 //===========================================================================
\r
1096 void CastNuke (void)
\r
1100 if (!gamestate.nukes)
\r
1102 SD_PlaySound (NOITEMSND);
\r
1107 lastnuke = TimeCount;
\r
1109 for (angle = 0; angle < ANGLES; angle+= ANGLES/16)
\r
1111 SpawnNewObjFrac (player->x,player->y,&s_bigpshot1,24*PIXRADIUS);
\r
1112 new->obclass = bigpshotobj;
\r
1113 new->speed = SHOTSPEED;
\r
1114 new->angle = angle;
\r
1118 //===========================================================================
\r
1128 void DrinkPotion (void)
\r
1130 unsigned source,dest,topline;
\r
1132 if (!gamestate.potions)
\r
1134 SD_PlaySound (NOITEMSND);
\r
1139 gamestate.body = MAXBODY;
\r
1142 // draw a full up bar
\r
1144 source = latchpics[L_BODYBAR];
\r
1145 dest = BODYLINE*SCREENWIDTH+34;
\r
1147 asm mov es,[screenseg]
\r
1148 asm mov si,[source]
\r
1153 asm mov cx,MAXBODY
\r
1155 asm mov al,[es:si]
\r
1156 asm mov [es:di+PAGE1START],al
\r
1157 asm mov [es:di+PAGE2START],al
\r
1158 asm mov [es:di+PAGE3START],al
\r
1159 asm mov al,[es:si+1]
\r
1160 asm mov [es:di+1+PAGE1START],al
\r
1161 asm mov [es:di+1+PAGE2START],al
\r
1162 asm mov [es:di+1+PAGE3START],al
\r
1163 asm mov al,[es:si+2]
\r
1164 asm mov [es:di+2+PAGE1START],al
\r
1165 asm mov [es:di+2+PAGE2START],al
\r
1166 asm mov [es:di+2+PAGE3START],al
\r
1167 asm mov al,[es:si+3]
\r
1168 asm mov [es:di+3+PAGE1START],al
\r
1169 asm mov [es:di+3+PAGE2START],al
\r
1170 asm mov [es:di+3+PAGE3START],al
\r
1171 asm mov al,[es:si+4]
\r
1172 asm mov [es:di+4+PAGE1START],al
\r
1173 asm mov [es:di+4+PAGE2START],al
\r
1174 asm mov [es:di+4+PAGE3START],al
\r
1175 asm add di,SCREENWIDTH
\r
1185 //===========================================================================
\r
1195 extern boolean tileneeded[NUMFLOORS];
\r
1197 void ReadScroll (int scroll)
\r
1202 // make wall pictures purgable
\r
1204 for (i=0;i<NUMSCALEWALLS;i++)
\r
1205 if (walldirectory[i])
\r
1206 MM_SetPurge (&(memptr)walldirectory[i],3);
\r
1208 CA_CacheGrChunk (SCROLLTOPPIC);
\r
1209 CA_CacheGrChunk (SCROLL1PIC + scroll);
\r
1210 VW_DrawPic (0,0,SCROLLTOPPIC);
\r
1211 VW_DrawPic (0,32,SCROLL1PIC + scroll);
\r
1212 UNMARKGRCHUNK(SCROLL1PIC + scroll);
\r
1213 UNMARKGRCHUNK(SCROLLTOPPIC);
\r
1214 MM_FreePtr (&grsegs[SCROLL1PIC + scroll]);
\r
1215 MM_FreePtr (&grsegs[SCROLLTOPPIC]);
\r
1218 // cache wall pictures back in
\r
1220 for (i=1;i<NUMFLOORS;i++)
\r
1221 if (tileneeded[i])
\r
1223 SetupScaleWall (walllight1[i]);
\r
1224 SetupScaleWall (walllight2[i]);
\r
1225 SetupScaleWall (walldark1[i]);
\r
1226 SetupScaleWall (walldark2[i]);
\r
1231 IN_ClearKeysDown ();
\r
1246 void TakeDamage (int points)
\r
1248 unsigned source,dest,topline;
\r
1250 if (!gamestate.body || bordertime || godmode)
\r
1253 if (points >= gamestate.body)
\r
1255 points = gamestate.body;
\r
1256 playstate = ex_died;
\r
1259 bordertime = points*FLASHTICS;
\r
1260 VW_ColorBorder (FLASHCOLOR);
\r
1262 if (gamestate.body<MAXBODY/3)
\r
1263 SD_PlaySound (TAKEDMGHURTSND);
\r
1265 SD_PlaySound (TAKEDAMAGESND);
\r
1267 gamestate.body -= points;
\r
1269 // shrink the body bar
\r
1271 source = latchpics[L_NOBODY]+gamestate.body*SIDEBARWIDTH;
\r
1272 dest = (BODYLINE+gamestate.body)*SCREENWIDTH+34;
\r
1275 asm mov es,[screenseg]
\r
1276 asm mov si,[source]
\r
1281 asm mov cx,[points]
\r
1283 asm mov al,[es:si]
\r
1284 asm mov [es:di+PAGE1START],al
\r
1285 asm mov [es:di+PAGE2START],al
\r
1286 asm mov [es:di+PAGE3START],al
\r
1287 asm mov al,[es:si+1]
\r
1288 asm mov [es:di+1+PAGE1START],al
\r
1289 asm mov [es:di+1+PAGE2START],al
\r
1290 asm mov [es:di+1+PAGE3START],al
\r
1291 asm mov al,[es:si+2]
\r
1292 asm mov [es:di+2+PAGE1START],al
\r
1293 asm mov [es:di+2+PAGE2START],al
\r
1294 asm mov [es:di+2+PAGE3START],al
\r
1295 asm mov al,[es:si+3]
\r
1296 asm mov [es:di+3+PAGE1START],al
\r
1297 asm mov [es:di+3+PAGE2START],al
\r
1298 asm mov [es:di+3+PAGE3START],al
\r
1299 asm mov al,[es:si+4]
\r
1300 asm mov [es:di+4+PAGE1START],al
\r
1301 asm mov [es:di+4+PAGE2START],al
\r
1302 asm mov [es:di+4+PAGE3START],al
\r
1304 asm add di,SCREENWIDTH
\r
1316 =============================================================================
\r
1320 =============================================================================
\r
1325 ==================
\r
1329 ==================
\r
1332 void OpenDoor (unsigned bx, unsigned by, unsigned doorbase)
\r
1335 unsigned far *map;
\r
1339 map = mapsegs[0]+farmapylookup[y]+x;
\r
1340 while (tilemap[x][y]-doorbase<4)
\r
1342 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;
\r
1347 map = mapsegs[0]+farmapylookup[y]+x;
\r
1348 while (tilemap[x][y]-doorbase<4)
\r
1350 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;
\r
1356 map = mapsegs[0]+farmapylookup[y]+x;
\r
1357 while (tilemap[x][y]-doorbase<4)
\r
1359 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;
\r
1364 map = mapsegs[0]+farmapylookup[y]+x;
\r
1365 while (tilemap[x][y]-doorbase<4)
\r
1367 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;
\r
1375 ==================
\r
1379 = Returns true if the move is blocked
\r
1381 ==================
\r
1384 boolean HitSpecialTile (unsigned x, unsigned y, unsigned tile)
\r
1392 if (!gamestate.keys[0])
\r
1395 OpenDoor (x,y,SPECTILESTART+0);
\r
1402 if (!gamestate.keys[1])
\r
1405 OpenDoor (x,y,SPECTILESTART+4);
\r
1412 if (!gamestate.keys[2])
\r
1415 OpenDoor (x,y,SPECTILESTART+8);
\r
1422 if (!gamestate.keys[3])
\r
1425 OpenDoor (x,y,SPECTILESTART+12);
\r
1436 ==================
\r
1440 = Returns true if the move is blocked
\r
1442 ==================
\r
1445 boolean TouchActor (objtype *ob, objtype *check)
\r
1447 if (ob->xh < check->xl || ob->xl > check->xh ||
\r
1448 ob->yh < check->yl || ob->yl > check->yh)
\r
1449 return false; // not quite touching
\r
1451 switch (check->obclass)
\r
1454 if (check->temp1 == B_BOLT)
\r
1456 else if (check->temp1 == B_NUKE)
\r
1458 else if (check->temp1 == B_POTION)
\r
1460 else if (check->temp1 >= B_RKEY && check->temp1 <= B_BKEY)
\r
1461 GiveKey (check->temp1-B_RKEY);
\r
1462 else if (check->temp1 >= B_SCROLL1 && check->temp1 <= B_SCROLL8)
\r
1463 GiveScroll (check->temp1-B_SCROLL1,true);
\r
1464 else if (check->temp1 == B_CHEST)
\r
1466 else if (check->temp1 == B_GOAL)
\r
1468 (unsigned)actorat[check->tilex][check->tiley] = 0;
\r
1469 RemoveObj (check);
\r
1479 ==================
\r
1483 ==================
\r
1486 void CalcBounds (objtype *ob)
\r
1489 // calculate hit rect
\r
1491 ob->xl = ob->x - ob->size;
\r
1492 ob->xh = ob->x + ob->size;
\r
1493 ob->yl = ob->y - ob->size;
\r
1494 ob->yh = ob->y + ob->size;
\r
1499 ===================
\r
1503 ===================
\r
1506 boolean LocationInActor (objtype *ob)
\r
1508 int x,y,xmin,ymin,xmax,ymax;
\r
1513 xmin = (ob->x >> TILESHIFT)-2;
\r
1514 ymin = (ob->y >> TILESHIFT)-2;
\r
1518 for (x=xmin;x<xmax;x++)
\r
1519 for (y=ymin;y<ymax;y++)
\r
1521 check = actorat[x][y];
\r
1522 if (check>(objtype *)LASTSPECIALTILE
\r
1523 && check->shootable
\r
1524 && ob->xl <= check->xh
\r
1525 && ob->xh >= check->xl
\r
1526 && ob->yl <= check->yh
\r
1527 && ob->yh >= check->yl)
\r
1536 ===================
\r
1540 = Only checks corners, so the object better be less than one tile wide!
\r
1542 ===================
\r
1545 void ClipMove (objtype *ob, long xmove, long ymove)
\r
1547 int xl,yl,xh,yh,tx,ty,nt1,nt2,x,y;
\r
1548 long intersect,basex,basey,pointx,pointy;
\r
1549 unsigned inside,total,tile;
\r
1554 // move player and check to see if any corners are in solid tiles
\r
1564 xl = ob->xl>>TILESHIFT;
\r
1565 yl = ob->yl>>TILESHIFT;
\r
1567 xh = ob->xh>>TILESHIFT;
\r
1568 yh = ob->yh>>TILESHIFT;
\r
1570 for (y=yl;y<=yh;y++)
\r
1571 for (x=xl;x<=xh;x++)
\r
1573 check = actorat[x][y];
\r
1575 continue; // blank floor, walk ok
\r
1577 if ((unsigned)check<=LASTWALLTILE)
\r
1578 goto blockmove; // solid wall
\r
1580 if ((unsigned)check<=LASTSPECIALTILE)
\r
1582 if ( HitSpecialTile (x,y,(unsigned)check-SPECTILESTART) )
\r
1583 goto blockmove; // whatever it was, it blocked the move
\r
1587 TouchActor(ob,check); // pick up items
\r
1591 // check nearby actors
\r
1593 if (LocationInActor(ob))
\r
1596 if (LocationInActor(ob))
\r
1600 if (LocationInActor(ob))
\r
1604 return; // move is OK!
\r
1609 if (!SD_SoundPlaying())
\r
1610 SD_PlaySound (HITWALLSND);
\r
1629 xl = ob->xl>>TILESHIFT;
\r
1630 yl = ob->yl>>TILESHIFT;
\r
1631 xh = ob->xh>>TILESHIFT;
\r
1632 yh = ob->yh>>TILESHIFT;
\r
1633 if (tilemap[xl][yl] || tilemap[xh][yl]
\r
1634 || tilemap[xh][yh] || tilemap[xl][yh] )
\r
1637 if (xmove>=-2048 && xmove <=2048 && ymove>=-2048 && ymove <=2048)
\r
1646 if (xmove>=-2048 && xmove <=2048 && ymove>=-2048 && ymove <=2048)
\r
1654 //==========================================================================
\r
1658 ===================
\r
1662 = Only checks corners, so the object better be less than one tile wide!
\r
1664 ===================
\r
1667 boolean ShotClipMove (objtype *ob, long xmove, long ymove)
\r
1669 int xl,yl,xh,yh,tx,ty,nt1,nt2,x,y;
\r
1670 long intersect,basex,basey,pointx,pointy;
\r
1671 unsigned inside,total,tile;
\r
1676 // move shot and check to see if any corners are in solid tiles
\r
1686 xl = ob->xl>>TILESHIFT;
\r
1687 yl = ob->yl>>TILESHIFT;
\r
1689 xh = ob->xh>>TILESHIFT;
\r
1690 yh = ob->yh>>TILESHIFT;
\r
1692 for (y=yl;y<=yh;y++)
\r
1693 for (x=xl;x<=xh;x++)
\r
1695 tile = tilemap[x][y];
\r
1698 if ((unsigned)(tile-EXPWALLSTART)<NUMEXPWALLS)
\r
1699 ExplodeWall (x,y);
\r
1703 return false; // move is OK!
\r
1708 SD_PlaySound (SHOOTWALLSND);
\r
1727 xl = ob->xl>>TILESHIFT;
\r
1728 yl = ob->yl>>TILESHIFT;
\r
1729 xh = ob->xh>>TILESHIFT;
\r
1730 yh = ob->yh>>TILESHIFT;
\r
1731 if (tilemap[xl][yl] || tilemap[xh][yl]
\r
1732 || tilemap[xh][yh] || tilemap[xl][yh] )
\r
1735 if (xmove>=-2048 && xmove <=2048 && ymove>=-2048 && ymove <=2048)
\r
1744 if (xmove>=-2048 && xmove <=2048 && ymove>=-2048 && ymove <=2048)
\r
1754 =============================================================================
\r
1758 =============================================================================
\r
1763 void T_Player (objtype *ob);
\r
1765 statetype s_player = {0,0,&T_Player,&s_player};
\r
1775 void SpawnPlayer (int tilex, int tiley, int dir)
\r
1777 player->obclass = playerobj;
\r
1778 player->active = true;
\r
1779 player->tilex = tilex;
\r
1780 player->tiley = tiley;
\r
1781 player->x = ((long)tilex<<TILESHIFT)+TILEGLOBAL/2;
\r
1782 player->y = ((long)tiley<<TILESHIFT)+TILEGLOBAL/2;
\r
1783 player->state = &s_player;
\r
1784 player->angle = (1-dir)*90;
\r
1785 player->size = MINDIST;
\r
1786 CalcBounds (player);
\r
1787 if (player->angle<0)
\r
1788 player->angle += ANGLES;
\r
1793 ===================
\r
1797 ===================
\r
1800 void Thrust (int angle, unsigned speed)
\r
1804 if (lasttimecount>>5 != ((lasttimecount-tics)>>5) )
\r
1809 if (lasttimecount&32)
\r
1810 SD_PlaySound (WALK1SND);
\r
1812 SD_PlaySound (WALK2SND);
\r
1815 xmove = FixedByFrac(speed,costable[angle]);
\r
1816 ymove = -FixedByFrac(speed,sintable[angle]);
\r
1818 ClipMove(player,xmove,ymove);
\r
1819 player->tilex = player->x >> TILESHIFT;
\r
1820 player->tiley = player->y >> TILESHIFT;
\r
1826 =======================
\r
1830 =======================
\r
1833 void ControlMovement (objtype *ob)
\r
1845 // side to side move
\r
1849 else if (mousexmove<0)
\r
1850 speed = -(long)mousexmove*300;
\r
1852 speed = -(long)mousexmove*300;
\r
1854 if (c.xaxis == -1)
\r
1857 speed += RUNSPEED*tics;
\r
1859 speed += PLAYERSPEED*tics;
\r
1861 else if (c.xaxis == 1)
\r
1864 speed -= RUNSPEED*tics;
\r
1866 speed -= PLAYERSPEED*tics;
\r
1871 if (speed >= TILEGLOBAL)
\r
1872 speed = TILEGLOBAL-1;
\r
1873 angle = ob->angle + ANGLES/4;
\r
1874 if (angle >= ANGLES)
\r
1876 Thrust (angle,speed); // move to left
\r
1878 else if (speed < 0)
\r
1880 if (speed <= -TILEGLOBAL)
\r
1881 speed = -TILEGLOBAL+1;
\r
1882 angle = ob->angle - ANGLES/4;
\r
1885 Thrust (angle,-speed); // move to right
\r
1899 ob->angle -= tics;
\r
1900 if (running) // fast turn
\r
1901 ob->angle -= tics;
\r
1903 else if (c.xaxis == -1)
\r
1906 if (running) // fast turn
\r
1907 ob->angle += tics;
\r
1910 ob->angle -= (mousexmove/10);
\r
1912 if (ob->angle >= ANGLES)
\r
1913 ob->angle -= ANGLES;
\r
1914 if (ob->angle < 0)
\r
1915 ob->angle += ANGLES;
\r
1920 // forward/backwards move
\r
1924 else if (mouseymove<0)
\r
1925 speed = -(long)mouseymove*500;
\r
1927 speed = -(long)mouseymove*200;
\r
1929 if (c.yaxis == -1)
\r
1932 speed += RUNSPEED*tics;
\r
1934 speed += PLAYERSPEED*tics;
\r
1936 else if (c.yaxis == 1)
\r
1939 speed -= RUNSPEED*tics;
\r
1941 speed -= PLAYERSPEED*tics;
\r
1946 if (speed >= TILEGLOBAL)
\r
1947 speed = TILEGLOBAL-1;
\r
1948 Thrust (ob->angle,speed); // move forwards
\r
1950 else if (speed < 0)
\r
1952 if (speed <= -TILEGLOBAL)
\r
1953 speed = -TILEGLOBAL+1;
\r
1954 angle = ob->angle + ANGLES/2;
\r
1955 if (angle >= ANGLES)
\r
1957 Thrust (angle,-speed); // move backwards
\r
1970 void T_Player (objtype *ob)
\r
1972 int angle,speed,scroll;
\r
1973 unsigned text,tilex,tiley;
\r
1977 ControlMovement (ob);
\r
1985 handheight+=(tics<<2);
\r
1986 if (handheight>MAXHANDHEIGHT)
\r
1987 handheight = MAXHANDHEIGHT;
\r
1990 lasthand = lasttimecount;
\r
1996 handheight+=(tics<<2);
\r
1997 if (handheight>MAXHANDHEIGHT)
\r
1998 handheight = MAXHANDHEIGHT;
\r
2000 if ((unsigned)TimeCount/FIRETIME != lastfiretime)
\r
2001 BuildShotPower ();
\r
2002 lasthand = lasttimecount;
\r
2006 if (lasttimecount > lasthand+HANDPAUSE)
\r
2008 handheight-=(tics<<1);
\r
2013 if (gamestate.shotpower == MAXSHOTPOWER)
\r
2015 lastfiretime = (unsigned)TimeCount/FIRETIME;
\r
2018 else if (gamestate.shotpower)
\r
2020 lastfiretime = (unsigned)TimeCount/FIRETIME;
\r
2027 // special actions
\r
2030 if ( (Keyboard[sc_Space] || Keyboard[sc_H]) && gamestate.body != MAXBODY)
\r
2033 if (Keyboard[sc_B] && !boltsleft)
\r
2036 if ( (Keyboard[sc_Enter] || Keyboard[sc_N]) && TimeCount-lastnuke > NUKETIME)
\r
2039 scroll = LastScan-2;
\r
2040 if ( scroll>=0 && scroll<NUMSCROLLS && gamestate.scrolls[scroll])
\r
2041 ReadScroll (scroll);
\r