1 /* Catacomb Armageddon 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
26 =============================================================================
\r
30 =============================================================================
\r
33 ////////#define NUMSCROLLS 8
\r
41 #define STATUSCOLOR 8
\r
42 #define TEXTCOLOR 14
\r
44 #define SIDEBARWIDTH 5
\r
47 #define POWERLINE 80
\r
49 #define SPECTILESTART 0 // 18
\r
52 #define SHOTDAMAGE 1
\r
53 #define BIGSHOTDAMAGE 3
\r
56 #define PLAYERSPEED 5120
\r
57 #define RUNSPEED (8192<<1)
\r
59 #define SHOTSPEED 10000
\r
61 //#define LASTWALLTILE 47
\r
62 //#define LASTSPECIALTILE 37
\r
64 #define LASTTILE (LASTWALLPIC-FIRSTWALLPIC) // 47
\r
68 #define HANDPAUSE 60
\r
70 #define RIGHTEDGE 205;
\r
71 #define LEFTEDGE 95;
\r
77 =============================================================================
\r
81 =============================================================================
\r
84 long lastnuke,lasthand;
\r
87 int boltsleft,bolttimer;
\r
88 short RadarXY[MAX_RADAR_BLIPS][3]={-1,-1,-1};
\r
89 short radarx=RADARX,radary=RADARY,radar_xcenter=RADAR_XCENTER,radar_ycenter=RADAR_YCENTER;
\r
90 int key_x[4]={24,27,27,24},key_y[4]={30,57,30,57};
\r
92 boolean redraw_gems,button0down;
\r
95 =============================================================================
\r
99 =============================================================================
\r
103 unsigned lastfiretime;
\r
105 int strafeangle[9] = {0,90,180,270,45,135,225,315,0};
\r
107 short RotateAngle = -1; // -1 == No Angle to turn to...
\r
108 short FreezeTime = 0; // Stops all think (except player)
\r
109 short RotateSpeed; // Speed (and dir) to rotate..
\r
112 //===========================================================================
\r
114 void CalcBounds(objtype *ob);
\r
115 boolean VerifyGateExit(void);
\r
116 void DrawNSEWIcons(void);
\r
117 void DrawGems(void);
\r
118 void DrawRadar (void);
\r
119 void DrawChar (unsigned x, unsigned y, unsigned tile);
\r
120 void RedrawStatusWindow (void);
\r
121 void GiveBolt (void);
\r
122 void TakeBolt (void);
\r
123 void GiveNuke (void);
\r
124 void TakeNuke (void);
\r
125 void GivePotion (void);
\r
126 void TakePotion (void);
\r
127 void GiveKey (int keytype);
\r
128 void TakeKey (int keytype);
\r
129 ////////////void GiveScroll (int scrolltype,boolean show);
\r
130 ////////////void ReadScroll (int scroll);
\r
131 ////////////void DrawScrolls(void);
\r
133 void DrawNum(short x,short y,short value,short maxdigits);
\r
138 void BigShoot (void);
\r
139 void CastBolt (void);
\r
140 void CastNuke (void);
\r
141 void DrinkPotion (void);
\r
144 void DrawHealth(void);
\r
146 void SpawnPlayer (int tilex, int tiley, int dir);
\r
147 void Thrust (int angle, unsigned speed);
\r
148 void T_Player (objtype *ob);
\r
150 //void AddPoints (int points);
\r
152 void ClipMove (objtype *ob, long xmove, long ymove);
\r
153 boolean ShotClipMove (objtype *ob, long xmove, long ymove);
\r
155 //===========================================================================
\r
166 void DrawChar (unsigned x, unsigned y, unsigned tile)
\r
168 unsigned junk = latchpics[0];
\r
173 asm mov di,[WORD PTR ylookup+bx]
\r
179 asm add si,[junk] // the damn inline assembler won't reference latchpics
\r
180 asm mov ax,[screenseg]
\r
183 asm mov dx,SCREENWIDTH-1
\r
206 //===========================================================================
\r
211 = RedrawStatusWindow
\r
216 void RedrawStatusWindow (void)
\r
221 for (keytype=0; keytype<4; keytype++)
\r
222 DrawNum(key_x[keytype],key_y[keytype],gamestate.keys[keytype],2);
\r
223 DrawNum(20,54,gamestate.potions,2);
\r
224 DrawNum(20,36,gamestate.nukes,2);
\r
225 DrawNum(20,18,gamestate.bolts,2);
\r
231 //////// DrawScrolls();
\r
232 redraw_gems = false;
\r
236 //===========================================================================
\r
246 void GiveBolt (void)
\r
248 if (gamestate.bolts == 99)
\r
251 SD_PlaySound (GETBOLTSND);
\r
252 DrawNum(20,18,++gamestate.bolts,2);
\r
264 void TakeBolt (void)
\r
266 SD_PlaySound (USEBOLTSND);
\r
267 DrawNum(20,18,--gamestate.bolts,2);
\r
270 //===========================================================================
\r
280 void GiveNuke (void)
\r
282 if (gamestate.nukes == 99)
\r
285 SD_PlaySound (GETNUKESND);
\r
286 DrawNum(20,36,++gamestate.nukes,2);
\r
298 void TakeNuke (void)
\r
300 SD_PlaySound (USENUKESND);
\r
301 DrawNum(20,36,--gamestate.nukes,2);
\r
304 //===========================================================================
\r
314 void GivePotion (void)
\r
316 if (gamestate.potions == 99)
\r
319 SD_PlaySound (GETPOTIONSND);
\r
320 DrawNum(20,54,++gamestate.potions,2);
\r
332 void TakePotion (void)
\r
334 SD_PlaySound (USEPOTIONSND);
\r
335 DrawNum(20,54,--gamestate.potions,2);
\r
338 //===========================================================================
\r
348 void GiveKey (int keytype)
\r
352 if (gamestate.keys[keytype] == 99)
\r
355 SD_PlaySound (GETKEYSND);
\r
356 DrawNum(key_x[keytype],key_y[keytype],++gamestate.keys[keytype],2);
\r
368 void TakeKey (int keytype)
\r
371 char *key_colors[] = {"a RED key",
\r
377 SD_PlaySound (USEKEYSND);
\r
378 DrawNum(key_x[keytype],key_y[keytype],--gamestate.keys[keytype],2);
\r
379 displayofs = bufferofs = screenloc[screenpage];
\r
380 CenterWindow(20,5);
\r
381 US_CPrint("\nYou use\n");
\r
382 US_CPrint(key_colors[keytype]);
\r
388 //===========================================================================
\r
398 void GiveGem (int gemtype)
\r
403 SD_PlaySound (GETKEYSND);
\r
404 DrawNum(key_x[keytype],key_y[keytype],++gamestate.keys[keytype],2);
\r
417 void TakeGem (int gemtype)
\r
422 SD_PlaySound (USEKEYSND);
\r
423 DrawNum(key_x[keytype],key_y[keytype],--gamestate.keys[keytype],2);
\r
439 redraw_gems = false;
\r
442 LatchDrawPic (31,51,RADAR_BOTTOMPIC);
\r
443 for (loop=0; loop<5; loop++)
\r
444 if (gamestate.gems[loop])
\r
445 LatchDrawPic (32+loop,53,RADAR_RGEMPIC+loop);
\r
448 //===========================================================================
\r
460 void GiveScroll (int scrolltype,boolean show)
\r
462 int i,j,x,y,scrollnum;
\r
464 SD_PlaySound (GETSCROLLSND);
\r
465 gamestate.scrolls[scrolltype] = true;
\r
467 y = 30 + ((scrolltype > 3) * 10);
\r
468 x = 26 + (scrolltype % 4);
\r
469 DrawChar(x,y,SCROLLCHARS+scrolltype);
\r
472 ReadScroll(scrolltype);
\r
480 = Force draw of all scrolls
\r
488 VW_Bar(210,30,30,18,0xf);
\r
490 for (loop=0;loop<8;loop++)
\r
491 if (gamestate.scrolls[loop])
\r
493 y = 30 + ((loop > 3) * 10);
\r
494 x = 26 + (loop % 4);
\r
495 DrawChar(x,y,SCROLLCHARS+loop);
\r
501 //===========================================================================
\r
512 void GivePoints (int points)
\r
515 pointsleft += points;
\r
520 //===========================================================================
\r
531 void AddPoints (int points)
\r
536 gamestate.score += points;
\r
538 ltoa (gamestate.score,str,10);
\r
539 len = strlen (str);
\r
542 for (i=0;i<len;i++)
\r
543 DrawChar(x++,40,NUMBERCHARS+str[i]-'0');
\r
548 //===========================================================================
\r
562 percentage = PERCENTAGE(100,MAXBODY,gamestate.body,9);
\r
564 DrawNum(11,57,percentage,3);
\r
566 if (percentage > 75)
\r
569 if (percentage > 50)
\r
572 if (percentage > 25)
\r
580 CA_CacheGrChunk (picnum);
\r
586 UNMARKGRCHUNK(picnum);
\r
587 // VW_DrawPic(8,14,picnum);
\r
588 VW_DrawPic(10,14,picnum);
\r
591 LatchDrawPic(10,14,picnum);
\r
594 //===========================================================================
\r
603 void DrawFreezeTime()
\r
606 percentage = PERCENTAGE(100,MAXFREEZETIME,(long)FreezeTime,7);
\r
607 DrawNum(23,70,percentage,3);
\r
610 //===========================================================================
\r
619 void DrawNum(short x,short y,short value,short maxdigits)
\r
621 char str[10],len,i;
\r
623 itoa(value,str,10);
\r
626 for (i=len; i<maxdigits; i++)
\r
627 DrawChar(x++,y,BLANKCHAR);
\r
629 for (i=0;i<len;i++)
\r
630 DrawChar(x++,y,NUMBERCHARS+str[i]-'0');
\r
633 //===========================================================================
\r
643 void GiveChest(void)
\r
647 for (i=0;i<random(4);i++)
\r
650 SD_WaitSoundDone();
\r
653 for (i=0;i<random(3);i++)
\r
656 SD_WaitSoundDone();
\r
659 for (i=0;i<random(2);i++)
\r
662 SD_WaitSoundDone();
\r
667 //===========================================================================
\r
677 void GiveGoal (void)
\r
679 SD_PlaySound (GETPOINTSSND);
\r
680 playstate = ex_victorious;
\r
684 //===========================================================================
\r
695 void DrawLevelNumber (int number)
\r
707 VW_Bar (5,4,16,9,STATUSCOLOR);
\r
709 fontcolor = TEXTCOLOR^STATUSCOLOR;
\r
710 US_PrintUnsigned (number+1);
\r
716 //===========================================================================
\r
726 void DrawText (boolean draw_text_whether_it_needs_it_or_not)
\r
734 // draw a new text description if needed
\r
736 number = *(mapsegs[0]+farmapylookup[player->tiley]+player->tilex)-NAMESTART;
\r
741 if ((number == lasttext) && (!draw_text_whether_it_needs_it_or_not))
\r
746 text = (char _seg *)grsegs[LEVEL1TEXT+mapon]+textstarts[number];
\r
748 _fmemcpy (str,text,80);
\r
749 DisplayMsg(str,NULL);
\r
752 //===========================================================================
\r
762 char DisplayMsg(char *text,char *choices)
\r
772 VW_Bar (WindowX,2,WindowW,8,STATUSCOLOR);
\r
774 fontcolor = TEXTCOLOR^STATUSCOLOR;
\r
775 US_CPrintLine (text);
\r
780 ch=GetKeyChoice(choices,true);
\r
794 char DisplaySMsg(char *text,char *choices)
\r
804 VW_Bar(WindowX,PrintY+1,WindowW,8,STATUSCOLOR);
\r
806 fontcolor = TEXTCOLOR^STATUSCOLOR;
\r
807 US_CPrintLine (text);
\r
812 ch=GetKeyChoice(choices,true);
\r
819 //===========================================================================
\r
829 void DrawRadar (void)
\r
835 LatchDrawPic (radarx,radary,RADAR_TOPPIC);
\r
838 asm mov dx,GC_INDEX
\r
839 asm mov ax,2*256+GC_MODE
\r
840 asm out dx,ax // write mode 2
\r
842 asm mov ax,GC_DATAROTATE
\r
843 asm out dx,ax // no rotation / logical operation
\r
845 asm mov dx,SC_INDEX
\r
846 asm mov al,SC_MAPMASK
\r
848 asm out dx,ax // write to all four planes
\r
852 while (RadarXY[objnum][2] != -1)
\r
854 RadarBlip(radar_xcenter+RadarXY[objnum][0],radar_ycenter+RadarXY[objnum][1],RadarXY[objnum][2]);
\r
859 asm mov dx,GC_INDEX
\r
860 asm mov ax,255*256+GC_BITMASK
\r
861 asm out dx,ax // reset bitmask to %11111111
\r
865 //===========================================================================
\r
868 //--------------------------------------------------------------------------
\r
869 // DrawNSEWIcons(void)
\r
870 //--------------------------------------------------------------------------
\r
872 void DrawRadarObj(short dx, short dy, unsigned sprnum,signed long psin,signed long pcos);
\r
874 void DrawNSEWIcons()
\r
878 x = -FixedByFrac(RADAR_X_IRADIUS,costable[player->angle]);
\r
879 y = -FixedByFrac(RADAR_Y_IRADIUS,sintable[player->angle]);
\r
881 VWB_DrawSprite(radar_xcenter+x-3,radar_ycenter+y-3,NORTHICONSPR);
\r
894 void DrawBars (void)
\r
897 unsigned source,dest,topline;
\r
901 bufferofs = screenloc[i];
\r
902 VW_Bar (34*8,POWERLINE,40,MAXSHOTPOWER,1);
\r
905 asm mov es,[screenseg]
\r
910 if (gamestate.shotpower)
\r
912 topline = MAXSHOTPOWER - gamestate.shotpower;
\r
914 source = latchpics[SHOTPOWERPIC-FIRSTLATCHPIC]+topline*SIDEBARWIDTH;
\r
915 dest = (POWERLINE+topline)*SCREENWIDTH+34;
\r
917 asm mov si,[source]
\r
920 asm mov cx,[WORD PTR gamestate.shotpower]
\r
923 asm mov [es:di+PAGE1START],al
\r
924 asm mov [es:di+PAGE2START],al
\r
925 asm mov [es:di+PAGE3START],al
\r
926 asm mov al,[es:si+1]
\r
927 asm mov [es:di+1+PAGE1START],al
\r
928 asm mov [es:di+1+PAGE2START],al
\r
929 asm mov [es:di+1+PAGE3START],al
\r
930 asm mov al,[es:si+2]
\r
931 asm mov [es:di+2+PAGE1START],al
\r
932 asm mov [es:di+2+PAGE2START],al
\r
933 asm mov [es:di+2+PAGE3START],al
\r
934 asm mov al,[es:si+3]
\r
935 asm mov [es:di+3+PAGE1START],al
\r
936 asm mov [es:di+3+PAGE2START],al
\r
937 asm mov [es:di+3+PAGE3START],al
\r
938 asm mov al,[es:si+4]
\r
939 asm mov [es:di+4+PAGE1START],al
\r
940 asm mov [es:di+4+PAGE2START],al
\r
941 asm mov [es:di+4+PAGE3START],al
\r
943 asm add di,SCREENWIDTH
\r
952 if (gamestate.body)
\r
954 source = latchpics[BODYPIC-FIRSTLATCHPIC];
\r
955 dest = BODYLINE*SCREENWIDTH+34;
\r
957 asm mov si,[source]
\r
960 asm mov cx,[WORD PTR gamestate.body]
\r
963 asm mov [es:di+PAGE1START],al
\r
964 asm mov [es:di+PAGE2START],al
\r
965 asm mov [es:di+PAGE3START],al
\r
966 asm mov al,[es:si+1]
\r
967 asm mov [es:di+1+PAGE1START],al
\r
968 asm mov [es:di+1+PAGE2START],al
\r
969 asm mov [es:di+1+PAGE3START],al
\r
970 asm mov al,[es:si+2]
\r
971 asm mov [es:di+2+PAGE1START],al
\r
972 asm mov [es:di+2+PAGE2START],al
\r
973 asm mov [es:di+2+PAGE3START],al
\r
974 asm mov al,[es:si+3]
\r
975 asm mov [es:di+3+PAGE1START],al
\r
976 asm mov [es:di+3+PAGE2START],al
\r
977 asm mov [es:di+3+PAGE3START],al
\r
978 asm mov al,[es:si+4]
\r
979 asm mov [es:di+4+PAGE1START],al
\r
980 asm mov [es:di+4+PAGE2START],al
\r
981 asm mov [es:di+4+PAGE3START],al
\r
983 asm add di,SCREENWIDTH
\r
989 if (gamestate.body != MAXBODY)
\r
991 source = latchpics[NOBODYPIC-FIRSTLATCHPIC]+gamestate.body*SIDEBARWIDTH;
\r
992 dest = (BODYLINE+gamestate.body)*SCREENWIDTH+34;
\r
993 topline = MAXBODY-gamestate.body;
\r
995 asm mov si,[source]
\r
998 asm mov cx,[WORD PTR topline]
\r
1000 asm mov al,[es:si]
\r
1001 asm mov [es:di+PAGE1START],al
\r
1002 asm mov [es:di+PAGE2START],al
\r
1003 asm mov [es:di+PAGE3START],al
\r
1004 asm mov al,[es:si+1]
\r
1005 asm mov [es:di+1+PAGE1START],al
\r
1006 asm mov [es:di+1+PAGE2START],al
\r
1007 asm mov [es:di+1+PAGE3START],al
\r
1008 asm mov al,[es:si+2]
\r
1009 asm mov [es:di+2+PAGE1START],al
\r
1010 asm mov [es:di+2+PAGE2START],al
\r
1011 asm mov [es:di+2+PAGE3START],al
\r
1012 asm mov al,[es:si+3]
\r
1013 asm mov [es:di+3+PAGE1START],al
\r
1014 asm mov [es:di+3+PAGE2START],al
\r
1015 asm mov [es:di+3+PAGE3START],al
\r
1016 asm mov al,[es:si+4]
\r
1017 asm mov [es:di+4+PAGE1START],al
\r
1018 asm mov [es:di+4+PAGE2START],al
\r
1019 asm mov [es:di+4+PAGE3START],al
\r
1021 asm add di,SCREENWIDTH
\r
1031 /////////////////////////////////////////////////////////////////////////////
\r
1033 // Check the object and make sure it is a monster. Used in making the sound
\r
1034 // of a monster being shot.
\r
1036 /////////////////////////////////////////////////////////////////////////////
\r
1038 boolean PlayMonsterSound(classtype objclass)
\r
1043 case realsolidobj:
\r
1052 =============================================================================
\r
1056 =============================================================================
\r
1059 void T_Pshot (objtype *ob);
\r
1062 extern statetype s_pshot1;
\r
1063 extern statetype s_pshot2;
\r
1065 //extern statetype s_bigpshot1;
\r
1066 //extern statetype s_bigpshot2;
\r
1069 statetype s_pshot1 = {PSHOT1PIC,8,&T_Pshot,&s_pshot2};
\r
1070 statetype s_pshot2 = {PSHOT2PIC,8,&T_Pshot,&s_pshot1};
\r
1073 statetype s_pshot_exp1 = {PSHOT_EXP1PIC,7,NULL,&s_pshot_exp2};
\r
1074 statetype s_pshot_exp2 = {PSHOT_EXP2PIC,7,NULL,&s_pshot_exp3};
\r
1075 statetype s_pshot_exp3 = {PSHOT_EXP3PIC,7,NULL,NULL};
\r
1078 //statetype s_shotexplode = {PSHOT2PIC,8,NULL,NULL};
\r
1080 //statetype s_bigpshot1 = {BIGPSHOT1PIC,8,&T_Pshot,&s_bigpshot2};
\r
1081 //statetype s_bigpshot2 = {BIGPSHOT2PIC,8,&T_Pshot,&s_bigpshot1};
\r
1085 ===================
\r
1089 ===================
\r
1092 void SpawnPShot (void)
\r
1094 DSpawnNewObjFrac (player->x,player->y,&s_pshot1,PIXRADIUS*7);
\r
1095 new->obclass = pshotobj;
\r
1096 new->speed = SHOTSPEED;
\r
1097 new->angle = player->angle;
\r
1098 new->active = always;
\r
1102 void SpawnBigPShot (void)
\r
1104 SpawnNewObjFrac (player->x,player->y,&s_bigpshot1,24*PIXRADIUS);
\r
1105 new->obclass = bigpshotobj;
\r
1106 new->speed = SHOTSPEED;
\r
1107 new->angle = player->angle;
\r
1113 ===================
\r
1115 = JimsShotClipMove
\r
1117 = Only checks corners, so the object better be less than one tile wide!
\r
1119 ===================
\r
1121 boolean JimsShotClipMove (objtype *ob, long xmove, long ymove)
\r
1123 int xl,yl,xh,yh,tx,ty,nt1,nt2,x,y;
\r
1124 long intersect,basex,basey,pointx,pointy;
\r
1125 unsigned inside,total,tile;
\r
1130 // move player and check to see if any corners are in solid tiles
\r
1135 // ob->x += xmove;
\r
1136 // ob->y += ymove;
\r
1138 // CalcBounds (ob);
\r
1140 xl = ob->xl>>TILESHIFT;
\r
1141 yl = ob->yl>>TILESHIFT;
\r
1143 xh = ob->xh>>TILESHIFT;
\r
1144 yh = ob->yh>>TILESHIFT;
\r
1146 for (y=yl;y<=yh;y++)
\r
1147 for (x=xl;x<=xh;x++)
\r
1149 check = actorat[x][y];
\r
1151 if ((!check) || (check == player) || (!(check->flags & of_shootable)))
\r
1157 if (check->obclass != solidobj && check->obclass != hbunnyobj)
\r
1159 if (PlayMonsterSound(check->obclass))
\r
1160 SD_PlaySound (SHOOTMONSTERSND);
\r
1161 if (ob->obclass == bigpshotobj)
\r
1162 ShootActor (check,BIGSHOTDAMAGE);
\r
1164 ShootActor (check,SHOTDAMAGE);
\r
1167 if (check->obclass == solidobj && (check->flags & of_forcefield))
\r
1169 if (PlayMonsterSound(check->obclass))
\r
1170 SD_PlaySound (SHOOTMONSTERSND);
\r
1171 if (ob->obclass == bigpshotobj)
\r
1172 ShootActor (check,BIGSHOTDAMAGE);
\r
1174 ShootActor (check,SHOTDAMAGE);
\r
1176 ob->state = &s_pshot_exp1;
\r
1177 ob->ticcount = ob->state->tictime;
\r
1181 return(false); // move is OK!
\r
1194 void T_Pshot (objtype *ob)
\r
1197 long xmove,ymove,speed;
\r
1200 // check current position for monsters having moved into it
\r
1202 for (check = player->next; check; check=check->next)
\r
1203 if ((check->flags & of_shootable)
\r
1204 && ob->xl <= check->xh
\r
1205 && ob->xh >= check->xl
\r
1206 && ob->yl <= check->yh
\r
1207 && ob->yh >= check->yl)
\r
1210 if (check->obclass != solidobj)
\r
1212 if (PlayMonsterSound(check->obclass))
\r
1213 SD_PlaySound (SHOOTMONSTERSND);
\r
1214 if (ob->obclass == bigpshotobj)
\r
1215 ShootActor (check,BIGSHOTDAMAGE);
\r
1217 ShootActor (check,SHOTDAMAGE);
\r
1220 ob->state = &s_pshot_exp1;
\r
1221 ob->ticcount = ob->state->tictime;
\r
1227 // move ahead, possibly hitting a wall
\r
1229 speed = ob->speed*tics;
\r
1231 xmove = FixedByFrac(speed,costable[ob->angle]);
\r
1232 ymove = -FixedByFrac(speed,sintable[ob->angle]);
\r
1234 if (ShotClipMove(ob,xmove,ymove))
\r
1236 ob->state = &s_pshot_exp1;
\r
1237 ob->ticcount = ob->state->tictime;
\r
1241 ob->tilex = ob->x >> TILESHIFT;
\r
1242 ob->tiley = ob->y >> TILESHIFT;
\r
1245 // check final position for monsters hit
\r
1247 for (check = player->next; check; check=check->next)
\r
1248 if ((ob->flags & of_shootable)
\r
1249 && ob->xl <= check->xh
\r
1250 && ob->xh >= check->xl
\r
1251 && ob->yl <= check->yh
\r
1252 && ob->yh >= check->yl)
\r
1254 ShootActor (check,SHOTDAMAGE);
\r
1255 ob->state = &s_pshot_exp1;
\r
1256 ob->ticcount = ob->state->tictime;
\r
1264 void T_Pshot (objtype *ob)
\r
1267 long xmove,ymove,speed;
\r
1268 int xl,yl,xh,yh,tx,ty,nt1,nt2,x,y;
\r
1269 long intersect,basex,basey,pointx,pointy;
\r
1270 unsigned inside,total,tile;
\r
1274 // check current position for monsters having moved into it
\r
1276 for (check = player->next; check; check=check->next)
\r
1277 if ((check->flags & of_shootable)
\r
1278 && ob->xl <= check->xh
\r
1279 && ob->xh >= check->xl
\r
1280 && ob->yl <= check->yh
\r
1281 && ob->yh >= check->yl)
\r
1284 if (check->obclass != solidobj && check->obclass != hbunnyobj)
\r
1286 if (PlayMonsterSound(check->obclass))
\r
1287 SD_PlaySound (SHOOTMONSTERSND);
\r
1288 if (ob->obclass == bigpshotobj)
\r
1289 ShootActor (check,BIGSHOTDAMAGE);
\r
1291 ShootActor (check,SHOTDAMAGE);
\r
1294 ob->state = &s_pshot_exp1;
\r
1295 ob->obclass = expobj;
\r
1296 ob->ticcount = ob->state->tictime;
\r
1302 // move ahead, possibly hitting a wall
\r
1304 speed = ob->speed*tics;
\r
1306 xmove = FixedByFrac(speed,costable[ob->angle]);
\r
1307 ymove = -FixedByFrac(speed,sintable[ob->angle]);
\r
1309 if (ShotClipMove(ob,xmove,ymove))
\r
1311 ob->state = &s_pshot_exp1;
\r
1312 ob->obclass = expobj;
\r
1313 ob->ticcount = ob->state->tictime;
\r
1317 ob->tilex = ob->x >> TILESHIFT;
\r
1318 ob->tiley = ob->y >> TILESHIFT;
\r
1321 // check final position for monsters hit
\r
1324 JimsShotClipMove(obj,xmove,ymove);
\r
1330 =============================================================================
\r
1334 =============================================================================
\r
1345 void BuildShotPower (void)
\r
1347 int newlines,topline;
\r
1349 unsigned source,dest;
\r
1351 if (gamestate.shotpower == MAXSHOTPOWER)
\r
1355 for (i=lasttimecount-realtics;i<lasttimecount;i++)
\r
1356 newlines += (i&1);
\r
1358 gamestate.shotpower += newlines;
\r
1360 if (gamestate.shotpower > MAXSHOTPOWER)
\r
1362 newlines -= (gamestate.shotpower - MAXSHOTPOWER);
\r
1363 gamestate.shotpower = MAXSHOTPOWER;
\r
1368 //===========================================================================
\r
1378 void ClearShotPower (void)
\r
1380 unsigned source,dest,topline;
\r
1383 topline = MAXSHOTPOWER - gamestate.shotpower;
\r
1385 source = latchpics[L_NOSHOT]+topline*SIDEBARWIDTH;
\r
1386 dest = (POWERLINE+topline)*SCREENWIDTH+34;
\r
1388 asm mov es,[screenseg]
\r
1389 asm mov si,[source]
\r
1392 if (!gamestate.shotpower)
\r
1397 asm mov cx,[WORD PTR gamestate.shotpower]
\r
1399 asm mov al,[es:si]
\r
1400 asm mov [es:di+PAGE1START],al
\r
1401 asm mov [es:di+PAGE2START],al
\r
1402 asm mov [es:di+PAGE3START],al
\r
1403 asm mov al,[es:si+1]
\r
1404 asm mov [es:di+1+PAGE1START],al
\r
1405 asm mov [es:di+1+PAGE2START],al
\r
1406 asm mov [es:di+1+PAGE3START],al
\r
1407 asm mov al,[es:si+2]
\r
1408 asm mov [es:di+2+PAGE1START],al
\r
1409 asm mov [es:di+2+PAGE2START],al
\r
1410 asm mov [es:di+2+PAGE3START],al
\r
1411 asm mov al,[es:si+3]
\r
1412 asm mov [es:di+3+PAGE1START],al
\r
1413 asm mov [es:di+3+PAGE2START],al
\r
1414 asm mov [es:di+3+PAGE3START],al
\r
1415 asm mov al,[es:si+4]
\r
1416 asm mov [es:di+4+PAGE1START],al
\r
1417 asm mov [es:di+4+PAGE2START],al
\r
1418 asm mov [es:di+4+PAGE3START],al
\r
1420 asm add di,SCREENWIDTH
\r
1428 gamestate.shotpower = 0;
\r
1431 //===========================================================================
\r
1443 ClearShotPower ();
\r
1444 SD_PlaySound (SHOOTSND);
\r
1448 //===========================================================================
\r
1459 void BigShoot (void)
\r
1461 ClearShotPower ();
\r
1462 SD_PlaySound (BIGSHOOTSND);
\r
1467 //===========================================================================
\r
1477 void CastBolt (void)
\r
1479 if (!gamestate.bolts)
\r
1481 SD_PlaySound (NOITEMSND);
\r
1486 boltsleft = NUMBOLTS;
\r
1487 bolttimer = BOLTTICS;
\r
1500 void ContinueBolt (void)
\r
1502 bolttimer-=realtics;
\r
1506 bolttimer = BOLTTICS;
\r
1512 //===========================================================================
\r
1522 void CastNuke (void)
\r
1524 extern boolean autofire;
\r
1528 if (!gamestate.nukes)
\r
1530 SD_PlaySound (NOITEMSND);
\r
1536 lastnuke = TimeCount;
\r
1538 for (angle = 0; angle < ANGLES; angle+= ANGLES/16)
\r
1540 DSpawnNewObjFrac (player->x,player->y,&s_pshot1,24*PIXRADIUS);
\r
1541 new->obclass = bigpshotobj;
\r
1542 new->speed = SHOTSPEED;
\r
1543 new->angle = angle;
\r
1544 new->active = always;
\r
1548 //===========================================================================
\r
1558 void DrinkPotion (void)
\r
1560 unsigned source,dest,topline;
\r
1562 if (!gamestate.potions)
\r
1564 SD_PlaySound (NOITEMSND);
\r
1568 DisplaySMsg("Curing", NULL);
\r
1570 gamestate.body = MAXBODY;
\r
1572 status_flag = S_NONE;
\r
1576 // draw a full up bar
\r
1578 source = latchpics[L_BODYBAR];
\r
1579 dest = BODYLINE*SCREENWIDTH+34;
\r
1581 asm mov es,[screenseg]
\r
1582 asm mov si,[source]
\r
1587 asm mov cx,MAXBODY
\r
1589 asm mov al,[es:si]
\r
1590 asm mov [es:di+PAGE1START],al
\r
1591 asm mov [es:di+PAGE2START],al
\r
1592 asm mov [es:di+PAGE3START],al
\r
1593 asm mov al,[es:si+1]
\r
1594 asm mov [es:di+1+PAGE1START],al
\r
1595 asm mov [es:di+1+PAGE2START],al
\r
1596 asm mov [es:di+1+PAGE3START],al
\r
1597 asm mov al,[es:si+2]
\r
1598 asm mov [es:di+2+PAGE1START],al
\r
1599 asm mov [es:di+2+PAGE2START],al
\r
1600 asm mov [es:di+2+PAGE3START],al
\r
1601 asm mov al,[es:si+3]
\r
1602 asm mov [es:di+3+PAGE1START],al
\r
1603 asm mov [es:di+3+PAGE2START],al
\r
1604 asm mov [es:di+3+PAGE3START],al
\r
1605 asm mov al,[es:si+4]
\r
1606 asm mov [es:di+4+PAGE1START],al
\r
1607 asm mov [es:di+4+PAGE2START],al
\r
1608 asm mov [es:di+4+PAGE3START],al
\r
1609 asm add di,SCREENWIDTH
\r
1620 //===========================================================================
\r
1624 ////////////////////////////////////////////////////////////////////////////
\r
1628 // parms - scroll -- the number of the scroll to display
\r
1629 // returns - a far pointer to the scroll text
\r
1631 ////////////////////////////////////////////////////////////////////////////
\r
1633 char far *GetScrollText (int scroll)
\r
1640 CA_CacheGrChunk(SCROLLTEXT);
\r
1645 txt = (char _seg *)grsegs[SCROLLTEXT];
\r
1649 while (*txt != '\n')
\r
1659 ofset = FP_OFF(txt);
\r
1661 while (*txt != '\n')
\r
1670 txt = (char _seg *)grsegs[SCROLLTEXT]+ofset;
\r
1672 UNMARKGRCHUNK(SCROLLTEXT);
\r
1674 } //End of GetScrollText
\r
1676 //===========================================================================
\r
1686 extern boolean tileneeded[NUMFLOORS];
\r
1688 void ReadScroll (int scroll)
\r
1692 unsigned *skytemp,*gndtemp,blackcolor=0;
\r
1693 char far *scrolltext;
\r
1695 DisplaySMsg("Reading Scroll", NULL);
\r
1696 bufferofs = displayofs = screenloc[screenpage];
\r
1698 if (status_flag != S_TIMESTOP)
\r
1699 status_flag = S_NONE;
\r
1703 CA_CacheGrChunk (SCROLLTOPPIC);
\r
1704 CA_CacheGrChunk (SCROLL1PIC);
\r
1705 CA_CacheGrChunk (SCROLLBOTTOMPIC);
\r
1707 skytemp = skycolor;
\r
1708 gndtemp = groundcolor;
\r
1709 skycolor = groundcolor = &blackcolor;
\r
1711 VW_Bar(0,0,VIEWWIDTH,VIEWHEIGHT,0);
\r
1712 VW_DrawPic (10,0,SCROLLTOPPIC);
\r
1713 VW_DrawPic (10,32,SCROLL1PIC);
\r
1714 VW_DrawPic (10,88,SCROLLBOTTOMPIC);
\r
1716 scrolltext = GetScrollText(scroll);
\r
1720 pi.xh = RIGHTEDGE;
\r
1723 pi.script[0] = (char far *)scrolltext;
\r
1726 skycolor = skytemp;
\r
1727 groundcolor = gndtemp;
\r
1729 UNMARKGRCHUNK(SCROLL1PIC);
\r
1730 UNMARKGRCHUNK(SCROLLTOPPIC);
\r
1731 UNMARKGRCHUNK(SCROLLBOTTOMPIC);
\r
1732 MM_FreePtr (&grsegs[SCROLL1PIC]);
\r
1733 MM_FreePtr (&grsegs[SCROLLTOPPIC]);
\r
1734 MM_FreePtr (&grsegs[SCROLLBOTTOMPIC]);
\r
1738 IN_ClearKeysDown ();
\r
1740 DisplayMsg("Press ENTER or ESC to exit.",NULL);
\r
1741 while ((!Keyboard[sc_Escape]) && (!Keyboard[sc_Enter]));
\r
1742 IN_ClearKeysDown ();
\r
1744 if (status_flag == S_TIMESTOP)
\r
1745 DisplaySMsg("Time Stopped: ",NULL);
\r
1759 FreezeTime = MAXFREEZETIME;
\r
1760 SD_PlaySound(FREEZETIMESND);
\r
1761 DisplaySMsg("Time Stopped: ",NULL);
\r
1762 status_flag = S_TIMESTOP;
\r
1774 void TakeDamage (int points)
\r
1776 unsigned source,dest,topline;
\r
1778 if (!gamestate.body || (bordertime && bcolor==FLASHCOLOR) || godmode)
\r
1782 points = EasyDoDamage(points);
\r
1784 if (points >= gamestate.body)
\r
1786 points = gamestate.body;
\r
1790 bordertime = FLASHTICS<<2;
\r
1791 bcolor = FLASHCOLOR;
\r
1792 VW_ColorBorder (FLASHCOLOR);
\r
1794 DisplaySMsg("Damaging blows!", NULL);
\r
1795 status_flag = S_NONE;
\r
1796 status_delay = 80;
\r
1798 if (gamestate.body<MAXBODY/3)
\r
1799 SD_PlaySound (TAKEDMGHURTSND);
\r
1801 SD_PlaySound (TAKEDAMAGESND);
\r
1803 gamestate.body -= points;
\r
1807 =============================================================================
\r
1811 =============================================================================
\r
1817 ==================
\r
1821 ==================
\r
1824 void OpenDoor (unsigned bx, unsigned by, unsigned doorbase)
\r
1827 unsigned far *map;
\r
1831 map = mapsegs[0]+farmapylookup[y]+x;
\r
1832 while (tilemap[x][y]-doorbase<4)
\r
1834 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;
\r
1839 map = mapsegs[0]+farmapylookup[y]+x;
\r
1840 while (tilemap[x][y]-doorbase<4)
\r
1842 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;
\r
1848 map = mapsegs[0]+farmapylookup[y]+x;
\r
1849 while (tilemap[x][y]-doorbase<4)
\r
1851 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;
\r
1856 map = mapsegs[0]+farmapylookup[y]+x;
\r
1857 while (tilemap[x][y]-doorbase<4)
\r
1859 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;
\r
1868 ==================
\r
1870 = RemoveWalls - similar to OpenDoor(), but on a different plane
\r
1872 ==================
\r
1874 void RemoveWalls (unsigned bx, unsigned by, unsigned remove_code)
\r
1877 unsigned far *map,*p2;
\r
1881 p2 = *(mapsegs[2]+farmapylookup[y]+x);
\r
1882 map = mapsegs[0]+farmapylookup[y]+x;
\r
1883 while (*p2 == remove_code)
\r
1885 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;
\r
1891 p2 = *(mapsegs[2]+farmapylookup[y]+x);
\r
1892 map = mapsegs[0]+farmapylookup[y]+x;
\r
1893 while (*p2 == remove_code)
\r
1895 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;
\r
1902 p2 = *(mapsegs[2]+farmapylookup[y]+x);
\r
1903 map = mapsegs[0]+farmapylookup[y]+x;
\r
1904 while (*p2 == remove_code)
\r
1906 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;
\r
1912 p2 = *(mapsegs[2]+farmapylookup[y]+x);
\r
1913 map = mapsegs[0]+farmapylookup[y]+x;
\r
1914 while (*p2 == remove_code)
\r
1916 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;
\r
1925 ==================
\r
1929 = Returns true if the move is blocked
\r
1931 ==================
\r
1934 boolean HitSpecialTile (unsigned x, unsigned y, unsigned tile)
\r
1938 unsigned temp,spot,curmap=gamestate.mapon,newlevel;
\r
1939 char *key_colors[] = {"a RED key",
\r
1947 playstate = ex_victorious;
\r
1964 if (!playstate && !FreezeTime)
\r
1967 // Is this an openable door? (Is "openable" a word?)
\r
1969 spot = (*(mapsegs[2]+farmapylookup[y]+x)) >> 8;
\r
1970 if (spot == CANT_OPEN_CODE) // CAN'T EVER OPEN (it's just for looks)
\r
1972 CenterWindow(30,4);
\r
1973 US_CPrint("\nThis door is permanently blocked");
\r
1974 VW_UpdateScreen();
\r
1975 IN_ClearKeysDown();
\r
1980 // make sure player has key to get into door
\r
1983 if (TILE_FLAGS(tile) & tf_EMBEDDED_KEY_COLOR)
\r
1984 keyspot = GATE_KEY_COLOR(tile);
\r
1986 keyspot = (*(mapsegs[2]+farmapylookup[y+1]+x)) >> 8;
\r
1989 if (!gamestate.keys[keyspot])
\r
1991 SD_PlaySound(HIT_GATESND);
\r
1992 CenterWindow(20,5);
\r
1993 US_CPrint("\nYou need\n");
\r
1994 US_CPrint(key_colors[keyspot]);
\r
1995 VW_UpdateScreen();
\r
1996 IN_ClearKeysDown();
\r
2002 // deal with this gate (warp? simply open? whatever...)
\r
2006 case NEXT_LEVEL_CODE: // WARP TO NEXT LEVEL
\r
2007 newlevel = gamestate.mapon+1;
\r
2008 playstate = ex_warped;
\r
2011 case REMOVE_DOOR_CODE: // REMOVE DOOR
\r
2012 (unsigned)actorat[x][y] = tilemap[x][y] = *(mapsegs[0]+farmapylookup[y]+x) = 0;
\r
2013 *(mapsegs[2]+farmapylookup[y+1]+x) = 0; // key no longer needed
\r
2018 default: // WARP TO A LEVEL
\r
2020 playstate = ex_warped;
\r
2024 if (playstate == ex_warped)
\r
2026 SD_PlaySound(HIT_GATESND);
\r
2027 // levelinfo *li=&gamestate.levels[curmap];
\r
2029 // OldAngle = FaceDoor(x,y);
\r
2031 if (!VerifyGateExit())
\r
2033 IN_ClearKeysDown ();
\r
2034 playstate = ex_stillplaying;
\r
2038 // FaceAngle(OldAngle);
\r
2042 *(mapsegs[2]+farmapylookup[y+1]+x) = 0; // key no longer needed
\r
2044 gamestate.mapon = newlevel;
\r
2045 SD_PlaySound(WARPUPSND);
\r
2046 IN_ClearKeysDown ();
\r
2048 // li->x = player->tilex;
\r
2049 // li->y = player->tiley;
\r
2050 // li->angle = player->angle+180;
\r
2051 // if (li->angle > 360)
\r
2052 // li->angle -= 360;
\r
2061 //-------------------------------------------------------------------------
\r
2062 // VerifyGateExit()
\r
2063 //-------------------------------------------------------------------------
\r
2064 boolean VerifyGateExit()
\r
2066 char choices[] = {sc_Escape,sc_Y,sc_N,0},ch;
\r
2068 ch=DisplayMsg("Pass this way? Y/N",choices);
\r
2071 return(ch == sc_Y);
\r
2076 ==================
\r
2080 = Returns true if the move is blocked
\r
2082 ==================
\r
2085 boolean TouchActor (objtype *ob, objtype *check)
\r
2087 if (ob->xh < check->xl || ob->xl > check->xh ||
\r
2088 ob->yh < check->yl || ob->yl > check->yh)
\r
2089 return false; // not quite touching
\r
2091 switch (check->obclass)
\r
2094 switch (check->temp1)
\r
2096 case B_BOLT: GiveBolt (); break;
\r
2098 case B_NUKE: GiveNuke (); break;
\r
2100 case B_POTION: GivePotion (); break;
\r
2102 // case B_RKEY2: GiveKey(B_RKEY-B_RKEY); break;
\r
2107 case B_BKEY: GiveKey (check->temp1-B_RKEY); break;
\r
2117 case B_SCROLL8: GiveScroll (check->temp1-B_SCROLL1,true); break;
\r
2120 case B_CHEST: GiveChest (); break;
\r
2127 SD_PlaySound(GETGEMSND);
\r
2128 gamestate.gems[check->temp1-B_RGEM] = GEM_DELAY_TIME;
\r
2129 redraw_gems = true;
\r
2133 Quit("TouchActor(): INVALID BONUS");
\r
2137 (unsigned)actorat[check->tilex][check->tiley] = 0;
\r
2138 RemoveObj (check);
\r
2144 (unsigned)actorat[check->tilex][check->tiley] = 0;
\r
2158 ==================
\r
2162 ==================
\r
2165 void CalcBounds (objtype *ob)
\r
2168 // calculate hit rect
\r
2170 ob->xl = ob->x - ob->size;
\r
2171 ob->xh = ob->x + ob->size;
\r
2172 ob->yl = ob->y - ob->size;
\r
2173 ob->yh = ob->y + ob->size;
\r
2178 ===================
\r
2182 ===================
\r
2185 boolean LocationInActor (objtype *ob)
\r
2187 int x,y,xmin,ymin,xmax,ymax;
\r
2192 xmin = (ob->x >> TILESHIFT)-2;
\r
2193 ymin = (ob->y >> TILESHIFT)-2;
\r
2197 for (x=xmin;x<xmax;x++)
\r
2198 for (y=ymin;y<ymax;y++)
\r
2200 check = actorat[x][y];
\r
2201 if (check>(objtype *)LASTTILE
\r
2202 && (check->flags & of_shootable)
\r
2203 && (check->obclass != bonusobj)
\r
2204 && (check->obclass != freezeobj)
\r
2205 && (check->obclass != solidobj)
\r
2206 && ob->xl-SIZE_TEST <= check->xh
\r
2207 && ob->xh+SIZE_TEST >= check->xl
\r
2208 && ob->yl-SIZE_TEST <= check->yh
\r
2209 && ob->yh+SIZE_TEST >= check->yl)
\r
2217 ===================
\r
2221 = Only checks corners, so the object better be less than one tile wide!
\r
2223 ===================
\r
2225 void ClipXMove (objtype *ob, long xmove)
\r
2227 int xl,yl,xh,yh,tx,ty,nt1,nt2,x,y;
\r
2228 long intersect,basex,basey,pointx,pointy;
\r
2229 unsigned inside,total,tile;
\r
2232 boolean invisible_present = false;
\r
2235 // move player and check to see if any corners are in solid tiles
\r
2244 xl = ob->xl>>TILESHIFT;
\r
2245 yl = ob->yl>>TILESHIFT;
\r
2247 xh = ob->xh>>TILESHIFT;
\r
2248 yh = ob->yh>>TILESHIFT;
\r
2250 for (y=yl;y<=yh;y++)
\r
2251 for (x=xl;x<=xh;x++)
\r
2253 check = actorat[x][y];
\r
2256 continue; // blank floor, walk ok
\r
2258 if ((unsigned)check <= LASTTILE)
\r
2260 if (TILE_FLAGS((unsigned)check) & tf_SPECIAL)
\r
2262 HitSpecialTile(x,y,(unsigned)check-SPECTILESTART);
\r
2266 if (TILE_FLAGS((unsigned)check) & tf_INVISIBLE_WALL)
\r
2268 invisible_present = true;
\r
2273 if (TILE_FLAGS((unsigned)check) & tf_SOLID)
\r
2275 goto blockmove; // solid wall
\r
2279 TouchActor(ob,check); // pick up items
\r
2283 // check nearby actors
\r
2285 if (LocationInActor(ob))
\r
2288 if (LocationInActor(ob))
\r
2291 if (LocationInActor(ob))
\r
2295 return; // move is OK!
\r
2300 // if (!SD_SoundPlaying())
\r
2301 // SD_PlaySound (HITWALLSND);
\r
2317 xl = ob->xl>>TILESHIFT;
\r
2318 yl = ob->yl>>TILESHIFT;
\r
2319 xh = ob->xh>>TILESHIFT;
\r
2320 yh = ob->yh>>TILESHIFT;
\r
2321 if (tilemap[xl][yl] || tilemap[xh][yl]
\r
2322 || tilemap[xh][yh] || tilemap[xl][yh] )
\r
2325 if (xmove>=-2048 && xmove <=2048)
\r
2333 if (invisible_present)
\r
2336 if (xmove>=-2048 && xmove <=2048)
\r
2344 if (xmove>=-2048 && xmove <=2048)
\r
2352 ===================
\r
2356 = Only checks corners, so the object better be less than one tile wide!
\r
2358 ===================
\r
2360 void ClipYMove (objtype *ob, long ymove)
\r
2362 int xl,yl,xh,yh,tx,ty,nt1,nt2,x,y;
\r
2363 long intersect,basex,basey,pointx,pointy;
\r
2364 unsigned inside,total,tile;
\r
2367 boolean invisible_present = false;
\r
2370 // move player and check to see if any corners are in solid tiles
\r
2379 xl = ob->xl>>TILESHIFT;
\r
2380 yl = ob->yl>>TILESHIFT;
\r
2382 xh = ob->xh>>TILESHIFT;
\r
2383 yh = ob->yh>>TILESHIFT;
\r
2385 for (y=yl;y<=yh;y++)
\r
2386 for (x=xl;x<=xh;x++)
\r
2388 check = actorat[x][y];
\r
2390 continue; // blank floor, walk ok
\r
2392 if ((unsigned)check <= LASTTILE)
\r
2394 if (TILE_FLAGS((unsigned)check) & tf_SPECIAL) // <=LASTSPECIALTILE)
\r
2396 HitSpecialTile (x,y,(unsigned)check-SPECTILESTART);
\r
2400 if (TILE_FLAGS((unsigned)check) & tf_INVISIBLE_WALL)
\r
2402 invisible_present = true;
\r
2407 if (TILE_FLAGS((unsigned)check) & tf_SOLID) // LASTWALLTILE)
\r
2409 goto blockmove; // solid wall
\r
2413 TouchActor(ob,check); // pick up items
\r
2417 // check nearby actors
\r
2419 if (LocationInActor(ob))
\r
2421 if (LocationInActor(ob))
\r
2426 return; // move is OK!
\r
2431 // if (!SD_SoundPlaying())
\r
2432 // SD_PlaySound (HITWALLSND);
\r
2448 xl = ob->xl>>TILESHIFT;
\r
2449 yl = ob->yl>>TILESHIFT;
\r
2450 xh = ob->xh>>TILESHIFT;
\r
2451 yh = ob->yh>>TILESHIFT;
\r
2452 if (tilemap[xl][yl] || tilemap[xh][yl]
\r
2453 || tilemap[xh][yh] || tilemap[xl][yh] )
\r
2456 if (ymove>=-2048 && ymove <=2048)
\r
2464 if (invisible_present)
\r
2467 if (ymove>=-2048 && ymove <=2048)
\r
2475 if (ymove>=-2048 && ymove <=2048)
\r
2482 //==========================================================================
\r
2486 ===================
\r
2490 = Only checks corners, so the object better be less than one tile wide!
\r
2492 ===================
\r
2495 boolean ShotClipMove (objtype *ob, long xmove, long ymove)
\r
2497 int xl,yl,xh,yh,tx,ty,nt1,nt2,x,y;
\r
2498 long intersect,basex,basey,pointx,pointy;
\r
2499 unsigned inside,total,spot,tile;
\r
2504 // move shot and check to see if any corners are in solid tiles
\r
2514 xl = ob->xl>>TILESHIFT;
\r
2515 yl = ob->yl>>TILESHIFT;
\r
2517 xh = ob->xh>>TILESHIFT;
\r
2518 yh = ob->yh>>TILESHIFT;
\r
2520 for (y=yl;y<=yh;y++)
\r
2521 for (x=xl;x<=xh;x++)
\r
2523 spot = (*(mapsegs[2]+farmapylookup[y]+x)) >> 8;
\r
2524 if (spot == EXP_WALL_CODE)
\r
2525 switch (ob->obclass)
\r
2529 ExplodeWall (x,y);
\r
2534 tile = *(mapsegs[0]+farmapylookup[y]+x);
\r
2535 if (TILE_FLAGS(tile) & tf_SOLID)
\r
2538 return false; // move is OK!
\r
2543 SD_PlaySound (SHOOTWALLSND);
\r
2562 xl = ob->xl>>TILESHIFT;
\r
2563 yl = ob->yl>>TILESHIFT;
\r
2564 xh = ob->xh>>TILESHIFT;
\r
2565 yh = ob->yh>>TILESHIFT;
\r
2566 if (tilemap[xl][yl] || tilemap[xh][yl]
\r
2567 || tilemap[xh][yh] || tilemap[xl][yh] )
\r
2570 if (xmove>=-2048 && xmove <=2048 && ymove>=-2048 && ymove <=2048)
\r
2579 if (xmove>=-2048 && xmove <=2048 && ymove>=-2048 && ymove <=2048)
\r
2589 =============================================================================
\r
2593 =============================================================================
\r
2598 void T_Player (objtype *ob);
\r
2600 statetype s_player = {0,0,&T_Player,&s_player};
\r
2610 void SpawnPlayer (int tilex, int tiley, int dir)
\r
2613 levelinfo *li=&gamestate.levels[gamestate.mapon];
\r
2619 player->angle = li->angle;
\r
2622 player->angle = (1-dir)*90;
\r
2625 player->obclass = playerobj;
\r
2626 player->active = always;
\r
2627 player->tilex = tilex;
\r
2628 player->tiley = tiley;
\r
2629 player->x = ((long)tilex<<TILESHIFT)+TILEGLOBAL/2;
\r
2630 player->y = ((long)tiley<<TILESHIFT)+TILEGLOBAL/2;
\r
2631 player->state = &s_player;
\r
2632 player->size = MINDIST;
\r
2633 CalcBounds(player);
\r
2634 player->angle = (1-dir)*90;
\r
2635 if (player->angle<0)
\r
2636 player->angle += ANGLES;
\r
2641 ===================
\r
2645 ===================
\r
2648 void Thrust (int angle, unsigned speed)
\r
2652 if (lasttimecount>>5 != ((lasttimecount-tics)>>5) )
\r
2657 if (lasttimecount&32)
\r
2658 SD_PlaySound (WALK1SND);
\r
2660 SD_PlaySound (WALK2SND);
\r
2663 xmove = FixedByFrac(speed,costable[angle]);
\r
2664 ymove = -FixedByFrac(speed,sintable[angle]);
\r
2666 ClipXMove(player,xmove);
\r
2667 ClipYMove(player,ymove);
\r
2668 player->tilex = player->x >> TILESHIFT;
\r
2669 player->tiley = player->y >> TILESHIFT;
\r
2675 =======================
\r
2679 =======================
\r
2682 void ControlMovement (objtype *ob)
\r
2688 if (control.button1)
\r
2694 // side to side move
\r
2698 else if (mousexmove<0)
\r
2699 speed = -(long)mousexmove*300;
\r
2701 speed = -(long)mousexmove*300;
\r
2703 if (control.xaxis == -1)
\r
2705 speed += PLAYERSPEED*tics;
\r
2707 else if (control.xaxis == 1)
\r
2709 speed -= PLAYERSPEED*tics;
\r
2714 if (speed >= TILEGLOBAL)
\r
2715 speed = TILEGLOBAL-1;
\r
2716 angle = ob->angle + ANGLES/4;
\r
2717 if (angle >= ANGLES)
\r
2719 Thrust (angle,speed); // move to left
\r
2721 else if (speed < 0)
\r
2723 if (speed <= -TILEGLOBAL)
\r
2724 speed = -TILEGLOBAL+1;
\r
2725 angle = ob->angle - ANGLES/4;
\r
2728 Thrust (angle,-speed); // move to right
\r
2740 if (control.xaxis == 1)
\r
2742 ob->angle -= tics;
\r
2743 if (running) // fast turn
\r
2744 ob->angle -= (tics<<1);
\r
2746 else if (control.xaxis == -1)
\r
2749 if (running) // fast turn
\r
2750 ob->angle += (tics<<1);
\r
2753 ob->angle -= (mousexmove/10);
\r
2755 if (ob->angle >= ANGLES)
\r
2756 ob->angle -= ANGLES;
\r
2757 if (ob->angle < 0)
\r
2758 ob->angle += ANGLES;
\r
2763 // forward/backwards move
\r
2767 else if (mouseymove<0)
\r
2768 speed = -(long)mouseymove*500;
\r
2770 speed = -(long)mouseymove*200;
\r
2772 if (control.yaxis == -1)
\r
2774 speed += PLAYERSPEED*tics;
\r
2776 else if (control.yaxis == 1)
\r
2778 speed -= PLAYERSPEED*tics;
\r
2783 if (speed >= TILEGLOBAL)
\r
2784 speed = TILEGLOBAL-1;
\r
2785 Thrust (ob->angle,speed); // move forwards
\r
2787 else if (speed < 0)
\r
2789 if (speed <= -TILEGLOBAL)
\r
2790 speed = -TILEGLOBAL+1;
\r
2791 angle = ob->angle + ANGLES/2;
\r
2792 if (angle >= ANGLES)
\r
2794 Thrust (angle,-speed); // move backwards
\r
2807 void T_Player (objtype *ob)
\r
2809 extern boolean autofire;
\r
2811 int angle,speed,scroll,loop;
\r
2812 unsigned text,tilex,tiley;
\r
2815 // boolean radar_moved=false;
\r
2818 ControlMovement (ob);
\r
2826 handheight+=(realtics<<2);
\r
2827 if (handheight>MAXHANDHEIGHT)
\r
2828 handheight = MAXHANDHEIGHT;
\r
2831 lasthand = lasttimecount;
\r
2835 if (control.button0)
\r
2837 handheight+=(realtics<<2);
\r
2838 if (handheight>MAXHANDHEIGHT)
\r
2839 handheight = MAXHANDHEIGHT;
\r
2840 lasthand = lasttimecount;
\r
2850 if (lasttimecount > lasthand+HANDPAUSE)
\r
2852 handheight-=(realtics<<1);
\r
2857 button0down = false;
\r
2862 if (control.button0)
\r
2864 handheight+=(realtics<<2);
\r
2865 if (handheight>MAXHANDHEIGHT)
\r
2866 handheight = MAXHANDHEIGHT;
\r
2868 if ((unsigned)TimeCount/FIRETIME != lastfiretime)
\r
2869 BuildShotPower ();
\r
2870 lasthand = lasttimecount;
\r
2874 if (lasttimecount > lasthand+HANDPAUSE)
\r
2876 handheight-=(realtics<<1);
\r
2881 if (gamestate.shotpower)
\r
2883 lastfiretime = (unsigned)TimeCount/FIRETIME;
\r
2891 // special actions
\r
2894 if ((Keyboard[sc_Space] || Keyboard[sc_C]) && gamestate.body != MAXBODY)
\r
2897 if (Keyboard[sc_Z] && !boltsleft)
\r
2900 if ( (Keyboard[sc_Enter] || Keyboard[sc_X]) && ((TimeCount-lastnuke > NUKETIME) || (autofire)))
\r
2904 scroll = LastScan-2;
\r
2905 if ( scroll>=0 && scroll<NUMSCROLLS && gamestate.scrolls[scroll])
\r
2906 ReadScroll (scroll);
\r
2921 // gems fade out over time...
\r
2923 for (loop=0; loop<5; loop++)
\r
2924 if (gamestate.gems[loop])
\r
2926 gamestate.gems[loop] -= realtics;
\r
2927 if (gamestate.gems[loop] < 0)
\r
2929 gamestate.gems[loop] = 0;
\r
2930 redraw_gems = true;
\r
2937 //------------------------------------------------------------------------
\r
2940 // PARAMS : x,y - pixle coords to bring in to view.
\r
2942 // NOTE : Params CAN NOT be shifted fracs!
\r
2943 //------------------------------------------------------------------------
\r
2944 void FaceDir(short x,short y,boolean StopTime)
\r
2948 RotateAngle = CalcAngle(x-(player->x>>16l),(player->y>>16l)-y);
\r
2949 FreezeTime = StopTime;
\r
2951 diff = player->angle - RotateAngle;
\r
2953 if (((diff>0) && (diff<180)) || ((diff<0) && (diff>-180)))
\r
2954 RotateSpeed = -ROTATE_SPEED;
\r
2956 RotateSpeed = ROTATE_SPEED;
\r
2961 //------------------------------------------------------------------------
\r
2964 // DESC: Calculates the angle from a given dy & dx
\r
2965 //------------------------------------------------------------------------
\r
2966 short CalcAngle(short dx,short dy)
\r
2968 #define degtorad (180/PI)
\r
2975 angle = atan((float)dy/dx)* degtorad;
\r
2986 angle = 0 + 90; // Above player (NORTH)
\r
2988 angle = 180 + 90; // Below player (SOUTH)
\r
2991 if (!angle) // HACK
\r
2994 return((short)abs(angle));
\r
3001 //-------------------------------------------------------------------------
\r
3004 // DESC : Rotates view (current view of game) to a dest angle.
\r
3005 //-------------------------------------------------------------------------
\r
3010 // Store old angle position then change angle...
\r
3013 LastPos = player->angle;
\r
3015 player->angle += RotateSpeed;
\r
3017 // Check to see if we cranked past out dest angle...
\r
3021 if ((player->angle>ANGLES) || (!player->angle))
\r
3022 player->angle = 1;
\r
3024 if (player->angle<1)
\r
3025 player->angle = ANGLES;
\r
3027 // Check to see if we over shot our dest angle...
\r
3030 if (((LastPos < RotateAngle) && (player->angle > RotateAngle) && (RotateSpeed > 0)) ||
\r
3031 ((LastPos > RotateAngle) && (player->angle < RotateAngle) && (RotateSpeed < 0)))
\r
3032 player->angle = RotateAngle;
\r
3034 // Check for ending force turn....
\r
3037 if (player->angle == RotateAngle)
\r
3043 //--------------------------------------------------------------------------
\r
3045 //--------------------------------------------------------------------------
\r
3046 void InitRotate(short DestAngle)
\r
3048 if (player->angle != DestAngle)
\r
3050 RotateAngle = DestAngle;
\r
3052 if (player->angle > DestAngle)
\r
3053 RotateSpeed = -ROTATE_SPEED;
\r
3055 RotateSpeed = ROTATE_SPEED;
\r
3057 if (abs(player->angle - RotateAngle) > 180)
\r
3058 RotateSpeed =- RotateSpeed;
\r
3064 //------------------------------------------------------------------------
\r
3067 // PARAMS : DestAngle - Destination angle to turn to
\r
3068 //------------------------------------------------------------------------
\r
3069 void FaceAngle(short DestAngle)
\r
3071 signed long dx,dy,radius,psin,pcos,newx,newy;
\r
3073 short objnum,LastPos;
\r
3074 signed long ox,oy,xl,xh,yl,yh,px,py,norm_dx,norm_dy;
\r
3079 // Calculate the direction we want to turn to...
\r
3082 InitRotate(DestAngle);
\r
3084 RedrawStatusWindow();
\r
3086 while (RotateAngle != -1)
\r
3091 // PollControls();
\r
3095 for (obj = player;obj;obj = obj->next)
\r
3097 if (obj->active >= yes)
\r
3100 // keep a list of objects around the player for radar updates
\r
3102 if (obj == player)
\r
3106 psin = sintable[player->angle];
\r
3107 pcos = costable[player->angle];
\r
3108 xl = px-((long)RADAR_WIDTH<<TILESHIFT)/2;
\r
3109 xh = px+((long)RADAR_WIDTH<<TILESHIFT)/2-1;
\r
3110 yl = py-((long)RADAR_HEIGHT<<TILESHIFT)/2;
\r
3111 yh = py+((long)RADAR_HEIGHT<<TILESHIFT)/2;
\r
3114 if (objnum > MAX_RADAR_BLIPS-2)
\r
3115 objnum = MAX_RADAR_BLIPS-2;
\r
3121 if ((ox >= xl) && (ox <= xh) && (oy >= yl) && (oy <= yh))
\r
3123 norm_dx = (dx = px-ox)>>TILESHIFT;
\r
3124 norm_dy = (dy = oy-py)>>TILESHIFT;
\r
3126 o_radius = IntSqrt((norm_dx * norm_dx) + (norm_dy * norm_dy));
\r
3128 if (o_radius < RADAR_RADIUS)
\r
3130 newx = FixedByFrac(dy,pcos)-FixedByFrac(dx,psin);
\r
3131 newy = FixedByFrac(dy,psin)+FixedByFrac(dx,pcos);
\r
3133 RadarXY[objnum][0]=newx>>TILESHIFT;
\r
3134 RadarXY[objnum][1]=newy>>TILESHIFT;
\r
3136 // Define color to use for this object...
\r
3139 switch (obj->obclass)
\r
3142 RadarXY[objnum++][2]=15;
\r
3148 if (gamestate.gems[B_RGEM-B_RGEM])
\r
3149 if (obj->active == always)
\r
3150 RadarXY[objnum++][2]=12;
\r
3156 if (gamestate.gems[B_GGEM-B_RGEM])
\r
3157 if (obj->active == always)
\r
3158 RadarXY[objnum++][2]=10;
\r
3164 if (gamestate.gems[B_YGEM-B_RGEM])
\r
3165 if (obj->active == always)
\r
3166 RadarXY[objnum++][2]=14;
\r
3173 if (gamestate.gems[B_BGEM-B_RGEM])
\r
3174 if (obj->active == always)
\r
3175 RadarXY[objnum++][2]=9;
\r
3181 if (gamestate.gems[B_PGEM-B_RGEM])
\r
3182 if (obj->active == always)
\r
3183 RadarXY[objnum++][2]=13;
\r
3191 RadarXY[objnum][2]=-1; // Signals end of RadarXY list...
\r
3206 //-------------------------------------------------------------------------
\r
3207 // FaceDoor() - Turns the player to face a door (a tile) at a given TILE x & y
\r
3209 // RETURNS : Returns the orginal angle of the player.
\r
3210 //------------------------------------------------------------------------
\r
3211 short FaceDoor(short x, short y)
\r
3213 short p_x,p_y,angle,old_angle;
\r
3215 old_angle = player->angle;
\r
3217 p_x = player->x>>16l;
\r
3218 p_y = player->y>>16l;
\r
3223 angle = 180; // Face Left
\r
3225 angle = 1; // Face Right
\r
3231 angle = 90; // Face Up
\r
3233 angle = 270; // Face Down
\r
3238 return(old_angle);
\r
3246 /*==========================================================================
\r
3248 EXPLOSION SPAWNING ROUTINES
\r
3250 ===========================================================================*/
\r
3252 statetype s_explode = {0,1,T_ExpThink,&s_explode};
\r
3254 //-------------------------------------------------------------------------
\r
3255 // SpawnExplosion()
\r
3256 //------------------------------------------------------------------------
\r
3257 void SpawnExplosion(fixed x, fixed y, short Delay)
\r
3259 DSpawnNewObjFrac(x,y,&s_explode,PIXRADIUS*7);
\r
3260 new->obclass = expobj;
\r
3261 new->active = always;
\r
3262 new->temp1 = Delay;
\r
3266 //---------------------------------------------------------------------------
\r
3268 //---------------------------------------------------------------------------
\r
3269 void T_ExpThink(objtype *obj)
\r
3273 if ((obj->temp1-=realtics) <= 0)
\r
3278 obj->state = &s_pshot_exp1;
\r
3279 obj->ticcount = obj->state->tictime;
\r
3280 SD_PlaySound(BOOMSND);
\r
3286 //-------------------------------------------------------------------------
\r
3287 // SpawnBigExplosion()
\r
3288 //------------------------------------------------------------------------
\r
3289 void SpawnBigExplosion(fixed x, fixed y, short Delay, fixed Range)
\r
3291 SpawnExplosion(x-random(Range),y+random(Range),random(Delay));
\r
3292 SpawnExplosion(x+random(Range),y-random(Range),random(Delay));
\r
3293 SpawnExplosion(x-random(Range),y-random(Range),random(Delay));
\r
3294 SpawnExplosion(x+random(Range),y+random(Range),random(Delay));
\r