]> 4ch.mooo.com Git - 16.git/blob - src/lib/hb/c6_wiz.c
[16_ca needs huge amounts of work and I should remember what needs to be done soon...
[16.git] / src / lib / hb / c6_wiz.c
1 /* Catacomb Apocalypse 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             1\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               30\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         short temp =  fontcolor;\r
606         long percentage;\r
607         percentage = PERCENTAGE(100,MAXFREEZETIME,(long)FreezeTime,7);\r
608         fontcolor = 1 ^ 14;\r
609         DrawNum(23,70,percentage,3);\r
610         fontcolor = temp;\r
611 }\r
612 \r
613 //===========================================================================\r
614 \r
615 /*\r
616 ===============\r
617 =\r
618 = DrawNum\r
619 =\r
620 ===============\r
621 */\r
622 void DrawNum(short x,short y,short value,short maxdigits)\r
623 {\r
624         char str[10],len,i;\r
625 \r
626         itoa(value,str,10);\r
627         len=strlen(str);\r
628 \r
629         for (i=len; i<maxdigits; i++)\r
630                 DrawChar(x++,y,BLANKCHAR);\r
631 \r
632         for (i=0;i<len;i++)\r
633                 DrawChar(x++,y,NUMBERCHARS+str[i]-'0');\r
634 }\r
635 \r
636 //===========================================================================\r
637 \r
638 /*\r
639 ===============\r
640 =\r
641 = GiveChest\r
642 =\r
643 ===============\r
644 */\r
645 \r
646 void GiveChest(void)\r
647 {\r
648         char i;\r
649 \r
650         for (i=0;i<random(4);i++)\r
651         {\r
652                 GiveBolt();\r
653                 SD_WaitSoundDone();\r
654         }\r
655 \r
656         for (i=0;i<random(3);i++)\r
657         {\r
658                 GiveNuke();\r
659                 SD_WaitSoundDone();\r
660         }\r
661 \r
662         for (i=0;i<random(2);i++)\r
663         {\r
664                 GivePotion();\r
665                 SD_WaitSoundDone();\r
666         }\r
667 }\r
668 \r
669 \r
670 //===========================================================================\r
671 \r
672 /*\r
673 ===============\r
674 =\r
675 = GiveGoal\r
676 =\r
677 ===============\r
678 */\r
679 \r
680 void GiveGoal (void)\r
681 {\r
682         SD_PlaySound (GETPOINTSSND);\r
683         playstate = ex_victorious;\r
684 }\r
685 \r
686 \r
687 //===========================================================================\r
688 \r
689 #if 0\r
690 /*\r
691 ===============\r
692 =\r
693 = DrawLevelNumber\r
694 =\r
695 ===============\r
696 */\r
697 \r
698 void DrawLevelNumber (int number)\r
699 {\r
700         char    str[10];\r
701         int             len;\r
702         unsigned        temp;\r
703 \r
704         bufferofs = 0;\r
705         if (number<9)\r
706                 PrintX=13;\r
707         else\r
708                 PrintX = 5;\r
709         PrintY = 4;\r
710         VW_Bar (5,4,16,9,STATUSCOLOR);\r
711         temp = fontcolor;\r
712         fontcolor = TEXTCOLOR^STATUSCOLOR;\r
713         US_PrintUnsigned (number+1);\r
714         fontcolor = temp;\r
715 }\r
716 #endif\r
717 \r
718 \r
719 //===========================================================================\r
720 \r
721 /*\r
722 ===============\r
723 =\r
724 = DrawText\r
725 =\r
726 ===============\r
727 */\r
728 \r
729 void DrawText (boolean draw_text_whether_it_needs_it_or_not)\r
730 {\r
731         unsigned        number;\r
732         char            str[80];\r
733         char            far *text;\r
734         unsigned        temp;\r
735 \r
736         //\r
737         // draw a new text description if needed\r
738         //\r
739         number = *(mapsegs[0]+farmapylookup[player->tiley]+player->tilex)-NAMESTART;\r
740 \r
741         if ( number>26 )\r
742                 number = 0;\r
743 \r
744         if ((number == lasttext) && (!draw_text_whether_it_needs_it_or_not))\r
745                 return;\r
746 \r
747         lasttext = number;\r
748 \r
749         text = (char _seg *)grsegs[LEVEL1TEXT+mapon]+textstarts[number];\r
750 \r
751         if (text[0] == '@')\r
752         {\r
753                 bordertime = 20;//FLASHTICS;\r
754                 bcolor = 15;\r
755                 VW_ColorBorder (15 | 56);\r
756                 text++;\r
757         }\r
758 \r
759         _fmemcpy (str,text,80);\r
760         DisplayMsg(str,NULL);\r
761 }\r
762 \r
763 //===========================================================================\r
764 \r
765 /*\r
766 ===============\r
767 =\r
768 = DisplayMsg\r
769 =\r
770 ===============\r
771 */\r
772 \r
773 char DisplayMsg(char *text,char *choices)\r
774 {\r
775         char ch=true;\r
776         short temp;\r
777 \r
778         bufferofs = 0;\r
779         PrintY = 1;\r
780         WindowX = 20;\r
781         WindowW = 270;\r
782 \r
783         VW_Bar (WindowX,2,WindowW,8,STATUSCOLOR);\r
784         temp = fontcolor;\r
785         fontcolor = TEXTCOLOR^STATUSCOLOR;\r
786         US_CPrintLine (text);\r
787         fontcolor = temp;\r
788 \r
789         if (choices)\r
790         {\r
791                 ch=GetKeyChoice(choices,true);\r
792                 LastScan = 0;\r
793         }\r
794 \r
795         return(ch);\r
796 }\r
797 \r
798 /*\r
799 ===============\r
800 =\r
801 = DisplaySMsg\r
802 =\r
803 ===============\r
804 */\r
805 char DisplaySMsg(char *text,char *choices)\r
806 {\r
807         char ch=true;\r
808         short temp;\r
809 \r
810         bufferofs = 0;\r
811         PrintY = 69;\r
812         WindowX = 98;\r
813         WindowW = 115;\r
814 \r
815         VW_Bar(WindowX,PrintY+1,WindowW,8,STATUSCOLOR);\r
816         temp = fontcolor;\r
817         fontcolor = TEXTCOLOR^STATUSCOLOR;\r
818         US_CPrintLine (text);\r
819         fontcolor = temp;\r
820 \r
821         if (choices)\r
822         {\r
823                 ch=GetKeyChoice(choices,true);\r
824                 LastScan = 0;\r
825         }\r
826 \r
827         return(ch);\r
828 }\r
829 \r
830 //===========================================================================\r
831 \r
832 /*\r
833 ===============\r
834 =\r
835 = DrawRadar\r
836 =\r
837 ===============\r
838 */\r
839 \r
840 void DrawRadar (void)\r
841 {\r
842         int             angle,number;\r
843         short objnum;\r
844 \r
845         bufferofs = 0;\r
846         LatchDrawPic (radarx,radary,RADAR_TOPPIC);\r
847 \r
848         asm     cli\r
849         asm     mov     dx,GC_INDEX\r
850         asm     mov     ax,2*256+GC_MODE\r
851         asm     out     dx,ax                                           // write mode 2\r
852 \r
853         asm     mov     ax,GC_DATAROTATE\r
854         asm     out     dx,ax                // no rotation / logical operation\r
855 \r
856         asm     mov     dx,SC_INDEX\r
857         asm     mov     al,SC_MAPMASK\r
858         asm     mov     ah,15\r
859         asm     out     dx,ax                                           // write to all four planes\r
860         asm     sti\r
861 \r
862         objnum = 0;\r
863         while (RadarXY[objnum][2] != -1)\r
864         {\r
865                 RadarBlip(radar_xcenter+RadarXY[objnum][0],radar_ycenter+RadarXY[objnum][1],RadarXY[objnum][2]);\r
866                 objnum++;\r
867         }\r
868 \r
869         asm     cli\r
870         asm     mov     dx,GC_INDEX\r
871         asm     mov     ax,255*256+GC_BITMASK\r
872         asm     out     dx,ax                                           // reset bitmask to %11111111\r
873         asm     sti\r
874 }\r
875 \r
876 //===========================================================================\r
877 \r
878 \r
879 //--------------------------------------------------------------------------\r
880 // DrawNSEWIcons(void)\r
881 //--------------------------------------------------------------------------\r
882 \r
883 void DrawRadarObj(short dx, short dy, unsigned sprnum,signed long psin,signed long pcos);\r
884 \r
885 void DrawNSEWIcons()\r
886 {\r
887         signed x,y;\r
888 \r
889         x = -FixedByFrac(RADAR_X_IRADIUS,costable[player->angle]);\r
890         y = -FixedByFrac(RADAR_Y_IRADIUS,sintable[player->angle]);\r
891 \r
892         VWB_DrawSprite(radar_xcenter+x-3,radar_ycenter+y-3,NORTHICONSPR);\r
893 \r
894 }\r
895 \r
896 #if 0\r
897 /*\r
898 ===============\r
899 =\r
900 = DrawBars\r
901 =\r
902 ===============\r
903 */\r
904 \r
905 void DrawBars (void)\r
906 {\r
907         int                     i;\r
908         unsigned        source,dest,topline;\r
909 \r
910         for (i=0;i<3;i++)\r
911         {\r
912                 bufferofs = screenloc[i];\r
913                 VW_Bar (34*8,POWERLINE,40,MAXSHOTPOWER,1);\r
914         }\r
915         EGAWRITEMODE(1);\r
916         asm     mov     es,[screenseg]\r
917 \r
918 //\r
919 // shot power\r
920 //\r
921         if (gamestate.shotpower)\r
922         {\r
923                 topline = MAXSHOTPOWER - gamestate.shotpower;\r
924 \r
925                 source = latchpics[SHOTPOWERPIC-FIRSTLATCHPIC]+topline*SIDEBARWIDTH;\r
926                 dest = (POWERLINE+topline)*SCREENWIDTH+34;\r
927 \r
928                 asm     mov     si,[source]\r
929                 asm     mov     di,[dest]\r
930 \r
931                 asm     mov     cx,[WORD PTR gamestate.shotpower]\r
932 newline:\r
933         asm     mov     al,[es:si]\r
934         asm     mov     [es:di+PAGE1START],al\r
935         asm     mov     [es:di+PAGE2START],al\r
936         asm     mov     [es:di+PAGE3START],al\r
937         asm     mov     al,[es:si+1]\r
938         asm     mov     [es:di+1+PAGE1START],al\r
939         asm     mov     [es:di+1+PAGE2START],al\r
940         asm     mov     [es:di+1+PAGE3START],al\r
941         asm     mov     al,[es:si+2]\r
942         asm     mov     [es:di+2+PAGE1START],al\r
943         asm     mov     [es:di+2+PAGE2START],al\r
944         asm     mov     [es:di+2+PAGE3START],al\r
945         asm     mov     al,[es:si+3]\r
946         asm     mov     [es:di+3+PAGE1START],al\r
947         asm     mov     [es:di+3+PAGE2START],al\r
948         asm     mov     [es:di+3+PAGE3START],al\r
949         asm     mov     al,[es:si+4]\r
950         asm     mov     [es:di+4+PAGE1START],al\r
951         asm     mov     [es:di+4+PAGE2START],al\r
952         asm     mov     [es:di+4+PAGE3START],al\r
953 \r
954         asm     add     di,SCREENWIDTH\r
955         asm     add     si,5\r
956 \r
957                 asm     loop    newline\r
958         }\r
959 \r
960 //\r
961 // body\r
962 //\r
963         if (gamestate.body)\r
964         {\r
965                 source = latchpics[BODYPIC-FIRSTLATCHPIC];\r
966                 dest = BODYLINE*SCREENWIDTH+34;\r
967 \r
968                 asm     mov     si,[source]\r
969                 asm     mov     di,[dest]\r
970 \r
971                 asm     mov     cx,[WORD PTR gamestate.body]\r
972 newline2:\r
973         asm     mov     al,[es:si]\r
974         asm     mov     [es:di+PAGE1START],al\r
975         asm     mov     [es:di+PAGE2START],al\r
976         asm     mov     [es:di+PAGE3START],al\r
977         asm     mov     al,[es:si+1]\r
978         asm     mov     [es:di+1+PAGE1START],al\r
979         asm     mov     [es:di+1+PAGE2START],al\r
980         asm     mov     [es:di+1+PAGE3START],al\r
981         asm     mov     al,[es:si+2]\r
982         asm     mov     [es:di+2+PAGE1START],al\r
983         asm     mov     [es:di+2+PAGE2START],al\r
984         asm     mov     [es:di+2+PAGE3START],al\r
985         asm     mov     al,[es:si+3]\r
986         asm     mov     [es:di+3+PAGE1START],al\r
987         asm     mov     [es:di+3+PAGE2START],al\r
988         asm     mov     [es:di+3+PAGE3START],al\r
989         asm     mov     al,[es:si+4]\r
990         asm     mov     [es:di+4+PAGE1START],al\r
991         asm     mov     [es:di+4+PAGE2START],al\r
992         asm     mov     [es:di+4+PAGE3START],al\r
993 \r
994         asm     add     di,SCREENWIDTH\r
995         asm     add     si,5\r
996 \r
997                 asm     loop    newline2\r
998         }\r
999 \r
1000         if (gamestate.body != MAXBODY)\r
1001         {\r
1002                 source = latchpics[NOBODYPIC-FIRSTLATCHPIC]+gamestate.body*SIDEBARWIDTH;\r
1003                 dest = (BODYLINE+gamestate.body)*SCREENWIDTH+34;\r
1004                 topline = MAXBODY-gamestate.body;\r
1005 \r
1006                 asm     mov     si,[source]\r
1007                 asm     mov     di,[dest]\r
1008 \r
1009                 asm     mov     cx,[WORD PTR topline]\r
1010 newline3:\r
1011         asm     mov     al,[es:si]\r
1012         asm     mov     [es:di+PAGE1START],al\r
1013         asm     mov     [es:di+PAGE2START],al\r
1014         asm     mov     [es:di+PAGE3START],al\r
1015         asm     mov     al,[es:si+1]\r
1016         asm     mov     [es:di+1+PAGE1START],al\r
1017         asm     mov     [es:di+1+PAGE2START],al\r
1018         asm     mov     [es:di+1+PAGE3START],al\r
1019         asm     mov     al,[es:si+2]\r
1020         asm     mov     [es:di+2+PAGE1START],al\r
1021         asm     mov     [es:di+2+PAGE2START],al\r
1022         asm     mov     [es:di+2+PAGE3START],al\r
1023         asm     mov     al,[es:si+3]\r
1024         asm     mov     [es:di+3+PAGE1START],al\r
1025         asm     mov     [es:di+3+PAGE2START],al\r
1026         asm     mov     [es:di+3+PAGE3START],al\r
1027         asm     mov     al,[es:si+4]\r
1028         asm     mov     [es:di+4+PAGE1START],al\r
1029         asm     mov     [es:di+4+PAGE2START],al\r
1030         asm     mov     [es:di+4+PAGE3START],al\r
1031 \r
1032         asm     add     di,SCREENWIDTH\r
1033         asm     add     si,5\r
1034 \r
1035                 asm     loop    newline3\r
1036         }\r
1037 \r
1038         EGAWRITEMODE(0);\r
1039 }\r
1040 #endif\r
1041 \r
1042 /////////////////////////////////////////////////////////////////////////////\r
1043 //\r
1044 //  Check the object and make sure it is a monster.  Used in making the sound\r
1045 //  of a monster being shot.\r
1046 //\r
1047 /////////////////////////////////////////////////////////////////////////////\r
1048 \r
1049 boolean PlayMonsterSound(classtype objclass)\r
1050 {\r
1051         switch (objclass)\r
1052         {\r
1053                 case solidobj:\r
1054                 case realsolidobj:\r
1055                         return false;\r
1056                 default:\r
1057                         return true;\r
1058         }\r
1059 }\r
1060 \r
1061 \r
1062 /*\r
1063 =============================================================================\r
1064 \r
1065                                                         SHOTS\r
1066 \r
1067 =============================================================================\r
1068 */\r
1069 \r
1070 void T_Pshot (objtype *ob);\r
1071 \r
1072 \r
1073 extern  statetype s_pshot1;\r
1074 extern  statetype s_pshot2;\r
1075 \r
1076 //extern        statetype s_bigpshot1;\r
1077 //extern        statetype s_bigpshot2;\r
1078 \r
1079 \r
1080 statetype s_pshot1 = {PSHOT1PIC,8,&T_Pshot,&s_pshot2};\r
1081 statetype s_pshot2 = {PSHOT2PIC,8,&T_Pshot,&s_pshot1};\r
1082 \r
1083 \r
1084 statetype s_pshot_exp1 = {PSHOT_EXP1PIC,7,NULL,&s_pshot_exp2};\r
1085 statetype s_pshot_exp2 = {PSHOT_EXP2PIC,7,NULL,&s_pshot_exp3};\r
1086 statetype s_pshot_exp3 = {PSHOT_EXP3PIC,7,NULL,NULL};\r
1087 \r
1088 \r
1089 //statetype s_shotexplode = {PSHOT2PIC,8,NULL,NULL};\r
1090 \r
1091 //statetype s_bigpshot1 = {BIGPSHOT1PIC,8,&T_Pshot,&s_bigpshot2};\r
1092 //statetype s_bigpshot2 = {BIGPSHOT2PIC,8,&T_Pshot,&s_bigpshot1};\r
1093 \r
1094 \r
1095 /*\r
1096 ===================\r
1097 =\r
1098 = SpawnPShot\r
1099 =\r
1100 ===================\r
1101 */\r
1102 \r
1103 void SpawnPShot (void)\r
1104 {\r
1105         DSpawnNewObjFrac (player->x,player->y,&s_pshot1,PIXRADIUS*2);\r
1106         new->obclass = pshotobj;\r
1107         new->speed = SHOTSPEED;\r
1108         new->angle = player->angle;\r
1109         new->active = always;\r
1110 }\r
1111 \r
1112 #if 0\r
1113 void SpawnBigPShot (void)\r
1114 {\r
1115         SpawnNewObjFrac (player->x,player->y,&s_bigpshot1,24*PIXRADIUS);\r
1116         new->obclass = bigpshotobj;\r
1117         new->speed = SHOTSPEED;\r
1118         new->angle = player->angle;\r
1119 }\r
1120 #endif\r
1121 \r
1122 \r
1123 /*\r
1124 ===================\r
1125 =\r
1126 = JimsShotClipMove\r
1127 =\r
1128 = Only checks corners, so the object better be less than one tile wide!\r
1129 =\r
1130 ===================\r
1131 */\r
1132 boolean JimsShotClipMove (objtype *ob, long xmove, long ymove)\r
1133 {\r
1134         int                     xl,yl,xh,yh,tx,ty,nt1,nt2,x,y;\r
1135         long            intersect,basex,basey,pointx,pointy;\r
1136         unsigned        inside,total,tile;\r
1137         objtype         *check;\r
1138         boolean         moveok;\r
1139 \r
1140 //\r
1141 // move player and check to see if any corners are in solid tiles\r
1142 //\r
1143 //      basex = ob->x;\r
1144 //      basey = ob->y;\r
1145 \r
1146 //      ob->x += xmove;\r
1147 //      ob->y += ymove;\r
1148 \r
1149 //      CalcBounds (ob);\r
1150 \r
1151         xl = ob->xl>>TILESHIFT;\r
1152         yl = ob->yl>>TILESHIFT;\r
1153 \r
1154         xh = ob->xh>>TILESHIFT;\r
1155         yh = ob->yh>>TILESHIFT;\r
1156 \r
1157         for (y=yl;y<=yh;y++)\r
1158                 for (x=xl;x<=xh;x++)\r
1159                 {\r
1160                         check = actorat[x][y];\r
1161 \r
1162                         if ((!check) || (check == player) || (!(check->flags & of_shootable)))\r
1163                                 continue;\r
1164 \r
1165                         ob->x -= xmove;\r
1166                         ob->y -= ymove;\r
1167 \r
1168                         if (check->obclass != solidobj)\r
1169                         {\r
1170                                 if (PlayMonsterSound(check->obclass))\r
1171                                         SD_PlaySound (SHOOTMONSTERSND);\r
1172                                 if (ob->obclass == bigpshotobj)\r
1173                                         ShootActor (check,BIGSHOTDAMAGE);\r
1174                                 else\r
1175                                         ShootActor (check,SHOTDAMAGE);\r
1176                         }\r
1177                         else\r
1178                                 if (check->obclass == solidobj && (check->flags & of_forcefield))\r
1179                                 {\r
1180                                         if (PlayMonsterSound(check->obclass))\r
1181                                                 SD_PlaySound (SHOOTMONSTERSND);\r
1182                                         if (ob->obclass == bigpshotobj)\r
1183                                                 ShootActor (check,BIGSHOTDAMAGE);\r
1184                                         else\r
1185                                                 ShootActor (check,SHOTDAMAGE);\r
1186                                 }\r
1187                         ob->state = &s_pshot_exp1;\r
1188                         ob->ticcount = ob->state->tictime;\r
1189                         return(true);\r
1190                 }\r
1191 \r
1192         return(false);          // move is OK!\r
1193 \r
1194 }\r
1195 \r
1196 \r
1197 /*\r
1198 ===============\r
1199 =\r
1200 = T_Pshot\r
1201 =\r
1202 ===============\r
1203 */\r
1204 #if 0\r
1205 void T_Pshot (objtype *ob)\r
1206 {\r
1207         objtype *check;\r
1208         long    xmove,ymove,speed;\r
1209 \r
1210 //\r
1211 // check current position for monsters having moved into it\r
1212 //\r
1213         for (check = player->next; check; check=check->next)\r
1214                 if ((check->flags & of_shootable)\r
1215                 && ob->xl <= check->xh\r
1216                 && ob->xh >= check->xl\r
1217                 && ob->yl <= check->yh\r
1218                 && ob->yh >= check->yl)\r
1219                 {\r
1220 \r
1221                         if (check->obclass != solidobj)\r
1222                         {\r
1223                                 if (PlayMonsterSound(check->obclass))\r
1224                                         SD_PlaySound (SHOOTMONSTERSND);\r
1225                                 if (ob->obclass == bigpshotobj)\r
1226                                         ShootActor (check,BIGSHOTDAMAGE);\r
1227                                 else\r
1228                                         ShootActor (check,SHOTDAMAGE);\r
1229                         }\r
1230 \r
1231                         ob->state = &s_pshot_exp1;\r
1232                         ob->ticcount = ob->state->tictime;\r
1233                         return;\r
1234                 }\r
1235 \r
1236 \r
1237 //\r
1238 // move ahead, possibly hitting a wall\r
1239 //\r
1240         speed = ob->speed*tics;\r
1241 \r
1242         xmove = FixedByFrac(speed,costable[ob->angle]);\r
1243         ymove = -FixedByFrac(speed,sintable[ob->angle]);\r
1244 \r
1245         if (ShotClipMove(ob,xmove,ymove))\r
1246         {\r
1247                 ob->state = &s_pshot_exp1;\r
1248                 ob->ticcount = ob->state->tictime;\r
1249                 return;\r
1250         }\r
1251 \r
1252         ob->tilex = ob->x >> TILESHIFT;\r
1253         ob->tiley = ob->y >> TILESHIFT;\r
1254 \r
1255 //\r
1256 // check final position for monsters hit\r
1257 //\r
1258         for (check = player->next; check; check=check->next)\r
1259                 if ((ob->flags & of_shootable)\r
1260                 && ob->xl <= check->xh\r
1261                 && ob->xh >= check->xl\r
1262                 && ob->yl <= check->yh\r
1263                 && ob->yh >= check->yl)\r
1264                 {\r
1265                         ShootActor (check,SHOTDAMAGE);\r
1266                         ob->state = &s_pshot_exp1;\r
1267                         ob->ticcount = ob->state->tictime;\r
1268                         return;\r
1269                 }\r
1270 }\r
1271 #endif\r
1272 \r
1273 \r
1274 \r
1275 void T_Pshot (objtype *ob)\r
1276 {\r
1277         objtype *check;\r
1278         long    xmove,ymove,speed;\r
1279         int                     xl,yl,xh,yh,tx,ty,nt1,nt2,x,y;\r
1280         long            intersect,basex,basey,pointx,pointy;\r
1281         unsigned        inside,total,tile;\r
1282         boolean         moveok;\r
1283 \r
1284 //\r
1285 // check current position for monsters having moved into it\r
1286 //\r
1287         for (check = player->next; check; check=check->next)\r
1288                 if ((check->flags & of_shootable)\r
1289                 && ob->xl <= check->xh\r
1290                 && ob->xh >= check->xl\r
1291                 && ob->yl <= check->yh\r
1292                 && ob->yh >= check->yl)\r
1293                 {\r
1294 \r
1295                         if (check->obclass != solidobj)\r
1296                         {\r
1297                                 if (PlayMonsterSound(check->obclass))\r
1298                                         SD_PlaySound (SHOOTMONSTERSND);\r
1299                                 if (ob->obclass == bigpshotobj)\r
1300                                         ShootActor (check,BIGSHOTDAMAGE);\r
1301                                 else\r
1302                                         ShootActor (check,SHOTDAMAGE);\r
1303                         }\r
1304 \r
1305                         ob->state = &s_pshot_exp1;\r
1306                         ob->obclass = expobj;\r
1307                         ob->ticcount = ob->state->tictime;\r
1308                         return;\r
1309                 }\r
1310 \r
1311 \r
1312 //\r
1313 // move ahead, possibly hitting a wall\r
1314 //\r
1315         speed = ob->speed*tics;\r
1316 \r
1317         xmove = FixedByFrac(speed,costable[ob->angle]);\r
1318         ymove = -FixedByFrac(speed,sintable[ob->angle]);\r
1319 \r
1320         if (ShotClipMove(ob,xmove,ymove))\r
1321         {\r
1322                 ob->state = &s_pshot_exp1;\r
1323                 ob->obclass = expobj;\r
1324                 ob->ticcount = ob->state->tictime;\r
1325                 return;\r
1326         }\r
1327 \r
1328         ob->tilex = ob->x >> TILESHIFT;\r
1329         ob->tiley = ob->y >> TILESHIFT;\r
1330 \r
1331 //\r
1332 // check final position for monsters hit\r
1333 //\r
1334 \r
1335         JimsShotClipMove(obj,xmove,ymove);\r
1336 \r
1337 }\r
1338 \r
1339 \r
1340 /*\r
1341 =============================================================================\r
1342 \r
1343                                                         PLAYER ACTIONS\r
1344 \r
1345 =============================================================================\r
1346 */\r
1347 \r
1348 /*\r
1349 ===============\r
1350 =\r
1351 = BuildShotPower\r
1352 =\r
1353 ===============\r
1354 */\r
1355 \r
1356 void BuildShotPower (void)\r
1357 {\r
1358         int             newlines,topline;\r
1359         long    i;\r
1360         unsigned        source,dest;\r
1361 \r
1362         if (gamestate.shotpower == MAXSHOTPOWER)\r
1363                 return;\r
1364 \r
1365         newlines = 0;\r
1366         for (i=lasttimecount-realtics;i<lasttimecount;i++)\r
1367                 newlines += (i&1);\r
1368 \r
1369         gamestate.shotpower += newlines;\r
1370 \r
1371         if (gamestate.shotpower > MAXSHOTPOWER)\r
1372         {\r
1373                 newlines -= (gamestate.shotpower - MAXSHOTPOWER);\r
1374                 gamestate.shotpower = MAXSHOTPOWER;\r
1375         }\r
1376 }\r
1377 \r
1378 \r
1379 //===========================================================================\r
1380 \r
1381 /*\r
1382 ===============\r
1383 =\r
1384 = ClearShotPower\r
1385 =\r
1386 ===============\r
1387 */\r
1388 \r
1389 void ClearShotPower (void)\r
1390 {\r
1391         unsigned        source,dest,topline;\r
1392 \r
1393 #if 0\r
1394         topline = MAXSHOTPOWER - gamestate.shotpower;\r
1395 \r
1396         source = latchpics[L_NOSHOT]+topline*SIDEBARWIDTH;\r
1397         dest = (POWERLINE+topline)*SCREENWIDTH+34;\r
1398 \r
1399         asm     mov     es,[screenseg]\r
1400         asm     mov     si,[source]\r
1401         asm     mov     di,[dest]\r
1402 \r
1403         if (!gamestate.shotpower)\r
1404                 return;\r
1405 \r
1406         EGAWRITEMODE(1);\r
1407 \r
1408         asm     mov     cx,[WORD PTR gamestate.shotpower]\r
1409 newline:\r
1410         asm     mov     al,[es:si]\r
1411         asm     mov     [es:di+PAGE1START],al\r
1412         asm     mov     [es:di+PAGE2START],al\r
1413         asm     mov     [es:di+PAGE3START],al\r
1414         asm     mov     al,[es:si+1]\r
1415         asm     mov     [es:di+1+PAGE1START],al\r
1416         asm     mov     [es:di+1+PAGE2START],al\r
1417         asm     mov     [es:di+1+PAGE3START],al\r
1418         asm     mov     al,[es:si+2]\r
1419         asm     mov     [es:di+2+PAGE1START],al\r
1420         asm     mov     [es:di+2+PAGE2START],al\r
1421         asm     mov     [es:di+2+PAGE3START],al\r
1422         asm     mov     al,[es:si+3]\r
1423         asm     mov     [es:di+3+PAGE1START],al\r
1424         asm     mov     [es:di+3+PAGE2START],al\r
1425         asm     mov     [es:di+3+PAGE3START],al\r
1426         asm     mov     al,[es:si+4]\r
1427         asm     mov     [es:di+4+PAGE1START],al\r
1428         asm     mov     [es:di+4+PAGE2START],al\r
1429         asm     mov     [es:di+4+PAGE3START],al\r
1430 \r
1431         asm     add     di,SCREENWIDTH\r
1432         asm     add     si,5\r
1433 \r
1434         asm     loop    newline\r
1435 \r
1436         EGAWRITEMODE(0);\r
1437 #endif\r
1438 \r
1439         gamestate.shotpower = 0;\r
1440 }\r
1441 \r
1442 //===========================================================================\r
1443 \r
1444 /*\r
1445 ===============\r
1446 =\r
1447 = Shoot\r
1448 =\r
1449 ===============\r
1450 */\r
1451 \r
1452 void Shoot (void)\r
1453 {\r
1454         ClearShotPower ();\r
1455         SD_PlaySound (SHOOTSND);\r
1456         SpawnPShot ();\r
1457 }\r
1458 \r
1459 //===========================================================================\r
1460 \r
1461 #if 0\r
1462 /*\r
1463 ===============\r
1464 =\r
1465 = BigShoot\r
1466 =\r
1467 ===============\r
1468 */\r
1469 \r
1470 void BigShoot (void)\r
1471 {\r
1472         ClearShotPower ();\r
1473         SD_PlaySound (BIGSHOOTSND);\r
1474         SpawnBigPShot ();\r
1475 }\r
1476 #endif\r
1477 \r
1478 //===========================================================================\r
1479 \r
1480 /*\r
1481 ===============\r
1482 =\r
1483 = CastBolt\r
1484 =\r
1485 ===============\r
1486 */\r
1487 \r
1488 void CastBolt (void)\r
1489 {\r
1490         if (!gamestate.bolts)\r
1491         {\r
1492                 SD_PlaySound (NOITEMSND);\r
1493                 return;\r
1494         }\r
1495 \r
1496         TakeBolt ();\r
1497         boltsleft = NUMBOLTS;\r
1498         bolttimer = BOLTTICS;\r
1499         Shoot ();\r
1500 }\r
1501 \r
1502 \r
1503 /*\r
1504 ===============\r
1505 =\r
1506 = ContinueBolt\r
1507 =\r
1508 ===============\r
1509 */\r
1510 \r
1511 void ContinueBolt (void)\r
1512 {\r
1513         bolttimer-=realtics;\r
1514         if (bolttimer<0)\r
1515         {\r
1516                 boltsleft--;\r
1517                 bolttimer = BOLTTICS;\r
1518                 Shoot ();\r
1519         }\r
1520 }\r
1521 \r
1522 \r
1523 //===========================================================================\r
1524 \r
1525 /*\r
1526 ===============\r
1527 =\r
1528 = CastNuke\r
1529 =\r
1530 ===============\r
1531 */\r
1532 \r
1533 void CastNuke (void)\r
1534 {\r
1535 //      extern boolean autofire;\r
1536 \r
1537         int     angle;\r
1538 \r
1539         if (!gamestate.nukes)\r
1540         {\r
1541                 SD_PlaySound (NOITEMSND);\r
1542                 return;\r
1543         }\r
1544 \r
1545 //      if (!autofire)\r
1546                 TakeNuke ();\r
1547         lastnuke = TimeCount;\r
1548 \r
1549         for (angle = 0; angle < ANGLES; angle+= ANGLES/16)\r
1550         {\r
1551                 DSpawnNewObjFrac (player->x,player->y,&s_pshot1,24*PIXRADIUS);\r
1552                 new->obclass = bigpshotobj;\r
1553                 new->speed = SHOTSPEED;\r
1554                 new->angle = angle;\r
1555                 new->active = always;\r
1556         }\r
1557 }\r
1558 \r
1559 //===========================================================================\r
1560 \r
1561 /*\r
1562 ===============\r
1563 =\r
1564 = DrinkPotion\r
1565 =\r
1566 ===============\r
1567 */\r
1568 \r
1569 void DrinkPotion (void)\r
1570 {\r
1571         unsigned        source,dest,topline;\r
1572 \r
1573         if (!gamestate.potions)\r
1574         {\r
1575                 SD_PlaySound (NOITEMSND);\r
1576                 return;\r
1577         }\r
1578 \r
1579         DisplaySMsg("Curing", NULL);\r
1580         TakePotion ();\r
1581         gamestate.body = MAXBODY;\r
1582         VW_WaitVBL(30);\r
1583         status_flag    = S_NONE;\r
1584 \r
1585 #if 0\r
1586 //\r
1587 // draw a full up bar\r
1588 //\r
1589         source = latchpics[L_BODYBAR];\r
1590         dest = BODYLINE*SCREENWIDTH+34;\r
1591 \r
1592         asm     mov     es,[screenseg]\r
1593         asm     mov     si,[source]\r
1594         asm     mov     di,[dest]\r
1595 \r
1596         EGAWRITEMODE(1);\r
1597 \r
1598         asm     mov     cx,MAXBODY\r
1599 newline:\r
1600         asm     mov     al,[es:si]\r
1601         asm     mov     [es:di+PAGE1START],al\r
1602         asm     mov     [es:di+PAGE2START],al\r
1603         asm     mov     [es:di+PAGE3START],al\r
1604         asm     mov     al,[es:si+1]\r
1605         asm     mov     [es:di+1+PAGE1START],al\r
1606         asm     mov     [es:di+1+PAGE2START],al\r
1607         asm     mov     [es:di+1+PAGE3START],al\r
1608         asm     mov     al,[es:si+2]\r
1609         asm     mov     [es:di+2+PAGE1START],al\r
1610         asm     mov     [es:di+2+PAGE2START],al\r
1611         asm     mov     [es:di+2+PAGE3START],al\r
1612         asm     mov     al,[es:si+3]\r
1613         asm     mov     [es:di+3+PAGE1START],al\r
1614         asm     mov     [es:di+3+PAGE2START],al\r
1615         asm     mov     [es:di+3+PAGE3START],al\r
1616         asm     mov     al,[es:si+4]\r
1617         asm     mov     [es:di+4+PAGE1START],al\r
1618         asm     mov     [es:di+4+PAGE2START],al\r
1619         asm     mov     [es:di+4+PAGE3START],al\r
1620         asm     add     di,SCREENWIDTH\r
1621         asm     add     si,5\r
1622 \r
1623         asm     loop    newline\r
1624 \r
1625         EGAWRITEMODE(0);\r
1626 #endif\r
1627 }\r
1628 \r
1629 \r
1630 \r
1631 //===========================================================================\r
1632 \r
1633 #if 0\r
1634 \r
1635 ////////////////////////////////////////////////////////////////////////////\r
1636 //\r
1637 //   GetScrollText\r
1638 //\r
1639 //   parms   - scroll -- the number of the scroll to display\r
1640 //   returns - a far pointer to the scroll text\r
1641 //\r
1642 ////////////////////////////////////////////////////////////////////////////\r
1643 \r
1644 char far *GetScrollText (int scroll)\r
1645 {\r
1646         boolean found;\r
1647         int     i;\r
1648         char far *txt;\r
1649         unsigned ofset;\r
1650 \r
1651         CA_CacheGrChunk(SCROLLTEXT);\r
1652 \r
1653         found = false;\r
1654         i     = 0;\r
1655 \r
1656         txt = (char _seg *)grsegs[SCROLLTEXT];\r
1657 \r
1658         while (!found)\r
1659         {\r
1660                 while (*txt != '\n')\r
1661                 {\r
1662                         if (*txt == '\r')\r
1663                                 *txt = 0;\r
1664                         txt++;\r
1665                 }\r
1666                 txt++;\r
1667                 if (i == scroll)\r
1668                 {\r
1669                         found   = true;\r
1670                         ofset = FP_OFF(txt);\r
1671 \r
1672                         while (*txt != '\n')\r
1673                         {\r
1674                                 if (*txt == '\r')\r
1675                                         *txt = 0;\r
1676                                 txt++;\r
1677                         }\r
1678                 }\r
1679                 i++;\r
1680         }\r
1681         txt = (char _seg *)grsegs[SCROLLTEXT]+ofset;\r
1682 \r
1683         UNMARKGRCHUNK(SCROLLTEXT);\r
1684         return(txt);\r
1685 }       //End of GetScrollText\r
1686 \r
1687 //===========================================================================\r
1688 \r
1689 /*\r
1690 ===============\r
1691 =\r
1692 = ReadScroll\r
1693 =\r
1694 ===============\r
1695 */\r
1696 \r
1697 extern  boolean tileneeded[NUMFLOORS];\r
1698 \r
1699 void ReadScroll (int scroll)\r
1700 {\r
1701         PresenterInfo pi;\r
1702         int     i;\r
1703         unsigned *skytemp,*gndtemp,blackcolor=0;\r
1704         char far *scrolltext;\r
1705 \r
1706         DisplaySMsg("Reading Scroll", NULL);\r
1707         bufferofs = displayofs = screenloc[screenpage];\r
1708 \r
1709         if (status_flag != S_TIMESTOP)\r
1710                 status_flag = S_NONE;\r
1711 \r
1712         FreeUpMemory();\r
1713 \r
1714         CA_CacheGrChunk (SCROLLTOPPIC);\r
1715         CA_CacheGrChunk (SCROLL1PIC);\r
1716         CA_CacheGrChunk (SCROLLBOTTOMPIC);\r
1717 \r
1718         skytemp = skycolor;\r
1719         gndtemp = groundcolor;\r
1720         skycolor = groundcolor = &blackcolor;\r
1721 \r
1722         VW_Bar(0,0,VIEWWIDTH,VIEWHEIGHT,0);\r
1723         VW_DrawPic (10,0,SCROLLTOPPIC);\r
1724         VW_DrawPic (10,32,SCROLL1PIC);\r
1725         VW_DrawPic (10,88,SCROLLBOTTOMPIC);\r
1726 \r
1727         scrolltext = GetScrollText(scroll);\r
1728 \r
1729         pi.xl = LEFTEDGE;\r
1730         pi.yl = PRNY;\r
1731         pi.xh = RIGHTEDGE;\r
1732         pi.yh = PRNY+1;\r
1733         pi.bgcolor = 7;\r
1734         pi.script[0] = (char far *)scrolltext;\r
1735         Presenter(&pi);\r
1736 \r
1737         skycolor = skytemp;\r
1738         groundcolor = gndtemp;\r
1739 \r
1740         UNMARKGRCHUNK(SCROLL1PIC);\r
1741         UNMARKGRCHUNK(SCROLLTOPPIC);\r
1742         UNMARKGRCHUNK(SCROLLBOTTOMPIC);\r
1743         MM_FreePtr (&grsegs[SCROLL1PIC]);\r
1744         MM_FreePtr (&grsegs[SCROLLTOPPIC]);\r
1745         MM_FreePtr (&grsegs[SCROLLBOTTOMPIC]);\r
1746 \r
1747         CacheScaleds();\r
1748 \r
1749         IN_ClearKeysDown ();\r
1750         lasttext = -1;\r
1751         DisplayMsg("Press ENTER or ESC to exit.",NULL);\r
1752         while ((!Keyboard[sc_Escape]) && (!Keyboard[sc_Enter]));\r
1753         IN_ClearKeysDown ();\r
1754 \r
1755         if (status_flag == S_TIMESTOP)\r
1756                 DisplaySMsg("Time Stopped:     ",NULL);\r
1757 }\r
1758 \r
1759 #endif\r
1760 \r
1761 \r
1762 //===============\r
1763 //\r
1764 // StopTime()\r
1765 //\r
1766 //\r
1767 //===============\r
1768 void StopTime()\r
1769 {\r
1770         FreezeTime = MAXFREEZETIME;\r
1771         SD_PlaySound(FREEZETIMESND);\r
1772         DisplaySMsg("Time Stopped:     ",NULL);\r
1773         status_flag = S_TIMESTOP;\r
1774 }\r
1775 \r
1776 \r
1777 /*\r
1778 ===============\r
1779 =\r
1780 = TakeDamage\r
1781 =\r
1782 ===============\r
1783 */\r
1784 \r
1785 void TakeDamage (int points)\r
1786 {\r
1787         unsigned        source,dest,topline;\r
1788 \r
1789         if (!gamestate.body || (bordertime && bcolor==FLASHCOLOR) || godmode)\r
1790                 return;\r
1791 \r
1792         points = EasyDoDamage(points);\r
1793 \r
1794         if (points >= gamestate.body)\r
1795         {\r
1796                 points = gamestate.body;\r
1797                 Flags |= FL_DEAD;\r
1798         }\r
1799 \r
1800         bordertime = FLASHTICS<<2;\r
1801         bcolor = FLASHCOLOR;\r
1802         VW_ColorBorder (FLASHCOLOR);\r
1803 \r
1804         DisplaySMsg("Damaging blows!", NULL);\r
1805         status_flag  = S_NONE;\r
1806         status_delay = 80;\r
1807 \r
1808         if (gamestate.body<MAXBODY/3)\r
1809                 SD_PlaySound (TAKEDMGHURTSND);\r
1810         else\r
1811                 SD_PlaySound (TAKEDAMAGESND);\r
1812 \r
1813         gamestate.body -= points;\r
1814 }\r
1815 \r
1816 /*\r
1817 =============================================================================\r
1818 \r
1819                                                         INTERACTION\r
1820 \r
1821 =============================================================================\r
1822 */\r
1823 \r
1824 \r
1825 #if 0\r
1826 /*\r
1827 ==================\r
1828 =\r
1829 = OpenDoor\r
1830 =\r
1831 ==================\r
1832 */\r
1833 \r
1834 void OpenDoor (unsigned bx, unsigned by, unsigned doorbase)\r
1835 {\r
1836         int x,y;\r
1837         unsigned        far *map;\r
1838 \r
1839         x=bx;\r
1840         y=by;\r
1841         map = mapsegs[0]+farmapylookup[y]+x;\r
1842         while (tilemap[x][y]-doorbase<4)\r
1843         {\r
1844                 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
1845                 map--;\r
1846                 x--;\r
1847         }\r
1848         x=bx+1;\r
1849         map = mapsegs[0]+farmapylookup[y]+x;\r
1850         while (tilemap[x][y]-doorbase<4)\r
1851         {\r
1852                 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
1853                 map++;\r
1854                 x++;\r
1855         }\r
1856         x=bx;\r
1857         y=by-1;\r
1858         map = mapsegs[0]+farmapylookup[y]+x;\r
1859         while (tilemap[x][y]-doorbase<4)\r
1860         {\r
1861                 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
1862                 map-=mapwidth;\r
1863                 y--;\r
1864         }\r
1865         y=by+1;\r
1866         map = mapsegs[0]+farmapylookup[y]+x;\r
1867         while (tilemap[x][y]-doorbase<4)\r
1868         {\r
1869                 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
1870                 map+=mapwidth;\r
1871                 y++;\r
1872         }\r
1873 }\r
1874 #endif\r
1875 \r
1876 #if 0\r
1877 /*\r
1878 ==================\r
1879 =\r
1880 = RemoveWalls - similar to OpenDoor(), but on a different plane\r
1881 =\r
1882 ==================\r
1883 */\r
1884 void RemoveWalls (unsigned bx, unsigned by, unsigned remove_code)\r
1885 {\r
1886         int x,y;\r
1887         unsigned        far *map,*p2;\r
1888 \r
1889         x=bx;\r
1890         y=by;\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+1;\r
1901         p2 = *(mapsegs[2]+farmapylookup[y]+x);\r
1902         map = mapsegs[0]+farmapylookup[y]+x;\r
1903         while (*p2 == remove_code)\r
1904         {\r
1905                 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
1906                 map++;\r
1907                 p2++;\r
1908                 x++;\r
1909         }\r
1910         x=bx;\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         y=by+1;\r
1922         p2 = *(mapsegs[2]+farmapylookup[y]+x);\r
1923         map = mapsegs[0]+farmapylookup[y]+x;\r
1924         while (*p2 == remove_code)\r
1925         {\r
1926                 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
1927                 map+=mapwidth;\r
1928                 p2 += mapwidth;\r
1929                 y++;\r
1930         }\r
1931 }\r
1932 #endif\r
1933 \r
1934 /*\r
1935 ==================\r
1936 =\r
1937 = HitSpecialTile\r
1938 =\r
1939 = Returns true if the move is blocked\r
1940 =\r
1941 ==================\r
1942 */\r
1943 \r
1944 boolean HitSpecialTile (unsigned x, unsigned y, unsigned tile)\r
1945 {\r
1946         objtype *check;\r
1947         short keyspot;\r
1948         unsigned        temp,spot,curmap=gamestate.mapon,newlevel;\r
1949         char *key_colors[] = {"a RED key",\r
1950                                         "a YELLOW key",\r
1951                                         "a GREEN key",\r
1952                                         "a BLUE key"};\r
1953 \r
1954         switch (tile)\r
1955         {\r
1956                 case 44:\r
1957                         playstate = ex_victorious;\r
1958                 break;\r
1959 \r
1960                 case 17:\r
1961                 case 30:\r
1962                 case 31:\r
1963                 case 35:\r
1964                 case 46:\r
1965                 case 47:\r
1966                 case 48:\r
1967                 case 49:\r
1968                 case 57:\r
1969                 case 58:\r
1970                 case 71:\r
1971                 case 85:\r
1972                 case 94:\r
1973 \r
1974                         if (!playstate && !FreezeTime)\r
1975                         {\r
1976 \r
1977                         // Is this an openable door? (Is "openable" a word?)\r
1978                         //\r
1979                                 spot = (*(mapsegs[2]+farmapylookup[y]+x)) >> 8;\r
1980                                 if (spot == CANT_OPEN_CODE)     // CAN'T EVER OPEN (it's just for looks)\r
1981                                 {\r
1982                                         CenterWindow(30,4);\r
1983                                         US_CPrint("\nThis door is permanently blocked");\r
1984                                         VW_UpdateScreen();\r
1985                                         IN_ClearKeysDown();\r
1986                                         IN_Ack();\r
1987                                         return;\r
1988                                 }\r
1989 \r
1990                                 // make sure player has key to get into door\r
1991                                 //\r
1992 \r
1993                                 if (TILE_FLAGS(tile) & tf_EMBEDDED_KEY_COLOR)\r
1994                                         keyspot = GATE_KEY_COLOR(tile);\r
1995                                 else\r
1996                                         keyspot = (*(mapsegs[2]+farmapylookup[y+1]+x)) >> 8;\r
1997 \r
1998                                 if (keyspot--)\r
1999                                         if (!gamestate.keys[keyspot])\r
2000                                         {\r
2001                                                 SD_PlaySound(HIT_GATESND);\r
2002                                                 CenterWindow(20,5);\r
2003                                                 US_CPrint("\nYou need\n");\r
2004                                                 US_CPrint(key_colors[keyspot]);\r
2005                                                 VW_UpdateScreen();\r
2006                                                 IN_ClearKeysDown();\r
2007                                                 IN_Ack();\r
2008                                                 return;\r
2009                                         }\r
2010 \r
2011                         //\r
2012                         // deal with this gate (warp? simply open? whatever...)\r
2013                         //\r
2014                                 switch (spot)\r
2015                                 {\r
2016                                         case NEXT_LEVEL_CODE:           // WARP TO NEXT LEVEL\r
2017                                                 newlevel = gamestate.mapon+1;\r
2018                                                 playstate = ex_warped;\r
2019                                         break;\r
2020 \r
2021                                         case REMOVE_DOOR_CODE:          // REMOVE DOOR\r
2022                                                 (unsigned)actorat[x][y] = tilemap[x][y] =       *(mapsegs[0]+farmapylookup[y]+x) = 0;\r
2023                                                 *(mapsegs[2]+farmapylookup[y+1]+x) = 0; // key no longer needed\r
2024                                                 if (keyspot>=0)\r
2025                                                         TakeKey(keyspot);\r
2026                                         break;\r
2027 \r
2028                                         default:                        // WARP TO A LEVEL\r
2029                                                 newlevel = spot;\r
2030                                                 playstate = ex_warped;\r
2031                                         break;\r
2032                                 }\r
2033 \r
2034                                 if (playstate == ex_warped)\r
2035                                 {\r
2036                                         SD_PlaySound(HIT_GATESND);\r
2037 //                                      levelinfo *li=&gamestate.levels[curmap];\r
2038 \r
2039 //                                      OldAngle = FaceDoor(x,y);\r
2040 \r
2041                                         if (!VerifyGateExit())\r
2042                                         {\r
2043                                                 IN_ClearKeysDown ();\r
2044                                                 playstate = ex_stillplaying;\r
2045                                                 break;\r
2046                                         }\r
2047 \r
2048 //                                      FaceAngle(OldAngle);\r
2049 \r
2050                                         if (keyspot>=0)\r
2051                                                 TakeKey(keyspot);\r
2052                                         *(mapsegs[2]+farmapylookup[y+1]+x) = 0; // key no longer needed\r
2053 \r
2054                                         gamestate.mapon = newlevel;\r
2055                                         SD_PlaySound(WARPUPSND);\r
2056                                         IN_ClearKeysDown ();\r
2057 \r
2058 //                                      li->x = player->tilex;\r
2059 //                                      li->y = player->tiley;\r
2060 //                                      li->angle = player->angle+180;\r
2061 //                                      if (li->angle > 360)\r
2062 //                                              li->angle -= 360;\r
2063                                 }\r
2064                         }\r
2065                 break;\r
2066         }\r
2067 \r
2068         return true;\r
2069 }\r
2070 \r
2071 //-------------------------------------------------------------------------\r
2072 // VerifyGateExit()\r
2073 //-------------------------------------------------------------------------\r
2074 boolean VerifyGateExit()\r
2075 {\r
2076         char choices[] = {sc_Escape,sc_Y,sc_N,0},ch;\r
2077 \r
2078         ch=DisplayMsg("Pass this way?      Y/N",choices);\r
2079         DrawText(true);\r
2080 \r
2081         return(ch == sc_Y);\r
2082 }\r
2083 \r
2084 \r
2085 /*\r
2086 ==================\r
2087 =\r
2088 = TouchActor\r
2089 =\r
2090 = Returns true if the move is blocked\r
2091 =\r
2092 ==================\r
2093 */\r
2094 \r
2095 boolean TouchActor (objtype *ob, objtype *check)\r
2096 {\r
2097         if (ob->xh < check->xl || ob->xl > check->xh ||\r
2098                 ob->yh < check->yl || ob->yl > check->yh)\r
2099                 return false;                           // not quite touching\r
2100 \r
2101         switch (check->obclass)\r
2102         {\r
2103                 case bonusobj:\r
2104                         switch (check->temp1)\r
2105                         {\r
2106                                 case B_BOLT:            GiveBolt ();            break;\r
2107 \r
2108                                 case B_NUKE:            GiveNuke ();            break;\r
2109 \r
2110                                 case B_POTION:          GivePotion ();          break;\r
2111 \r
2112 //                              case B_RKEY2:           GiveKey(B_RKEY-B_RKEY);                                 break;\r
2113 \r
2114                                 case B_RKEY:\r
2115                                 case B_YKEY:\r
2116                                 case B_GKEY:\r
2117                                 case B_BKEY:            GiveKey (check->temp1-B_RKEY);          break;\r
2118 \r
2119 #if 0\r
2120                                 case B_SCROLL1:\r
2121                                 case B_SCROLL2:\r
2122                                 case B_SCROLL3:\r
2123                                 case B_SCROLL4:\r
2124                                 case B_SCROLL5:\r
2125                                 case B_SCROLL6:\r
2126                                 case B_SCROLL7:\r
2127                                 case B_SCROLL8: GiveScroll (check->temp1-B_SCROLL1,true);       break;\r
2128 #endif\r
2129 \r
2130                                 case B_OLDCHEST:\r
2131                                 case B_CHEST:           GiveChest ();           break;\r
2132 \r
2133                                 case B_RGEM:\r
2134                                 case B_YGEM:\r
2135                                 case B_GGEM:\r
2136                                 case B_BGEM:\r
2137                                 case B_PGEM:\r
2138                                         SD_PlaySound(GETGEMSND);\r
2139                                         gamestate.gems[check->temp1-B_RGEM] = GEM_DELAY_TIME;\r
2140                                         redraw_gems = true;\r
2141                                 break;\r
2142 \r
2143                                 default:\r
2144                                         Quit("TouchActor(): INVALID BONUS");\r
2145                                 break;\r
2146                         }\r
2147 \r
2148                         (unsigned)actorat[check->tilex][check->tiley] = 0;\r
2149                         RemoveObj (check);\r
2150 \r
2151                         return false;\r
2152 \r
2153                 case freezeobj:\r
2154                         StopTime();\r
2155                         (unsigned)actorat[check->tilex][check->tiley] = 0;\r
2156                         RemoveObj(check);\r
2157                         return(false);\r
2158         }\r
2159 \r
2160         return  true;\r
2161 }\r
2162 \r
2163 \r
2164 /*\r
2165 ==================\r
2166 =\r
2167 = CalcBounds\r
2168 =\r
2169 ==================\r
2170 */\r
2171 \r
2172 void CalcBounds (objtype *ob)\r
2173 {\r
2174 //\r
2175 // calculate hit rect\r
2176 //\r
2177   ob->xl = ob->x - ob->size;\r
2178   ob->xh = ob->x + ob->size;\r
2179   ob->yl = ob->y - ob->size;\r
2180   ob->yh = ob->y + ob->size;\r
2181 }\r
2182 \r
2183 \r
2184 /*\r
2185 ===================\r
2186 =\r
2187 = LocationInActor\r
2188 =\r
2189 ===================\r
2190 */\r
2191 \r
2192 boolean LocationInActor (objtype *ob)\r
2193 {\r
2194         int     x,y,xmin,ymin,xmax,ymax;\r
2195         objtype *check;\r
2196 \r
2197         CalcBounds (ob);\r
2198 \r
2199         xmin = (ob->x >> TILESHIFT)-2;\r
2200         ymin = (ob->y >> TILESHIFT)-2;\r
2201         xmax = xmin+5;\r
2202         ymax = ymin+5;\r
2203 \r
2204         for (x=xmin;x<xmax;x++)\r
2205                 for (y=ymin;y<ymax;y++)\r
2206                 {\r
2207                         check = actorat[x][y];\r
2208                         if (check>(objtype *)LASTTILE\r
2209                                 && (check->flags & of_shootable)\r
2210                                 &&      (check->obclass != bonusobj)\r
2211                                 && (check->obclass != freezeobj)\r
2212                                 && (check->obclass != solidobj)\r
2213                                 && ob->xl-SIZE_TEST <= check->xh\r
2214                                 && ob->xh+SIZE_TEST >= check->xl\r
2215                                 && ob->yl-SIZE_TEST <= check->yh\r
2216                                 && ob->yh+SIZE_TEST >= check->yl)\r
2217                                         return true;\r
2218                 }\r
2219 \r
2220         return false;\r
2221 }\r
2222 \r
2223 /*\r
2224 ===================\r
2225 =\r
2226 = ClipXMove\r
2227 =\r
2228 = Only checks corners, so the object better be less than one tile wide!\r
2229 =\r
2230 ===================\r
2231 */\r
2232 void ClipXMove (objtype *ob, long xmove)\r
2233 {\r
2234         int                     xl,yl,xh,yh,tx,ty,nt1,nt2,x,y;\r
2235         long            intersect,basex,basey,pointx,pointy;\r
2236         unsigned        inside,total,tile;\r
2237         objtype         *check;\r
2238         boolean         moveok;\r
2239         boolean         invisible_present = false;\r
2240 \r
2241 //\r
2242 // move player and check to see if any corners are in solid tiles\r
2243 //\r
2244         basex = ob->x;\r
2245         basey = ob->y;\r
2246 \r
2247         ob->x += xmove;\r
2248 \r
2249         CalcBounds (ob);\r
2250 \r
2251         xl = ob->xl>>TILESHIFT;\r
2252         yl = ob->yl>>TILESHIFT;\r
2253 \r
2254         xh = ob->xh>>TILESHIFT;\r
2255         yh = ob->yh>>TILESHIFT;\r
2256 \r
2257         for (y=yl;y<=yh;y++)\r
2258                 for (x=xl;x<=xh;x++)\r
2259                 {\r
2260                         check = actorat[x][y];\r
2261 \r
2262                         if (!check)\r
2263                                 continue;               // blank floor, walk ok\r
2264 \r
2265                         if ((unsigned)check <= LASTTILE)\r
2266                         {\r
2267                                 if (TILE_FLAGS((unsigned)check) & tf_SPECIAL)\r
2268                                 {\r
2269                                         HitSpecialTile(x,y,(unsigned)check-SPECTILESTART);\r
2270                                         goto blockmove;\r
2271                                 }\r
2272 \r
2273                                 if (TILE_FLAGS((unsigned)check) & tf_INVISIBLE_WALL)\r
2274                                 {\r
2275                                         invisible_present = true;\r
2276                                         goto blockmove;\r
2277                                 }\r
2278 \r
2279 \r
2280                                 if (TILE_FLAGS((unsigned)check) & tf_SOLID)\r
2281                                 {\r
2282                                         goto blockmove;                 // solid wall\r
2283                                 }\r
2284                         }\r
2285 \r
2286                         TouchActor(ob,check);           // pick up items\r
2287                 }\r
2288 \r
2289 //\r
2290 // check nearby actors\r
2291 //\r
2292         if (LocationInActor(ob))\r
2293         {\r
2294                 ob->x -= xmove;\r
2295                 if (LocationInActor(ob))\r
2296                 {\r
2297                         ob->x += xmove;\r
2298                         if (LocationInActor(ob))\r
2299                                 ob->x -= xmove;\r
2300                 }\r
2301         }\r
2302         return;         // move is OK!\r
2303 \r
2304 \r
2305 blockmove:\r
2306 \r
2307 //      if (!SD_SoundPlaying())\r
2308 //              SD_PlaySound (HITWALLSND);\r
2309 \r
2310         moveok = false;\r
2311 \r
2312         do\r
2313         {\r
2314                 xmove /= 2;\r
2315                 if (moveok)\r
2316                 {\r
2317                         ob->x += xmove;\r
2318                 }\r
2319                 else\r
2320                 {\r
2321                         ob->x -= xmove;\r
2322                 }\r
2323                 CalcBounds (ob);\r
2324                 xl = ob->xl>>TILESHIFT;\r
2325                 yl = ob->yl>>TILESHIFT;\r
2326                 xh = ob->xh>>TILESHIFT;\r
2327                 yh = ob->yh>>TILESHIFT;\r
2328                 if (tilemap[xl][yl] || tilemap[xh][yl]\r
2329                 || tilemap[xh][yh] || tilemap[xl][yh] )\r
2330                 {\r
2331                         moveok = false;\r
2332                         if (xmove>=-2048 && xmove <=2048)\r
2333                         {\r
2334                                 ob->x = basex;\r
2335                                 ob->y = basey;\r
2336                                 return;\r
2337                         }\r
2338                 }\r
2339                 else\r
2340                         if (invisible_present)\r
2341                         {\r
2342                                 moveok = false;\r
2343                                 if (xmove>=-2048 && xmove <=2048)\r
2344                                 {\r
2345                                         ob->x = basex;\r
2346                                         ob->y = basey;\r
2347                                         return;\r
2348                                 }\r
2349                         }\r
2350                         else\r
2351                                 if (xmove>=-2048 && xmove <=2048)\r
2352                                         return;\r
2353                                 moveok = true;\r
2354         } while (1);\r
2355 }\r
2356 \r
2357 \r
2358 /*\r
2359 ===================\r
2360 =\r
2361 = ClipYMove\r
2362 =\r
2363 = Only checks corners, so the object better be less than one tile wide!\r
2364 =\r
2365 ===================\r
2366 */\r
2367 void ClipYMove (objtype *ob, long ymove)\r
2368 {\r
2369         int                     xl,yl,xh,yh,tx,ty,nt1,nt2,x,y;\r
2370         long            intersect,basex,basey,pointx,pointy;\r
2371         unsigned        inside,total,tile;\r
2372         objtype         *check;\r
2373         boolean         moveok;\r
2374         boolean         invisible_present = false;\r
2375 \r
2376 //\r
2377 // move player and check to see if any corners are in solid tiles\r
2378 //\r
2379         basex = ob->x;\r
2380         basey = ob->y;\r
2381 \r
2382         ob->y += ymove;\r
2383 \r
2384         CalcBounds (ob);\r
2385 \r
2386         xl = ob->xl>>TILESHIFT;\r
2387         yl = ob->yl>>TILESHIFT;\r
2388 \r
2389         xh = ob->xh>>TILESHIFT;\r
2390         yh = ob->yh>>TILESHIFT;\r
2391 \r
2392         for (y=yl;y<=yh;y++)\r
2393                 for (x=xl;x<=xh;x++)\r
2394                 {\r
2395                         check = actorat[x][y];\r
2396                         if (!check)\r
2397                                 continue;               // blank floor, walk ok\r
2398 \r
2399                         if ((unsigned)check <= LASTTILE)\r
2400                         {\r
2401                                 if (TILE_FLAGS((unsigned)check) & tf_SPECIAL)           // <=LASTSPECIALTILE)\r
2402                                 {\r
2403                                         HitSpecialTile (x,y,(unsigned)check-SPECTILESTART);\r
2404                                         goto blockmove;\r
2405                                 }\r
2406 \r
2407                                 if (TILE_FLAGS((unsigned)check) & tf_INVISIBLE_WALL)\r
2408                                 {\r
2409                                         invisible_present = true;\r
2410                                         goto blockmove;\r
2411                                 }\r
2412 \r
2413 \r
2414                                 if (TILE_FLAGS((unsigned)check) & tf_SOLID)             // LASTWALLTILE)\r
2415                                 {\r
2416                                         goto blockmove; // solid wall\r
2417                                 }\r
2418                         }\r
2419 \r
2420                         TouchActor(ob,check);           // pick up items\r
2421                 }\r
2422 \r
2423 //\r
2424 // check nearby actors\r
2425 //\r
2426         if (LocationInActor(ob))\r
2427         {\r
2428                 if (LocationInActor(ob))\r
2429                 {\r
2430                         ob->y -= ymove;\r
2431                 }\r
2432         }\r
2433         return;         // move is OK!\r
2434 \r
2435 \r
2436 blockmove:\r
2437 \r
2438 //      if (!SD_SoundPlaying())\r
2439 //              SD_PlaySound (HITWALLSND);\r
2440 \r
2441         moveok = false;\r
2442 \r
2443         do\r
2444         {\r
2445                 ymove /= 2;\r
2446                 if (moveok)\r
2447                 {\r
2448                         ob->y += ymove;\r
2449                 }\r
2450                 else\r
2451                 {\r
2452                         ob->y -= ymove;\r
2453                 }\r
2454                 CalcBounds (ob);\r
2455                 xl = ob->xl>>TILESHIFT;\r
2456                 yl = ob->yl>>TILESHIFT;\r
2457                 xh = ob->xh>>TILESHIFT;\r
2458                 yh = ob->yh>>TILESHIFT;\r
2459                 if (tilemap[xl][yl] || tilemap[xh][yl]\r
2460                 || tilemap[xh][yh] || tilemap[xl][yh] )\r
2461                 {\r
2462                         moveok = false;\r
2463                         if (ymove>=-2048 && ymove <=2048)\r
2464                         {\r
2465                                 ob->x = basex;\r
2466                                 ob->y = basey;\r
2467                                 return;\r
2468                         }\r
2469                 }\r
2470                 else\r
2471                         if (invisible_present)\r
2472                         {\r
2473                                 moveok = false;\r
2474                                 if (ymove>=-2048 && ymove <=2048)\r
2475                                 {\r
2476                                         ob->x = basex;\r
2477                                         ob->y = basey;\r
2478                                         return;\r
2479                                 }\r
2480                         }\r
2481                         else\r
2482                                 if (ymove>=-2048 && ymove <=2048)\r
2483                                         return;\r
2484                                 moveok = true;\r
2485         } while (1);\r
2486 }\r
2487 \r
2488 \r
2489 //==========================================================================\r
2490 \r
2491 \r
2492 /*\r
2493 ===================\r
2494 =\r
2495 = ShotClipMove\r
2496 =\r
2497 = Only checks corners, so the object better be less than one tile wide!\r
2498 =\r
2499 ===================\r
2500 */\r
2501 \r
2502 boolean ShotClipMove (objtype *ob, long xmove, long ymove)\r
2503 {\r
2504         int                     xl,yl,xh,yh,tx,ty,nt1,nt2,x,y;\r
2505         long            intersect,basex,basey,pointx,pointy;\r
2506         unsigned        inside,total,spot,tile;\r
2507         objtype         *check;\r
2508         boolean         moveok;\r
2509 \r
2510 //\r
2511 // move shot and check to see if any corners are in solid tiles\r
2512 //\r
2513         basex = ob->x;\r
2514         basey = ob->y;\r
2515 \r
2516         ob->x += xmove;\r
2517         ob->y += ymove;\r
2518 \r
2519         CalcBounds (ob);\r
2520 \r
2521         xl = ob->xl>>TILESHIFT;\r
2522         yl = ob->yl>>TILESHIFT;\r
2523 \r
2524         xh = ob->xh>>TILESHIFT;\r
2525         yh = ob->yh>>TILESHIFT;\r
2526 \r
2527         for (y=yl;y<=yh;y++)\r
2528                 for (x=xl;x<=xh;x++)\r
2529                 {\r
2530                         spot = (*(mapsegs[2]+farmapylookup[y]+x)) >> 8;\r
2531                         if (spot == EXP_WALL_CODE)\r
2532                                 switch (ob->obclass)\r
2533                                 {\r
2534                                         case pshotobj:\r
2535                                         case bigpshotobj:\r
2536                                                 ExplodeWall (x,y);\r
2537                                                 goto blockmove;\r
2538 //                                      break;\r
2539                                 }\r
2540 \r
2541                         tile = *(mapsegs[0]+farmapylookup[y]+x);\r
2542                         if (TILE_FLAGS(tile) & tf_SOLID)\r
2543                                 goto blockmove;\r
2544                 }\r
2545         return false;           // move is OK!\r
2546 \r
2547 \r
2548 blockmove:\r
2549 \r
2550         if (ob->obclass == pshotobj)\r
2551                 SD_PlaySound (SHOOTWALLSND);\r
2552 \r
2553         moveok = false;\r
2554 \r
2555         do\r
2556         {\r
2557                 xmove /= 2;\r
2558                 ymove /= 2;\r
2559                 if (moveok)\r
2560                 {\r
2561                         ob->x += xmove;\r
2562                         ob->y += ymove;\r
2563                 }\r
2564                 else\r
2565                 {\r
2566                         ob->x -= xmove;\r
2567                         ob->y -= ymove;\r
2568                 }\r
2569                 CalcBounds (ob);\r
2570                 xl = ob->xl>>TILESHIFT;\r
2571                 yl = ob->yl>>TILESHIFT;\r
2572                 xh = ob->xh>>TILESHIFT;\r
2573                 yh = ob->yh>>TILESHIFT;\r
2574                 if (tilemap[xl][yl] || tilemap[xh][yl]\r
2575                 || tilemap[xh][yh] || tilemap[xl][yh] )\r
2576                 {\r
2577                         moveok = false;\r
2578                         if (xmove>=-2048 && xmove <=2048 && ymove>=-2048 && ymove <=2048)\r
2579                         {\r
2580                                 ob->x = basex;\r
2581                                 ob->y = basey;\r
2582                                 return true;\r
2583                         }\r
2584                 }\r
2585                 else\r
2586                 {\r
2587                         if (xmove>=-2048 && xmove <=2048 && ymove>=-2048 && ymove <=2048)\r
2588                                 return true;\r
2589                         moveok = true;\r
2590                 }\r
2591         } while (1);\r
2592 }\r
2593 \r
2594 \r
2595 \r
2596 /*\r
2597 =============================================================================\r
2598 \r
2599                                                         PLAYER CONTROL\r
2600 \r
2601 =============================================================================\r
2602 */\r
2603 \r
2604 \r
2605 \r
2606 void    T_Player (objtype *ob);\r
2607 \r
2608 statetype s_player = {0,0,&T_Player,&s_player};\r
2609 \r
2610 /*\r
2611 ===============\r
2612 =\r
2613 = SpawnPlayer\r
2614 =\r
2615 ===============\r
2616 */\r
2617 \r
2618 void SpawnPlayer (int tilex, int tiley, int dir)\r
2619 {\r
2620 #if 0\r
2621         levelinfo *li=&gamestate.levels[gamestate.mapon];\r
2622 \r
2623         if (li->x != -1)\r
2624         {\r
2625                 tilex = li->x;\r
2626                 tiley = li->y;\r
2627                 player->angle = li->angle;\r
2628         }\r
2629         else\r
2630                 player->angle = (1-dir)*90;\r
2631 #endif\r
2632 \r
2633         player->obclass = playerobj;\r
2634         player->active = always;\r
2635         player->tilex = tilex;\r
2636         player->tiley = tiley;\r
2637         player->x = ((long)tilex<<TILESHIFT)+TILEGLOBAL/2;\r
2638         player->y = ((long)tiley<<TILESHIFT)+TILEGLOBAL/2;\r
2639         player->state = &s_player;\r
2640         player->size = MINDIST;\r
2641         CalcBounds(player);\r
2642         player->angle = (1-dir)*90;\r
2643         if (player->angle<0)\r
2644                 player->angle += ANGLES;\r
2645 }\r
2646 \r
2647 \r
2648 /*\r
2649 ===================\r
2650 =\r
2651 = Thrust\r
2652 =\r
2653 ===================\r
2654 */\r
2655 \r
2656 void Thrust (int angle, unsigned speed)\r
2657 {\r
2658         long xmove,ymove;\r
2659 \r
2660         if (lasttimecount>>5 != ((lasttimecount-tics)>>5) )\r
2661         {\r
2662         //\r
2663         // walk sound\r
2664         //\r
2665                 if (lasttimecount&32)\r
2666                         SD_PlaySound (WALK1SND);\r
2667                 else\r
2668                         SD_PlaySound (WALK2SND);\r
2669         }\r
2670 \r
2671         xmove = FixedByFrac(speed,costable[angle]);\r
2672         ymove = -FixedByFrac(speed,sintable[angle]);\r
2673 \r
2674         ClipXMove(player,xmove);\r
2675         ClipYMove(player,ymove);\r
2676         player->tilex = player->x >> TILESHIFT;\r
2677         player->tiley = player->y >> TILESHIFT;\r
2678 }\r
2679 \r
2680 \r
2681 \r
2682 /*\r
2683 =======================\r
2684 =\r
2685 = ControlMovement\r
2686 =\r
2687 =======================\r
2688 */\r
2689 \r
2690 void ControlMovement (objtype *ob)\r
2691 {\r
2692         int     angle;\r
2693         long    speed;\r
2694 \r
2695 \r
2696         if (control.button1)\r
2697         {\r
2698         //\r
2699         // strafing\r
2700         //\r
2701                 //\r
2702                 // side to side move\r
2703                 //\r
2704                 if (!mousexmove)\r
2705                         speed = 0;\r
2706                 else if (mousexmove<0)\r
2707                         speed = -(long)mousexmove*300;\r
2708                 else\r
2709                         speed = -(long)mousexmove*300;\r
2710 \r
2711                 if (control.xaxis == -1)\r
2712                 {\r
2713                         speed += PLAYERSPEED*tics;\r
2714                 }\r
2715                 else if (control.xaxis == 1)\r
2716                 {\r
2717                         speed -= PLAYERSPEED*tics;\r
2718                 }\r
2719 \r
2720                 if (speed > 0)\r
2721                 {\r
2722                         if (speed >= TILEGLOBAL)\r
2723                                 speed = TILEGLOBAL-1;\r
2724                         angle = ob->angle + ANGLES/4;\r
2725                         if (angle >= ANGLES)\r
2726                                 angle -= ANGLES;\r
2727                         Thrust (angle,speed);                           // move to left\r
2728                 }\r
2729                 else if (speed < 0)\r
2730                 {\r
2731                         if (speed <= -TILEGLOBAL)\r
2732                                 speed = -TILEGLOBAL+1;\r
2733                         angle = ob->angle - ANGLES/4;\r
2734                         if (angle < 0)\r
2735                                 angle += ANGLES;\r
2736                         Thrust (angle,-speed);                          // move to right\r
2737                 }\r
2738         }\r
2739         else\r
2740         {\r
2741         //\r
2742         // not strafing\r
2743         //\r
2744 \r
2745                 //\r
2746                 // turning\r
2747                 //\r
2748                 if (control.xaxis == 1)\r
2749                 {\r
2750                         ob->angle -= tics;\r
2751                         if (running)                            // fast turn\r
2752                                 ob->angle -= (tics<<1);\r
2753                 }\r
2754                 else if (control.xaxis == -1)\r
2755                 {\r
2756                         ob->angle+= tics;\r
2757                         if (running)                            // fast turn\r
2758                                 ob->angle += (tics<<1);\r
2759                 }\r
2760 \r
2761                 ob->angle -= (mousexmove/10);\r
2762 \r
2763                 if (ob->angle >= ANGLES)\r
2764                         ob->angle -= ANGLES;\r
2765                 if (ob->angle < 0)\r
2766                         ob->angle += ANGLES;\r
2767 \r
2768         }\r
2769 \r
2770         //\r
2771         // forward/backwards move\r
2772         //\r
2773         if (!mouseymove)\r
2774                 speed = 0;\r
2775         else if (mouseymove<0)\r
2776                 speed = -(long)mouseymove*500;\r
2777         else\r
2778                 speed = -(long)mouseymove*200;\r
2779 \r
2780         if (control.yaxis == -1)\r
2781         {\r
2782                 speed += PLAYERSPEED*tics;\r
2783         }\r
2784         else if (control.yaxis == 1)\r
2785         {\r
2786                 speed -= PLAYERSPEED*tics;\r
2787         }\r
2788 \r
2789         if (speed > 0)\r
2790         {\r
2791                 if (speed >= TILEGLOBAL)\r
2792                         speed = TILEGLOBAL-1;\r
2793                 Thrust (ob->angle,speed);                       // move forwards\r
2794         }\r
2795         else if (speed < 0)\r
2796         {\r
2797                 if (speed <= -TILEGLOBAL)\r
2798                         speed = -TILEGLOBAL+1;\r
2799                 angle = ob->angle + ANGLES/2;\r
2800                 if (angle >= ANGLES)\r
2801                         angle -= ANGLES;\r
2802                 Thrust (angle,-speed);                          // move backwards\r
2803         }\r
2804 }\r
2805 \r
2806 \r
2807 /*\r
2808 ===============\r
2809 =\r
2810 = T_Player\r
2811 =\r
2812 ===============\r
2813 */\r
2814 \r
2815 void    T_Player (objtype *ob)\r
2816 {\r
2817 //      extern boolean autofire;\r
2818 \r
2819         int     angle,speed,scroll,loop;\r
2820         unsigned        text,tilex,tiley;\r
2821         long    lspeed;\r
2822 \r
2823 //      boolean radar_moved=false;\r
2824 \r
2825 \r
2826         ControlMovement (ob);\r
2827 \r
2828 \r
2829         //\r
2830         // firing\r
2831         //\r
2832         if (boltsleft)\r
2833         {\r
2834                 handheight+=(realtics<<2);\r
2835                 if (handheight>MAXHANDHEIGHT)\r
2836                         handheight = MAXHANDHEIGHT;\r
2837 \r
2838                 ContinueBolt ();\r
2839                 lasthand = lasttimecount;\r
2840         }\r
2841         else\r
2842         {\r
2843                 if (control.button0)\r
2844                 {\r
2845                         handheight+=(realtics<<2);\r
2846                         if (handheight>MAXHANDHEIGHT)\r
2847                                 handheight = MAXHANDHEIGHT;\r
2848                         lasthand = lasttimecount;\r
2849 \r
2850                         if (!button0down)\r
2851                                 Shoot();\r
2852 \r
2853 //                      if (!autofire)\r
2854                                 button0down=true;\r
2855                 }\r
2856                 else\r
2857                 {\r
2858                         if (lasttimecount > lasthand+HANDPAUSE)\r
2859                         {\r
2860                                 handheight-=(realtics<<1);\r
2861                                 if (handheight<0)\r
2862                                         handheight = 0;\r
2863                         }\r
2864 \r
2865                         button0down = false;\r
2866                 }\r
2867 }\r
2868 \r
2869 #if 0\r
2870                 if (control.button0)\r
2871                 {\r
2872                         handheight+=(realtics<<2);\r
2873                         if (handheight>MAXHANDHEIGHT)\r
2874                                 handheight = MAXHANDHEIGHT;\r
2875 \r
2876                         if ((unsigned)TimeCount/FIRETIME != lastfiretime)\r
2877                                 BuildShotPower ();\r
2878                         lasthand = lasttimecount;\r
2879                 }\r
2880                 else\r
2881                 {\r
2882                         if (lasttimecount > lasthand+HANDPAUSE)\r
2883                         {\r
2884                                 handheight-=(realtics<<1);\r
2885                                 if (handheight<0)\r
2886                                         handheight = 0;\r
2887                         }\r
2888 \r
2889                         if (gamestate.shotpower)\r
2890                         {\r
2891                                 lastfiretime = (unsigned)TimeCount/FIRETIME;\r
2892                                 Shoot ();\r
2893                         }\r
2894                 }\r
2895         }\r
2896 #endif\r
2897 \r
2898         //\r
2899         // special actions\r
2900         //\r
2901 \r
2902         if ((Keyboard[sc_Space] || Keyboard[sc_C]) && gamestate.body != MAXBODY)\r
2903                 DrinkPotion ();\r
2904 \r
2905         if (Keyboard[sc_Z] && !boltsleft)\r
2906                 CastBolt ();\r
2907 \r
2908         if ( (Keyboard[sc_Enter] || Keyboard[sc_X]) && ((TimeCount-lastnuke > NUKETIME))) //|| (autofire)))\r
2909                 CastNuke ();\r
2910 \r
2911 #if 0\r
2912         scroll = LastScan-2;\r
2913         if ( scroll>=0 && scroll<NUMSCROLLS && gamestate.scrolls[scroll])\r
2914                 ReadScroll (scroll);\r
2915 #endif\r
2916 \r
2917         DrawText(false);\r
2918         DrawHealth();\r
2919         if (FreezeTime)\r
2920                 DrawFreezeTime();\r
2921         DrawRadar();\r
2922         EGAWRITEMODE(0);\r
2923         DrawNSEWIcons();\r
2924 \r
2925         if (redraw_gems)\r
2926                 DrawGems();\r
2927 \r
2928 #if 0\r
2929 // gems fade out over time...\r
2930 //\r
2931         for (loop=0; loop<5; loop++)\r
2932                 if (gamestate.gems[loop])\r
2933                 {\r
2934                         gamestate.gems[loop] -= realtics;\r
2935                         if (gamestate.gems[loop] < 0)\r
2936                         {\r
2937                                 gamestate.gems[loop] = 0;\r
2938                                 redraw_gems = true;\r
2939                         }\r
2940                 }\r
2941 #endif\r
2942 }\r
2943 \r
2944 #if 0\r
2945 //------------------------------------------------------------------------\r
2946 // FaceDir() -\r
2947 //\r
2948 // PARAMS : x,y - pixle coords to bring in to view.\r
2949 //\r
2950 // NOTE : Params CAN NOT be shifted fracs!\r
2951 //------------------------------------------------------------------------\r
2952 void FaceDir(short x,short y,boolean StopTime)\r
2953 {\r
2954         short diff;\r
2955 \r
2956         RotateAngle = CalcAngle(x-(player->x>>16l),(player->y>>16l)-y);\r
2957         FreezeTime = StopTime;\r
2958 \r
2959         diff = player->angle - RotateAngle;\r
2960 \r
2961         if (((diff>0) && (diff<180)) || ((diff<0) && (diff>-180)))\r
2962                 RotateSpeed = -ROTATE_SPEED;\r
2963         else\r
2964                 RotateSpeed = ROTATE_SPEED;\r
2965 }\r
2966 #endif\r
2967 \r
2968 #if 0\r
2969 //------------------------------------------------------------------------\r
2970 // CalcAngle() -\r
2971 //\r
2972 // DESC: Calculates the angle from a given dy & dx\r
2973 //------------------------------------------------------------------------\r
2974 short CalcAngle(short dx,short dy)\r
2975 {\r
2976         #define degtorad                                (180/PI)\r
2977         float angle;\r
2978         short diff;\r
2979         float rad_angle;\r
2980 \r
2981         if (dx)\r
2982         {\r
2983                 angle = atan((float)dy/dx)* degtorad;\r
2984                 if (angle<=0)\r
2985                         angle += 180;\r
2986                 if (dy>0)\r
2987                         angle += 180;\r
2988         }\r
2989         else\r
2990         {\r
2991                 // 90 Deg shift\r
2992 \r
2993                 if (dy < 0)\r
2994                         angle = 0 + 90;                         // Above player (NORTH)\r
2995                 else\r
2996                         angle = 180 + 90;                       // Below player (SOUTH)\r
2997         }\r
2998 \r
2999         if (!angle)                             // HACK\r
3000                 angle++;\r
3001 \r
3002         return((short)abs(angle));\r
3003 }\r
3004 \r
3005 #endif\r
3006 \r
3007 #if 0\r
3008 \r
3009 //-------------------------------------------------------------------------\r
3010 // RotateView() -\r
3011 //\r
3012 // DESC : Rotates view (current view of game) to a dest angle.\r
3013 //-------------------------------------------------------------------------\r
3014 void RotateView()\r
3015 {\r
3016         short LastPos;\r
3017 \r
3018         // Store old angle position then change angle...\r
3019         //\r
3020 \r
3021         LastPos = player->angle;\r
3022 \r
3023         player->angle += RotateSpeed;\r
3024 \r
3025         // Check to see if we cranked past out dest angle...\r
3026         //\r
3027 \r
3028 \r
3029         if ((player->angle>ANGLES) || (!player->angle))\r
3030                 player->angle = 1;\r
3031         else\r
3032         if (player->angle<1)\r
3033                 player->angle = ANGLES;\r
3034 \r
3035         // Check to see if we over shot our dest angle...\r
3036         //\r
3037 \r
3038         if (((LastPos < RotateAngle) && (player->angle > RotateAngle) && (RotateSpeed > 0)) ||\r
3039                 ((LastPos > RotateAngle) && (player->angle < RotateAngle) && (RotateSpeed < 0)))\r
3040                 player->angle = RotateAngle;\r
3041 \r
3042         // Check for ending force turn....\r
3043         //\r
3044 \r
3045         if (player->angle == RotateAngle)\r
3046                 RotateAngle = -1;\r
3047 \r
3048 }\r
3049 \r
3050 \r
3051 //--------------------------------------------------------------------------\r
3052 // InitRotate()\r
3053 //--------------------------------------------------------------------------\r
3054 void InitRotate(short DestAngle)\r
3055 {\r
3056         if (player->angle != DestAngle)\r
3057         {\r
3058                 RotateAngle = DestAngle;\r
3059 \r
3060                 if (player->angle > DestAngle)\r
3061                         RotateSpeed = -ROTATE_SPEED;\r
3062                 else\r
3063                         RotateSpeed = ROTATE_SPEED;\r
3064 \r
3065                 if (abs(player->angle - RotateAngle) > 180)\r
3066                         RotateSpeed =- RotateSpeed;\r
3067         }\r
3068 }\r
3069 \r
3070 \r
3071 \r
3072 //------------------------------------------------------------------------\r
3073 // FaceAngle() -\r
3074 //\r
3075 // PARAMS : DestAngle - Destination angle to turn to\r
3076 //------------------------------------------------------------------------\r
3077 void FaceAngle(short DestAngle)\r
3078 {\r
3079         signed long dx,dy,radius,psin,pcos,newx,newy;\r
3080         int             give;\r
3081         short objnum,LastPos;\r
3082         signed long ox,oy,xl,xh,yl,yh,px,py,norm_dx,norm_dy;\r
3083         short o_radius;\r
3084         void (*think)();\r
3085 \r
3086 \r
3087         // Calculate the direction we want to turn to...\r
3088         //\r
3089 \r
3090         InitRotate(DestAngle);\r
3091 \r
3092         RedrawStatusWindow();\r
3093 \r
3094         while (RotateAngle != -1)\r
3095         {\r
3096 \r
3097                 RotateView();\r
3098 \r
3099 //              PollControls();\r
3100 \r
3101                 objnum=0;\r
3102 \r
3103                 for (obj = player;obj;obj = obj->next)\r
3104                 {\r
3105                         if (obj->active >= yes)\r
3106                         {\r
3107 \r
3108                         // keep a list of objects around the player for radar updates\r
3109                         //\r
3110                                 if (obj == player)\r
3111                                 {\r
3112                                         px = player->x;\r
3113                                         py = player->y;\r
3114                                         psin = sintable[player->angle];\r
3115                                         pcos = costable[player->angle];\r
3116                                         xl = px-((long)RADAR_WIDTH<<TILESHIFT)/2;\r
3117                                         xh = px+((long)RADAR_WIDTH<<TILESHIFT)/2-1;\r
3118                                         yl = py-((long)RADAR_HEIGHT<<TILESHIFT)/2;\r
3119                                         yh = py+((long)RADAR_HEIGHT<<TILESHIFT)/2;\r
3120                                 }\r
3121 \r
3122                                 if (objnum > MAX_RADAR_BLIPS-2)\r
3123                                         objnum = MAX_RADAR_BLIPS-2;\r
3124 \r
3125                                 ox = obj->x;\r
3126                                 oy = obj->y;\r
3127 \r
3128 \r
3129                                 if ((ox >= xl) && (ox <= xh) && (oy >= yl) && (oy <= yh))\r
3130                                 {\r
3131                                         norm_dx = (dx = px-ox)>>TILESHIFT;\r
3132                                         norm_dy = (dy = oy-py)>>TILESHIFT;\r
3133 \r
3134                                         o_radius = IntSqrt((norm_dx * norm_dx) + (norm_dy * norm_dy));\r
3135 \r
3136                                         if (o_radius < RADAR_RADIUS)\r
3137                                         {\r
3138                                                 newx = FixedByFrac(dy,pcos)-FixedByFrac(dx,psin);\r
3139                                                 newy = FixedByFrac(dy,psin)+FixedByFrac(dx,pcos);\r
3140 \r
3141                                                 RadarXY[objnum][0]=newx>>TILESHIFT;\r
3142                                                 RadarXY[objnum][1]=newy>>TILESHIFT;\r
3143 \r
3144                                                 // Define color to use for this object...\r
3145                                                 //\r
3146 \r
3147                                                 switch (obj->obclass)\r
3148                                                 {\r
3149                                                         case playerobj:\r
3150                                                                 RadarXY[objnum++][2]=15;\r
3151                                                         break;\r
3152 \r
3153                                                 // RED GEM\r
3154                                                 //\r
3155                                                         // STOMPY                                                                               (DK RED)\r
3156                                                         //\r
3157                                                         case invisdudeobj:\r
3158                                                         case stompyobj:\r
3159                                                                 RadarXY[objnum++][2]=4;\r
3160                                                         break;\r
3161 \r
3162                                                         // BLOB                                                                                 (LT RED)\r
3163                                                         //\r
3164                                                         case blobobj:\r
3165                                                                 RadarXY[objnum++][2]=12;\r
3166                                                         break;\r
3167 \r
3168                                                 // BLUE GEM\r
3169                                                 //\r
3170                                                         // ROBOTANK                                                                             (LT BLUE)\r
3171                                                         //\r
3172                                                         case robotankobj:\r
3173                                                         case fmageobj:\r
3174                                                                 RadarXY[objnum++][2]=9;\r
3175                                                         break;\r
3176 \r
3177 #if 1\r
3178                                                         // BLUE DEMON                                                                   (DK BLUE)\r
3179                                                         //\r
3180                                                         case demonobj:\r
3181                                                                 RadarXY[objnum++][2]=1;\r
3182                                                         break;\r
3183 #endif\r
3184 \r
3185                                                 // GREEN GEM\r
3186                                                 //\r
3187                                                         // WIZARD                                                                               (LT GREEN)\r
3188                                                         //\r
3189                                                         case wizardobj:\r
3190                                                                 RadarXY[objnum++][2]=10;\r
3191                                                         break;\r
3192 \r
3193                                                         // AQUA MAN                                                                             (DK GREEN)\r
3194                                                         //\r
3195                                                         case aquamanobj:\r
3196                                                                 RadarXY[objnum++][2]=2;\r
3197                                                         break;\r
3198 \r
3199                                                 // YELLOW GEM\r
3200                                                 //\r
3201                                                         // EQYPTIAN HEAD                                                                (BROWN)\r
3202                                                         //\r
3203                                                         case headobj:\r
3204                                                                 RadarXY[objnum++][2]=6;\r
3205                                                         break;\r
3206 \r
3207                                                         //      RAMBONE                                                                         (YELLOW)\r
3208                                                         //      TROLL\r
3209                                                         case ramboneobj:\r
3210                                                         case trollobj:\r
3211                                                                 RadarXY[objnum++][2]=14;\r
3212                                                         break;\r
3213 \r
3214                                                         //      BUG                                                                                     (LIGHT GRAY)\r
3215                                                         case bugobj:\r
3216                                                                 RadarXY[objnum++][2]=7;\r
3217                                                         break;\r
3218 \r
3219                                                         //      RAY                                                                                     (DARK GRAY)\r
3220                                                         case rayobj:\r
3221                                                                 RadarXY[objnum++][2]=8;\r
3222                                                         break;\r
3223 \r
3224                                                 // PURPLE GEM\r
3225                                                 //\r
3226                                                         // MEC DEMON                                                                    (PURPLE)\r
3227                                                         //\r
3228                                                         case cyborgdemonobj:\r
3229                                                                 RadarXY[objnum++][2]=5;\r
3230                                                         break;\r
3231 \r
3232                                                         // EYE                                                                                  (LT PURPLE)\r
3233                                                         //\r
3234                                                         case eyeobj:\r
3235                                                         case reyeobj:\r
3236                                                                 RadarXY[objnum++][2]=13;\r
3237                                                         break;\r
3238                                                 }\r
3239                                         }\r
3240                                 }\r
3241                         }\r
3242                 }\r
3243 \r
3244                 RadarXY[objnum][2]=-1;          // Signals end of RadarXY list...\r
3245 \r
3246 // refresh all\r
3247 //\r
3248 \r
3249                 ThreeDRefresh();\r
3250                 DrawRadar();\r
3251                 EGAWRITEMODE(0);\r
3252                 DrawNSEWIcons();\r
3253 \r
3254 //              CheckKeys();\r
3255         }\r
3256 }\r
3257 \r
3258 \r
3259 //-------------------------------------------------------------------------\r
3260 // FaceDoor() - Turns the player to face a door (a tile) at a given TILE x & y\r
3261 //\r
3262 // RETURNS : Returns the orginal angle of the player.\r
3263 //------------------------------------------------------------------------\r
3264 short FaceDoor(short x, short y)\r
3265 {\r
3266         short p_x,p_y,angle,old_angle;\r
3267 \r
3268         old_angle = player->angle;\r
3269 \r
3270         p_x = player->x>>16l;\r
3271         p_y = player->y>>16l;\r
3272 \r
3273         if (p_x != x)\r
3274         {\r
3275                 if (p_x > x)\r
3276                         angle = 180;            // Face Left\r
3277                 else\r
3278                         angle = 1;                      // Face Right\r
3279         }\r
3280 \r
3281         if (p_y != y)\r
3282         {\r
3283                 if (p_y > y)\r
3284                         angle = 90;                     // Face Up\r
3285                 else\r
3286                         angle = 270;            // Face Down\r
3287         }\r
3288 \r
3289         FaceAngle(angle);\r
3290 \r
3291         return(old_angle);\r
3292 }\r
3293 \r
3294 \r
3295 #endif\r
3296 \r
3297 \r
3298 \r
3299 /*==========================================================================\r
3300 \r
3301                                                                 EXPLOSION SPAWNING ROUTINES\r
3302 \r
3303 ===========================================================================*/\r
3304 \r
3305 statetype s_explode = {0,1,T_ExpThink,&s_explode};\r
3306 \r
3307 //-------------------------------------------------------------------------\r
3308 // SpawnExplosion()\r
3309 //------------------------------------------------------------------------\r
3310 void SpawnExplosion(fixed x, fixed y, short Delay)\r
3311 {\r
3312         DSpawnNewObjFrac(x,y,&s_explode,PIXRADIUS*7);\r
3313         new->obclass = expobj;\r
3314         new->active = always;\r
3315         new->temp1 = Delay;\r
3316 }\r
3317 \r
3318 \r
3319 //---------------------------------------------------------------------------\r
3320 // T_ExpThink()\r
3321 //---------------------------------------------------------------------------\r
3322 void T_ExpThink(objtype *obj)\r
3323 {\r
3324         if (obj->temp1)\r
3325         {\r
3326                 if ((obj->temp1-=realtics) <= 0)\r
3327                         obj->temp1 = 0;\r
3328         }\r
3329         else\r
3330         {\r
3331                 obj->state = &s_pshot_exp1;\r
3332                 obj->ticcount = obj->state->tictime;\r
3333                 SD_PlaySound(BOOMSND);\r
3334         }\r
3335 }\r
3336 \r
3337 \r
3338 \r
3339 //-------------------------------------------------------------------------\r
3340 // SpawnBigExplosion()\r
3341 //------------------------------------------------------------------------\r
3342 void SpawnBigExplosion(fixed x, fixed y, short Delay, fixed Range)\r
3343 {\r
3344         SpawnExplosion(x-random(Range),y+random(Range),random(Delay));\r
3345         SpawnExplosion(x+random(Range),y-random(Range),random(Delay));\r
3346         SpawnExplosion(x-random(Range),y-random(Range),random(Delay));\r
3347         SpawnExplosion(x+random(Range),y+random(Range),random(Delay));\r
3348 }\r
3349 \r