]> 4ch.mooo.com Git - 16.git/blob - 16/cawat/C5_WIZ.C
wwww
[16.git] / 16 / cawat / C5_WIZ.C
1 /* Catacomb Armageddon Source Code\r
2  * Copyright (C) 1993-2014 Flat Rock Software\r
3  *\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
8  *\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
13  *\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
17  */\r
18 \r
19 // C3_WIZ.C\r
20 \r
21 #include "DEF.H"\r
22 #include "gelib.h"\r
23 #pragma hdrstop\r
24 \r
25 /*\r
26 =============================================================================\r
27 \r
28                                                  LOCAL CONSTANTS\r
29 \r
30 =============================================================================\r
31 */\r
32 \r
33 ////////#define NUMSCROLLS      8\r
34 \r
35 #define SHOWITEMS       9\r
36 \r
37 #define NUKETIME        40\r
38 #define NUMBOLTS        10\r
39 #define BOLTTICS        6\r
40 \r
41 #define STATUSCOLOR     8\r
42 #define TEXTCOLOR       14\r
43 \r
44 #define SIDEBARWIDTH    5\r
45 \r
46 #define BODYLINE    8\r
47 #define POWERLINE       80\r
48 \r
49 #define SPECTILESTART   0                       // 18\r
50 \r
51 \r
52 #define SHOTDAMAGE              1\r
53 #define BIGSHOTDAMAGE   3\r
54 \r
55 \r
56 #define PLAYERSPEED     5120\r
57 #define RUNSPEED        (8192<<1)\r
58 \r
59 #define SHOTSPEED       10000\r
60 \r
61 //#define LASTWALLTILE  47\r
62 //#define LASTSPECIALTILE       37\r
63 \r
64 #define LASTTILE  (LASTWALLPIC-FIRSTWALLPIC)                                                    // 47\r
65 \r
66 #define FIRETIME        2\r
67 \r
68 #define HANDPAUSE       60\r
69 \r
70 #define RIGHTEDGE       205;\r
71 #define LEFTEDGE        95;\r
72 #define PRNY            32;\r
73 #define WINX            10;\r
74 #define WINY            32;\r
75 \r
76 /*\r
77 =============================================================================\r
78 \r
79                                                  GLOBAL VARIABLES\r
80 \r
81 =============================================================================\r
82 */\r
83 \r
84 long            lastnuke,lasthand;\r
85 int                     lasttext;\r
86 int                     handheight;\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
91 \r
92 boolean redraw_gems,button0down;\r
93 \r
94 /*\r
95 =============================================================================\r
96 \r
97                                                  LOCAL VARIABLES\r
98 \r
99 =============================================================================\r
100 */\r
101 \r
102 int                     lastradar;\r
103 unsigned        lastfiretime;\r
104 \r
105 int     strafeangle[9] = {0,90,180,270,45,135,225,315,0};\r
106 \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
110 \r
111 \r
112 //===========================================================================\r
113 \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
132 \r
133 void DrawNum(short x,short y,short value,short maxdigits);\r
134 \r
135 //----------\r
136 \r
137 void Shoot (void);\r
138 void BigShoot (void);\r
139 void CastBolt (void);\r
140 void CastNuke (void);\r
141 void DrinkPotion (void);\r
142 \r
143 //----------\r
144 void DrawHealth(void);\r
145 \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
149 \r
150 //void AddPoints (int points);\r
151 \r
152 void ClipMove (objtype *ob, long xmove, long ymove);\r
153 boolean ShotClipMove (objtype *ob, long xmove, long ymove);\r
154 \r
155 //===========================================================================\r
156 \r
157 \r
158 /*\r
159 ===============\r
160 =\r
161 = DrawChar\r
162 =\r
163 ===============\r
164 */\r
165 \r
166 void DrawChar (unsigned x, unsigned y, unsigned tile)\r
167 {\r
168         unsigned junk = latchpics[0];\r
169 \r
170         EGAWRITEMODE(1);\r
171 asm     mov     bx,[y]\r
172 asm     shl     bx,1\r
173 asm     mov     di,[WORD PTR ylookup+bx]\r
174 asm     add     di,[x]\r
175 asm     mov     si,[tile]\r
176 asm     shl     si,1\r
177 asm     shl     si,1\r
178 asm     shl     si,1\r
179 asm     add     si,[junk]               // the damn inline assembler won't reference latchpics\r
180 asm     mov     ax,[screenseg]\r
181 asm     mov     es,ax\r
182 asm     mov     ds,ax\r
183 asm     mov     dx,SCREENWIDTH-1\r
184 asm     movsb\r
185 asm     add     di,dx\r
186 asm     movsb\r
187 asm     add     di,dx\r
188 asm     movsb\r
189 asm     add     di,dx\r
190 asm     movsb\r
191 asm     add     di,dx\r
192 asm     movsb\r
193 asm     add     di,dx\r
194 asm     movsb\r
195 asm     add     di,dx\r
196 asm     movsb\r
197 asm     add     di,dx\r
198 asm     movsb\r
199 \r
200 asm     mov     ax,ss\r
201 asm     mov     ds,ax\r
202         EGAWRITEMODE(0);\r
203 }\r
204 \r
205 \r
206 //===========================================================================\r
207 \r
208 /*\r
209 ===============\r
210 =\r
211 = RedrawStatusWindow\r
212 =\r
213 ===============\r
214 */\r
215 \r
216 void RedrawStatusWindow (void)\r
217 {\r
218         short keytype;\r
219 \r
220         EGABITMASK(0xff);\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
226 \r
227         DrawHealth();\r
228         DrawRadar();\r
229         EGAWRITEMODE(0);\r
230         DrawGems();\r
231 ////////        DrawScrolls();\r
232         redraw_gems = false;\r
233 }\r
234 \r
235 \r
236 //===========================================================================\r
237 \r
238 /*\r
239 ===============\r
240 =\r
241 = GiveBolt\r
242 =\r
243 ===============\r
244 */\r
245 \r
246 void GiveBolt (void)\r
247 {\r
248         if (gamestate.bolts == 99)\r
249                 return;\r
250 \r
251         SD_PlaySound (GETBOLTSND);\r
252         DrawNum(20,18,++gamestate.bolts,2);\r
253 }\r
254 \r
255 \r
256 /*\r
257 ===============\r
258 =\r
259 = TakeBolt\r
260 =\r
261 ===============\r
262 */\r
263 \r
264 void TakeBolt (void)\r
265 {\r
266         SD_PlaySound (USEBOLTSND);\r
267         DrawNum(20,18,--gamestate.bolts,2);\r
268 }\r
269 \r
270 //===========================================================================\r
271 \r
272 /*\r
273 ===============\r
274 =\r
275 = GiveNuke\r
276 =\r
277 ===============\r
278 */\r
279 \r
280 void GiveNuke (void)\r
281 {\r
282         if (gamestate.nukes == 99)\r
283                 return;\r
284 \r
285         SD_PlaySound (GETNUKESND);\r
286         DrawNum(20,36,++gamestate.nukes,2);\r
287 }\r
288 \r
289 \r
290 /*\r
291 ===============\r
292 =\r
293 = TakeNuke\r
294 =\r
295 ===============\r
296 */\r
297 \r
298 void TakeNuke (void)\r
299 {\r
300         SD_PlaySound (USENUKESND);\r
301         DrawNum(20,36,--gamestate.nukes,2);\r
302 }\r
303 \r
304 //===========================================================================\r
305 \r
306 /*\r
307 ===============\r
308 =\r
309 = GivePotion\r
310 =\r
311 ===============\r
312 */\r
313 \r
314 void GivePotion (void)\r
315 {\r
316         if (gamestate.potions == 99)\r
317                 return;\r
318 \r
319         SD_PlaySound (GETPOTIONSND);\r
320         DrawNum(20,54,++gamestate.potions,2);\r
321 }\r
322 \r
323 \r
324 /*\r
325 ===============\r
326 =\r
327 = TakePotion\r
328 =\r
329 ===============\r
330 */\r
331 \r
332 void TakePotion (void)\r
333 {\r
334         SD_PlaySound (USEPOTIONSND);\r
335         DrawNum(20,54,--gamestate.potions,2);\r
336 }\r
337 \r
338 //===========================================================================\r
339 \r
340 /*\r
341 ===============\r
342 =\r
343 = GiveKey\r
344 =\r
345 ===============\r
346 */\r
347 \r
348 void GiveKey (int keytype)\r
349 {\r
350         int     i,j,x;\r
351 \r
352         if (gamestate.keys[keytype] == 99)\r
353                 return;\r
354 \r
355         SD_PlaySound (GETKEYSND);\r
356         DrawNum(key_x[keytype],key_y[keytype],++gamestate.keys[keytype],2);\r
357 }\r
358 \r
359 \r
360 /*\r
361 ===============\r
362 =\r
363 = TakeKey\r
364 =\r
365 ===============\r
366 */\r
367 \r
368 void TakeKey (int keytype)\r
369 {\r
370         int     i,j,x;\r
371         char *key_colors[] = {"a RED key",\r
372                                                                  "a YELLOW key",\r
373                                                                  "a GREEN key",\r
374                                                                  "a BLUE key"};\r
375 \r
376 \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
383         VW_UpdateScreen();\r
384         VW_WaitVBL(120);\r
385 }\r
386 \r
387 \r
388 //===========================================================================\r
389 \r
390 /*\r
391 ===============\r
392 =\r
393 = GiveGem\r
394 =\r
395 ===============\r
396 */\r
397 \r
398 void GiveGem (int gemtype)\r
399 {\r
400 #if 0\r
401         int     i,j,x;\r
402 \r
403         SD_PlaySound (GETKEYSND);\r
404         DrawNum(key_x[keytype],key_y[keytype],++gamestate.keys[keytype],2);\r
405 #endif\r
406 }\r
407 \r
408 \r
409 /*\r
410 ===============\r
411 =\r
412 = TakeGem\r
413 =\r
414 ===============\r
415 */\r
416 \r
417 void TakeGem (int gemtype)\r
418 {\r
419 #if 0\r
420         int     i,j,x;\r
421 \r
422         SD_PlaySound (USEKEYSND);\r
423         DrawNum(key_x[keytype],key_y[keytype],--gamestate.keys[keytype],2);\r
424 #endif\r
425 }\r
426 \r
427 /*\r
428 ===============\r
429 =\r
430 = DrawGem\r
431 =\r
432 ===============\r
433 */\r
434 \r
435 void DrawGems()\r
436 {\r
437         short loop;\r
438 \r
439         redraw_gems = false;\r
440 \r
441         bufferofs = 0;\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
446 }\r
447 \r
448 //===========================================================================\r
449 \r
450 #if 0\r
451 \r
452 /*\r
453 ===============\r
454 =\r
455 = GiveScroll\r
456 =\r
457 ===============\r
458 */\r
459 \r
460 void GiveScroll (int scrolltype,boolean show)\r
461 {\r
462         int     i,j,x,y,scrollnum;\r
463 \r
464         SD_PlaySound (GETSCROLLSND);\r
465         gamestate.scrolls[scrolltype] = true;\r
466 \r
467         y = 30 + ((scrolltype > 3) * 10);\r
468         x = 26 + (scrolltype % 4);\r
469         DrawChar(x,y,SCROLLCHARS+scrolltype);\r
470 \r
471         if (show)\r
472                 ReadScroll(scrolltype);\r
473 }\r
474 \r
475 /*\r
476 ===============\r
477 =\r
478 = DrawScrolls\r
479 =\r
480 = Force draw of all scrolls\r
481 =\r
482 ===============\r
483 */\r
484 void DrawScrolls()\r
485 {\r
486         int loop,x,y;\r
487 \r
488         VW_Bar(210,30,30,18,0xf);\r
489 \r
490         for (loop=0;loop<8;loop++)\r
491                 if (gamestate.scrolls[loop])\r
492                 {\r
493                         y = 30 + ((loop > 3) * 10);\r
494                         x = 26 + (loop % 4);\r
495                         DrawChar(x,y,SCROLLCHARS+loop);\r
496                 }\r
497 }\r
498 #endif\r
499 \r
500 \r
501 //===========================================================================\r
502 \r
503 #if 0\r
504 /*\r
505 ===============\r
506 =\r
507 = GivePoints\r
508 =\r
509 ===============\r
510 */\r
511 \r
512 void GivePoints (int points)\r
513 {\r
514         pointcount = 1;\r
515         pointsleft += points;\r
516 }\r
517 #endif\r
518 \r
519 \r
520 //===========================================================================\r
521 \r
522 #if 0\r
523 /*\r
524 ===============\r
525 =\r
526 = AddPoints\r
527 =\r
528 ===============\r
529 */\r
530 \r
531 void AddPoints (int points)\r
532 {\r
533         char    str[10];\r
534         int             len,x,i;\r
535 \r
536         gamestate.score += points;\r
537 \r
538         ltoa (gamestate.score,str,10);\r
539         len = strlen (str);\r
540 \r
541         x=24+(8-len);\r
542         for (i=0;i<len;i++)\r
543                 DrawChar(x++,40,NUMBERCHARS+str[i]-'0');\r
544 }\r
545 #endif\r
546 \r
547 \r
548 //===========================================================================\r
549 \r
550 /*\r
551 ===============\r
552 =\r
553 = DrawHealth\r
554 =\r
555 ===============\r
556 */\r
557 void DrawHealth()\r
558 {\r
559         char picnum;\r
560         int percentage;\r
561 \r
562         percentage = PERCENTAGE(100,MAXBODY,gamestate.body,9);\r
563 \r
564         DrawNum(11,57,percentage,3);\r
565 \r
566         if (percentage > 75)\r
567                 picnum = FACE1PIC;\r
568         else\r
569         if (percentage > 50)\r
570                 picnum = FACE2PIC;\r
571         else\r
572         if (percentage > 25)\r
573                 picnum = FACE3PIC;\r
574         else\r
575         if (percentage)\r
576                 picnum = FACE4PIC;\r
577         else\r
578         {\r
579                 picnum = FACE5PIC;\r
580                 CA_CacheGrChunk (picnum);\r
581         }\r
582 \r
583         bufferofs = 0;\r
584         if (!percentage)\r
585         {\r
586                 UNMARKGRCHUNK(picnum);\r
587 //              VW_DrawPic(8,14,picnum);\r
588                 VW_DrawPic(10,14,picnum);\r
589         }\r
590         else\r
591                 LatchDrawPic(10,14,picnum);\r
592 }\r
593 \r
594 //===========================================================================\r
595 \r
596 /*\r
597 ===============\r
598 =\r
599 = DrawFreezeTime\r
600 =\r
601 ===============\r
602 */\r
603 void DrawFreezeTime()\r
604 {\r
605         long percentage;\r
606         percentage = PERCENTAGE(100,MAXFREEZETIME,(long)FreezeTime,7);\r
607         DrawNum(23,70,percentage,3);\r
608 }\r
609 \r
610 //===========================================================================\r
611 \r
612 /*\r
613 ===============\r
614 =\r
615 = DrawNum\r
616 =\r
617 ===============\r
618 */\r
619 void DrawNum(short x,short y,short value,short maxdigits)\r
620 {\r
621         char str[10],len,i;\r
622 \r
623         itoa(value,str,10);\r
624         len=strlen(str);\r
625 \r
626         for (i=len; i<maxdigits; i++)\r
627                 DrawChar(x++,y,BLANKCHAR);\r
628 \r
629         for (i=0;i<len;i++)\r
630                 DrawChar(x++,y,NUMBERCHARS+str[i]-'0');\r
631 }\r
632 \r
633 //===========================================================================\r
634 \r
635 /*\r
636 ===============\r
637 =\r
638 = GiveChest\r
639 =\r
640 ===============\r
641 */\r
642 \r
643 void GiveChest(void)\r
644 {\r
645         char i;\r
646 \r
647         for (i=0;i<random(4);i++)\r
648         {\r
649                 GiveBolt();\r
650                 SD_WaitSoundDone();\r
651         }\r
652 \r
653         for (i=0;i<random(3);i++)\r
654         {\r
655                 GiveNuke();\r
656                 SD_WaitSoundDone();\r
657         }\r
658 \r
659         for (i=0;i<random(2);i++)\r
660         {\r
661                 GivePotion();\r
662                 SD_WaitSoundDone();\r
663         }\r
664 }\r
665 \r
666 \r
667 //===========================================================================\r
668 \r
669 /*\r
670 ===============\r
671 =\r
672 = GiveGoal\r
673 =\r
674 ===============\r
675 */\r
676 \r
677 void GiveGoal (void)\r
678 {\r
679         SD_PlaySound (GETPOINTSSND);\r
680         playstate = ex_victorious;\r
681 }\r
682 \r
683 \r
684 //===========================================================================\r
685 \r
686 #if 0\r
687 /*\r
688 ===============\r
689 =\r
690 = DrawLevelNumber\r
691 =\r
692 ===============\r
693 */\r
694 \r
695 void DrawLevelNumber (int number)\r
696 {\r
697         char    str[10];\r
698         int             len;\r
699         unsigned        temp;\r
700 \r
701         bufferofs = 0;\r
702         if (number<9)\r
703                 PrintX=13;\r
704         else\r
705                 PrintX = 5;\r
706         PrintY = 4;\r
707         VW_Bar (5,4,16,9,STATUSCOLOR);\r
708         temp = fontcolor;\r
709         fontcolor = TEXTCOLOR^STATUSCOLOR;\r
710         US_PrintUnsigned (number+1);\r
711         fontcolor = temp;\r
712 }\r
713 #endif\r
714 \r
715 \r
716 //===========================================================================\r
717 \r
718 /*\r
719 ===============\r
720 =\r
721 = DrawText\r
722 =\r
723 ===============\r
724 */\r
725 \r
726 void DrawText (boolean draw_text_whether_it_needs_it_or_not)\r
727 {\r
728         unsigned        number;\r
729         char            str[80];\r
730         char            far *text;\r
731         unsigned        temp;\r
732 \r
733         //\r
734         // draw a new text description if needed\r
735         //\r
736         number = *(mapsegs[0]+farmapylookup[player->tiley]+player->tilex)-NAMESTART;\r
737 \r
738         if ( number>26 )\r
739                 number = 0;\r
740 \r
741         if ((number == lasttext) && (!draw_text_whether_it_needs_it_or_not))\r
742                 return;\r
743 \r
744         lasttext = number;\r
745 \r
746         text = (char _seg *)grsegs[LEVEL1TEXT+mapon]+textstarts[number];\r
747 \r
748         _fmemcpy (str,text,80);\r
749         DisplayMsg(str,NULL);\r
750 }\r
751 \r
752 //===========================================================================\r
753 \r
754 /*\r
755 ===============\r
756 =\r
757 = DisplayMsg\r
758 =\r
759 ===============\r
760 */\r
761 \r
762 char DisplayMsg(char *text,char *choices)\r
763 {\r
764         char ch=true;\r
765         short temp;\r
766 \r
767         bufferofs = 0;\r
768         PrintY = 1;\r
769         WindowX = 20;\r
770         WindowW = 270;\r
771 \r
772         VW_Bar (WindowX,2,WindowW,8,STATUSCOLOR);\r
773         temp = fontcolor;\r
774         fontcolor = TEXTCOLOR^STATUSCOLOR;\r
775         US_CPrintLine (text);\r
776         fontcolor = temp;\r
777 \r
778         if (choices)\r
779         {\r
780                 ch=GetKeyChoice(choices,true);\r
781                 LastScan = 0;\r
782         }\r
783 \r
784         return(ch);\r
785 }\r
786 \r
787 /*\r
788 ===============\r
789 =\r
790 = DisplaySMsg\r
791 =\r
792 ===============\r
793 */\r
794 char DisplaySMsg(char *text,char *choices)\r
795 {\r
796         char ch=true;\r
797         short temp;\r
798 \r
799         bufferofs = 0;\r
800         PrintY = 69;\r
801         WindowX = 98;\r
802         WindowW = 115;\r
803 \r
804         VW_Bar(WindowX,PrintY+1,WindowW,8,STATUSCOLOR);\r
805         temp = fontcolor;\r
806         fontcolor = TEXTCOLOR^STATUSCOLOR;\r
807         US_CPrintLine (text);\r
808         fontcolor = temp;\r
809 \r
810         if (choices)\r
811         {\r
812                 ch=GetKeyChoice(choices,true);\r
813                 LastScan = 0;\r
814         }\r
815 \r
816         return(ch);\r
817 }\r
818 \r
819 //===========================================================================\r
820 \r
821 /*\r
822 ===============\r
823 =\r
824 = DrawRadar\r
825 =\r
826 ===============\r
827 */\r
828 \r
829 void DrawRadar (void)\r
830 {\r
831         int             angle,number;\r
832         short objnum;\r
833 \r
834         bufferofs = 0;\r
835         LatchDrawPic (radarx,radary,RADAR_TOPPIC);\r
836 \r
837         asm     cli\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
841 \r
842         asm     mov     ax,GC_DATAROTATE\r
843         asm     out     dx,ax                // no rotation / logical operation\r
844 \r
845         asm     mov     dx,SC_INDEX\r
846         asm     mov     al,SC_MAPMASK\r
847         asm     mov     ah,15\r
848         asm     out     dx,ax                                           // write to all four planes\r
849         asm     sti\r
850 \r
851         objnum = 0;\r
852         while (RadarXY[objnum][2] != -1)\r
853         {\r
854                 RadarBlip(radar_xcenter+RadarXY[objnum][0],radar_ycenter+RadarXY[objnum][1],RadarXY[objnum][2]);\r
855                 objnum++;\r
856         }\r
857 \r
858         asm     cli\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
862         asm     sti\r
863 }\r
864 \r
865 //===========================================================================\r
866 \r
867 \r
868 //--------------------------------------------------------------------------\r
869 // DrawNSEWIcons(void)\r
870 //--------------------------------------------------------------------------\r
871 \r
872 void DrawRadarObj(short dx, short dy, unsigned sprnum,signed long psin,signed long pcos);\r
873 \r
874 void DrawNSEWIcons()\r
875 {\r
876         signed x,y;\r
877 \r
878         x = -FixedByFrac(RADAR_X_IRADIUS,costable[player->angle]);\r
879         y = -FixedByFrac(RADAR_Y_IRADIUS,sintable[player->angle]);\r
880 \r
881         VWB_DrawSprite(radar_xcenter+x-3,radar_ycenter+y-3,NORTHICONSPR);\r
882 \r
883 }\r
884 \r
885 #if 0\r
886 /*\r
887 ===============\r
888 =\r
889 = DrawBars\r
890 =\r
891 ===============\r
892 */\r
893 \r
894 void DrawBars (void)\r
895 {\r
896         int                     i;\r
897         unsigned        source,dest,topline;\r
898 \r
899         for (i=0;i<3;i++)\r
900         {\r
901                 bufferofs = screenloc[i];\r
902                 VW_Bar (34*8,POWERLINE,40,MAXSHOTPOWER,1);\r
903         }\r
904         EGAWRITEMODE(1);\r
905         asm     mov     es,[screenseg]\r
906 \r
907 //\r
908 // shot power\r
909 //\r
910         if (gamestate.shotpower)\r
911         {\r
912                 topline = MAXSHOTPOWER - gamestate.shotpower;\r
913 \r
914                 source = latchpics[SHOTPOWERPIC-FIRSTLATCHPIC]+topline*SIDEBARWIDTH;\r
915                 dest = (POWERLINE+topline)*SCREENWIDTH+34;\r
916 \r
917                 asm     mov     si,[source]\r
918                 asm     mov     di,[dest]\r
919 \r
920                 asm     mov     cx,[WORD PTR gamestate.shotpower]\r
921 newline:\r
922         asm     mov     al,[es:si]\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
942 \r
943         asm     add     di,SCREENWIDTH\r
944         asm     add     si,5\r
945 \r
946                 asm     loop    newline\r
947         }\r
948 \r
949 //\r
950 // body\r
951 //\r
952         if (gamestate.body)\r
953         {\r
954                 source = latchpics[BODYPIC-FIRSTLATCHPIC];\r
955                 dest = BODYLINE*SCREENWIDTH+34;\r
956 \r
957                 asm     mov     si,[source]\r
958                 asm     mov     di,[dest]\r
959 \r
960                 asm     mov     cx,[WORD PTR gamestate.body]\r
961 newline2:\r
962         asm     mov     al,[es:si]\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
982 \r
983         asm     add     di,SCREENWIDTH\r
984         asm     add     si,5\r
985 \r
986                 asm     loop    newline2\r
987         }\r
988 \r
989         if (gamestate.body != MAXBODY)\r
990         {\r
991                 source = latchpics[NOBODYPIC-FIRSTLATCHPIC]+gamestate.body*SIDEBARWIDTH;\r
992                 dest = (BODYLINE+gamestate.body)*SCREENWIDTH+34;\r
993                 topline = MAXBODY-gamestate.body;\r
994 \r
995                 asm     mov     si,[source]\r
996                 asm     mov     di,[dest]\r
997 \r
998                 asm     mov     cx,[WORD PTR topline]\r
999 newline3:\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
1020 \r
1021         asm     add     di,SCREENWIDTH\r
1022         asm     add     si,5\r
1023 \r
1024                 asm     loop    newline3\r
1025         }\r
1026 \r
1027         EGAWRITEMODE(0);\r
1028 }\r
1029 #endif\r
1030 \r
1031 /////////////////////////////////////////////////////////////////////////////\r
1032 //\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
1035 //\r
1036 /////////////////////////////////////////////////////////////////////////////\r
1037 \r
1038 boolean PlayMonsterSound(classtype objclass)\r
1039 {\r
1040         switch (objclass)\r
1041         {\r
1042                 case solidobj:\r
1043                 case realsolidobj:\r
1044                         return false;\r
1045                 default:\r
1046                         return true;\r
1047         }\r
1048 }\r
1049 \r
1050 \r
1051 /*\r
1052 =============================================================================\r
1053 \r
1054                                                         SHOTS\r
1055 \r
1056 =============================================================================\r
1057 */\r
1058 \r
1059 void T_Pshot (objtype *ob);\r
1060 \r
1061 \r
1062 extern  statetype s_pshot1;\r
1063 extern  statetype s_pshot2;\r
1064 \r
1065 //extern        statetype s_bigpshot1;\r
1066 //extern        statetype s_bigpshot2;\r
1067 \r
1068 \r
1069 statetype s_pshot1 = {PSHOT1PIC,8,&T_Pshot,&s_pshot2};\r
1070 statetype s_pshot2 = {PSHOT2PIC,8,&T_Pshot,&s_pshot1};\r
1071 \r
1072 \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
1076 \r
1077 \r
1078 //statetype s_shotexplode = {PSHOT2PIC,8,NULL,NULL};\r
1079 \r
1080 //statetype s_bigpshot1 = {BIGPSHOT1PIC,8,&T_Pshot,&s_bigpshot2};\r
1081 //statetype s_bigpshot2 = {BIGPSHOT2PIC,8,&T_Pshot,&s_bigpshot1};\r
1082 \r
1083 \r
1084 /*\r
1085 ===================\r
1086 =\r
1087 = SpawnPShot\r
1088 =\r
1089 ===================\r
1090 */\r
1091 \r
1092 void SpawnPShot (void)\r
1093 {\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
1099 }\r
1100 \r
1101 #if 0\r
1102 void SpawnBigPShot (void)\r
1103 {\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
1108 }\r
1109 #endif\r
1110 \r
1111 \r
1112 /*\r
1113 ===================\r
1114 =\r
1115 = JimsShotClipMove\r
1116 =\r
1117 = Only checks corners, so the object better be less than one tile wide!\r
1118 =\r
1119 ===================\r
1120 */\r
1121 boolean JimsShotClipMove (objtype *ob, long xmove, long ymove)\r
1122 {\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
1126         objtype         *check;\r
1127         boolean         moveok;\r
1128 \r
1129 //\r
1130 // move player and check to see if any corners are in solid tiles\r
1131 //\r
1132 //      basex = ob->x;\r
1133 //      basey = ob->y;\r
1134 \r
1135 //      ob->x += xmove;\r
1136 //      ob->y += ymove;\r
1137 \r
1138 //      CalcBounds (ob);\r
1139 \r
1140         xl = ob->xl>>TILESHIFT;\r
1141         yl = ob->yl>>TILESHIFT;\r
1142 \r
1143         xh = ob->xh>>TILESHIFT;\r
1144         yh = ob->yh>>TILESHIFT;\r
1145 \r
1146         for (y=yl;y<=yh;y++)\r
1147                 for (x=xl;x<=xh;x++)\r
1148                 {\r
1149                         check = actorat[x][y];\r
1150 \r
1151                         if ((!check) || (check == player) || (!(check->flags & of_shootable)))\r
1152                                 continue;\r
1153 \r
1154                         ob->x -= xmove;\r
1155                         ob->y -= ymove;\r
1156 \r
1157                         if (check->obclass != solidobj && check->obclass != hbunnyobj)\r
1158                         {\r
1159                                 if (PlayMonsterSound(check->obclass))\r
1160                                         SD_PlaySound (SHOOTMONSTERSND);\r
1161                                 if (ob->obclass == bigpshotobj)\r
1162                                         ShootActor (check,BIGSHOTDAMAGE);\r
1163                                 else\r
1164                                         ShootActor (check,SHOTDAMAGE);\r
1165                         }\r
1166                         else\r
1167                                 if (check->obclass == solidobj && (check->flags & of_forcefield))\r
1168                                 {\r
1169                                         if (PlayMonsterSound(check->obclass))\r
1170                                                 SD_PlaySound (SHOOTMONSTERSND);\r
1171                                         if (ob->obclass == bigpshotobj)\r
1172                                                 ShootActor (check,BIGSHOTDAMAGE);\r
1173                                         else\r
1174                                                 ShootActor (check,SHOTDAMAGE);\r
1175                                 }\r
1176                         ob->state = &s_pshot_exp1;\r
1177                         ob->ticcount = ob->state->tictime;\r
1178                         return(true);\r
1179                 }\r
1180 \r
1181         return(false);          // move is OK!\r
1182 \r
1183 }\r
1184 \r
1185 \r
1186 /*\r
1187 ===============\r
1188 =\r
1189 = T_Pshot\r
1190 =\r
1191 ===============\r
1192 */\r
1193 #if 0\r
1194 void T_Pshot (objtype *ob)\r
1195 {\r
1196         objtype *check;\r
1197         long    xmove,ymove,speed;\r
1198 \r
1199 //\r
1200 // check current position for monsters having moved into it\r
1201 //\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
1208                 {\r
1209 \r
1210                         if (check->obclass != solidobj)\r
1211                         {\r
1212                                 if (PlayMonsterSound(check->obclass))\r
1213                                         SD_PlaySound (SHOOTMONSTERSND);\r
1214                                 if (ob->obclass == bigpshotobj)\r
1215                                         ShootActor (check,BIGSHOTDAMAGE);\r
1216                                 else\r
1217                                         ShootActor (check,SHOTDAMAGE);\r
1218                         }\r
1219 \r
1220                         ob->state = &s_pshot_exp1;\r
1221                         ob->ticcount = ob->state->tictime;\r
1222                         return;\r
1223                 }\r
1224 \r
1225 \r
1226 //\r
1227 // move ahead, possibly hitting a wall\r
1228 //\r
1229         speed = ob->speed*tics;\r
1230 \r
1231         xmove = FixedByFrac(speed,costable[ob->angle]);\r
1232         ymove = -FixedByFrac(speed,sintable[ob->angle]);\r
1233 \r
1234         if (ShotClipMove(ob,xmove,ymove))\r
1235         {\r
1236                 ob->state = &s_pshot_exp1;\r
1237                 ob->ticcount = ob->state->tictime;\r
1238                 return;\r
1239         }\r
1240 \r
1241         ob->tilex = ob->x >> TILESHIFT;\r
1242         ob->tiley = ob->y >> TILESHIFT;\r
1243 \r
1244 //\r
1245 // check final position for monsters hit\r
1246 //\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
1253                 {\r
1254                         ShootActor (check,SHOTDAMAGE);\r
1255                         ob->state = &s_pshot_exp1;\r
1256                         ob->ticcount = ob->state->tictime;\r
1257                         return;\r
1258                 }\r
1259 }\r
1260 #endif\r
1261 \r
1262 \r
1263 \r
1264 void T_Pshot (objtype *ob)\r
1265 {\r
1266         objtype *check;\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
1271         boolean         moveok;\r
1272 \r
1273 //\r
1274 // check current position for monsters having moved into it\r
1275 //\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
1282                 {\r
1283 \r
1284                         if (check->obclass != solidobj && check->obclass != hbunnyobj)\r
1285                         {\r
1286                                 if (PlayMonsterSound(check->obclass))\r
1287                                         SD_PlaySound (SHOOTMONSTERSND);\r
1288                                 if (ob->obclass == bigpshotobj)\r
1289                                         ShootActor (check,BIGSHOTDAMAGE);\r
1290                                 else\r
1291                                         ShootActor (check,SHOTDAMAGE);\r
1292                         }\r
1293 \r
1294                         ob->state = &s_pshot_exp1;\r
1295                         ob->obclass = expobj;\r
1296                         ob->ticcount = ob->state->tictime;\r
1297                         return;\r
1298                 }\r
1299 \r
1300 \r
1301 //\r
1302 // move ahead, possibly hitting a wall\r
1303 //\r
1304         speed = ob->speed*tics;\r
1305 \r
1306         xmove = FixedByFrac(speed,costable[ob->angle]);\r
1307         ymove = -FixedByFrac(speed,sintable[ob->angle]);\r
1308 \r
1309         if (ShotClipMove(ob,xmove,ymove))\r
1310         {\r
1311                 ob->state = &s_pshot_exp1;\r
1312                 ob->obclass = expobj;\r
1313                 ob->ticcount = ob->state->tictime;\r
1314                 return;\r
1315         }\r
1316 \r
1317         ob->tilex = ob->x >> TILESHIFT;\r
1318         ob->tiley = ob->y >> TILESHIFT;\r
1319 \r
1320 //\r
1321 // check final position for monsters hit\r
1322 //\r
1323 \r
1324         JimsShotClipMove(obj,xmove,ymove);\r
1325 \r
1326 }\r
1327 \r
1328 \r
1329 /*\r
1330 =============================================================================\r
1331 \r
1332                                                         PLAYER ACTIONS\r
1333 \r
1334 =============================================================================\r
1335 */\r
1336 \r
1337 /*\r
1338 ===============\r
1339 =\r
1340 = BuildShotPower\r
1341 =\r
1342 ===============\r
1343 */\r
1344 \r
1345 void BuildShotPower (void)\r
1346 {\r
1347         int             newlines,topline;\r
1348         long    i;\r
1349         unsigned        source,dest;\r
1350 \r
1351         if (gamestate.shotpower == MAXSHOTPOWER)\r
1352                 return;\r
1353 \r
1354         newlines = 0;\r
1355         for (i=lasttimecount-realtics;i<lasttimecount;i++)\r
1356                 newlines += (i&1);\r
1357 \r
1358         gamestate.shotpower += newlines;\r
1359 \r
1360         if (gamestate.shotpower > MAXSHOTPOWER)\r
1361         {\r
1362                 newlines -= (gamestate.shotpower - MAXSHOTPOWER);\r
1363                 gamestate.shotpower = MAXSHOTPOWER;\r
1364         }\r
1365 }\r
1366 \r
1367 \r
1368 //===========================================================================\r
1369 \r
1370 /*\r
1371 ===============\r
1372 =\r
1373 = ClearShotPower\r
1374 =\r
1375 ===============\r
1376 */\r
1377 \r
1378 void ClearShotPower (void)\r
1379 {\r
1380         unsigned        source,dest,topline;\r
1381 \r
1382 #if 0\r
1383         topline = MAXSHOTPOWER - gamestate.shotpower;\r
1384 \r
1385         source = latchpics[L_NOSHOT]+topline*SIDEBARWIDTH;\r
1386         dest = (POWERLINE+topline)*SCREENWIDTH+34;\r
1387 \r
1388         asm     mov     es,[screenseg]\r
1389         asm     mov     si,[source]\r
1390         asm     mov     di,[dest]\r
1391 \r
1392         if (!gamestate.shotpower)\r
1393                 return;\r
1394 \r
1395         EGAWRITEMODE(1);\r
1396 \r
1397         asm     mov     cx,[WORD PTR gamestate.shotpower]\r
1398 newline:\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
1419 \r
1420         asm     add     di,SCREENWIDTH\r
1421         asm     add     si,5\r
1422 \r
1423         asm     loop    newline\r
1424 \r
1425         EGAWRITEMODE(0);\r
1426 #endif\r
1427 \r
1428         gamestate.shotpower = 0;\r
1429 }\r
1430 \r
1431 //===========================================================================\r
1432 \r
1433 /*\r
1434 ===============\r
1435 =\r
1436 = Shoot\r
1437 =\r
1438 ===============\r
1439 */\r
1440 \r
1441 void Shoot (void)\r
1442 {\r
1443         ClearShotPower ();\r
1444         SD_PlaySound (SHOOTSND);\r
1445         SpawnPShot ();\r
1446 }\r
1447 \r
1448 //===========================================================================\r
1449 \r
1450 #if 0\r
1451 /*\r
1452 ===============\r
1453 =\r
1454 = BigShoot\r
1455 =\r
1456 ===============\r
1457 */\r
1458 \r
1459 void BigShoot (void)\r
1460 {\r
1461         ClearShotPower ();\r
1462         SD_PlaySound (BIGSHOOTSND);\r
1463         SpawnBigPShot ();\r
1464 }\r
1465 #endif\r
1466 \r
1467 //===========================================================================\r
1468 \r
1469 /*\r
1470 ===============\r
1471 =\r
1472 = CastBolt\r
1473 =\r
1474 ===============\r
1475 */\r
1476 \r
1477 void CastBolt (void)\r
1478 {\r
1479         if (!gamestate.bolts)\r
1480         {\r
1481                 SD_PlaySound (NOITEMSND);\r
1482                 return;\r
1483         }\r
1484 \r
1485         TakeBolt ();\r
1486         boltsleft = NUMBOLTS;\r
1487         bolttimer = BOLTTICS;\r
1488         Shoot ();\r
1489 }\r
1490 \r
1491 \r
1492 /*\r
1493 ===============\r
1494 =\r
1495 = ContinueBolt\r
1496 =\r
1497 ===============\r
1498 */\r
1499 \r
1500 void ContinueBolt (void)\r
1501 {\r
1502         bolttimer-=realtics;\r
1503         if (bolttimer<0)\r
1504         {\r
1505                 boltsleft--;\r
1506                 bolttimer = BOLTTICS;\r
1507                 Shoot ();\r
1508         }\r
1509 }\r
1510 \r
1511 \r
1512 //===========================================================================\r
1513 \r
1514 /*\r
1515 ===============\r
1516 =\r
1517 = CastNuke\r
1518 =\r
1519 ===============\r
1520 */\r
1521 \r
1522 void CastNuke (void)\r
1523 {\r
1524         extern boolean autofire;\r
1525 \r
1526         int     angle;\r
1527 \r
1528         if (!gamestate.nukes)\r
1529         {\r
1530                 SD_PlaySound (NOITEMSND);\r
1531                 return;\r
1532         }\r
1533 \r
1534         if (!autofire)\r
1535                 TakeNuke ();\r
1536         lastnuke = TimeCount;\r
1537 \r
1538         for (angle = 0; angle < ANGLES; angle+= ANGLES/16)\r
1539         {\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
1545         }\r
1546 }\r
1547 \r
1548 //===========================================================================\r
1549 \r
1550 /*\r
1551 ===============\r
1552 =\r
1553 = DrinkPotion\r
1554 =\r
1555 ===============\r
1556 */\r
1557 \r
1558 void DrinkPotion (void)\r
1559 {\r
1560         unsigned        source,dest,topline;\r
1561 \r
1562         if (!gamestate.potions)\r
1563         {\r
1564                 SD_PlaySound (NOITEMSND);\r
1565                 return;\r
1566         }\r
1567 \r
1568         DisplaySMsg("Curing", NULL);\r
1569         TakePotion ();\r
1570         gamestate.body = MAXBODY;\r
1571         VW_WaitVBL(30);\r
1572         status_flag    = S_NONE;\r
1573 \r
1574 #if 0\r
1575 //\r
1576 // draw a full up bar\r
1577 //\r
1578         source = latchpics[L_BODYBAR];\r
1579         dest = BODYLINE*SCREENWIDTH+34;\r
1580 \r
1581         asm     mov     es,[screenseg]\r
1582         asm     mov     si,[source]\r
1583         asm     mov     di,[dest]\r
1584 \r
1585         EGAWRITEMODE(1);\r
1586 \r
1587         asm     mov     cx,MAXBODY\r
1588 newline:\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
1610         asm     add     si,5\r
1611 \r
1612         asm     loop    newline\r
1613 \r
1614         EGAWRITEMODE(0);\r
1615 #endif\r
1616 }\r
1617 \r
1618 \r
1619 \r
1620 //===========================================================================\r
1621 \r
1622 #if 0\r
1623 \r
1624 ////////////////////////////////////////////////////////////////////////////\r
1625 //\r
1626 //   GetScrollText\r
1627 //\r
1628 //   parms   - scroll -- the number of the scroll to display\r
1629 //   returns - a far pointer to the scroll text\r
1630 //\r
1631 ////////////////////////////////////////////////////////////////////////////\r
1632 \r
1633 char far *GetScrollText (int scroll)\r
1634 {\r
1635         boolean found;\r
1636         int     i;\r
1637         char far *txt;\r
1638         unsigned ofset;\r
1639 \r
1640         CA_CacheGrChunk(SCROLLTEXT);\r
1641 \r
1642         found = false;\r
1643         i     = 0;\r
1644 \r
1645         txt = (char _seg *)grsegs[SCROLLTEXT];\r
1646 \r
1647         while (!found)\r
1648         {\r
1649                 while (*txt != '\n')\r
1650                 {\r
1651                         if (*txt == '\r')\r
1652                                 *txt = 0;\r
1653                         txt++;\r
1654                 }\r
1655                 txt++;\r
1656                 if (i == scroll)\r
1657                 {\r
1658                         found   = true;\r
1659                         ofset = FP_OFF(txt);\r
1660 \r
1661                         while (*txt != '\n')\r
1662                         {\r
1663                                 if (*txt == '\r')\r
1664                                         *txt = 0;\r
1665                                 txt++;\r
1666                         }\r
1667                 }\r
1668                 i++;\r
1669         }\r
1670         txt = (char _seg *)grsegs[SCROLLTEXT]+ofset;\r
1671 \r
1672         UNMARKGRCHUNK(SCROLLTEXT);\r
1673         return(txt);\r
1674 }       //End of GetScrollText\r
1675 \r
1676 //===========================================================================\r
1677 \r
1678 /*\r
1679 ===============\r
1680 =\r
1681 = ReadScroll\r
1682 =\r
1683 ===============\r
1684 */\r
1685 \r
1686 extern  boolean tileneeded[NUMFLOORS];\r
1687 \r
1688 void ReadScroll (int scroll)\r
1689 {\r
1690         PresenterInfo pi;\r
1691         int     i;\r
1692         unsigned *skytemp,*gndtemp,blackcolor=0;\r
1693         char far *scrolltext;\r
1694 \r
1695         DisplaySMsg("Reading Scroll", NULL);\r
1696         bufferofs = displayofs = screenloc[screenpage];\r
1697 \r
1698         if (status_flag != S_TIMESTOP)\r
1699                 status_flag = S_NONE;\r
1700 \r
1701         FreeUpMemory();\r
1702 \r
1703         CA_CacheGrChunk (SCROLLTOPPIC);\r
1704         CA_CacheGrChunk (SCROLL1PIC);\r
1705         CA_CacheGrChunk (SCROLLBOTTOMPIC);\r
1706 \r
1707         skytemp = skycolor;\r
1708         gndtemp = groundcolor;\r
1709         skycolor = groundcolor = &blackcolor;\r
1710 \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
1715 \r
1716         scrolltext = GetScrollText(scroll);\r
1717 \r
1718         pi.xl = LEFTEDGE;\r
1719         pi.yl = PRNY;\r
1720         pi.xh = RIGHTEDGE;\r
1721         pi.yh = PRNY+1;\r
1722         pi.bgcolor = 7;\r
1723         pi.script[0] = (char far *)scrolltext;\r
1724         Presenter(&pi);\r
1725 \r
1726         skycolor = skytemp;\r
1727         groundcolor = gndtemp;\r
1728 \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
1735 \r
1736         CacheScaleds();\r
1737 \r
1738         IN_ClearKeysDown ();\r
1739         lasttext = -1;\r
1740         DisplayMsg("Press ENTER or ESC to exit.",NULL);\r
1741         while ((!Keyboard[sc_Escape]) && (!Keyboard[sc_Enter]));\r
1742         IN_ClearKeysDown ();\r
1743 \r
1744         if (status_flag == S_TIMESTOP)\r
1745                 DisplaySMsg("Time Stopped:     ",NULL);\r
1746 }\r
1747 \r
1748 #endif\r
1749 \r
1750 \r
1751 //===============\r
1752 //\r
1753 // StopTime()\r
1754 //\r
1755 //\r
1756 //===============\r
1757 void StopTime()\r
1758 {\r
1759         FreezeTime = MAXFREEZETIME;\r
1760         SD_PlaySound(FREEZETIMESND);\r
1761         DisplaySMsg("Time Stopped:     ",NULL);\r
1762         status_flag = S_TIMESTOP;\r
1763 }\r
1764 \r
1765 \r
1766 /*\r
1767 ===============\r
1768 =\r
1769 = TakeDamage\r
1770 =\r
1771 ===============\r
1772 */\r
1773 \r
1774 void TakeDamage (int points)\r
1775 {\r
1776         unsigned        source,dest,topline;\r
1777 \r
1778         if (!gamestate.body || (bordertime && bcolor==FLASHCOLOR) || godmode)\r
1779                 return;\r
1780 \r
1781         if (points != 1)\r
1782                 points = EasyDoDamage(points);\r
1783 \r
1784         if (points >= gamestate.body)\r
1785         {\r
1786                 points = gamestate.body;\r
1787                 Flags |= FL_DEAD;\r
1788         }\r
1789 \r
1790         bordertime = FLASHTICS<<2;\r
1791         bcolor = FLASHCOLOR;\r
1792         VW_ColorBorder (FLASHCOLOR);\r
1793 \r
1794         DisplaySMsg("Damaging blows!", NULL);\r
1795         status_flag  = S_NONE;\r
1796         status_delay = 80;\r
1797 \r
1798         if (gamestate.body<MAXBODY/3)\r
1799                 SD_PlaySound (TAKEDMGHURTSND);\r
1800         else\r
1801                 SD_PlaySound (TAKEDAMAGESND);\r
1802 \r
1803         gamestate.body -= points;\r
1804 }\r
1805 \r
1806 /*\r
1807 =============================================================================\r
1808 \r
1809                                                         INTERACTION\r
1810 \r
1811 =============================================================================\r
1812 */\r
1813 \r
1814 \r
1815 #if 0\r
1816 /*\r
1817 ==================\r
1818 =\r
1819 = OpenDoor\r
1820 =\r
1821 ==================\r
1822 */\r
1823 \r
1824 void OpenDoor (unsigned bx, unsigned by, unsigned doorbase)\r
1825 {\r
1826         int x,y;\r
1827         unsigned        far *map;\r
1828 \r
1829         x=bx;\r
1830         y=by;\r
1831         map = mapsegs[0]+farmapylookup[y]+x;\r
1832         while (tilemap[x][y]-doorbase<4)\r
1833         {\r
1834                 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
1835                 map--;\r
1836                 x--;\r
1837         }\r
1838         x=bx+1;\r
1839         map = mapsegs[0]+farmapylookup[y]+x;\r
1840         while (tilemap[x][y]-doorbase<4)\r
1841         {\r
1842                 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
1843                 map++;\r
1844                 x++;\r
1845         }\r
1846         x=bx;\r
1847         y=by-1;\r
1848         map = mapsegs[0]+farmapylookup[y]+x;\r
1849         while (tilemap[x][y]-doorbase<4)\r
1850         {\r
1851                 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
1852                 map-=mapwidth;\r
1853                 y--;\r
1854         }\r
1855         y=by+1;\r
1856         map = mapsegs[0]+farmapylookup[y]+x;\r
1857         while (tilemap[x][y]-doorbase<4)\r
1858         {\r
1859                 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
1860                 map+=mapwidth;\r
1861                 y++;\r
1862         }\r
1863 }\r
1864 #endif\r
1865 \r
1866 #if 0\r
1867 /*\r
1868 ==================\r
1869 =\r
1870 = RemoveWalls - similar to OpenDoor(), but on a different plane\r
1871 =\r
1872 ==================\r
1873 */\r
1874 void RemoveWalls (unsigned bx, unsigned by, unsigned remove_code)\r
1875 {\r
1876         int x,y;\r
1877         unsigned        far *map,*p2;\r
1878 \r
1879         x=bx;\r
1880         y=by;\r
1881         p2 = *(mapsegs[2]+farmapylookup[y]+x);\r
1882         map = mapsegs[0]+farmapylookup[y]+x;\r
1883         while (*p2 == remove_code)\r
1884         {\r
1885                 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
1886                 map--;\r
1887                 p2--;\r
1888                 x--;\r
1889         }\r
1890         x=bx+1;\r
1891         p2 = *(mapsegs[2]+farmapylookup[y]+x);\r
1892         map = mapsegs[0]+farmapylookup[y]+x;\r
1893         while (*p2 == remove_code)\r
1894         {\r
1895                 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
1896                 map++;\r
1897                 p2++;\r
1898                 x++;\r
1899         }\r
1900         x=bx;\r
1901         y=by-1;\r
1902         p2 = *(mapsegs[2]+farmapylookup[y]+x);\r
1903         map = mapsegs[0]+farmapylookup[y]+x;\r
1904         while (*p2 == remove_code)\r
1905         {\r
1906                 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
1907                 map-=mapwidth;\r
1908                 p2 -= mapwidth;\r
1909                 y--;\r
1910         }\r
1911         y=by+1;\r
1912         p2 = *(mapsegs[2]+farmapylookup[y]+x);\r
1913         map = mapsegs[0]+farmapylookup[y]+x;\r
1914         while (*p2 == remove_code)\r
1915         {\r
1916                 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
1917                 map+=mapwidth;\r
1918                 p2 += mapwidth;\r
1919                 y++;\r
1920         }\r
1921 }\r
1922 #endif\r
1923 \r
1924 /*\r
1925 ==================\r
1926 =\r
1927 = HitSpecialTile\r
1928 =\r
1929 = Returns true if the move is blocked\r
1930 =\r
1931 ==================\r
1932 */\r
1933 \r
1934 boolean HitSpecialTile (unsigned x, unsigned y, unsigned tile)\r
1935 {\r
1936         objtype *check;\r
1937         short keyspot;\r
1938         unsigned        temp,spot,curmap=gamestate.mapon,newlevel;\r
1939         char *key_colors[] = {"a RED key",\r
1940                               "a YELLOW key",\r
1941                               "a GREEN key",\r
1942                               "a BLUE key"};\r
1943 \r
1944         switch (tile)\r
1945         {\r
1946                 case 65:\r
1947                         playstate = ex_victorious;\r
1948                 break;\r
1949 \r
1950                 case 9:\r
1951                 case 15:\r
1952                 case 27:\r
1953                 case 30:\r
1954                 case 40:\r
1955                 case 42:\r
1956                 case 43:\r
1957                 case 45:\r
1958                 case 46:\r
1959                 case 47:\r
1960                 case 49:\r
1961                 case 76:\r
1962                 case 77:\r
1963 \r
1964                         if (!playstate && !FreezeTime)\r
1965                         {\r
1966 \r
1967                         // Is this an openable door? (Is "openable" a word?)\r
1968                         //\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
1971                                 {\r
1972                                         CenterWindow(30,4);\r
1973                                         US_CPrint("\nThis door is permanently blocked");\r
1974                                         VW_UpdateScreen();\r
1975                                         IN_ClearKeysDown();\r
1976                                         IN_Ack();\r
1977                                         return;\r
1978                                 }\r
1979 \r
1980                                 // make sure player has key to get into door\r
1981                                 //\r
1982 \r
1983                                 if (TILE_FLAGS(tile) & tf_EMBEDDED_KEY_COLOR)\r
1984                                         keyspot = GATE_KEY_COLOR(tile);\r
1985                                 else\r
1986                                         keyspot = (*(mapsegs[2]+farmapylookup[y+1]+x)) >> 8;\r
1987 \r
1988                                 if (keyspot--)\r
1989                                         if (!gamestate.keys[keyspot])\r
1990                                         {\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
1997                                                 IN_Ack();\r
1998                                                 return;\r
1999                                         }\r
2000 \r
2001                         //\r
2002                         // deal with this gate (warp? simply open? whatever...)\r
2003                         //\r
2004                                 switch (spot)\r
2005                                 {\r
2006                                         case NEXT_LEVEL_CODE:           // WARP TO NEXT LEVEL\r
2007                                                 newlevel = gamestate.mapon+1;\r
2008                                                 playstate = ex_warped;\r
2009                                         break;\r
2010 \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
2014                                                 if (keyspot>=0)\r
2015                                                         TakeKey(keyspot);\r
2016                                         break;\r
2017 \r
2018                                         default:                        // WARP TO A LEVEL\r
2019                                                 newlevel = spot;\r
2020                                                 playstate = ex_warped;\r
2021                                         break;\r
2022                                 }\r
2023 \r
2024                                 if (playstate == ex_warped)\r
2025                                 {\r
2026                                         SD_PlaySound(HIT_GATESND);\r
2027 //                                      levelinfo *li=&gamestate.levels[curmap];\r
2028 \r
2029 //                                      OldAngle = FaceDoor(x,y);\r
2030 \r
2031                                         if (!VerifyGateExit())\r
2032                                         {\r
2033                                                 IN_ClearKeysDown ();\r
2034                                                 playstate = ex_stillplaying;\r
2035                                                 break;\r
2036                                         }\r
2037 \r
2038 //                                      FaceAngle(OldAngle);\r
2039 \r
2040                                         if (keyspot>=0)\r
2041                                                 TakeKey(keyspot);\r
2042                                         *(mapsegs[2]+farmapylookup[y+1]+x) = 0; // key no longer needed\r
2043 \r
2044                                         gamestate.mapon = newlevel;\r
2045                                         SD_PlaySound(WARPUPSND);\r
2046                                         IN_ClearKeysDown ();\r
2047 \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
2053                                 }\r
2054                         }\r
2055                 break;\r
2056         }\r
2057 \r
2058         return true;\r
2059 }\r
2060 \r
2061 //-------------------------------------------------------------------------\r
2062 // VerifyGateExit()\r
2063 //-------------------------------------------------------------------------\r
2064 boolean VerifyGateExit()\r
2065 {\r
2066         char choices[] = {sc_Escape,sc_Y,sc_N,0},ch;\r
2067 \r
2068         ch=DisplayMsg("Pass this way?      Y/N",choices);\r
2069         DrawText(true);\r
2070 \r
2071         return(ch == sc_Y);\r
2072 }\r
2073 \r
2074 \r
2075 /*\r
2076 ==================\r
2077 =\r
2078 = TouchActor\r
2079 =\r
2080 = Returns true if the move is blocked\r
2081 =\r
2082 ==================\r
2083 */\r
2084 \r
2085 boolean TouchActor (objtype *ob, objtype *check)\r
2086 {\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
2090 \r
2091         switch (check->obclass)\r
2092         {\r
2093                 case bonusobj:\r
2094                         switch (check->temp1)\r
2095                         {\r
2096                                 case B_BOLT:            GiveBolt ();            break;\r
2097 \r
2098                                 case B_NUKE:            GiveNuke ();            break;\r
2099 \r
2100                                 case B_POTION:          GivePotion ();          break;\r
2101 \r
2102 //                              case B_RKEY2:           GiveKey(B_RKEY-B_RKEY);                                 break;\r
2103 \r
2104                                 case B_RKEY:\r
2105                                 case B_YKEY:\r
2106                                 case B_GKEY:\r
2107                                 case B_BKEY:            GiveKey (check->temp1-B_RKEY);          break;\r
2108 \r
2109 #if 0\r
2110                                 case B_SCROLL1:\r
2111                                 case B_SCROLL2:\r
2112                                 case B_SCROLL3:\r
2113                                 case B_SCROLL4:\r
2114                                 case B_SCROLL5:\r
2115                                 case B_SCROLL6:\r
2116                                 case B_SCROLL7:\r
2117                                 case B_SCROLL8: GiveScroll (check->temp1-B_SCROLL1,true);       break;\r
2118 #endif\r
2119 \r
2120                                 case B_CHEST:           GiveChest ();           break;\r
2121 \r
2122                                 case B_RGEM:\r
2123                                 case B_YGEM:\r
2124                                 case B_GGEM:\r
2125                                 case B_BGEM:\r
2126                                 case B_PGEM:\r
2127                                         SD_PlaySound(GETGEMSND);\r
2128                                         gamestate.gems[check->temp1-B_RGEM] = GEM_DELAY_TIME;\r
2129                                         redraw_gems = true;\r
2130                                 break;\r
2131 \r
2132                                 default:\r
2133                                         Quit("TouchActor(): INVALID BONUS");\r
2134                                 break;\r
2135                         }\r
2136 \r
2137                         (unsigned)actorat[check->tilex][check->tiley] = 0;\r
2138                         RemoveObj (check);\r
2139 \r
2140                         return false;\r
2141 \r
2142                 case freezeobj:\r
2143                         StopTime();\r
2144                         (unsigned)actorat[check->tilex][check->tiley] = 0;\r
2145                         RemoveObj(check);\r
2146                         return(false);\r
2147 \r
2148                 case cloudobj:\r
2149                         TakeDamage(2);\r
2150                         return false;\r
2151         }\r
2152 \r
2153         return  true;\r
2154 }\r
2155 \r
2156 \r
2157 /*\r
2158 ==================\r
2159 =\r
2160 = CalcBounds\r
2161 =\r
2162 ==================\r
2163 */\r
2164 \r
2165 void CalcBounds (objtype *ob)\r
2166 {\r
2167 //\r
2168 // calculate hit rect\r
2169 //\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
2174 }\r
2175 \r
2176 \r
2177 /*\r
2178 ===================\r
2179 =\r
2180 = LocationInActor\r
2181 =\r
2182 ===================\r
2183 */\r
2184 \r
2185 boolean LocationInActor (objtype *ob)\r
2186 {\r
2187         int     x,y,xmin,ymin,xmax,ymax;\r
2188         objtype *check;\r
2189 \r
2190         CalcBounds (ob);\r
2191 \r
2192         xmin = (ob->x >> TILESHIFT)-2;\r
2193         ymin = (ob->y >> TILESHIFT)-2;\r
2194         xmax = xmin+5;\r
2195         ymax = ymin+5;\r
2196 \r
2197         for (x=xmin;x<xmax;x++)\r
2198                 for (y=ymin;y<ymax;y++)\r
2199                 {\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
2210                                         return true;\r
2211                 }\r
2212 \r
2213         return false;\r
2214 }\r
2215 \r
2216 /*\r
2217 ===================\r
2218 =\r
2219 = ClipXMove\r
2220 =\r
2221 = Only checks corners, so the object better be less than one tile wide!\r
2222 =\r
2223 ===================\r
2224 */\r
2225 void ClipXMove (objtype *ob, long xmove)\r
2226 {\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
2230         objtype         *check;\r
2231         boolean         moveok;\r
2232         boolean         invisible_present = false;\r
2233 \r
2234 //\r
2235 // move player and check to see if any corners are in solid tiles\r
2236 //\r
2237         basex = ob->x;\r
2238         basey = ob->y;\r
2239 \r
2240         ob->x += xmove;\r
2241 \r
2242         CalcBounds (ob);\r
2243 \r
2244         xl = ob->xl>>TILESHIFT;\r
2245         yl = ob->yl>>TILESHIFT;\r
2246 \r
2247         xh = ob->xh>>TILESHIFT;\r
2248         yh = ob->yh>>TILESHIFT;\r
2249 \r
2250         for (y=yl;y<=yh;y++)\r
2251                 for (x=xl;x<=xh;x++)\r
2252                 {\r
2253                         check = actorat[x][y];\r
2254 \r
2255                         if (!check)\r
2256                                 continue;               // blank floor, walk ok\r
2257 \r
2258                         if ((unsigned)check <= LASTTILE)\r
2259                         {\r
2260                                 if (TILE_FLAGS((unsigned)check) & tf_SPECIAL)\r
2261                                 {\r
2262                                         HitSpecialTile(x,y,(unsigned)check-SPECTILESTART);\r
2263                                         goto blockmove;\r
2264                                 }\r
2265 \r
2266                                 if (TILE_FLAGS((unsigned)check) & tf_INVISIBLE_WALL)\r
2267                                 {\r
2268                                         invisible_present = true;\r
2269                                         goto blockmove;\r
2270                                 }\r
2271 \r
2272 \r
2273                                 if (TILE_FLAGS((unsigned)check) & tf_SOLID)\r
2274                                 {\r
2275                                         goto blockmove;                 // solid wall\r
2276                                 }\r
2277                         }\r
2278 \r
2279                         TouchActor(ob,check);           // pick up items\r
2280                 }\r
2281 \r
2282 //\r
2283 // check nearby actors\r
2284 //\r
2285         if (LocationInActor(ob))\r
2286         {\r
2287                 ob->x -= xmove;\r
2288                 if (LocationInActor(ob))\r
2289                 {\r
2290                         ob->x += xmove;\r
2291                         if (LocationInActor(ob))\r
2292                                 ob->x -= xmove;\r
2293                 }\r
2294         }\r
2295         return;         // move is OK!\r
2296 \r
2297 \r
2298 blockmove:\r
2299 \r
2300 //      if (!SD_SoundPlaying())\r
2301 //              SD_PlaySound (HITWALLSND);\r
2302 \r
2303         moveok = false;\r
2304 \r
2305         do\r
2306         {\r
2307                 xmove /= 2;\r
2308                 if (moveok)\r
2309                 {\r
2310                         ob->x += xmove;\r
2311                 }\r
2312                 else\r
2313                 {\r
2314                         ob->x -= xmove;\r
2315                 }\r
2316                 CalcBounds (ob);\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
2323                 {\r
2324                         moveok = false;\r
2325                         if (xmove>=-2048 && xmove <=2048)\r
2326                         {\r
2327                                 ob->x = basex;\r
2328                                 ob->y = basey;\r
2329                                 return;\r
2330                         }\r
2331                 }\r
2332                 else\r
2333                         if (invisible_present)\r
2334                         {\r
2335                                 moveok = false;\r
2336                                 if (xmove>=-2048 && xmove <=2048)\r
2337                                 {\r
2338                                         ob->x = basex;\r
2339                                         ob->y = basey;\r
2340                                         return;\r
2341                                 }\r
2342                         }\r
2343                         else\r
2344                                 if (xmove>=-2048 && xmove <=2048)\r
2345                                         return;\r
2346                                 moveok = true;\r
2347         } while (1);\r
2348 }\r
2349 \r
2350 \r
2351 /*\r
2352 ===================\r
2353 =\r
2354 = ClipYMove\r
2355 =\r
2356 = Only checks corners, so the object better be less than one tile wide!\r
2357 =\r
2358 ===================\r
2359 */\r
2360 void ClipYMove (objtype *ob, long ymove)\r
2361 {\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
2365         objtype         *check;\r
2366         boolean         moveok;\r
2367         boolean         invisible_present = false;\r
2368 \r
2369 //\r
2370 // move player and check to see if any corners are in solid tiles\r
2371 //\r
2372         basex = ob->x;\r
2373         basey = ob->y;\r
2374 \r
2375         ob->y += ymove;\r
2376 \r
2377         CalcBounds (ob);\r
2378 \r
2379         xl = ob->xl>>TILESHIFT;\r
2380         yl = ob->yl>>TILESHIFT;\r
2381 \r
2382         xh = ob->xh>>TILESHIFT;\r
2383         yh = ob->yh>>TILESHIFT;\r
2384 \r
2385         for (y=yl;y<=yh;y++)\r
2386                 for (x=xl;x<=xh;x++)\r
2387                 {\r
2388                         check = actorat[x][y];\r
2389                         if (!check)\r
2390                                 continue;               // blank floor, walk ok\r
2391 \r
2392                         if ((unsigned)check <= LASTTILE)\r
2393                         {\r
2394                                 if (TILE_FLAGS((unsigned)check) & tf_SPECIAL)           // <=LASTSPECIALTILE)\r
2395                                 {\r
2396                                         HitSpecialTile (x,y,(unsigned)check-SPECTILESTART);\r
2397                                         goto blockmove;\r
2398                                 }\r
2399 \r
2400                                 if (TILE_FLAGS((unsigned)check) & tf_INVISIBLE_WALL)\r
2401                                 {\r
2402                                         invisible_present = true;\r
2403                                         goto blockmove;\r
2404                                 }\r
2405 \r
2406 \r
2407                                 if (TILE_FLAGS((unsigned)check) & tf_SOLID)             // LASTWALLTILE)\r
2408                                 {\r
2409                                         goto blockmove; // solid wall\r
2410                                 }\r
2411                         }\r
2412 \r
2413                         TouchActor(ob,check);           // pick up items\r
2414                 }\r
2415 \r
2416 //\r
2417 // check nearby actors\r
2418 //\r
2419         if (LocationInActor(ob))\r
2420         {\r
2421                 if (LocationInActor(ob))\r
2422                 {\r
2423                         ob->y -= ymove;\r
2424                 }\r
2425         }\r
2426         return;         // move is OK!\r
2427 \r
2428 \r
2429 blockmove:\r
2430 \r
2431 //      if (!SD_SoundPlaying())\r
2432 //              SD_PlaySound (HITWALLSND);\r
2433 \r
2434         moveok = false;\r
2435 \r
2436         do\r
2437         {\r
2438                 ymove /= 2;\r
2439                 if (moveok)\r
2440                 {\r
2441                         ob->y += ymove;\r
2442                 }\r
2443                 else\r
2444                 {\r
2445                         ob->y -= ymove;\r
2446                 }\r
2447                 CalcBounds (ob);\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
2454                 {\r
2455                         moveok = false;\r
2456                         if (ymove>=-2048 && ymove <=2048)\r
2457                         {\r
2458                                 ob->x = basex;\r
2459                                 ob->y = basey;\r
2460                                 return;\r
2461                         }\r
2462                 }\r
2463                 else\r
2464                         if (invisible_present)\r
2465                         {\r
2466                                 moveok = false;\r
2467                                 if (ymove>=-2048 && ymove <=2048)\r
2468                                 {\r
2469                                         ob->x = basex;\r
2470                                         ob->y = basey;\r
2471                                         return;\r
2472                                 }\r
2473                         }\r
2474                         else\r
2475                                 if (ymove>=-2048 && ymove <=2048)\r
2476                                         return;\r
2477                                 moveok = true;\r
2478         } while (1);\r
2479 }\r
2480 \r
2481 \r
2482 //==========================================================================\r
2483 \r
2484 \r
2485 /*\r
2486 ===================\r
2487 =\r
2488 = ShotClipMove\r
2489 =\r
2490 = Only checks corners, so the object better be less than one tile wide!\r
2491 =\r
2492 ===================\r
2493 */\r
2494 \r
2495 boolean ShotClipMove (objtype *ob, long xmove, long ymove)\r
2496 {\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
2500         objtype         *check;\r
2501         boolean         moveok;\r
2502 \r
2503 //\r
2504 // move shot and check to see if any corners are in solid tiles\r
2505 //\r
2506         basex = ob->x;\r
2507         basey = ob->y;\r
2508 \r
2509         ob->x += xmove;\r
2510         ob->y += ymove;\r
2511 \r
2512         CalcBounds (ob);\r
2513 \r
2514         xl = ob->xl>>TILESHIFT;\r
2515         yl = ob->yl>>TILESHIFT;\r
2516 \r
2517         xh = ob->xh>>TILESHIFT;\r
2518         yh = ob->yh>>TILESHIFT;\r
2519 \r
2520         for (y=yl;y<=yh;y++)\r
2521                 for (x=xl;x<=xh;x++)\r
2522                 {\r
2523                         spot = (*(mapsegs[2]+farmapylookup[y]+x)) >> 8;\r
2524                         if (spot == EXP_WALL_CODE)\r
2525                                 switch (ob->obclass)\r
2526                                 {\r
2527                                         case pshotobj:\r
2528                                         case bigpshotobj:\r
2529                                                 ExplodeWall (x,y);\r
2530                                                 goto blockmove;\r
2531                                         break;\r
2532                                 }\r
2533 \r
2534                         tile = *(mapsegs[0]+farmapylookup[y]+x);\r
2535                         if (TILE_FLAGS(tile) & tf_SOLID)\r
2536                                 goto blockmove;\r
2537                 }\r
2538         return false;           // move is OK!\r
2539 \r
2540 \r
2541 blockmove:\r
2542 \r
2543         SD_PlaySound (SHOOTWALLSND);\r
2544 \r
2545         moveok = false;\r
2546 \r
2547         do\r
2548         {\r
2549                 xmove /= 2;\r
2550                 ymove /= 2;\r
2551                 if (moveok)\r
2552                 {\r
2553                         ob->x += xmove;\r
2554                         ob->y += ymove;\r
2555                 }\r
2556                 else\r
2557                 {\r
2558                         ob->x -= xmove;\r
2559                         ob->y -= ymove;\r
2560                 }\r
2561                 CalcBounds (ob);\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
2568                 {\r
2569                         moveok = false;\r
2570                         if (xmove>=-2048 && xmove <=2048 && ymove>=-2048 && ymove <=2048)\r
2571                         {\r
2572                                 ob->x = basex;\r
2573                                 ob->y = basey;\r
2574                                 return true;\r
2575                         }\r
2576                 }\r
2577                 else\r
2578                 {\r
2579                         if (xmove>=-2048 && xmove <=2048 && ymove>=-2048 && ymove <=2048)\r
2580                                 return true;\r
2581                         moveok = true;\r
2582                 }\r
2583         } while (1);\r
2584 }\r
2585 \r
2586 \r
2587 \r
2588 /*\r
2589 =============================================================================\r
2590 \r
2591                                                         PLAYER CONTROL\r
2592 \r
2593 =============================================================================\r
2594 */\r
2595 \r
2596 \r
2597 \r
2598 void    T_Player (objtype *ob);\r
2599 \r
2600 statetype s_player = {0,0,&T_Player,&s_player};\r
2601 \r
2602 /*\r
2603 ===============\r
2604 =\r
2605 = SpawnPlayer\r
2606 =\r
2607 ===============\r
2608 */\r
2609 \r
2610 void SpawnPlayer (int tilex, int tiley, int dir)\r
2611 {\r
2612 #if 0\r
2613         levelinfo *li=&gamestate.levels[gamestate.mapon];\r
2614 \r
2615         if (li->x != -1)\r
2616         {\r
2617                 tilex = li->x;\r
2618                 tiley = li->y;\r
2619                 player->angle = li->angle;\r
2620         }\r
2621         else\r
2622                 player->angle = (1-dir)*90;\r
2623 #endif\r
2624 \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
2637 }\r
2638 \r
2639 \r
2640 /*\r
2641 ===================\r
2642 =\r
2643 = Thrust\r
2644 =\r
2645 ===================\r
2646 */\r
2647 \r
2648 void Thrust (int angle, unsigned speed)\r
2649 {\r
2650         long xmove,ymove;\r
2651 \r
2652         if (lasttimecount>>5 != ((lasttimecount-tics)>>5) )\r
2653         {\r
2654         //\r
2655         // walk sound\r
2656         //\r
2657                 if (lasttimecount&32)\r
2658                         SD_PlaySound (WALK1SND);\r
2659                 else\r
2660                         SD_PlaySound (WALK2SND);\r
2661         }\r
2662 \r
2663         xmove = FixedByFrac(speed,costable[angle]);\r
2664         ymove = -FixedByFrac(speed,sintable[angle]);\r
2665 \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
2670 }\r
2671 \r
2672 \r
2673 \r
2674 /*\r
2675 =======================\r
2676 =\r
2677 = ControlMovement\r
2678 =\r
2679 =======================\r
2680 */\r
2681 \r
2682 void ControlMovement (objtype *ob)\r
2683 {\r
2684         int     angle;\r
2685         long    speed;\r
2686 \r
2687 \r
2688         if (control.button1)\r
2689         {\r
2690         //\r
2691         // strafing\r
2692         //\r
2693                 //\r
2694                 // side to side move\r
2695                 //\r
2696                 if (!mousexmove)\r
2697                         speed = 0;\r
2698                 else if (mousexmove<0)\r
2699                         speed = -(long)mousexmove*300;\r
2700                 else\r
2701                         speed = -(long)mousexmove*300;\r
2702 \r
2703                 if (control.xaxis == -1)\r
2704                 {\r
2705                         speed += PLAYERSPEED*tics;\r
2706                 }\r
2707                 else if (control.xaxis == 1)\r
2708                 {\r
2709                         speed -= PLAYERSPEED*tics;\r
2710                 }\r
2711 \r
2712                 if (speed > 0)\r
2713                 {\r
2714                         if (speed >= TILEGLOBAL)\r
2715                                 speed = TILEGLOBAL-1;\r
2716                         angle = ob->angle + ANGLES/4;\r
2717                         if (angle >= ANGLES)\r
2718                                 angle -= ANGLES;\r
2719                         Thrust (angle,speed);                           // move to left\r
2720                 }\r
2721                 else if (speed < 0)\r
2722                 {\r
2723                         if (speed <= -TILEGLOBAL)\r
2724                                 speed = -TILEGLOBAL+1;\r
2725                         angle = ob->angle - ANGLES/4;\r
2726                         if (angle < 0)\r
2727                                 angle += ANGLES;\r
2728                         Thrust (angle,-speed);                          // move to right\r
2729                 }\r
2730         }\r
2731         else\r
2732         {\r
2733         //\r
2734         // not strafing\r
2735         //\r
2736 \r
2737                 //\r
2738                 // turning\r
2739                 //\r
2740                 if (control.xaxis == 1)\r
2741                 {\r
2742                         ob->angle -= tics;\r
2743                         if (running)                            // fast turn\r
2744                                 ob->angle -= (tics<<1);\r
2745                 }\r
2746                 else if (control.xaxis == -1)\r
2747                 {\r
2748                         ob->angle+= tics;\r
2749                         if (running)                            // fast turn\r
2750                                 ob->angle += (tics<<1);\r
2751                 }\r
2752 \r
2753                 ob->angle -= (mousexmove/10);\r
2754 \r
2755                 if (ob->angle >= ANGLES)\r
2756                         ob->angle -= ANGLES;\r
2757                 if (ob->angle < 0)\r
2758                         ob->angle += ANGLES;\r
2759 \r
2760         }\r
2761 \r
2762         //\r
2763         // forward/backwards move\r
2764         //\r
2765         if (!mouseymove)\r
2766                 speed = 0;\r
2767         else if (mouseymove<0)\r
2768                 speed = -(long)mouseymove*500;\r
2769         else\r
2770                 speed = -(long)mouseymove*200;\r
2771 \r
2772         if (control.yaxis == -1)\r
2773         {\r
2774                 speed += PLAYERSPEED*tics;\r
2775         }\r
2776         else if (control.yaxis == 1)\r
2777         {\r
2778                 speed -= PLAYERSPEED*tics;\r
2779         }\r
2780 \r
2781         if (speed > 0)\r
2782         {\r
2783                 if (speed >= TILEGLOBAL)\r
2784                         speed = TILEGLOBAL-1;\r
2785                 Thrust (ob->angle,speed);                       // move forwards\r
2786         }\r
2787         else if (speed < 0)\r
2788         {\r
2789                 if (speed <= -TILEGLOBAL)\r
2790                         speed = -TILEGLOBAL+1;\r
2791                 angle = ob->angle + ANGLES/2;\r
2792                 if (angle >= ANGLES)\r
2793                         angle -= ANGLES;\r
2794                 Thrust (angle,-speed);                          // move backwards\r
2795         }\r
2796 }\r
2797 \r
2798 \r
2799 /*\r
2800 ===============\r
2801 =\r
2802 = T_Player\r
2803 =\r
2804 ===============\r
2805 */\r
2806 \r
2807 void    T_Player (objtype *ob)\r
2808 {\r
2809         extern boolean autofire;\r
2810 \r
2811         int     angle,speed,scroll,loop;\r
2812         unsigned        text,tilex,tiley;\r
2813         long    lspeed;\r
2814 \r
2815 //      boolean radar_moved=false;\r
2816 \r
2817 \r
2818         ControlMovement (ob);\r
2819 \r
2820 \r
2821         //\r
2822         // firing\r
2823         //\r
2824         if (boltsleft)\r
2825         {\r
2826                 handheight+=(realtics<<2);\r
2827                 if (handheight>MAXHANDHEIGHT)\r
2828                         handheight = MAXHANDHEIGHT;\r
2829 \r
2830                 ContinueBolt ();\r
2831                 lasthand = lasttimecount;\r
2832         }\r
2833         else\r
2834         {\r
2835                 if (control.button0)\r
2836                 {\r
2837                         handheight+=(realtics<<2);\r
2838                         if (handheight>MAXHANDHEIGHT)\r
2839                                 handheight = MAXHANDHEIGHT;\r
2840                         lasthand = lasttimecount;\r
2841 \r
2842                         if (!button0down)\r
2843                                 Shoot();\r
2844 \r
2845                         if (!autofire)\r
2846                                 button0down=true;\r
2847                 }\r
2848                 else\r
2849                 {\r
2850                         if (lasttimecount > lasthand+HANDPAUSE)\r
2851                         {\r
2852                                 handheight-=(realtics<<1);\r
2853                                 if (handheight<0)\r
2854                                         handheight = 0;\r
2855                         }\r
2856 \r
2857                         button0down = false;\r
2858                 }\r
2859 }\r
2860 \r
2861 #if 0\r
2862                 if (control.button0)\r
2863                 {\r
2864                         handheight+=(realtics<<2);\r
2865                         if (handheight>MAXHANDHEIGHT)\r
2866                                 handheight = MAXHANDHEIGHT;\r
2867 \r
2868                         if ((unsigned)TimeCount/FIRETIME != lastfiretime)\r
2869                                 BuildShotPower ();\r
2870                         lasthand = lasttimecount;\r
2871                 }\r
2872                 else\r
2873                 {\r
2874                         if (lasttimecount > lasthand+HANDPAUSE)\r
2875                         {\r
2876                                 handheight-=(realtics<<1);\r
2877                                 if (handheight<0)\r
2878                                         handheight = 0;\r
2879                         }\r
2880 \r
2881                         if (gamestate.shotpower)\r
2882                         {\r
2883                                 lastfiretime = (unsigned)TimeCount/FIRETIME;\r
2884                                 Shoot ();\r
2885                         }\r
2886                 }\r
2887         }\r
2888 #endif\r
2889 \r
2890         //\r
2891         // special actions\r
2892         //\r
2893 \r
2894         if ((Keyboard[sc_Space] || Keyboard[sc_C]) && gamestate.body != MAXBODY)\r
2895                 DrinkPotion ();\r
2896 \r
2897         if (Keyboard[sc_Z] && !boltsleft)\r
2898                 CastBolt ();\r
2899 \r
2900         if ( (Keyboard[sc_Enter] || Keyboard[sc_X]) && ((TimeCount-lastnuke > NUKETIME) || (autofire)))\r
2901                 CastNuke ();\r
2902 \r
2903 #if 0\r
2904         scroll = LastScan-2;\r
2905         if ( scroll>=0 && scroll<NUMSCROLLS && gamestate.scrolls[scroll])\r
2906                 ReadScroll (scroll);\r
2907 #endif\r
2908 \r
2909         DrawText(false);\r
2910         DrawHealth();\r
2911         if (FreezeTime)\r
2912                 DrawFreezeTime();\r
2913         DrawRadar();\r
2914         EGAWRITEMODE(0);\r
2915         DrawNSEWIcons();\r
2916 \r
2917         if (redraw_gems)\r
2918                 DrawGems();\r
2919 \r
2920 #if 0\r
2921 // gems fade out over time...\r
2922 //\r
2923         for (loop=0; loop<5; loop++)\r
2924                 if (gamestate.gems[loop])\r
2925                 {\r
2926                         gamestate.gems[loop] -= realtics;\r
2927                         if (gamestate.gems[loop] < 0)\r
2928                         {\r
2929                                 gamestate.gems[loop] = 0;\r
2930                                 redraw_gems = true;\r
2931                         }\r
2932                 }\r
2933 #endif\r
2934 }\r
2935 \r
2936 #if 0\r
2937 //------------------------------------------------------------------------\r
2938 // FaceDir() -\r
2939 //\r
2940 // PARAMS : x,y - pixle coords to bring in to view.\r
2941 //\r
2942 // NOTE : Params CAN NOT be shifted fracs!\r
2943 //------------------------------------------------------------------------\r
2944 void FaceDir(short x,short y,boolean StopTime)\r
2945 {\r
2946         short diff;\r
2947 \r
2948         RotateAngle = CalcAngle(x-(player->x>>16l),(player->y>>16l)-y);\r
2949         FreezeTime = StopTime;\r
2950 \r
2951         diff = player->angle - RotateAngle;\r
2952 \r
2953         if (((diff>0) && (diff<180)) || ((diff<0) && (diff>-180)))\r
2954                 RotateSpeed = -ROTATE_SPEED;\r
2955         else\r
2956                 RotateSpeed = ROTATE_SPEED;\r
2957 }\r
2958 #endif\r
2959 \r
2960 #if 0\r
2961 //------------------------------------------------------------------------\r
2962 // CalcAngle() -\r
2963 //\r
2964 // DESC: Calculates the angle from a given dy & dx\r
2965 //------------------------------------------------------------------------\r
2966 short CalcAngle(short dx,short dy)\r
2967 {\r
2968         #define degtorad                                (180/PI)\r
2969         float angle;\r
2970         short diff;\r
2971         float rad_angle;\r
2972 \r
2973         if (dx)\r
2974         {\r
2975                 angle = atan((float)dy/dx)* degtorad;\r
2976                 if (angle<=0)\r
2977                         angle += 180;\r
2978                 if (dy>0)\r
2979                         angle += 180;\r
2980         }\r
2981         else\r
2982         {\r
2983                 // 90 Deg shift\r
2984 \r
2985                 if (dy < 0)\r
2986                         angle = 0 + 90;                         // Above player (NORTH)\r
2987                 else\r
2988                         angle = 180 + 90;                       // Below player (SOUTH)\r
2989         }\r
2990 \r
2991         if (!angle)                             // HACK\r
2992                 angle++;\r
2993 \r
2994         return((short)abs(angle));\r
2995 }\r
2996 \r
2997 #endif\r
2998 \r
2999 #if 0\r
3000 \r
3001 //-------------------------------------------------------------------------\r
3002 // RotateView() -\r
3003 //\r
3004 // DESC : Rotates view (current view of game) to a dest angle.\r
3005 //-------------------------------------------------------------------------\r
3006 void RotateView()\r
3007 {\r
3008         short LastPos;\r
3009 \r
3010         // Store old angle position then change angle...\r
3011         //\r
3012 \r
3013         LastPos = player->angle;\r
3014 \r
3015         player->angle += RotateSpeed;\r
3016 \r
3017         // Check to see if we cranked past out dest angle...\r
3018         //\r
3019 \r
3020 \r
3021         if ((player->angle>ANGLES) || (!player->angle))\r
3022                 player->angle = 1;\r
3023         else\r
3024         if (player->angle<1)\r
3025                 player->angle = ANGLES;\r
3026 \r
3027         // Check to see if we over shot our dest angle...\r
3028         //\r
3029 \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
3033 \r
3034         // Check for ending force turn....\r
3035         //\r
3036 \r
3037         if (player->angle == RotateAngle)\r
3038                 RotateAngle = -1;\r
3039 \r
3040 }\r
3041 \r
3042 \r
3043 //--------------------------------------------------------------------------\r
3044 // InitRotate()\r
3045 //--------------------------------------------------------------------------\r
3046 void InitRotate(short DestAngle)\r
3047 {\r
3048         if (player->angle != DestAngle)\r
3049         {\r
3050                 RotateAngle = DestAngle;\r
3051 \r
3052                 if (player->angle > DestAngle)\r
3053                         RotateSpeed = -ROTATE_SPEED;\r
3054                 else\r
3055                         RotateSpeed = ROTATE_SPEED;\r
3056 \r
3057                 if (abs(player->angle - RotateAngle) > 180)\r
3058                         RotateSpeed =- RotateSpeed;\r
3059         }\r
3060 }\r
3061 \r
3062 \r
3063 \r
3064 //------------------------------------------------------------------------\r
3065 // FaceAngle() -\r
3066 //\r
3067 // PARAMS : DestAngle - Destination angle to turn to\r
3068 //------------------------------------------------------------------------\r
3069 void FaceAngle(short DestAngle)\r
3070 {\r
3071         signed long dx,dy,radius,psin,pcos,newx,newy;\r
3072         int             give;\r
3073         short objnum,LastPos;\r
3074         signed long ox,oy,xl,xh,yl,yh,px,py,norm_dx,norm_dy;\r
3075         short o_radius;\r
3076         void (*think)();\r
3077 \r
3078 \r
3079         // Calculate the direction we want to turn to...\r
3080         //\r
3081 \r
3082         InitRotate(DestAngle);\r
3083 \r
3084         RedrawStatusWindow();\r
3085 \r
3086         while (RotateAngle != -1)\r
3087         {\r
3088 \r
3089                 RotateView();\r
3090 \r
3091 //              PollControls();\r
3092 \r
3093                 objnum=0;\r
3094 \r
3095                 for (obj = player;obj;obj = obj->next)\r
3096                 {\r
3097                         if (obj->active >= yes)\r
3098                         {\r
3099 \r
3100                         // keep a list of objects around the player for radar updates\r
3101                         //\r
3102                                 if (obj == player)\r
3103                                 {\r
3104                                         px = player->x;\r
3105                                         py = player->y;\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
3112                                 }\r
3113 \r
3114                                 if (objnum > MAX_RADAR_BLIPS-2)\r
3115                                         objnum = MAX_RADAR_BLIPS-2;\r
3116 \r
3117                                 ox = obj->x;\r
3118                                 oy = obj->y;\r
3119 \r
3120 \r
3121                                 if ((ox >= xl) && (ox <= xh) && (oy >= yl) && (oy <= yh))\r
3122                                 {\r
3123                                         norm_dx = (dx = px-ox)>>TILESHIFT;\r
3124                                         norm_dy = (dy = oy-py)>>TILESHIFT;\r
3125 \r
3126                                         o_radius = IntSqrt((norm_dx * norm_dx) + (norm_dy * norm_dy));\r
3127 \r
3128                                         if (o_radius < RADAR_RADIUS)\r
3129                                         {\r
3130                                                 newx = FixedByFrac(dy,pcos)-FixedByFrac(dx,psin);\r
3131                                                 newy = FixedByFrac(dy,psin)+FixedByFrac(dx,pcos);\r
3132 \r
3133                                                 RadarXY[objnum][0]=newx>>TILESHIFT;\r
3134                                                 RadarXY[objnum][1]=newy>>TILESHIFT;\r
3135 \r
3136                                                 // Define color to use for this object...\r
3137                                                 //\r
3138 \r
3139                                                 switch (obj->obclass)\r
3140                                                 {\r
3141                                                         case playerobj:\r
3142                                                                 RadarXY[objnum++][2]=15;\r
3143                                                         break;\r
3144 \r
3145                                         // RED GEM\r
3146                                         //\r
3147                                                         case godessobj:\r
3148                                                                 if (gamestate.gems[B_RGEM-B_RGEM])\r
3149                                                                         if (obj->active == always)\r
3150                                                                                 RadarXY[objnum++][2]=12;\r
3151                                                         break;\r
3152 \r
3153                                         // GREEN GEM\r
3154                                         //\r
3155                                                         case fatdemonobj:\r
3156                                                                 if (gamestate.gems[B_GGEM-B_RGEM])\r
3157                                                                         if (obj->active == always)\r
3158                                                                                 RadarXY[objnum++][2]=10;\r
3159                                                         break;\r
3160 \r
3161                                         // YELLOW GEM\r
3162                                         //\r
3163                                                         case skeletonobj:\r
3164                                                                 if (gamestate.gems[B_YGEM-B_RGEM])\r
3165                                                                         if (obj->active == always)\r
3166                                                                                 RadarXY[objnum++][2]=14;\r
3167                                                         break;\r
3168 \r
3169                                         // BLUE GEM\r
3170                                         //\r
3171                                                         case mageobj:\r
3172                                                         case wetobj:\r
3173                                                                 if (gamestate.gems[B_BGEM-B_RGEM])\r
3174                                                                         if (obj->active == always)\r
3175                                                                                 RadarXY[objnum++][2]=9;\r
3176                                                         break;\r
3177 \r
3178                                         // PURPLE GEM\r
3179                                         //\r
3180                                                         case zombieobj:\r
3181                                                                 if (gamestate.gems[B_PGEM-B_RGEM])\r
3182                                                                         if (obj->active == always)\r
3183                                                                                 RadarXY[objnum++][2]=13;\r
3184                                                         break;\r
3185                                                 }\r
3186                                         }\r
3187                                 }\r
3188                         }\r
3189                 }\r
3190 \r
3191                 RadarXY[objnum][2]=-1;          // Signals end of RadarXY list...\r
3192 \r
3193 // refresh all\r
3194 //\r
3195 \r
3196                 ThreeDRefresh();\r
3197                 DrawRadar();\r
3198                 EGAWRITEMODE(0);\r
3199                 DrawNSEWIcons();\r
3200 \r
3201 //              CheckKeys();\r
3202         }\r
3203 }\r
3204 \r
3205 \r
3206 //-------------------------------------------------------------------------\r
3207 // FaceDoor() - Turns the player to face a door (a tile) at a given TILE x & y\r
3208 //\r
3209 // RETURNS : Returns the orginal angle of the player.\r
3210 //------------------------------------------------------------------------\r
3211 short FaceDoor(short x, short y)\r
3212 {\r
3213         short p_x,p_y,angle,old_angle;\r
3214 \r
3215         old_angle = player->angle;\r
3216 \r
3217         p_x = player->x>>16l;\r
3218         p_y = player->y>>16l;\r
3219 \r
3220         if (p_x != x)\r
3221         {\r
3222                 if (p_x > x)\r
3223                         angle = 180;            // Face Left\r
3224                 else\r
3225                         angle = 1;                      // Face Right\r
3226         }\r
3227 \r
3228         if (p_y != y)\r
3229         {\r
3230                 if (p_y > y)\r
3231                         angle = 90;                     // Face Up\r
3232                 else\r
3233                         angle = 270;            // Face Down\r
3234         }\r
3235 \r
3236         FaceAngle(angle);\r
3237 \r
3238         return(old_angle);\r
3239 }\r
3240 \r
3241 \r
3242 #endif\r
3243 \r
3244 \r
3245 \r
3246 /*==========================================================================\r
3247 \r
3248                                                                 EXPLOSION SPAWNING ROUTINES\r
3249 \r
3250 ===========================================================================*/\r
3251 \r
3252 statetype s_explode = {0,1,T_ExpThink,&s_explode};\r
3253 \r
3254 //-------------------------------------------------------------------------\r
3255 // SpawnExplosion()\r
3256 //------------------------------------------------------------------------\r
3257 void SpawnExplosion(fixed x, fixed y, short Delay)\r
3258 {\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
3263 }\r
3264 \r
3265 \r
3266 //---------------------------------------------------------------------------\r
3267 // T_ExpThink()\r
3268 //---------------------------------------------------------------------------\r
3269 void T_ExpThink(objtype *obj)\r
3270 {\r
3271         if (obj->temp1)\r
3272         {\r
3273                 if ((obj->temp1-=realtics) <= 0)\r
3274                         obj->temp1 = 0;\r
3275         }\r
3276         else\r
3277         {\r
3278                 obj->state = &s_pshot_exp1;\r
3279                 obj->ticcount = obj->state->tictime;\r
3280                 SD_PlaySound(BOOMSND);\r
3281         }\r
3282 }\r
3283 \r
3284 \r
3285 \r
3286 //-------------------------------------------------------------------------\r
3287 // SpawnBigExplosion()\r
3288 //------------------------------------------------------------------------\r
3289 void SpawnBigExplosion(fixed x, fixed y, short Delay, fixed Range)\r
3290 {\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
3295 }\r
3296 \r