1 /* Catacomb Apocalypse 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 1
\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 30
\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
605 short temp = fontcolor;
\r
607 percentage = PERCENTAGE(100,MAXFREEZETIME,(long)FreezeTime,7);
\r
608 fontcolor = 1 ^ 14;
\r
609 DrawNum(23,70,percentage,3);
\r
613 //===========================================================================
\r
622 void DrawNum(short x,short y,short value,short maxdigits)
\r
624 char str[10],len,i;
\r
626 itoa(value,str,10);
\r
629 for (i=len; i<maxdigits; i++)
\r
630 DrawChar(x++,y,BLANKCHAR);
\r
632 for (i=0;i<len;i++)
\r
633 DrawChar(x++,y,NUMBERCHARS+str[i]-'0');
\r
636 //===========================================================================
\r
646 void GiveChest(void)
\r
650 for (i=0;i<random(4);i++)
\r
653 SD_WaitSoundDone();
\r
656 for (i=0;i<random(3);i++)
\r
659 SD_WaitSoundDone();
\r
662 for (i=0;i<random(2);i++)
\r
665 SD_WaitSoundDone();
\r
670 //===========================================================================
\r
680 void GiveGoal (void)
\r
682 SD_PlaySound (GETPOINTSSND);
\r
683 playstate = ex_victorious;
\r
687 //===========================================================================
\r
698 void DrawLevelNumber (int number)
\r
710 VW_Bar (5,4,16,9,STATUSCOLOR);
\r
712 fontcolor = TEXTCOLOR^STATUSCOLOR;
\r
713 US_PrintUnsigned (number+1);
\r
719 //===========================================================================
\r
729 void DrawText (boolean draw_text_whether_it_needs_it_or_not)
\r
737 // draw a new text description if needed
\r
739 number = *(mapsegs[0]+farmapylookup[player->tiley]+player->tilex)-NAMESTART;
\r
744 if ((number == lasttext) && (!draw_text_whether_it_needs_it_or_not))
\r
749 text = (char _seg *)grsegs[LEVEL1TEXT+mapon]+textstarts[number];
\r
751 if (text[0] == '@')
\r
753 bordertime = 20;//FLASHTICS;
\r
755 VW_ColorBorder (15 | 56);
\r
759 _fmemcpy (str,text,80);
\r
760 DisplayMsg(str,NULL);
\r
763 //===========================================================================
\r
773 char DisplayMsg(char *text,char *choices)
\r
783 VW_Bar (WindowX,2,WindowW,8,STATUSCOLOR);
\r
785 fontcolor = TEXTCOLOR^STATUSCOLOR;
\r
786 US_CPrintLine (text);
\r
791 ch=GetKeyChoice(choices,true);
\r
805 char DisplaySMsg(char *text,char *choices)
\r
815 VW_Bar(WindowX,PrintY+1,WindowW,8,STATUSCOLOR);
\r
817 fontcolor = TEXTCOLOR^STATUSCOLOR;
\r
818 US_CPrintLine (text);
\r
823 ch=GetKeyChoice(choices,true);
\r
830 //===========================================================================
\r
840 void DrawRadar (void)
\r
846 LatchDrawPic (radarx,radary,RADAR_TOPPIC);
\r
849 asm mov dx,GC_INDEX
\r
850 asm mov ax,2*256+GC_MODE
\r
851 asm out dx,ax // write mode 2
\r
853 asm mov ax,GC_DATAROTATE
\r
854 asm out dx,ax // no rotation / logical operation
\r
856 asm mov dx,SC_INDEX
\r
857 asm mov al,SC_MAPMASK
\r
859 asm out dx,ax // write to all four planes
\r
863 while (RadarXY[objnum][2] != -1)
\r
865 RadarBlip(radar_xcenter+RadarXY[objnum][0],radar_ycenter+RadarXY[objnum][1],RadarXY[objnum][2]);
\r
870 asm mov dx,GC_INDEX
\r
871 asm mov ax,255*256+GC_BITMASK
\r
872 asm out dx,ax // reset bitmask to %11111111
\r
876 //===========================================================================
\r
879 //--------------------------------------------------------------------------
\r
880 // DrawNSEWIcons(void)
\r
881 //--------------------------------------------------------------------------
\r
883 void DrawRadarObj(short dx, short dy, unsigned sprnum,signed long psin,signed long pcos);
\r
885 void DrawNSEWIcons()
\r
889 x = -FixedByFrac(RADAR_X_IRADIUS,costable[player->angle]);
\r
890 y = -FixedByFrac(RADAR_Y_IRADIUS,sintable[player->angle]);
\r
892 VWB_DrawSprite(radar_xcenter+x-3,radar_ycenter+y-3,NORTHICONSPR);
\r
905 void DrawBars (void)
\r
908 unsigned source,dest,topline;
\r
912 bufferofs = screenloc[i];
\r
913 VW_Bar (34*8,POWERLINE,40,MAXSHOTPOWER,1);
\r
916 asm mov es,[screenseg]
\r
921 if (gamestate.shotpower)
\r
923 topline = MAXSHOTPOWER - gamestate.shotpower;
\r
925 source = latchpics[SHOTPOWERPIC-FIRSTLATCHPIC]+topline*SIDEBARWIDTH;
\r
926 dest = (POWERLINE+topline)*SCREENWIDTH+34;
\r
928 asm mov si,[source]
\r
931 asm mov cx,[WORD PTR gamestate.shotpower]
\r
934 asm mov [es:di+PAGE1START],al
\r
935 asm mov [es:di+PAGE2START],al
\r
936 asm mov [es:di+PAGE3START],al
\r
937 asm mov al,[es:si+1]
\r
938 asm mov [es:di+1+PAGE1START],al
\r
939 asm mov [es:di+1+PAGE2START],al
\r
940 asm mov [es:di+1+PAGE3START],al
\r
941 asm mov al,[es:si+2]
\r
942 asm mov [es:di+2+PAGE1START],al
\r
943 asm mov [es:di+2+PAGE2START],al
\r
944 asm mov [es:di+2+PAGE3START],al
\r
945 asm mov al,[es:si+3]
\r
946 asm mov [es:di+3+PAGE1START],al
\r
947 asm mov [es:di+3+PAGE2START],al
\r
948 asm mov [es:di+3+PAGE3START],al
\r
949 asm mov al,[es:si+4]
\r
950 asm mov [es:di+4+PAGE1START],al
\r
951 asm mov [es:di+4+PAGE2START],al
\r
952 asm mov [es:di+4+PAGE3START],al
\r
954 asm add di,SCREENWIDTH
\r
963 if (gamestate.body)
\r
965 source = latchpics[BODYPIC-FIRSTLATCHPIC];
\r
966 dest = BODYLINE*SCREENWIDTH+34;
\r
968 asm mov si,[source]
\r
971 asm mov cx,[WORD PTR gamestate.body]
\r
974 asm mov [es:di+PAGE1START],al
\r
975 asm mov [es:di+PAGE2START],al
\r
976 asm mov [es:di+PAGE3START],al
\r
977 asm mov al,[es:si+1]
\r
978 asm mov [es:di+1+PAGE1START],al
\r
979 asm mov [es:di+1+PAGE2START],al
\r
980 asm mov [es:di+1+PAGE3START],al
\r
981 asm mov al,[es:si+2]
\r
982 asm mov [es:di+2+PAGE1START],al
\r
983 asm mov [es:di+2+PAGE2START],al
\r
984 asm mov [es:di+2+PAGE3START],al
\r
985 asm mov al,[es:si+3]
\r
986 asm mov [es:di+3+PAGE1START],al
\r
987 asm mov [es:di+3+PAGE2START],al
\r
988 asm mov [es:di+3+PAGE3START],al
\r
989 asm mov al,[es:si+4]
\r
990 asm mov [es:di+4+PAGE1START],al
\r
991 asm mov [es:di+4+PAGE2START],al
\r
992 asm mov [es:di+4+PAGE3START],al
\r
994 asm add di,SCREENWIDTH
\r
1000 if (gamestate.body != MAXBODY)
\r
1002 source = latchpics[NOBODYPIC-FIRSTLATCHPIC]+gamestate.body*SIDEBARWIDTH;
\r
1003 dest = (BODYLINE+gamestate.body)*SCREENWIDTH+34;
\r
1004 topline = MAXBODY-gamestate.body;
\r
1006 asm mov si,[source]
\r
1009 asm mov cx,[WORD PTR topline]
\r
1011 asm mov al,[es:si]
\r
1012 asm mov [es:di+PAGE1START],al
\r
1013 asm mov [es:di+PAGE2START],al
\r
1014 asm mov [es:di+PAGE3START],al
\r
1015 asm mov al,[es:si+1]
\r
1016 asm mov [es:di+1+PAGE1START],al
\r
1017 asm mov [es:di+1+PAGE2START],al
\r
1018 asm mov [es:di+1+PAGE3START],al
\r
1019 asm mov al,[es:si+2]
\r
1020 asm mov [es:di+2+PAGE1START],al
\r
1021 asm mov [es:di+2+PAGE2START],al
\r
1022 asm mov [es:di+2+PAGE3START],al
\r
1023 asm mov al,[es:si+3]
\r
1024 asm mov [es:di+3+PAGE1START],al
\r
1025 asm mov [es:di+3+PAGE2START],al
\r
1026 asm mov [es:di+3+PAGE3START],al
\r
1027 asm mov al,[es:si+4]
\r
1028 asm mov [es:di+4+PAGE1START],al
\r
1029 asm mov [es:di+4+PAGE2START],al
\r
1030 asm mov [es:di+4+PAGE3START],al
\r
1032 asm add di,SCREENWIDTH
\r
1042 /////////////////////////////////////////////////////////////////////////////
\r
1044 // Check the object and make sure it is a monster. Used in making the sound
\r
1045 // of a monster being shot.
\r
1047 /////////////////////////////////////////////////////////////////////////////
\r
1049 boolean PlayMonsterSound(classtype objclass)
\r
1054 case realsolidobj:
\r
1063 =============================================================================
\r
1067 =============================================================================
\r
1070 void T_Pshot (objtype *ob);
\r
1073 extern statetype s_pshot1;
\r
1074 extern statetype s_pshot2;
\r
1076 //extern statetype s_bigpshot1;
\r
1077 //extern statetype s_bigpshot2;
\r
1080 statetype s_pshot1 = {PSHOT1PIC,8,&T_Pshot,&s_pshot2};
\r
1081 statetype s_pshot2 = {PSHOT2PIC,8,&T_Pshot,&s_pshot1};
\r
1084 statetype s_pshot_exp1 = {PSHOT_EXP1PIC,7,NULL,&s_pshot_exp2};
\r
1085 statetype s_pshot_exp2 = {PSHOT_EXP2PIC,7,NULL,&s_pshot_exp3};
\r
1086 statetype s_pshot_exp3 = {PSHOT_EXP3PIC,7,NULL,NULL};
\r
1089 //statetype s_shotexplode = {PSHOT2PIC,8,NULL,NULL};
\r
1091 //statetype s_bigpshot1 = {BIGPSHOT1PIC,8,&T_Pshot,&s_bigpshot2};
\r
1092 //statetype s_bigpshot2 = {BIGPSHOT2PIC,8,&T_Pshot,&s_bigpshot1};
\r
1096 ===================
\r
1100 ===================
\r
1103 void SpawnPShot (void)
\r
1105 DSpawnNewObjFrac (player->x,player->y,&s_pshot1,PIXRADIUS*2);
\r
1106 new->obclass = pshotobj;
\r
1107 new->speed = SHOTSPEED;
\r
1108 new->angle = player->angle;
\r
1109 new->active = always;
\r
1113 void SpawnBigPShot (void)
\r
1115 SpawnNewObjFrac (player->x,player->y,&s_bigpshot1,24*PIXRADIUS);
\r
1116 new->obclass = bigpshotobj;
\r
1117 new->speed = SHOTSPEED;
\r
1118 new->angle = player->angle;
\r
1124 ===================
\r
1126 = JimsShotClipMove
\r
1128 = Only checks corners, so the object better be less than one tile wide!
\r
1130 ===================
\r
1132 boolean JimsShotClipMove (objtype *ob, long xmove, long ymove)
\r
1134 int xl,yl,xh,yh,tx,ty,nt1,nt2,x,y;
\r
1135 long intersect,basex,basey,pointx,pointy;
\r
1136 unsigned inside,total,tile;
\r
1141 // move player and check to see if any corners are in solid tiles
\r
1146 // ob->x += xmove;
\r
1147 // ob->y += ymove;
\r
1149 // CalcBounds (ob);
\r
1151 xl = ob->xl>>TILESHIFT;
\r
1152 yl = ob->yl>>TILESHIFT;
\r
1154 xh = ob->xh>>TILESHIFT;
\r
1155 yh = ob->yh>>TILESHIFT;
\r
1157 for (y=yl;y<=yh;y++)
\r
1158 for (x=xl;x<=xh;x++)
\r
1160 check = actorat[x][y];
\r
1162 if ((!check) || (check == player) || (!(check->flags & of_shootable)))
\r
1168 if (check->obclass != solidobj)
\r
1170 if (PlayMonsterSound(check->obclass))
\r
1171 SD_PlaySound (SHOOTMONSTERSND);
\r
1172 if (ob->obclass == bigpshotobj)
\r
1173 ShootActor (check,BIGSHOTDAMAGE);
\r
1175 ShootActor (check,SHOTDAMAGE);
\r
1178 if (check->obclass == solidobj && (check->flags & of_forcefield))
\r
1180 if (PlayMonsterSound(check->obclass))
\r
1181 SD_PlaySound (SHOOTMONSTERSND);
\r
1182 if (ob->obclass == bigpshotobj)
\r
1183 ShootActor (check,BIGSHOTDAMAGE);
\r
1185 ShootActor (check,SHOTDAMAGE);
\r
1187 ob->state = &s_pshot_exp1;
\r
1188 ob->ticcount = ob->state->tictime;
\r
1192 return(false); // move is OK!
\r
1205 void T_Pshot (objtype *ob)
\r
1208 long xmove,ymove,speed;
\r
1211 // check current position for monsters having moved into it
\r
1213 for (check = player->next; check; check=check->next)
\r
1214 if ((check->flags & of_shootable)
\r
1215 && ob->xl <= check->xh
\r
1216 && ob->xh >= check->xl
\r
1217 && ob->yl <= check->yh
\r
1218 && ob->yh >= check->yl)
\r
1221 if (check->obclass != solidobj)
\r
1223 if (PlayMonsterSound(check->obclass))
\r
1224 SD_PlaySound (SHOOTMONSTERSND);
\r
1225 if (ob->obclass == bigpshotobj)
\r
1226 ShootActor (check,BIGSHOTDAMAGE);
\r
1228 ShootActor (check,SHOTDAMAGE);
\r
1231 ob->state = &s_pshot_exp1;
\r
1232 ob->ticcount = ob->state->tictime;
\r
1238 // move ahead, possibly hitting a wall
\r
1240 speed = ob->speed*tics;
\r
1242 xmove = FixedByFrac(speed,costable[ob->angle]);
\r
1243 ymove = -FixedByFrac(speed,sintable[ob->angle]);
\r
1245 if (ShotClipMove(ob,xmove,ymove))
\r
1247 ob->state = &s_pshot_exp1;
\r
1248 ob->ticcount = ob->state->tictime;
\r
1252 ob->tilex = ob->x >> TILESHIFT;
\r
1253 ob->tiley = ob->y >> TILESHIFT;
\r
1256 // check final position for monsters hit
\r
1258 for (check = player->next; check; check=check->next)
\r
1259 if ((ob->flags & of_shootable)
\r
1260 && ob->xl <= check->xh
\r
1261 && ob->xh >= check->xl
\r
1262 && ob->yl <= check->yh
\r
1263 && ob->yh >= check->yl)
\r
1265 ShootActor (check,SHOTDAMAGE);
\r
1266 ob->state = &s_pshot_exp1;
\r
1267 ob->ticcount = ob->state->tictime;
\r
1275 void T_Pshot (objtype *ob)
\r
1278 long xmove,ymove,speed;
\r
1279 int xl,yl,xh,yh,tx,ty,nt1,nt2,x,y;
\r
1280 long intersect,basex,basey,pointx,pointy;
\r
1281 unsigned inside,total,tile;
\r
1285 // check current position for monsters having moved into it
\r
1287 for (check = player->next; check; check=check->next)
\r
1288 if ((check->flags & of_shootable)
\r
1289 && ob->xl <= check->xh
\r
1290 && ob->xh >= check->xl
\r
1291 && ob->yl <= check->yh
\r
1292 && ob->yh >= check->yl)
\r
1295 if (check->obclass != solidobj)
\r
1297 if (PlayMonsterSound(check->obclass))
\r
1298 SD_PlaySound (SHOOTMONSTERSND);
\r
1299 if (ob->obclass == bigpshotobj)
\r
1300 ShootActor (check,BIGSHOTDAMAGE);
\r
1302 ShootActor (check,SHOTDAMAGE);
\r
1305 ob->state = &s_pshot_exp1;
\r
1306 ob->obclass = expobj;
\r
1307 ob->ticcount = ob->state->tictime;
\r
1313 // move ahead, possibly hitting a wall
\r
1315 speed = ob->speed*tics;
\r
1317 xmove = FixedByFrac(speed,costable[ob->angle]);
\r
1318 ymove = -FixedByFrac(speed,sintable[ob->angle]);
\r
1320 if (ShotClipMove(ob,xmove,ymove))
\r
1322 ob->state = &s_pshot_exp1;
\r
1323 ob->obclass = expobj;
\r
1324 ob->ticcount = ob->state->tictime;
\r
1328 ob->tilex = ob->x >> TILESHIFT;
\r
1329 ob->tiley = ob->y >> TILESHIFT;
\r
1332 // check final position for monsters hit
\r
1335 JimsShotClipMove(obj,xmove,ymove);
\r
1341 =============================================================================
\r
1345 =============================================================================
\r
1356 void BuildShotPower (void)
\r
1358 int newlines,topline;
\r
1360 unsigned source,dest;
\r
1362 if (gamestate.shotpower == MAXSHOTPOWER)
\r
1366 for (i=lasttimecount-realtics;i<lasttimecount;i++)
\r
1367 newlines += (i&1);
\r
1369 gamestate.shotpower += newlines;
\r
1371 if (gamestate.shotpower > MAXSHOTPOWER)
\r
1373 newlines -= (gamestate.shotpower - MAXSHOTPOWER);
\r
1374 gamestate.shotpower = MAXSHOTPOWER;
\r
1379 //===========================================================================
\r
1389 void ClearShotPower (void)
\r
1391 unsigned source,dest,topline;
\r
1394 topline = MAXSHOTPOWER - gamestate.shotpower;
\r
1396 source = latchpics[L_NOSHOT]+topline*SIDEBARWIDTH;
\r
1397 dest = (POWERLINE+topline)*SCREENWIDTH+34;
\r
1399 asm mov es,[screenseg]
\r
1400 asm mov si,[source]
\r
1403 if (!gamestate.shotpower)
\r
1408 asm mov cx,[WORD PTR gamestate.shotpower]
\r
1410 asm mov al,[es:si]
\r
1411 asm mov [es:di+PAGE1START],al
\r
1412 asm mov [es:di+PAGE2START],al
\r
1413 asm mov [es:di+PAGE3START],al
\r
1414 asm mov al,[es:si+1]
\r
1415 asm mov [es:di+1+PAGE1START],al
\r
1416 asm mov [es:di+1+PAGE2START],al
\r
1417 asm mov [es:di+1+PAGE3START],al
\r
1418 asm mov al,[es:si+2]
\r
1419 asm mov [es:di+2+PAGE1START],al
\r
1420 asm mov [es:di+2+PAGE2START],al
\r
1421 asm mov [es:di+2+PAGE3START],al
\r
1422 asm mov al,[es:si+3]
\r
1423 asm mov [es:di+3+PAGE1START],al
\r
1424 asm mov [es:di+3+PAGE2START],al
\r
1425 asm mov [es:di+3+PAGE3START],al
\r
1426 asm mov al,[es:si+4]
\r
1427 asm mov [es:di+4+PAGE1START],al
\r
1428 asm mov [es:di+4+PAGE2START],al
\r
1429 asm mov [es:di+4+PAGE3START],al
\r
1431 asm add di,SCREENWIDTH
\r
1439 gamestate.shotpower = 0;
\r
1442 //===========================================================================
\r
1454 ClearShotPower ();
\r
1455 SD_PlaySound (SHOOTSND);
\r
1459 //===========================================================================
\r
1470 void BigShoot (void)
\r
1472 ClearShotPower ();
\r
1473 SD_PlaySound (BIGSHOOTSND);
\r
1478 //===========================================================================
\r
1488 void CastBolt (void)
\r
1490 if (!gamestate.bolts)
\r
1492 SD_PlaySound (NOITEMSND);
\r
1497 boltsleft = NUMBOLTS;
\r
1498 bolttimer = BOLTTICS;
\r
1511 void ContinueBolt (void)
\r
1513 bolttimer-=realtics;
\r
1517 bolttimer = BOLTTICS;
\r
1523 //===========================================================================
\r
1533 void CastNuke (void)
\r
1535 // extern boolean autofire;
\r
1539 if (!gamestate.nukes)
\r
1541 SD_PlaySound (NOITEMSND);
\r
1547 lastnuke = TimeCount;
\r
1549 for (angle = 0; angle < ANGLES; angle+= ANGLES/16)
\r
1551 DSpawnNewObjFrac (player->x,player->y,&s_pshot1,24*PIXRADIUS);
\r
1552 new->obclass = bigpshotobj;
\r
1553 new->speed = SHOTSPEED;
\r
1554 new->angle = angle;
\r
1555 new->active = always;
\r
1559 //===========================================================================
\r
1569 void DrinkPotion (void)
\r
1571 unsigned source,dest,topline;
\r
1573 if (!gamestate.potions)
\r
1575 SD_PlaySound (NOITEMSND);
\r
1579 DisplaySMsg("Curing", NULL);
\r
1581 gamestate.body = MAXBODY;
\r
1583 status_flag = S_NONE;
\r
1587 // draw a full up bar
\r
1589 source = latchpics[L_BODYBAR];
\r
1590 dest = BODYLINE*SCREENWIDTH+34;
\r
1592 asm mov es,[screenseg]
\r
1593 asm mov si,[source]
\r
1598 asm mov cx,MAXBODY
\r
1600 asm mov al,[es:si]
\r
1601 asm mov [es:di+PAGE1START],al
\r
1602 asm mov [es:di+PAGE2START],al
\r
1603 asm mov [es:di+PAGE3START],al
\r
1604 asm mov al,[es:si+1]
\r
1605 asm mov [es:di+1+PAGE1START],al
\r
1606 asm mov [es:di+1+PAGE2START],al
\r
1607 asm mov [es:di+1+PAGE3START],al
\r
1608 asm mov al,[es:si+2]
\r
1609 asm mov [es:di+2+PAGE1START],al
\r
1610 asm mov [es:di+2+PAGE2START],al
\r
1611 asm mov [es:di+2+PAGE3START],al
\r
1612 asm mov al,[es:si+3]
\r
1613 asm mov [es:di+3+PAGE1START],al
\r
1614 asm mov [es:di+3+PAGE2START],al
\r
1615 asm mov [es:di+3+PAGE3START],al
\r
1616 asm mov al,[es:si+4]
\r
1617 asm mov [es:di+4+PAGE1START],al
\r
1618 asm mov [es:di+4+PAGE2START],al
\r
1619 asm mov [es:di+4+PAGE3START],al
\r
1620 asm add di,SCREENWIDTH
\r
1631 //===========================================================================
\r
1635 ////////////////////////////////////////////////////////////////////////////
\r
1639 // parms - scroll -- the number of the scroll to display
\r
1640 // returns - a far pointer to the scroll text
\r
1642 ////////////////////////////////////////////////////////////////////////////
\r
1644 char far *GetScrollText (int scroll)
\r
1651 CA_CacheGrChunk(SCROLLTEXT);
\r
1656 txt = (char _seg *)grsegs[SCROLLTEXT];
\r
1660 while (*txt != '\n')
\r
1670 ofset = FP_OFF(txt);
\r
1672 while (*txt != '\n')
\r
1681 txt = (char _seg *)grsegs[SCROLLTEXT]+ofset;
\r
1683 UNMARKGRCHUNK(SCROLLTEXT);
\r
1685 } //End of GetScrollText
\r
1687 //===========================================================================
\r
1697 extern boolean tileneeded[NUMFLOORS];
\r
1699 void ReadScroll (int scroll)
\r
1703 unsigned *skytemp,*gndtemp,blackcolor=0;
\r
1704 char far *scrolltext;
\r
1706 DisplaySMsg("Reading Scroll", NULL);
\r
1707 bufferofs = displayofs = screenloc[screenpage];
\r
1709 if (status_flag != S_TIMESTOP)
\r
1710 status_flag = S_NONE;
\r
1714 CA_CacheGrChunk (SCROLLTOPPIC);
\r
1715 CA_CacheGrChunk (SCROLL1PIC);
\r
1716 CA_CacheGrChunk (SCROLLBOTTOMPIC);
\r
1718 skytemp = skycolor;
\r
1719 gndtemp = groundcolor;
\r
1720 skycolor = groundcolor = &blackcolor;
\r
1722 VW_Bar(0,0,VIEWWIDTH,VIEWHEIGHT,0);
\r
1723 VW_DrawPic (10,0,SCROLLTOPPIC);
\r
1724 VW_DrawPic (10,32,SCROLL1PIC);
\r
1725 VW_DrawPic (10,88,SCROLLBOTTOMPIC);
\r
1727 scrolltext = GetScrollText(scroll);
\r
1731 pi.xh = RIGHTEDGE;
\r
1734 pi.script[0] = (char far *)scrolltext;
\r
1737 skycolor = skytemp;
\r
1738 groundcolor = gndtemp;
\r
1740 UNMARKGRCHUNK(SCROLL1PIC);
\r
1741 UNMARKGRCHUNK(SCROLLTOPPIC);
\r
1742 UNMARKGRCHUNK(SCROLLBOTTOMPIC);
\r
1743 MM_FreePtr (&grsegs[SCROLL1PIC]);
\r
1744 MM_FreePtr (&grsegs[SCROLLTOPPIC]);
\r
1745 MM_FreePtr (&grsegs[SCROLLBOTTOMPIC]);
\r
1749 IN_ClearKeysDown ();
\r
1751 DisplayMsg("Press ENTER or ESC to exit.",NULL);
\r
1752 while ((!Keyboard[sc_Escape]) && (!Keyboard[sc_Enter]));
\r
1753 IN_ClearKeysDown ();
\r
1755 if (status_flag == S_TIMESTOP)
\r
1756 DisplaySMsg("Time Stopped: ",NULL);
\r
1770 FreezeTime = MAXFREEZETIME;
\r
1771 SD_PlaySound(FREEZETIMESND);
\r
1772 DisplaySMsg("Time Stopped: ",NULL);
\r
1773 status_flag = S_TIMESTOP;
\r
1785 void TakeDamage (int points)
\r
1787 unsigned source,dest,topline;
\r
1789 if (!gamestate.body || (bordertime && bcolor==FLASHCOLOR) || godmode)
\r
1792 points = EasyDoDamage(points);
\r
1794 if (points >= gamestate.body)
\r
1796 points = gamestate.body;
\r
1800 bordertime = FLASHTICS<<2;
\r
1801 bcolor = FLASHCOLOR;
\r
1802 VW_ColorBorder (FLASHCOLOR);
\r
1804 DisplaySMsg("Damaging blows!", NULL);
\r
1805 status_flag = S_NONE;
\r
1806 status_delay = 80;
\r
1808 if (gamestate.body<MAXBODY/3)
\r
1809 SD_PlaySound (TAKEDMGHURTSND);
\r
1811 SD_PlaySound (TAKEDAMAGESND);
\r
1813 gamestate.body -= points;
\r
1817 =============================================================================
\r
1821 =============================================================================
\r
1827 ==================
\r
1831 ==================
\r
1834 void OpenDoor (unsigned bx, unsigned by, unsigned doorbase)
\r
1837 unsigned far *map;
\r
1841 map = mapsegs[0]+farmapylookup[y]+x;
\r
1842 while (tilemap[x][y]-doorbase<4)
\r
1844 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;
\r
1849 map = mapsegs[0]+farmapylookup[y]+x;
\r
1850 while (tilemap[x][y]-doorbase<4)
\r
1852 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;
\r
1858 map = mapsegs[0]+farmapylookup[y]+x;
\r
1859 while (tilemap[x][y]-doorbase<4)
\r
1861 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;
\r
1866 map = mapsegs[0]+farmapylookup[y]+x;
\r
1867 while (tilemap[x][y]-doorbase<4)
\r
1869 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;
\r
1878 ==================
\r
1880 = RemoveWalls - similar to OpenDoor(), but on a different plane
\r
1882 ==================
\r
1884 void RemoveWalls (unsigned bx, unsigned by, unsigned remove_code)
\r
1887 unsigned far *map,*p2;
\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
1901 p2 = *(mapsegs[2]+farmapylookup[y]+x);
\r
1902 map = mapsegs[0]+farmapylookup[y]+x;
\r
1903 while (*p2 == remove_code)
\r
1905 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
1922 p2 = *(mapsegs[2]+farmapylookup[y]+x);
\r
1923 map = mapsegs[0]+farmapylookup[y]+x;
\r
1924 while (*p2 == remove_code)
\r
1926 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;
\r
1935 ==================
\r
1939 = Returns true if the move is blocked
\r
1941 ==================
\r
1944 boolean HitSpecialTile (unsigned x, unsigned y, unsigned tile)
\r
1948 unsigned temp,spot,curmap=gamestate.mapon,newlevel;
\r
1949 char *key_colors[] = {"a RED key",
\r
1957 playstate = ex_victorious;
\r
1974 if (!playstate && !FreezeTime)
\r
1977 // Is this an openable door? (Is "openable" a word?)
\r
1979 spot = (*(mapsegs[2]+farmapylookup[y]+x)) >> 8;
\r
1980 if (spot == CANT_OPEN_CODE) // CAN'T EVER OPEN (it's just for looks)
\r
1982 CenterWindow(30,4);
\r
1983 US_CPrint("\nThis door is permanently blocked");
\r
1984 VW_UpdateScreen();
\r
1985 IN_ClearKeysDown();
\r
1990 // make sure player has key to get into door
\r
1993 if (TILE_FLAGS(tile) & tf_EMBEDDED_KEY_COLOR)
\r
1994 keyspot = GATE_KEY_COLOR(tile);
\r
1996 keyspot = (*(mapsegs[2]+farmapylookup[y+1]+x)) >> 8;
\r
1999 if (!gamestate.keys[keyspot])
\r
2001 SD_PlaySound(HIT_GATESND);
\r
2002 CenterWindow(20,5);
\r
2003 US_CPrint("\nYou need\n");
\r
2004 US_CPrint(key_colors[keyspot]);
\r
2005 VW_UpdateScreen();
\r
2006 IN_ClearKeysDown();
\r
2012 // deal with this gate (warp? simply open? whatever...)
\r
2016 case NEXT_LEVEL_CODE: // WARP TO NEXT LEVEL
\r
2017 newlevel = gamestate.mapon+1;
\r
2018 playstate = ex_warped;
\r
2021 case REMOVE_DOOR_CODE: // REMOVE DOOR
\r
2022 (unsigned)actorat[x][y] = tilemap[x][y] = *(mapsegs[0]+farmapylookup[y]+x) = 0;
\r
2023 *(mapsegs[2]+farmapylookup[y+1]+x) = 0; // key no longer needed
\r
2028 default: // WARP TO A LEVEL
\r
2030 playstate = ex_warped;
\r
2034 if (playstate == ex_warped)
\r
2036 SD_PlaySound(HIT_GATESND);
\r
2037 // levelinfo *li=&gamestate.levels[curmap];
\r
2039 // OldAngle = FaceDoor(x,y);
\r
2041 if (!VerifyGateExit())
\r
2043 IN_ClearKeysDown ();
\r
2044 playstate = ex_stillplaying;
\r
2048 // FaceAngle(OldAngle);
\r
2052 *(mapsegs[2]+farmapylookup[y+1]+x) = 0; // key no longer needed
\r
2054 gamestate.mapon = newlevel;
\r
2055 SD_PlaySound(WARPUPSND);
\r
2056 IN_ClearKeysDown ();
\r
2058 // li->x = player->tilex;
\r
2059 // li->y = player->tiley;
\r
2060 // li->angle = player->angle+180;
\r
2061 // if (li->angle > 360)
\r
2062 // li->angle -= 360;
\r
2071 //-------------------------------------------------------------------------
\r
2072 // VerifyGateExit()
\r
2073 //-------------------------------------------------------------------------
\r
2074 boolean VerifyGateExit()
\r
2076 char choices[] = {sc_Escape,sc_Y,sc_N,0},ch;
\r
2078 ch=DisplayMsg("Pass this way? Y/N",choices);
\r
2081 return(ch == sc_Y);
\r
2086 ==================
\r
2090 = Returns true if the move is blocked
\r
2092 ==================
\r
2095 boolean TouchActor (objtype *ob, objtype *check)
\r
2097 if (ob->xh < check->xl || ob->xl > check->xh ||
\r
2098 ob->yh < check->yl || ob->yl > check->yh)
\r
2099 return false; // not quite touching
\r
2101 switch (check->obclass)
\r
2104 switch (check->temp1)
\r
2106 case B_BOLT: GiveBolt (); break;
\r
2108 case B_NUKE: GiveNuke (); break;
\r
2110 case B_POTION: GivePotion (); break;
\r
2112 // case B_RKEY2: GiveKey(B_RKEY-B_RKEY); break;
\r
2117 case B_BKEY: GiveKey (check->temp1-B_RKEY); break;
\r
2127 case B_SCROLL8: GiveScroll (check->temp1-B_SCROLL1,true); break;
\r
2131 case B_CHEST: GiveChest (); break;
\r
2138 SD_PlaySound(GETGEMSND);
\r
2139 gamestate.gems[check->temp1-B_RGEM] = GEM_DELAY_TIME;
\r
2140 redraw_gems = true;
\r
2144 Quit("TouchActor(): INVALID BONUS");
\r
2148 (unsigned)actorat[check->tilex][check->tiley] = 0;
\r
2149 RemoveObj (check);
\r
2155 (unsigned)actorat[check->tilex][check->tiley] = 0;
\r
2165 ==================
\r
2169 ==================
\r
2172 void CalcBounds (objtype *ob)
\r
2175 // calculate hit rect
\r
2177 ob->xl = ob->x - ob->size;
\r
2178 ob->xh = ob->x + ob->size;
\r
2179 ob->yl = ob->y - ob->size;
\r
2180 ob->yh = ob->y + ob->size;
\r
2185 ===================
\r
2189 ===================
\r
2192 boolean LocationInActor (objtype *ob)
\r
2194 int x,y,xmin,ymin,xmax,ymax;
\r
2199 xmin = (ob->x >> TILESHIFT)-2;
\r
2200 ymin = (ob->y >> TILESHIFT)-2;
\r
2204 for (x=xmin;x<xmax;x++)
\r
2205 for (y=ymin;y<ymax;y++)
\r
2207 check = actorat[x][y];
\r
2208 if (check>(objtype *)LASTTILE
\r
2209 && (check->flags & of_shootable)
\r
2210 && (check->obclass != bonusobj)
\r
2211 && (check->obclass != freezeobj)
\r
2212 && (check->obclass != solidobj)
\r
2213 && ob->xl-SIZE_TEST <= check->xh
\r
2214 && ob->xh+SIZE_TEST >= check->xl
\r
2215 && ob->yl-SIZE_TEST <= check->yh
\r
2216 && ob->yh+SIZE_TEST >= check->yl)
\r
2224 ===================
\r
2228 = Only checks corners, so the object better be less than one tile wide!
\r
2230 ===================
\r
2232 void ClipXMove (objtype *ob, long xmove)
\r
2234 int xl,yl,xh,yh,tx,ty,nt1,nt2,x,y;
\r
2235 long intersect,basex,basey,pointx,pointy;
\r
2236 unsigned inside,total,tile;
\r
2239 boolean invisible_present = false;
\r
2242 // move player and check to see if any corners are in solid tiles
\r
2251 xl = ob->xl>>TILESHIFT;
\r
2252 yl = ob->yl>>TILESHIFT;
\r
2254 xh = ob->xh>>TILESHIFT;
\r
2255 yh = ob->yh>>TILESHIFT;
\r
2257 for (y=yl;y<=yh;y++)
\r
2258 for (x=xl;x<=xh;x++)
\r
2260 check = actorat[x][y];
\r
2263 continue; // blank floor, walk ok
\r
2265 if ((unsigned)check <= LASTTILE)
\r
2267 if (TILE_FLAGS((unsigned)check) & tf_SPECIAL)
\r
2269 HitSpecialTile(x,y,(unsigned)check-SPECTILESTART);
\r
2273 if (TILE_FLAGS((unsigned)check) & tf_INVISIBLE_WALL)
\r
2275 invisible_present = true;
\r
2280 if (TILE_FLAGS((unsigned)check) & tf_SOLID)
\r
2282 goto blockmove; // solid wall
\r
2286 TouchActor(ob,check); // pick up items
\r
2290 // check nearby actors
\r
2292 if (LocationInActor(ob))
\r
2295 if (LocationInActor(ob))
\r
2298 if (LocationInActor(ob))
\r
2302 return; // move is OK!
\r
2307 // if (!SD_SoundPlaying())
\r
2308 // SD_PlaySound (HITWALLSND);
\r
2324 xl = ob->xl>>TILESHIFT;
\r
2325 yl = ob->yl>>TILESHIFT;
\r
2326 xh = ob->xh>>TILESHIFT;
\r
2327 yh = ob->yh>>TILESHIFT;
\r
2328 if (tilemap[xl][yl] || tilemap[xh][yl]
\r
2329 || tilemap[xh][yh] || tilemap[xl][yh] )
\r
2332 if (xmove>=-2048 && xmove <=2048)
\r
2340 if (invisible_present)
\r
2343 if (xmove>=-2048 && xmove <=2048)
\r
2351 if (xmove>=-2048 && xmove <=2048)
\r
2359 ===================
\r
2363 = Only checks corners, so the object better be less than one tile wide!
\r
2365 ===================
\r
2367 void ClipYMove (objtype *ob, long ymove)
\r
2369 int xl,yl,xh,yh,tx,ty,nt1,nt2,x,y;
\r
2370 long intersect,basex,basey,pointx,pointy;
\r
2371 unsigned inside,total,tile;
\r
2374 boolean invisible_present = false;
\r
2377 // move player and check to see if any corners are in solid tiles
\r
2386 xl = ob->xl>>TILESHIFT;
\r
2387 yl = ob->yl>>TILESHIFT;
\r
2389 xh = ob->xh>>TILESHIFT;
\r
2390 yh = ob->yh>>TILESHIFT;
\r
2392 for (y=yl;y<=yh;y++)
\r
2393 for (x=xl;x<=xh;x++)
\r
2395 check = actorat[x][y];
\r
2397 continue; // blank floor, walk ok
\r
2399 if ((unsigned)check <= LASTTILE)
\r
2401 if (TILE_FLAGS((unsigned)check) & tf_SPECIAL) // <=LASTSPECIALTILE)
\r
2403 HitSpecialTile (x,y,(unsigned)check-SPECTILESTART);
\r
2407 if (TILE_FLAGS((unsigned)check) & tf_INVISIBLE_WALL)
\r
2409 invisible_present = true;
\r
2414 if (TILE_FLAGS((unsigned)check) & tf_SOLID) // LASTWALLTILE)
\r
2416 goto blockmove; // solid wall
\r
2420 TouchActor(ob,check); // pick up items
\r
2424 // check nearby actors
\r
2426 if (LocationInActor(ob))
\r
2428 if (LocationInActor(ob))
\r
2433 return; // move is OK!
\r
2438 // if (!SD_SoundPlaying())
\r
2439 // SD_PlaySound (HITWALLSND);
\r
2455 xl = ob->xl>>TILESHIFT;
\r
2456 yl = ob->yl>>TILESHIFT;
\r
2457 xh = ob->xh>>TILESHIFT;
\r
2458 yh = ob->yh>>TILESHIFT;
\r
2459 if (tilemap[xl][yl] || tilemap[xh][yl]
\r
2460 || tilemap[xh][yh] || tilemap[xl][yh] )
\r
2463 if (ymove>=-2048 && ymove <=2048)
\r
2471 if (invisible_present)
\r
2474 if (ymove>=-2048 && ymove <=2048)
\r
2482 if (ymove>=-2048 && ymove <=2048)
\r
2489 //==========================================================================
\r
2493 ===================
\r
2497 = Only checks corners, so the object better be less than one tile wide!
\r
2499 ===================
\r
2502 boolean ShotClipMove (objtype *ob, long xmove, long ymove)
\r
2504 int xl,yl,xh,yh,tx,ty,nt1,nt2,x,y;
\r
2505 long intersect,basex,basey,pointx,pointy;
\r
2506 unsigned inside,total,spot,tile;
\r
2511 // move shot and check to see if any corners are in solid tiles
\r
2521 xl = ob->xl>>TILESHIFT;
\r
2522 yl = ob->yl>>TILESHIFT;
\r
2524 xh = ob->xh>>TILESHIFT;
\r
2525 yh = ob->yh>>TILESHIFT;
\r
2527 for (y=yl;y<=yh;y++)
\r
2528 for (x=xl;x<=xh;x++)
\r
2530 spot = (*(mapsegs[2]+farmapylookup[y]+x)) >> 8;
\r
2531 if (spot == EXP_WALL_CODE)
\r
2532 switch (ob->obclass)
\r
2536 ExplodeWall (x,y);
\r
2541 tile = *(mapsegs[0]+farmapylookup[y]+x);
\r
2542 if (TILE_FLAGS(tile) & tf_SOLID)
\r
2545 return false; // move is OK!
\r
2550 if (ob->obclass == pshotobj)
\r
2551 SD_PlaySound (SHOOTWALLSND);
\r
2570 xl = ob->xl>>TILESHIFT;
\r
2571 yl = ob->yl>>TILESHIFT;
\r
2572 xh = ob->xh>>TILESHIFT;
\r
2573 yh = ob->yh>>TILESHIFT;
\r
2574 if (tilemap[xl][yl] || tilemap[xh][yl]
\r
2575 || tilemap[xh][yh] || tilemap[xl][yh] )
\r
2578 if (xmove>=-2048 && xmove <=2048 && ymove>=-2048 && ymove <=2048)
\r
2587 if (xmove>=-2048 && xmove <=2048 && ymove>=-2048 && ymove <=2048)
\r
2597 =============================================================================
\r
2601 =============================================================================
\r
2606 void T_Player (objtype *ob);
\r
2608 statetype s_player = {0,0,&T_Player,&s_player};
\r
2618 void SpawnPlayer (int tilex, int tiley, int dir)
\r
2621 levelinfo *li=&gamestate.levels[gamestate.mapon];
\r
2627 player->angle = li->angle;
\r
2630 player->angle = (1-dir)*90;
\r
2633 player->obclass = playerobj;
\r
2634 player->active = always;
\r
2635 player->tilex = tilex;
\r
2636 player->tiley = tiley;
\r
2637 player->x = ((long)tilex<<TILESHIFT)+TILEGLOBAL/2;
\r
2638 player->y = ((long)tiley<<TILESHIFT)+TILEGLOBAL/2;
\r
2639 player->state = &s_player;
\r
2640 player->size = MINDIST;
\r
2641 CalcBounds(player);
\r
2642 player->angle = (1-dir)*90;
\r
2643 if (player->angle<0)
\r
2644 player->angle += ANGLES;
\r
2649 ===================
\r
2653 ===================
\r
2656 void Thrust (int angle, unsigned speed)
\r
2660 if (lasttimecount>>5 != ((lasttimecount-tics)>>5) )
\r
2665 if (lasttimecount&32)
\r
2666 SD_PlaySound (WALK1SND);
\r
2668 SD_PlaySound (WALK2SND);
\r
2671 xmove = FixedByFrac(speed,costable[angle]);
\r
2672 ymove = -FixedByFrac(speed,sintable[angle]);
\r
2674 ClipXMove(player,xmove);
\r
2675 ClipYMove(player,ymove);
\r
2676 player->tilex = player->x >> TILESHIFT;
\r
2677 player->tiley = player->y >> TILESHIFT;
\r
2683 =======================
\r
2687 =======================
\r
2690 void ControlMovement (objtype *ob)
\r
2696 if (control.button1)
\r
2702 // side to side move
\r
2706 else if (mousexmove<0)
\r
2707 speed = -(long)mousexmove*300;
\r
2709 speed = -(long)mousexmove*300;
\r
2711 if (control.xaxis == -1)
\r
2713 speed += PLAYERSPEED*tics;
\r
2715 else if (control.xaxis == 1)
\r
2717 speed -= PLAYERSPEED*tics;
\r
2722 if (speed >= TILEGLOBAL)
\r
2723 speed = TILEGLOBAL-1;
\r
2724 angle = ob->angle + ANGLES/4;
\r
2725 if (angle >= ANGLES)
\r
2727 Thrust (angle,speed); // move to left
\r
2729 else if (speed < 0)
\r
2731 if (speed <= -TILEGLOBAL)
\r
2732 speed = -TILEGLOBAL+1;
\r
2733 angle = ob->angle - ANGLES/4;
\r
2736 Thrust (angle,-speed); // move to right
\r
2748 if (control.xaxis == 1)
\r
2750 ob->angle -= tics;
\r
2751 if (running) // fast turn
\r
2752 ob->angle -= (tics<<1);
\r
2754 else if (control.xaxis == -1)
\r
2757 if (running) // fast turn
\r
2758 ob->angle += (tics<<1);
\r
2761 ob->angle -= (mousexmove/10);
\r
2763 if (ob->angle >= ANGLES)
\r
2764 ob->angle -= ANGLES;
\r
2765 if (ob->angle < 0)
\r
2766 ob->angle += ANGLES;
\r
2771 // forward/backwards move
\r
2775 else if (mouseymove<0)
\r
2776 speed = -(long)mouseymove*500;
\r
2778 speed = -(long)mouseymove*200;
\r
2780 if (control.yaxis == -1)
\r
2782 speed += PLAYERSPEED*tics;
\r
2784 else if (control.yaxis == 1)
\r
2786 speed -= PLAYERSPEED*tics;
\r
2791 if (speed >= TILEGLOBAL)
\r
2792 speed = TILEGLOBAL-1;
\r
2793 Thrust (ob->angle,speed); // move forwards
\r
2795 else if (speed < 0)
\r
2797 if (speed <= -TILEGLOBAL)
\r
2798 speed = -TILEGLOBAL+1;
\r
2799 angle = ob->angle + ANGLES/2;
\r
2800 if (angle >= ANGLES)
\r
2802 Thrust (angle,-speed); // move backwards
\r
2815 void T_Player (objtype *ob)
\r
2817 // extern boolean autofire;
\r
2819 int angle,speed,scroll,loop;
\r
2820 unsigned text,tilex,tiley;
\r
2823 // boolean radar_moved=false;
\r
2826 ControlMovement (ob);
\r
2834 handheight+=(realtics<<2);
\r
2835 if (handheight>MAXHANDHEIGHT)
\r
2836 handheight = MAXHANDHEIGHT;
\r
2839 lasthand = lasttimecount;
\r
2843 if (control.button0)
\r
2845 handheight+=(realtics<<2);
\r
2846 if (handheight>MAXHANDHEIGHT)
\r
2847 handheight = MAXHANDHEIGHT;
\r
2848 lasthand = lasttimecount;
\r
2858 if (lasttimecount > lasthand+HANDPAUSE)
\r
2860 handheight-=(realtics<<1);
\r
2865 button0down = false;
\r
2870 if (control.button0)
\r
2872 handheight+=(realtics<<2);
\r
2873 if (handheight>MAXHANDHEIGHT)
\r
2874 handheight = MAXHANDHEIGHT;
\r
2876 if ((unsigned)TimeCount/FIRETIME != lastfiretime)
\r
2877 BuildShotPower ();
\r
2878 lasthand = lasttimecount;
\r
2882 if (lasttimecount > lasthand+HANDPAUSE)
\r
2884 handheight-=(realtics<<1);
\r
2889 if (gamestate.shotpower)
\r
2891 lastfiretime = (unsigned)TimeCount/FIRETIME;
\r
2899 // special actions
\r
2902 if ((Keyboard[sc_Space] || Keyboard[sc_C]) && gamestate.body != MAXBODY)
\r
2905 if (Keyboard[sc_Z] && !boltsleft)
\r
2908 if ( (Keyboard[sc_Enter] || Keyboard[sc_X]) && ((TimeCount-lastnuke > NUKETIME))) //|| (autofire)))
\r
2912 scroll = LastScan-2;
\r
2913 if ( scroll>=0 && scroll<NUMSCROLLS && gamestate.scrolls[scroll])
\r
2914 ReadScroll (scroll);
\r
2929 // gems fade out over time...
\r
2931 for (loop=0; loop<5; loop++)
\r
2932 if (gamestate.gems[loop])
\r
2934 gamestate.gems[loop] -= realtics;
\r
2935 if (gamestate.gems[loop] < 0)
\r
2937 gamestate.gems[loop] = 0;
\r
2938 redraw_gems = true;
\r
2945 //------------------------------------------------------------------------
\r
2948 // PARAMS : x,y - pixle coords to bring in to view.
\r
2950 // NOTE : Params CAN NOT be shifted fracs!
\r
2951 //------------------------------------------------------------------------
\r
2952 void FaceDir(short x,short y,boolean StopTime)
\r
2956 RotateAngle = CalcAngle(x-(player->x>>16l),(player->y>>16l)-y);
\r
2957 FreezeTime = StopTime;
\r
2959 diff = player->angle - RotateAngle;
\r
2961 if (((diff>0) && (diff<180)) || ((diff<0) && (diff>-180)))
\r
2962 RotateSpeed = -ROTATE_SPEED;
\r
2964 RotateSpeed = ROTATE_SPEED;
\r
2969 //------------------------------------------------------------------------
\r
2972 // DESC: Calculates the angle from a given dy & dx
\r
2973 //------------------------------------------------------------------------
\r
2974 short CalcAngle(short dx,short dy)
\r
2976 #define degtorad (180/PI)
\r
2983 angle = atan((float)dy/dx)* degtorad;
\r
2994 angle = 0 + 90; // Above player (NORTH)
\r
2996 angle = 180 + 90; // Below player (SOUTH)
\r
2999 if (!angle) // HACK
\r
3002 return((short)abs(angle));
\r
3009 //-------------------------------------------------------------------------
\r
3012 // DESC : Rotates view (current view of game) to a dest angle.
\r
3013 //-------------------------------------------------------------------------
\r
3018 // Store old angle position then change angle...
\r
3021 LastPos = player->angle;
\r
3023 player->angle += RotateSpeed;
\r
3025 // Check to see if we cranked past out dest angle...
\r
3029 if ((player->angle>ANGLES) || (!player->angle))
\r
3030 player->angle = 1;
\r
3032 if (player->angle<1)
\r
3033 player->angle = ANGLES;
\r
3035 // Check to see if we over shot our dest angle...
\r
3038 if (((LastPos < RotateAngle) && (player->angle > RotateAngle) && (RotateSpeed > 0)) ||
\r
3039 ((LastPos > RotateAngle) && (player->angle < RotateAngle) && (RotateSpeed < 0)))
\r
3040 player->angle = RotateAngle;
\r
3042 // Check for ending force turn....
\r
3045 if (player->angle == RotateAngle)
\r
3051 //--------------------------------------------------------------------------
\r
3053 //--------------------------------------------------------------------------
\r
3054 void InitRotate(short DestAngle)
\r
3056 if (player->angle != DestAngle)
\r
3058 RotateAngle = DestAngle;
\r
3060 if (player->angle > DestAngle)
\r
3061 RotateSpeed = -ROTATE_SPEED;
\r
3063 RotateSpeed = ROTATE_SPEED;
\r
3065 if (abs(player->angle - RotateAngle) > 180)
\r
3066 RotateSpeed =- RotateSpeed;
\r
3072 //------------------------------------------------------------------------
\r
3075 // PARAMS : DestAngle - Destination angle to turn to
\r
3076 //------------------------------------------------------------------------
\r
3077 void FaceAngle(short DestAngle)
\r
3079 signed long dx,dy,radius,psin,pcos,newx,newy;
\r
3081 short objnum,LastPos;
\r
3082 signed long ox,oy,xl,xh,yl,yh,px,py,norm_dx,norm_dy;
\r
3087 // Calculate the direction we want to turn to...
\r
3090 InitRotate(DestAngle);
\r
3092 RedrawStatusWindow();
\r
3094 while (RotateAngle != -1)
\r
3099 // PollControls();
\r
3103 for (obj = player;obj;obj = obj->next)
\r
3105 if (obj->active >= yes)
\r
3108 // keep a list of objects around the player for radar updates
\r
3110 if (obj == player)
\r
3114 psin = sintable[player->angle];
\r
3115 pcos = costable[player->angle];
\r
3116 xl = px-((long)RADAR_WIDTH<<TILESHIFT)/2;
\r
3117 xh = px+((long)RADAR_WIDTH<<TILESHIFT)/2-1;
\r
3118 yl = py-((long)RADAR_HEIGHT<<TILESHIFT)/2;
\r
3119 yh = py+((long)RADAR_HEIGHT<<TILESHIFT)/2;
\r
3122 if (objnum > MAX_RADAR_BLIPS-2)
\r
3123 objnum = MAX_RADAR_BLIPS-2;
\r
3129 if ((ox >= xl) && (ox <= xh) && (oy >= yl) && (oy <= yh))
\r
3131 norm_dx = (dx = px-ox)>>TILESHIFT;
\r
3132 norm_dy = (dy = oy-py)>>TILESHIFT;
\r
3134 o_radius = IntSqrt((norm_dx * norm_dx) + (norm_dy * norm_dy));
\r
3136 if (o_radius < RADAR_RADIUS)
\r
3138 newx = FixedByFrac(dy,pcos)-FixedByFrac(dx,psin);
\r
3139 newy = FixedByFrac(dy,psin)+FixedByFrac(dx,pcos);
\r
3141 RadarXY[objnum][0]=newx>>TILESHIFT;
\r
3142 RadarXY[objnum][1]=newy>>TILESHIFT;
\r
3144 // Define color to use for this object...
\r
3147 switch (obj->obclass)
\r
3150 RadarXY[objnum++][2]=15;
\r
3155 // STOMPY (DK RED)
\r
3157 case invisdudeobj:
\r
3159 RadarXY[objnum++][2]=4;
\r
3165 RadarXY[objnum++][2]=12;
\r
3170 // ROBOTANK (LT BLUE)
\r
3174 RadarXY[objnum++][2]=9;
\r
3178 // BLUE DEMON (DK BLUE)
\r
3181 RadarXY[objnum++][2]=1;
\r
3187 // WIZARD (LT GREEN)
\r
3190 RadarXY[objnum++][2]=10;
\r
3193 // AQUA MAN (DK GREEN)
\r
3196 RadarXY[objnum++][2]=2;
\r
3201 // EQYPTIAN HEAD (BROWN)
\r
3204 RadarXY[objnum++][2]=6;
\r
3207 // RAMBONE (YELLOW)
\r
3211 RadarXY[objnum++][2]=14;
\r
3214 // BUG (LIGHT GRAY)
\r
3216 RadarXY[objnum++][2]=7;
\r
3219 // RAY (DARK GRAY)
\r
3221 RadarXY[objnum++][2]=8;
\r
3226 // MEC DEMON (PURPLE)
\r
3228 case cyborgdemonobj:
\r
3229 RadarXY[objnum++][2]=5;
\r
3232 // EYE (LT PURPLE)
\r
3236 RadarXY[objnum++][2]=13;
\r
3244 RadarXY[objnum][2]=-1; // Signals end of RadarXY list...
\r
3259 //-------------------------------------------------------------------------
\r
3260 // FaceDoor() - Turns the player to face a door (a tile) at a given TILE x & y
\r
3262 // RETURNS : Returns the orginal angle of the player.
\r
3263 //------------------------------------------------------------------------
\r
3264 short FaceDoor(short x, short y)
\r
3266 short p_x,p_y,angle,old_angle;
\r
3268 old_angle = player->angle;
\r
3270 p_x = player->x>>16l;
\r
3271 p_y = player->y>>16l;
\r
3276 angle = 180; // Face Left
\r
3278 angle = 1; // Face Right
\r
3284 angle = 90; // Face Up
\r
3286 angle = 270; // Face Down
\r
3291 return(old_angle);
\r
3299 /*==========================================================================
\r
3301 EXPLOSION SPAWNING ROUTINES
\r
3303 ===========================================================================*/
\r
3305 statetype s_explode = {0,1,T_ExpThink,&s_explode};
\r
3307 //-------------------------------------------------------------------------
\r
3308 // SpawnExplosion()
\r
3309 //------------------------------------------------------------------------
\r
3310 void SpawnExplosion(fixed x, fixed y, short Delay)
\r
3312 DSpawnNewObjFrac(x,y,&s_explode,PIXRADIUS*7);
\r
3313 new->obclass = expobj;
\r
3314 new->active = always;
\r
3315 new->temp1 = Delay;
\r
3319 //---------------------------------------------------------------------------
\r
3321 //---------------------------------------------------------------------------
\r
3322 void T_ExpThink(objtype *obj)
\r
3326 if ((obj->temp1-=realtics) <= 0)
\r
3331 obj->state = &s_pshot_exp1;
\r
3332 obj->ticcount = obj->state->tictime;
\r
3333 SD_PlaySound(BOOMSND);
\r
3339 //-------------------------------------------------------------------------
\r
3340 // SpawnBigExplosion()
\r
3341 //------------------------------------------------------------------------
\r
3342 void SpawnBigExplosion(fixed x, fixed y, short Delay, fixed Range)
\r
3344 SpawnExplosion(x-random(Range),y+random(Range),random(Delay));
\r
3345 SpawnExplosion(x+random(Range),y-random(Range),random(Delay));
\r
3346 SpawnExplosion(x-random(Range),y-random(Range),random(Delay));
\r
3347 SpawnExplosion(x+random(Range),y+random(Range),random(Delay));
\r