]> 4ch.mooo.com Git - 16.git/blob - src/lib/hb/c3_wiz.c
[16_ca needs huge amounts of work and I should remember what needs to be done soon...
[16.git] / src / lib / hb / c3_wiz.c
1 /* Catacomb 3-D 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 "C3_DEF.H"\r
22 #pragma hdrstop\r
23 \r
24 /*\r
25 =============================================================================\r
26 \r
27                                                  LOCAL CONSTANTS\r
28 \r
29 =============================================================================\r
30 */\r
31 \r
32 #define NUMSCROLLS      8\r
33 \r
34 #define SHOWITEMS       9\r
35 \r
36 #define NUKETIME        40\r
37 #define NUMBOLTS        10\r
38 #define BOLTTICS        6\r
39 \r
40 #define STATUSCOLOR     4\r
41 #define TEXTCOLOR       14\r
42 \r
43 #define SIDEBARWIDTH    5\r
44 \r
45 #define BODYLINE    8\r
46 #define POWERLINE       80\r
47 \r
48 #define SPECTILESTART   18\r
49 \r
50 \r
51 #define SHOTDAMAGE              1\r
52 #define BIGSHOTDAMAGE   3\r
53 \r
54 \r
55 #define PLAYERSPEED     5120\r
56 #define RUNSPEED        8192\r
57 \r
58 #define SHOTSPEED       10000\r
59 \r
60 #define LASTWALLTILE    17\r
61 #define LASTSPECIALTILE 37\r
62 \r
63 #define FIRETIME        4       // DEBUG 60\r
64 \r
65 #define HANDPAUSE       60\r
66 \r
67 #define COMPASSX        33\r
68 #define COMPASSY        0\r
69 \r
70 /*\r
71 =============================================================================\r
72 \r
73                                                  GLOBAL VARIABLES\r
74 \r
75 =============================================================================\r
76 */\r
77 \r
78 long            lastnuke,lasthand;\r
79 int                     handheight;\r
80 int                     boltsleft;\r
81 \r
82 /*\r
83 =============================================================================\r
84 \r
85                                                  LOCAL VARIABLES\r
86 \r
87 =============================================================================\r
88 */\r
89 \r
90 int                     lasttext,lastcompass;\r
91 int                     bolttimer;\r
92 unsigned        lastfiretime;\r
93 \r
94 int     strafeangle[9] = {0,90,180,270,45,135,225,315,0};\r
95 \r
96 \r
97 //===========================================================================\r
98 \r
99 void DrawChar (unsigned x, unsigned y, unsigned tile);\r
100 void RedrawStatusWindow (void);\r
101 void GiveBolt (void);\r
102 void TakeBolt (void);\r
103 void GiveNuke (void);\r
104 void TakeNuke (void);\r
105 void GivePotion (void);\r
106 void TakePotion (void);\r
107 void GiveKey (int keytype);\r
108 void TakeKey (int keytype);\r
109 void GiveScroll (int scrolltype,boolean show);\r
110 void ReadScroll (int scroll);\r
111 void GivePoints (int points);\r
112 void DrawLevelNumber (int number);\r
113 void DrawText (void);\r
114 void DrawBars (void);\r
115 \r
116 //----------\r
117 \r
118 void Shoot (void);\r
119 void BigShoot (void);\r
120 void CastBolt (void);\r
121 void CastNuke (void);\r
122 void DrinkPotion (void);\r
123 \r
124 //----------\r
125 \r
126 void SpawnPlayer (int tilex, int tiley, int dir);\r
127 void Thrust (int angle, unsigned speed);\r
128 void T_Player (objtype *ob);\r
129 \r
130 void AddPoints (int points);\r
131 \r
132 void ClipMove (objtype *ob, long xmove, long ymove);\r
133 boolean ShotClipMove (objtype *ob, long xmove, long ymove);\r
134 \r
135 //===========================================================================\r
136 \r
137 \r
138 /*\r
139 ===============\r
140 =\r
141 = DrawChar\r
142 =\r
143 ===============\r
144 */\r
145 \r
146 void DrawChar (unsigned x, unsigned y, unsigned tile)\r
147 {\r
148         unsigned junk = latchpics[0];\r
149 \r
150         EGAWRITEMODE(1);\r
151 asm     mov     bx,[y]\r
152 asm     shl     bx,1\r
153 asm     mov     di,[WORD PTR ylookup+bx]\r
154 asm     add     di,[x]\r
155 asm     mov     si,[tile]\r
156 asm     shl     si,1\r
157 asm     shl     si,1\r
158 asm     shl     si,1\r
159 asm     add     si,[junk]               // the damn inline assembler won't reference latchpics\r
160 asm     mov     ax,[screenseg]\r
161 asm     mov     es,ax\r
162 asm     mov     ds,ax\r
163 asm     mov     dx,SCREENWIDTH-1\r
164 asm     movsb\r
165 asm     add     di,dx\r
166 asm     movsb\r
167 asm     add     di,dx\r
168 asm     movsb\r
169 asm     add     di,dx\r
170 asm     movsb\r
171 asm     add     di,dx\r
172 asm     movsb\r
173 asm     add     di,dx\r
174 asm     movsb\r
175 asm     add     di,dx\r
176 asm     movsb\r
177 asm     add     di,dx\r
178 asm     movsb\r
179 \r
180 asm     mov     ax,ss\r
181 asm     mov     ds,ax\r
182         EGAWRITEMODE(0);\r
183 }\r
184 \r
185 \r
186 //===========================================================================\r
187 \r
188 /*\r
189 ===============\r
190 =\r
191 = RedrawStatusWindow\r
192 =\r
193 ===============\r
194 */\r
195 \r
196 void RedrawStatusWindow (void)\r
197 {\r
198         int     i,j,x;\r
199 \r
200         DrawLevelNumber (gamestate.mapon);\r
201         lasttext = -1;\r
202         lastcompass = -1;\r
203 \r
204         j = gamestate.bolts < SHOWITEMS ? gamestate.bolts : SHOWITEMS;\r
205         for (i=0;i<j;i++)\r
206                 DrawChar(7+i,20,BOLTCHAR);\r
207         j = gamestate.nukes < SHOWITEMS ? gamestate.nukes : SHOWITEMS;\r
208         for (i=0;i<j;i++)\r
209                 DrawChar(7+i,30,NUKECHAR);\r
210         j = gamestate.potions < SHOWITEMS ? gamestate.potions : SHOWITEMS;\r
211         for (i=0;i<j;i++)\r
212                 DrawChar(7+i,40,POTIONCHAR);\r
213 \r
214         x=24;\r
215         for (i=0;i<4;i++)\r
216                 for (j=0;j<gamestate.keys[i];j++)\r
217                         DrawChar(x++,20,KEYCHARS+i);\r
218 \r
219         x=24;\r
220         for (i=0;i<8;i++)\r
221                 if (gamestate.scrolls[i])\r
222                         DrawChar(x++,30,SCROLLCHARS+i);\r
223 \r
224         AddPoints(0);\r
225 \r
226         DrawBars ();\r
227 }\r
228 \r
229 \r
230 //===========================================================================\r
231 \r
232 /*\r
233 ===============\r
234 =\r
235 = GiveBolt\r
236 =\r
237 ===============\r
238 */\r
239 \r
240 void GiveBolt (void)\r
241 {\r
242         SD_PlaySound (GETBOLTSND);\r
243         if (++gamestate.bolts<=9)\r
244                 DrawChar(6+gamestate.bolts,20,BOLTCHAR);\r
245 }\r
246 \r
247 \r
248 /*\r
249 ===============\r
250 =\r
251 = TakeBolt\r
252 =\r
253 ===============\r
254 */\r
255 \r
256 void TakeBolt (void)\r
257 {\r
258         SD_PlaySound (USEBOLTSND);\r
259         if (--gamestate.bolts<=9)\r
260                 DrawChar(7+gamestate.bolts,20,BLANKCHAR);\r
261 }\r
262 \r
263 //===========================================================================\r
264 \r
265 /*\r
266 ===============\r
267 =\r
268 = GiveNuke\r
269 =\r
270 ===============\r
271 */\r
272 \r
273 void GiveNuke (void)\r
274 {\r
275         SD_PlaySound (GETNUKESND);\r
276         if (++gamestate.nukes<=9)\r
277                 DrawChar(6+gamestate.nukes,30,NUKECHAR);\r
278 }\r
279 \r
280 \r
281 /*\r
282 ===============\r
283 =\r
284 = TakeNuke\r
285 =\r
286 ===============\r
287 */\r
288 \r
289 void TakeNuke (void)\r
290 {\r
291         SD_PlaySound (USENUKESND);\r
292         if (--gamestate.nukes<=9)\r
293                 DrawChar(7+gamestate.nukes,30,BLANKCHAR);\r
294 }\r
295 \r
296 //===========================================================================\r
297 \r
298 /*\r
299 ===============\r
300 =\r
301 = GivePotion\r
302 =\r
303 ===============\r
304 */\r
305 \r
306 void GivePotion (void)\r
307 {\r
308         SD_PlaySound (GETPOTIONSND);\r
309         if (++gamestate.potions<=9)\r
310                 DrawChar(6+gamestate.potions,40,POTIONCHAR);\r
311 }\r
312 \r
313 \r
314 /*\r
315 ===============\r
316 =\r
317 = TakePotion\r
318 =\r
319 ===============\r
320 */\r
321 \r
322 void TakePotion (void)\r
323 {\r
324         SD_PlaySound (USEPOTIONSND);\r
325         if (--gamestate.potions<=9)\r
326                 DrawChar(7+gamestate.potions,40,BLANKCHAR);\r
327 }\r
328 \r
329 //===========================================================================\r
330 \r
331 /*\r
332 ===============\r
333 =\r
334 = GiveKey\r
335 =\r
336 ===============\r
337 */\r
338 \r
339 void GiveKey (int keytype)\r
340 {\r
341         int     i,j,x;\r
342 \r
343         SD_PlaySound (GETKEYSND);\r
344         gamestate.keys[keytype]++;\r
345 \r
346         x=24;\r
347         for (i=0;i<4;i++)\r
348                 for (j=0;j<gamestate.keys[i];j++)\r
349                         DrawChar(x++,20,KEYCHARS+i);\r
350 \r
351 }\r
352 \r
353 \r
354 /*\r
355 ===============\r
356 =\r
357 = TakeKey\r
358 =\r
359 ===============\r
360 */\r
361 \r
362 void TakeKey (int keytype)\r
363 {\r
364         int     i,j,x;\r
365 \r
366         SD_PlaySound (USEKEYSND);\r
367         gamestate.keys[keytype]--;\r
368 \r
369         x=24;\r
370         for (i=0;i<4;i++)\r
371                 for (j=0;j<gamestate.keys[i];j++)\r
372                         DrawChar(x++,20,KEYCHARS+i);\r
373 \r
374         DrawChar(x,20,BLANKCHAR);\r
375 }\r
376 \r
377 //===========================================================================\r
378 \r
379 /*\r
380 ===============\r
381 =\r
382 = GiveScroll\r
383 =\r
384 ===============\r
385 */\r
386 \r
387 void GiveScroll (int scrolltype,boolean show)\r
388 {\r
389         int     i,x;\r
390 \r
391         SD_PlaySound (GETSCROLLSND);\r
392         gamestate.scrolls[scrolltype] = true;\r
393 \r
394         x=24;\r
395         for (i=0;i<8;i++)\r
396                 if (gamestate.scrolls[i])\r
397                         DrawChar(x++,30,SCROLLCHARS+i);\r
398         if (show)\r
399                 ReadScroll(scrolltype);\r
400 }\r
401 \r
402 //===========================================================================\r
403 \r
404 /*\r
405 ===============\r
406 =\r
407 = GivePoints\r
408 =\r
409 ===============\r
410 */\r
411 \r
412 void GivePoints (int points)\r
413 {\r
414         pointcount = 1;\r
415         pointsleft += points;\r
416 }\r
417 \r
418 \r
419 //===========================================================================\r
420 \r
421 /*\r
422 ===============\r
423 =\r
424 = AddPoints\r
425 =\r
426 ===============\r
427 */\r
428 \r
429 void AddPoints (int points)\r
430 {\r
431         char    str[10];\r
432         int             len,x,i;\r
433 \r
434         gamestate.score += points;\r
435 \r
436         ltoa (gamestate.score,str,10);\r
437         len = strlen (str);\r
438 \r
439         x=24+(8-len);\r
440         for (i=0;i<len;i++)\r
441                 DrawChar(x++,40,NUMBERCHARS+str[i]-'0');\r
442 }\r
443 \r
444 \r
445 //===========================================================================\r
446 \r
447 /*\r
448 ===============\r
449 =\r
450 = GiveChest\r
451 =\r
452 ===============\r
453 */\r
454 \r
455 void GiveChest (void)\r
456 {\r
457         SD_PlaySound (GETPOINTSSND);\r
458         GivePoints ((gamestate.mapon+1)*100);\r
459 }\r
460 \r
461 \r
462 //===========================================================================\r
463 \r
464 /*\r
465 ===============\r
466 =\r
467 = GiveGoal\r
468 =\r
469 ===============\r
470 */\r
471 \r
472 void GiveGoal (void)\r
473 {\r
474         SD_PlaySound (GETPOINTSSND);\r
475         GivePoints (100000);\r
476         playstate = ex_victorious;\r
477 }\r
478 \r
479 \r
480 //===========================================================================\r
481 \r
482 /*\r
483 ===============\r
484 =\r
485 = DrawLevelNumber\r
486 =\r
487 ===============\r
488 */\r
489 \r
490 void DrawLevelNumber (int number)\r
491 {\r
492         char    str[10];\r
493         int             len;\r
494         unsigned        temp;\r
495 \r
496         bufferofs = 0;\r
497         if (number<9)\r
498                 PrintX=13;\r
499         else\r
500                 PrintX = 5;\r
501         PrintY = 4;\r
502         VW_Bar (5,4,16,9,STATUSCOLOR);\r
503         temp = fontcolor;\r
504         fontcolor = TEXTCOLOR^STATUSCOLOR;\r
505         US_PrintUnsigned (number+1);\r
506         fontcolor = temp;\r
507 }\r
508 \r
509 \r
510 //===========================================================================\r
511 \r
512 /*\r
513 ===============\r
514 =\r
515 = DrawText\r
516 =\r
517 ===============\r
518 */\r
519 \r
520 void DrawText (void)\r
521 {\r
522         unsigned        number;\r
523         char            str[80];\r
524         char            far *text;\r
525         unsigned        temp;\r
526 \r
527         //\r
528         // draw a new text description if needed\r
529         //\r
530         number = *(mapsegs[0]+farmapylookup[player->tiley]+player->tilex)-NAMESTART;\r
531 \r
532         if ( number>26 )\r
533                 number = 0;\r
534 \r
535         if (number == lasttext)\r
536                 return;\r
537 \r
538         bufferofs = 0;\r
539         lasttext = number;\r
540 \r
541         PrintY = 4;\r
542         WindowX = 26;\r
543         WindowW = 232;\r
544 \r
545         text = (char _seg *)grsegs[LEVEL1TEXT+mapon]+textstarts[number];\r
546 \r
547         _fmemcpy (str,text,80);\r
548 \r
549         VW_Bar (26,4,232,9,STATUSCOLOR);\r
550         temp = fontcolor;\r
551         fontcolor = TEXTCOLOR^STATUSCOLOR;\r
552         US_CPrintLine (str);\r
553         fontcolor = temp;\r
554 }\r
555 \r
556 //===========================================================================\r
557 \r
558 /*\r
559 ===============\r
560 =\r
561 = DrawCompass\r
562 =\r
563 ===============\r
564 */\r
565 \r
566 void DrawCompass (void)\r
567 {\r
568         int             angle,number;\r
569 \r
570         //\r
571         // draw the compass if needed\r
572         //\r
573         angle = player->angle-ANGLES/4;\r
574         angle -= ANGLES/32;\r
575         if (angle<0)\r
576                 angle+=ANGLES;\r
577         number = angle/(ANGLES/16);\r
578         if (number>15)                                  // because 360 angles doesn't divide by 16\r
579                 number = 15;\r
580 \r
581         if (number == lastcompass)\r
582                 return;\r
583 \r
584         lastcompass = number;\r
585 \r
586         bufferofs = 0;\r
587         LatchDrawPic (COMPASSX,COMPASSY,COMPAS1PIC+15-number);\r
588 }\r
589 \r
590 //===========================================================================\r
591 \r
592 \r
593 /*\r
594 ===============\r
595 =\r
596 = DrawBars\r
597 =\r
598 ===============\r
599 */\r
600 \r
601 void DrawBars (void)\r
602 {\r
603         int                     i;\r
604         unsigned        source,dest,topline;\r
605 \r
606         for (i=0;i<3;i++)\r
607         {\r
608                 bufferofs = screenloc[i];\r
609                 VW_Bar (34*8,POWERLINE,40,MAXSHOTPOWER,1);\r
610         }\r
611         EGAWRITEMODE(1);\r
612         asm     mov     es,[screenseg]\r
613 \r
614 //\r
615 // shot power\r
616 //\r
617         if (gamestate.shotpower)\r
618         {\r
619                 topline = MAXSHOTPOWER - gamestate.shotpower;\r
620 \r
621                 source = latchpics[SHOTPOWERPIC-FIRSTLATCHPIC]+topline*SIDEBARWIDTH;\r
622                 dest = (POWERLINE+topline)*SCREENWIDTH+34;\r
623 \r
624                 asm     mov     si,[source]\r
625                 asm     mov     di,[dest]\r
626 \r
627                 asm     mov     cx,[WORD PTR gamestate.shotpower]\r
628 newline:\r
629         asm     mov     al,[es:si]\r
630         asm     mov     [es:di+PAGE1START],al\r
631         asm     mov     [es:di+PAGE2START],al\r
632         asm     mov     [es:di+PAGE3START],al\r
633         asm     mov     al,[es:si+1]\r
634         asm     mov     [es:di+1+PAGE1START],al\r
635         asm     mov     [es:di+1+PAGE2START],al\r
636         asm     mov     [es:di+1+PAGE3START],al\r
637         asm     mov     al,[es:si+2]\r
638         asm     mov     [es:di+2+PAGE1START],al\r
639         asm     mov     [es:di+2+PAGE2START],al\r
640         asm     mov     [es:di+2+PAGE3START],al\r
641         asm     mov     al,[es:si+3]\r
642         asm     mov     [es:di+3+PAGE1START],al\r
643         asm     mov     [es:di+3+PAGE2START],al\r
644         asm     mov     [es:di+3+PAGE3START],al\r
645         asm     mov     al,[es:si+4]\r
646         asm     mov     [es:di+4+PAGE1START],al\r
647         asm     mov     [es:di+4+PAGE2START],al\r
648         asm     mov     [es:di+4+PAGE3START],al\r
649 \r
650         asm     add     di,SCREENWIDTH\r
651         asm     add     si,5\r
652 \r
653                 asm     loop    newline\r
654         }\r
655 \r
656 //\r
657 // body\r
658 //\r
659         if (gamestate.body)\r
660         {\r
661                 source = latchpics[BODYPIC-FIRSTLATCHPIC];\r
662                 dest = BODYLINE*SCREENWIDTH+34;\r
663 \r
664                 asm     mov     si,[source]\r
665                 asm     mov     di,[dest]\r
666 \r
667                 asm     mov     cx,[WORD PTR gamestate.body]\r
668 newline2:\r
669         asm     mov     al,[es:si]\r
670         asm     mov     [es:di+PAGE1START],al\r
671         asm     mov     [es:di+PAGE2START],al\r
672         asm     mov     [es:di+PAGE3START],al\r
673         asm     mov     al,[es:si+1]\r
674         asm     mov     [es:di+1+PAGE1START],al\r
675         asm     mov     [es:di+1+PAGE2START],al\r
676         asm     mov     [es:di+1+PAGE3START],al\r
677         asm     mov     al,[es:si+2]\r
678         asm     mov     [es:di+2+PAGE1START],al\r
679         asm     mov     [es:di+2+PAGE2START],al\r
680         asm     mov     [es:di+2+PAGE3START],al\r
681         asm     mov     al,[es:si+3]\r
682         asm     mov     [es:di+3+PAGE1START],al\r
683         asm     mov     [es:di+3+PAGE2START],al\r
684         asm     mov     [es:di+3+PAGE3START],al\r
685         asm     mov     al,[es:si+4]\r
686         asm     mov     [es:di+4+PAGE1START],al\r
687         asm     mov     [es:di+4+PAGE2START],al\r
688         asm     mov     [es:di+4+PAGE3START],al\r
689 \r
690         asm     add     di,SCREENWIDTH\r
691         asm     add     si,5\r
692 \r
693                 asm     loop    newline2\r
694         }\r
695 \r
696         if (gamestate.body != MAXBODY)\r
697         {\r
698                 source = latchpics[NOBODYPIC-FIRSTLATCHPIC]+gamestate.body*SIDEBARWIDTH;\r
699                 dest = (BODYLINE+gamestate.body)*SCREENWIDTH+34;\r
700                 topline = MAXBODY-gamestate.body;\r
701 \r
702                 asm     mov     si,[source]\r
703                 asm     mov     di,[dest]\r
704 \r
705                 asm     mov     cx,[WORD PTR topline]\r
706 newline3:\r
707         asm     mov     al,[es:si]\r
708         asm     mov     [es:di+PAGE1START],al\r
709         asm     mov     [es:di+PAGE2START],al\r
710         asm     mov     [es:di+PAGE3START],al\r
711         asm     mov     al,[es:si+1]\r
712         asm     mov     [es:di+1+PAGE1START],al\r
713         asm     mov     [es:di+1+PAGE2START],al\r
714         asm     mov     [es:di+1+PAGE3START],al\r
715         asm     mov     al,[es:si+2]\r
716         asm     mov     [es:di+2+PAGE1START],al\r
717         asm     mov     [es:di+2+PAGE2START],al\r
718         asm     mov     [es:di+2+PAGE3START],al\r
719         asm     mov     al,[es:si+3]\r
720         asm     mov     [es:di+3+PAGE1START],al\r
721         asm     mov     [es:di+3+PAGE2START],al\r
722         asm     mov     [es:di+3+PAGE3START],al\r
723         asm     mov     al,[es:si+4]\r
724         asm     mov     [es:di+4+PAGE1START],al\r
725         asm     mov     [es:di+4+PAGE2START],al\r
726         asm     mov     [es:di+4+PAGE3START],al\r
727 \r
728         asm     add     di,SCREENWIDTH\r
729         asm     add     si,5\r
730 \r
731                 asm     loop    newline3\r
732         }\r
733 \r
734         EGAWRITEMODE(0);\r
735 }\r
736 \r
737 \r
738 /*\r
739 =============================================================================\r
740 \r
741                                                         SHOTS\r
742 \r
743 =============================================================================\r
744 */\r
745 \r
746 void T_Pshot (objtype *ob);\r
747 \r
748 \r
749 extern  statetype s_pshot1;\r
750 extern  statetype s_pshot2;\r
751 \r
752 extern  statetype s_bigpshot1;\r
753 extern  statetype s_bigpshot2;\r
754 \r
755 \r
756 statetype s_pshot1 = {PSHOT1PIC,8,&T_Pshot,&s_pshot2};\r
757 statetype s_pshot2 = {PSHOT2PIC,8,&T_Pshot,&s_pshot1};\r
758 \r
759 statetype s_shotexplode = {PSHOT2PIC,8,NULL,NULL};\r
760 \r
761 statetype s_bigpshot1 = {BIGPSHOT1PIC,8,&T_Pshot,&s_bigpshot2};\r
762 statetype s_bigpshot2 = {BIGPSHOT2PIC,8,&T_Pshot,&s_bigpshot1};\r
763 \r
764 \r
765 /*\r
766 ===================\r
767 =\r
768 = SpawnPShot\r
769 =\r
770 ===================\r
771 */\r
772 \r
773 void SpawnPShot (void)\r
774 {\r
775         SpawnNewObjFrac (player->x,player->y,&s_pshot1,PIXRADIUS*14);\r
776         new->obclass = pshotobj;\r
777         new->speed = SHOTSPEED;\r
778         new->angle = player->angle;\r
779 }\r
780 \r
781 void SpawnBigPShot (void)\r
782 {\r
783         SpawnNewObjFrac (player->x,player->y,&s_bigpshot1,24*PIXRADIUS);\r
784         new->obclass = bigpshotobj;\r
785         new->speed = SHOTSPEED;\r
786         new->angle = player->angle;\r
787 }\r
788 \r
789 \r
790 /*\r
791 ===============\r
792 =\r
793 = T_Pshot\r
794 =\r
795 ===============\r
796 */\r
797 \r
798 void T_Pshot (objtype *ob)\r
799 {\r
800         objtype *check;\r
801         long    xmove,ymove,speed;\r
802 \r
803 //\r
804 // check current position for monsters having moved into it\r
805 //\r
806         for (check = player->next; check; check=check->next)\r
807                 if (check->shootable\r
808                 && ob->xl <= check->xh\r
809                 && ob->xh >= check->xl\r
810                 && ob->yl <= check->yh\r
811                 && ob->yh >= check->yl)\r
812                 {\r
813                         SD_PlaySound (SHOOTMONSTERSND);\r
814                         if (ob->obclass == bigpshotobj)\r
815                                 ShootActor (check,BIGSHOTDAMAGE);\r
816                         else\r
817                                 ShootActor (check,SHOTDAMAGE);\r
818                         ob->state = &s_shotexplode;\r
819                         ob->ticcount = ob->state->tictime;\r
820                         return;\r
821                 }\r
822 \r
823 \r
824 //\r
825 // move ahead, possibly hitting a wall\r
826 //\r
827         speed = ob->speed*tics;\r
828 \r
829         xmove = FixedByFrac(speed,costable[ob->angle]);\r
830         ymove = -FixedByFrac(speed,sintable[ob->angle]);\r
831 \r
832         if (ShotClipMove(ob,xmove,ymove))\r
833         {\r
834                 ob->state = &s_shotexplode;\r
835                 ob->ticcount = ob->state->tictime;\r
836                 return;\r
837         }\r
838 \r
839         ob->tilex = ob->x >> TILESHIFT;\r
840         ob->tiley = ob->y >> TILESHIFT;\r
841 \r
842 //\r
843 // check final position for monsters hit\r
844 //\r
845         for (check = player->next; check; check=check->next)\r
846                 if (ob->shootable\r
847                 && ob->xl <= check->xh\r
848                 && ob->xh >= check->xl\r
849                 && ob->yl <= check->yh\r
850                 && ob->yh >= check->yl)\r
851                 {\r
852                         ShootActor (check,SHOTDAMAGE);\r
853                         ob->state = &s_shotexplode;\r
854                         ob->ticcount = ob->state->tictime;\r
855                         return;\r
856                 }\r
857 \r
858 }\r
859 \r
860 \r
861 \r
862 /*\r
863 =============================================================================\r
864 \r
865                                                    PLAYER ACTIONS\r
866 \r
867 =============================================================================\r
868 */\r
869 \r
870 \r
871 /*\r
872 ===============\r
873 =\r
874 = BuildShotPower\r
875 =\r
876 ===============\r
877 */\r
878 \r
879 void BuildShotPower (void)\r
880 {\r
881         int             newlines,topline;\r
882         long    i;\r
883         unsigned        source,dest;\r
884 \r
885         if (gamestate.shotpower == MAXSHOTPOWER)\r
886                 return;\r
887 \r
888         newlines = 0;\r
889         for (i=lasttimecount-tics;i<lasttimecount;i++)\r
890                 newlines += (i&1);\r
891 \r
892         gamestate.shotpower += newlines;\r
893 \r
894         if (gamestate.shotpower > MAXSHOTPOWER)\r
895         {\r
896                 newlines -= (gamestate.shotpower - MAXSHOTPOWER);\r
897                 gamestate.shotpower = MAXSHOTPOWER;\r
898         }\r
899 \r
900         topline = MAXSHOTPOWER - gamestate.shotpower;\r
901 \r
902         source = latchpics[L_SHOTBAR]+topline*SIDEBARWIDTH;\r
903         dest = (POWERLINE+topline)*SCREENWIDTH+34;\r
904 \r
905         asm     mov     es,[screenseg]\r
906         asm     mov     si,[source]\r
907         asm     mov     di,[dest]\r
908 \r
909         EGAWRITEMODE(1);\r
910 \r
911         if (newlines)\r
912         {\r
913                 asm     mov     cx,[newlines]\r
914 newline:\r
915                 asm     mov     al,[es:si]\r
916                 asm     mov     [es:di+PAGE1START],al\r
917                 asm     mov     [es:di+PAGE2START],al\r
918                 asm     mov     [es:di+PAGE3START],al\r
919                 asm     mov     al,[es:si+1]\r
920                 asm     mov     [es:di+1+PAGE1START],al\r
921                 asm     mov     [es:di+1+PAGE2START],al\r
922                 asm     mov     [es:di+1+PAGE3START],al\r
923                 asm     mov     al,[es:si+2]\r
924                 asm     mov     [es:di+2+PAGE1START],al\r
925                 asm     mov     [es:di+2+PAGE2START],al\r
926                 asm     mov     [es:di+2+PAGE3START],al\r
927                 asm     mov     al,[es:si+3]\r
928                 asm     mov     [es:di+3+PAGE1START],al\r
929                 asm     mov     [es:di+3+PAGE2START],al\r
930                 asm     mov     [es:di+3+PAGE3START],al\r
931                 asm     mov     al,[es:si+4]\r
932                 asm     mov     [es:di+4+PAGE1START],al\r
933                 asm     mov     [es:di+4+PAGE2START],al\r
934                 asm     mov     [es:di+4+PAGE3START],al\r
935 \r
936                 asm     add     di,SCREENWIDTH\r
937                 asm     add     si,5\r
938 \r
939                 asm     loop    newline\r
940         }\r
941 \r
942         EGAWRITEMODE(0);\r
943 }\r
944 \r
945 \r
946 //===========================================================================\r
947 \r
948 /*\r
949 ===============\r
950 =\r
951 = ClearShotPower\r
952 =\r
953 ===============\r
954 */\r
955 \r
956 void ClearShotPower (void)\r
957 {\r
958         unsigned        source,dest,topline;\r
959 \r
960         topline = MAXSHOTPOWER - gamestate.shotpower;\r
961 \r
962         source = latchpics[L_NOSHOT]+topline*SIDEBARWIDTH;\r
963         dest = (POWERLINE+topline)*SCREENWIDTH+34;\r
964 \r
965         asm     mov     es,[screenseg]\r
966         asm     mov     si,[source]\r
967         asm     mov     di,[dest]\r
968 \r
969         if (!gamestate.shotpower)\r
970                 return;\r
971 \r
972         EGAWRITEMODE(1);\r
973 \r
974         asm     mov     cx,[WORD PTR gamestate.shotpower]\r
975 newline:\r
976         asm     mov     al,[es:si]\r
977         asm     mov     [es:di+PAGE1START],al\r
978         asm     mov     [es:di+PAGE2START],al\r
979         asm     mov     [es:di+PAGE3START],al\r
980         asm     mov     al,[es:si+1]\r
981         asm     mov     [es:di+1+PAGE1START],al\r
982         asm     mov     [es:di+1+PAGE2START],al\r
983         asm     mov     [es:di+1+PAGE3START],al\r
984         asm     mov     al,[es:si+2]\r
985         asm     mov     [es:di+2+PAGE1START],al\r
986         asm     mov     [es:di+2+PAGE2START],al\r
987         asm     mov     [es:di+2+PAGE3START],al\r
988         asm     mov     al,[es:si+3]\r
989         asm     mov     [es:di+3+PAGE1START],al\r
990         asm     mov     [es:di+3+PAGE2START],al\r
991         asm     mov     [es:di+3+PAGE3START],al\r
992         asm     mov     al,[es:si+4]\r
993         asm     mov     [es:di+4+PAGE1START],al\r
994         asm     mov     [es:di+4+PAGE2START],al\r
995         asm     mov     [es:di+4+PAGE3START],al\r
996 \r
997         asm     add     di,SCREENWIDTH\r
998         asm     add     si,5\r
999 \r
1000         asm     loop    newline\r
1001 \r
1002         EGAWRITEMODE(0);\r
1003 \r
1004         gamestate.shotpower = 0;\r
1005 }\r
1006 \r
1007 //===========================================================================\r
1008 \r
1009 /*\r
1010 ===============\r
1011 =\r
1012 = Shoot\r
1013 =\r
1014 ===============\r
1015 */\r
1016 \r
1017 void Shoot (void)\r
1018 {\r
1019         ClearShotPower ();\r
1020         SD_PlaySound (SHOOTSND);\r
1021         SpawnPShot ();\r
1022 }\r
1023 \r
1024 //===========================================================================\r
1025 \r
1026 /*\r
1027 ===============\r
1028 =\r
1029 = BigShoot\r
1030 =\r
1031 ===============\r
1032 */\r
1033 \r
1034 void BigShoot (void)\r
1035 {\r
1036         ClearShotPower ();\r
1037         SD_PlaySound (BIGSHOOTSND);\r
1038         SpawnBigPShot ();\r
1039 }\r
1040 \r
1041 //===========================================================================\r
1042 \r
1043 /*\r
1044 ===============\r
1045 =\r
1046 = CastBolt\r
1047 =\r
1048 ===============\r
1049 */\r
1050 \r
1051 void CastBolt (void)\r
1052 {\r
1053         if (!gamestate.bolts)\r
1054         {\r
1055                 SD_PlaySound (NOITEMSND);\r
1056                 return;\r
1057         }\r
1058 \r
1059         TakeBolt ();\r
1060         boltsleft = NUMBOLTS;\r
1061         bolttimer = BOLTTICS;\r
1062         BigShoot ();\r
1063 }\r
1064 \r
1065 \r
1066 /*\r
1067 ===============\r
1068 =\r
1069 = ContinueBolt\r
1070 =\r
1071 ===============\r
1072 */\r
1073 \r
1074 void ContinueBolt (void)\r
1075 {\r
1076         bolttimer-=tics;\r
1077         if (bolttimer<0)\r
1078         {\r
1079                 boltsleft--;\r
1080                 bolttimer = BOLTTICS;\r
1081                 BigShoot ();\r
1082         }\r
1083 }\r
1084 \r
1085 \r
1086 //===========================================================================\r
1087 \r
1088 /*\r
1089 ===============\r
1090 =\r
1091 = CastNuke\r
1092 =\r
1093 ===============\r
1094 */\r
1095 \r
1096 void CastNuke (void)\r
1097 {\r
1098         int     angle;\r
1099 \r
1100         if (!gamestate.nukes)\r
1101         {\r
1102                 SD_PlaySound (NOITEMSND);\r
1103                 return;\r
1104         }\r
1105 \r
1106         TakeNuke ();\r
1107         lastnuke = TimeCount;\r
1108 \r
1109         for (angle = 0; angle < ANGLES; angle+= ANGLES/16)\r
1110         {\r
1111                 SpawnNewObjFrac (player->x,player->y,&s_bigpshot1,24*PIXRADIUS);\r
1112                 new->obclass = bigpshotobj;\r
1113                 new->speed = SHOTSPEED;\r
1114                 new->angle = angle;\r
1115         }\r
1116 }\r
1117 \r
1118 //===========================================================================\r
1119 \r
1120 /*\r
1121 ===============\r
1122 =\r
1123 = DrinkPotion\r
1124 =\r
1125 ===============\r
1126 */\r
1127 \r
1128 void DrinkPotion (void)\r
1129 {\r
1130         unsigned        source,dest,topline;\r
1131 \r
1132         if (!gamestate.potions)\r
1133         {\r
1134                 SD_PlaySound (NOITEMSND);\r
1135                 return;\r
1136         }\r
1137 \r
1138         TakePotion ();\r
1139         gamestate.body = MAXBODY;\r
1140 \r
1141 //\r
1142 // draw a full up bar\r
1143 //\r
1144         source = latchpics[L_BODYBAR];\r
1145         dest = BODYLINE*SCREENWIDTH+34;\r
1146 \r
1147         asm     mov     es,[screenseg]\r
1148         asm     mov     si,[source]\r
1149         asm     mov     di,[dest]\r
1150 \r
1151         EGAWRITEMODE(1);\r
1152 \r
1153         asm     mov     cx,MAXBODY\r
1154 newline:\r
1155         asm     mov     al,[es:si]\r
1156         asm     mov     [es:di+PAGE1START],al\r
1157         asm     mov     [es:di+PAGE2START],al\r
1158         asm     mov     [es:di+PAGE3START],al\r
1159         asm     mov     al,[es:si+1]\r
1160         asm     mov     [es:di+1+PAGE1START],al\r
1161         asm     mov     [es:di+1+PAGE2START],al\r
1162         asm     mov     [es:di+1+PAGE3START],al\r
1163         asm     mov     al,[es:si+2]\r
1164         asm     mov     [es:di+2+PAGE1START],al\r
1165         asm     mov     [es:di+2+PAGE2START],al\r
1166         asm     mov     [es:di+2+PAGE3START],al\r
1167         asm     mov     al,[es:si+3]\r
1168         asm     mov     [es:di+3+PAGE1START],al\r
1169         asm     mov     [es:di+3+PAGE2START],al\r
1170         asm     mov     [es:di+3+PAGE3START],al\r
1171         asm     mov     al,[es:si+4]\r
1172         asm     mov     [es:di+4+PAGE1START],al\r
1173         asm     mov     [es:di+4+PAGE2START],al\r
1174         asm     mov     [es:di+4+PAGE3START],al\r
1175         asm     add     di,SCREENWIDTH\r
1176         asm     add     si,5\r
1177 \r
1178         asm     loop    newline\r
1179 \r
1180         EGAWRITEMODE(0);\r
1181 }\r
1182 \r
1183 \r
1184 \r
1185 //===========================================================================\r
1186 \r
1187 /*\r
1188 ===============\r
1189 =\r
1190 = ReadScroll\r
1191 =\r
1192 ===============\r
1193 */\r
1194 \r
1195 extern  boolean tileneeded[NUMFLOORS];\r
1196 \r
1197 void ReadScroll (int scroll)\r
1198 {\r
1199         int     i;\r
1200 \r
1201 //\r
1202 // make wall pictures purgable\r
1203 //\r
1204         for (i=0;i<NUMSCALEWALLS;i++)\r
1205                 if (walldirectory[i])\r
1206                         MM_SetPurge (&(memptr)walldirectory[i],3);\r
1207 \r
1208         CA_CacheGrChunk (SCROLLTOPPIC);\r
1209         CA_CacheGrChunk (SCROLL1PIC + scroll);\r
1210         VW_DrawPic (0,0,SCROLLTOPPIC);\r
1211         VW_DrawPic (0,32,SCROLL1PIC + scroll);\r
1212         UNMARKGRCHUNK(SCROLL1PIC + scroll);\r
1213         UNMARKGRCHUNK(SCROLLTOPPIC);\r
1214         MM_FreePtr (&grsegs[SCROLL1PIC + scroll]);\r
1215         MM_FreePtr (&grsegs[SCROLLTOPPIC]);\r
1216 \r
1217 //\r
1218 // cache wall pictures back in\r
1219 //\r
1220         for (i=1;i<NUMFLOORS;i++)\r
1221                 if (tileneeded[i])\r
1222                 {\r
1223                         SetupScaleWall (walllight1[i]);\r
1224                         SetupScaleWall (walllight2[i]);\r
1225                         SetupScaleWall (walldark1[i]);\r
1226                         SetupScaleWall (walldark2[i]);\r
1227                 }\r
1228 \r
1229         VW_WaitVBL(80);\r
1230 waitkey:\r
1231         IN_ClearKeysDown ();\r
1232         IN_Ack();\r
1233 \r
1234 }\r
1235 \r
1236 \r
1237 \r
1238 /*\r
1239 ===============\r
1240 =\r
1241 = TakeDamage\r
1242 =\r
1243 ===============\r
1244 */\r
1245 \r
1246 void TakeDamage (int points)\r
1247 {\r
1248         unsigned        source,dest,topline;\r
1249 \r
1250         if (!gamestate.body || bordertime || godmode)\r
1251                 return;\r
1252 \r
1253         if (points >= gamestate.body)\r
1254         {\r
1255                 points = gamestate.body;\r
1256                 playstate = ex_died;\r
1257         }\r
1258 \r
1259         bordertime = points*FLASHTICS;\r
1260         VW_ColorBorder (FLASHCOLOR);\r
1261 \r
1262         if (gamestate.body<MAXBODY/3)\r
1263                 SD_PlaySound (TAKEDMGHURTSND);\r
1264         else\r
1265                 SD_PlaySound (TAKEDAMAGESND);\r
1266 \r
1267         gamestate.body -= points;\r
1268 //\r
1269 // shrink the body bar\r
1270 //\r
1271         source = latchpics[L_NOBODY]+gamestate.body*SIDEBARWIDTH;\r
1272         dest = (BODYLINE+gamestate.body)*SCREENWIDTH+34;\r
1273 \r
1274 \r
1275         asm     mov     es,[screenseg]\r
1276         asm     mov     si,[source]\r
1277         asm     mov     di,[dest]\r
1278 \r
1279         EGAWRITEMODE(1);\r
1280 \r
1281         asm     mov     cx,[points]\r
1282 newline:\r
1283         asm     mov     al,[es:si]\r
1284         asm     mov     [es:di+PAGE1START],al\r
1285         asm     mov     [es:di+PAGE2START],al\r
1286         asm     mov     [es:di+PAGE3START],al\r
1287         asm     mov     al,[es:si+1]\r
1288         asm     mov     [es:di+1+PAGE1START],al\r
1289         asm     mov     [es:di+1+PAGE2START],al\r
1290         asm     mov     [es:di+1+PAGE3START],al\r
1291         asm     mov     al,[es:si+2]\r
1292         asm     mov     [es:di+2+PAGE1START],al\r
1293         asm     mov     [es:di+2+PAGE2START],al\r
1294         asm     mov     [es:di+2+PAGE3START],al\r
1295         asm     mov     al,[es:si+3]\r
1296         asm     mov     [es:di+3+PAGE1START],al\r
1297         asm     mov     [es:di+3+PAGE2START],al\r
1298         asm     mov     [es:di+3+PAGE3START],al\r
1299         asm     mov     al,[es:si+4]\r
1300         asm     mov     [es:di+4+PAGE1START],al\r
1301         asm     mov     [es:di+4+PAGE2START],al\r
1302         asm     mov     [es:di+4+PAGE3START],al\r
1303 \r
1304         asm     add     di,SCREENWIDTH\r
1305         asm     add     si,5\r
1306 \r
1307         asm     loop    newline\r
1308 \r
1309         EGAWRITEMODE(0);\r
1310 \r
1311 }\r
1312 \r
1313 \r
1314 \r
1315 /*\r
1316 =============================================================================\r
1317 \r
1318                                                         INTERACTION\r
1319 \r
1320 =============================================================================\r
1321 */\r
1322 \r
1323 \r
1324 /*\r
1325 ==================\r
1326 =\r
1327 = OpenDoor\r
1328 =\r
1329 ==================\r
1330 */\r
1331 \r
1332 void OpenDoor (unsigned bx, unsigned by, unsigned doorbase)\r
1333 {\r
1334         int x,y;\r
1335         unsigned        far *map;\r
1336 \r
1337         x=bx;\r
1338         y=by;\r
1339         map = mapsegs[0]+farmapylookup[y]+x;\r
1340         while (tilemap[x][y]-doorbase<4)\r
1341         {\r
1342                 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
1343                 map--;\r
1344                 x--;\r
1345         }\r
1346         x=bx+1;\r
1347         map = mapsegs[0]+farmapylookup[y]+x;\r
1348         while (tilemap[x][y]-doorbase<4)\r
1349         {\r
1350                 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
1351                 map++;\r
1352                 x++;\r
1353         }\r
1354         x=bx;\r
1355         y=by-1;\r
1356         map = mapsegs[0]+farmapylookup[y]+x;\r
1357         while (tilemap[x][y]-doorbase<4)\r
1358         {\r
1359                 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
1360                 map-=mapwidth;\r
1361                 y--;\r
1362         }\r
1363         y=by+1;\r
1364         map = mapsegs[0]+farmapylookup[y]+x;\r
1365         while (tilemap[x][y]-doorbase<4)\r
1366         {\r
1367                 tilemap[x][y] = (unsigned)actorat[x][y] = *map = 0;\r
1368                 map+=mapwidth;\r
1369                 y++;\r
1370         }\r
1371 }\r
1372 \r
1373 \r
1374 /*\r
1375 ==================\r
1376 =\r
1377 = HitSpecialTile\r
1378 =\r
1379 = Returns true if the move is blocked\r
1380 =\r
1381 ==================\r
1382 */\r
1383 \r
1384 boolean HitSpecialTile (unsigned x, unsigned y, unsigned tile)\r
1385 {\r
1386         switch (tile)\r
1387         {\r
1388         case 0:\r
1389         case 1:\r
1390         case 2:\r
1391         case 3:\r
1392                 if (!gamestate.keys[0])\r
1393                         return true;\r
1394                 TakeKey(0);\r
1395                 OpenDoor (x,y,SPECTILESTART+0);\r
1396                 return false;\r
1397 \r
1398         case 4:\r
1399         case 5:\r
1400         case 6:\r
1401         case 7:\r
1402                 if (!gamestate.keys[1])\r
1403                         return true;\r
1404                 TakeKey(1);\r
1405                 OpenDoor (x,y,SPECTILESTART+4);\r
1406                 return false;\r
1407 \r
1408         case 8:\r
1409         case 9:\r
1410         case 10:\r
1411         case 11:\r
1412                 if (!gamestate.keys[2])\r
1413                         return true;\r
1414                 TakeKey(2);\r
1415                 OpenDoor (x,y,SPECTILESTART+8);\r
1416                 return false;\r
1417 \r
1418         case 12:\r
1419         case 13:\r
1420         case 14:\r
1421         case 15:\r
1422                 if (!gamestate.keys[3])\r
1423                         return true;\r
1424                 TakeKey(3);\r
1425                 OpenDoor (x,y,SPECTILESTART+12);\r
1426                 return false;\r
1427 \r
1428         }\r
1429 \r
1430         return true;\r
1431 }\r
1432 \r
1433 \r
1434 \r
1435 /*\r
1436 ==================\r
1437 =\r
1438 = TouchActor\r
1439 =\r
1440 = Returns true if the move is blocked\r
1441 =\r
1442 ==================\r
1443 */\r
1444 \r
1445 boolean TouchActor (objtype *ob, objtype *check)\r
1446 {\r
1447         if (ob->xh < check->xl || ob->xl > check->xh ||\r
1448                 ob->yh < check->yl || ob->yl > check->yh)\r
1449                 return false;                           // not quite touching\r
1450 \r
1451         switch (check->obclass)\r
1452         {\r
1453         case bonusobj:\r
1454                 if (check->temp1 == B_BOLT)\r
1455                         GiveBolt ();\r
1456                 else if (check->temp1 == B_NUKE)\r
1457                         GiveNuke ();\r
1458                 else if (check->temp1 == B_POTION)\r
1459                         GivePotion ();\r
1460                 else if (check->temp1 >= B_RKEY && check->temp1 <= B_BKEY)\r
1461                         GiveKey (check->temp1-B_RKEY);\r
1462                 else if (check->temp1 >= B_SCROLL1 && check->temp1 <= B_SCROLL8)\r
1463                         GiveScroll (check->temp1-B_SCROLL1,true);\r
1464                 else if (check->temp1 == B_CHEST)\r
1465                         GiveChest ();\r
1466                 else if (check->temp1 == B_GOAL)\r
1467                         GiveGoal ();\r
1468                 (unsigned)actorat[check->tilex][check->tiley] = 0;\r
1469                 RemoveObj (check);\r
1470 \r
1471                 return false;\r
1472 \r
1473         }\r
1474         return  true;\r
1475 }\r
1476 \r
1477 \r
1478 /*\r
1479 ==================\r
1480 =\r
1481 = CalcBounds\r
1482 =\r
1483 ==================\r
1484 */\r
1485 \r
1486 void CalcBounds (objtype *ob)\r
1487 {\r
1488 //\r
1489 // calculate hit rect\r
1490 //\r
1491   ob->xl = ob->x - ob->size;\r
1492   ob->xh = ob->x + ob->size;\r
1493   ob->yl = ob->y - ob->size;\r
1494   ob->yh = ob->y + ob->size;\r
1495 }\r
1496 \r
1497 \r
1498 /*\r
1499 ===================\r
1500 =\r
1501 = LocationInActor\r
1502 =\r
1503 ===================\r
1504 */\r
1505 \r
1506 boolean LocationInActor (objtype *ob)\r
1507 {\r
1508         int     x,y,xmin,ymin,xmax,ymax;\r
1509         objtype *check;\r
1510 \r
1511         CalcBounds (ob);\r
1512 \r
1513         xmin = (ob->x >> TILESHIFT)-2;\r
1514         ymin = (ob->y >> TILESHIFT)-2;\r
1515         xmax = xmin+5;\r
1516         ymax = ymin+5;\r
1517 \r
1518         for (x=xmin;x<xmax;x++)\r
1519                 for (y=ymin;y<ymax;y++)\r
1520                 {\r
1521                         check = actorat[x][y];\r
1522                         if (check>(objtype *)LASTSPECIALTILE\r
1523                         && check->shootable\r
1524                         && ob->xl <= check->xh\r
1525                         && ob->xh >= check->xl\r
1526                         && ob->yl <= check->yh\r
1527                         && ob->yh >= check->yl)\r
1528                                 return true;\r
1529                 }\r
1530 \r
1531         return false;\r
1532 }\r
1533 \r
1534 \r
1535 /*\r
1536 ===================\r
1537 =\r
1538 = ClipMove\r
1539 =\r
1540 = Only checks corners, so the object better be less than one tile wide!\r
1541 =\r
1542 ===================\r
1543 */\r
1544 \r
1545 void ClipMove (objtype *ob, long xmove, long ymove)\r
1546 {\r
1547         int                     xl,yl,xh,yh,tx,ty,nt1,nt2,x,y;\r
1548         long            intersect,basex,basey,pointx,pointy;\r
1549         unsigned        inside,total,tile;\r
1550         objtype         *check;\r
1551         boolean         moveok;\r
1552 \r
1553 //\r
1554 // move player and check to see if any corners are in solid tiles\r
1555 //\r
1556         basex = ob->x;\r
1557         basey = ob->y;\r
1558 \r
1559         ob->x += xmove;\r
1560         ob->y += ymove;\r
1561 \r
1562         CalcBounds (ob);\r
1563 \r
1564         xl = ob->xl>>TILESHIFT;\r
1565         yl = ob->yl>>TILESHIFT;\r
1566 \r
1567         xh = ob->xh>>TILESHIFT;\r
1568         yh = ob->yh>>TILESHIFT;\r
1569 \r
1570         for (y=yl;y<=yh;y++)\r
1571                 for (x=xl;x<=xh;x++)\r
1572                 {\r
1573                         check = actorat[x][y];\r
1574                         if (!check)\r
1575                                 continue;               // blank floor, walk ok\r
1576 \r
1577                         if ((unsigned)check<=LASTWALLTILE)\r
1578                                 goto blockmove; // solid wall\r
1579 \r
1580                         if ((unsigned)check<=LASTSPECIALTILE)\r
1581                         {\r
1582                                 if ( HitSpecialTile (x,y,(unsigned)check-SPECTILESTART) )\r
1583                                         goto blockmove;         // whatever it was, it blocked the move\r
1584                                 else\r
1585                                         continue;\r
1586                         }\r
1587                         TouchActor(ob,check);           // pick up items\r
1588                 }\r
1589 \r
1590 //\r
1591 // check nearby actors\r
1592 //\r
1593         if (LocationInActor(ob))\r
1594         {\r
1595                 ob->x -= xmove;\r
1596                 if (LocationInActor(ob))\r
1597                 {\r
1598                         ob->x += xmove;\r
1599                         ob->y -= ymove;\r
1600                         if (LocationInActor(ob))\r
1601                                 ob->x -= xmove;\r
1602                 }\r
1603         }\r
1604         return;         // move is OK!\r
1605 \r
1606 \r
1607 blockmove:\r
1608 \r
1609         if (!SD_SoundPlaying())\r
1610                 SD_PlaySound (HITWALLSND);\r
1611 \r
1612         moveok = false;\r
1613 \r
1614         do\r
1615         {\r
1616                 xmove /= 2;\r
1617                 ymove /= 2;\r
1618                 if (moveok)\r
1619                 {\r
1620                         ob->x += xmove;\r
1621                         ob->y += ymove;\r
1622                 }\r
1623                 else\r
1624                 {\r
1625                         ob->x -= xmove;\r
1626                         ob->y -= ymove;\r
1627                 }\r
1628                 CalcBounds (ob);\r
1629                 xl = ob->xl>>TILESHIFT;\r
1630                 yl = ob->yl>>TILESHIFT;\r
1631                 xh = ob->xh>>TILESHIFT;\r
1632                 yh = ob->yh>>TILESHIFT;\r
1633                 if (tilemap[xl][yl] || tilemap[xh][yl]\r
1634                 || tilemap[xh][yh] || tilemap[xl][yh] )\r
1635                 {\r
1636                         moveok = false;\r
1637                         if (xmove>=-2048 && xmove <=2048 && ymove>=-2048 && ymove <=2048)\r
1638                         {\r
1639                                 ob->x = basex;\r
1640                                 ob->y = basey;\r
1641                                 return;\r
1642                         }\r
1643                 }\r
1644                 else\r
1645                 {\r
1646                         if (xmove>=-2048 && xmove <=2048 && ymove>=-2048 && ymove <=2048)\r
1647                                 return;\r
1648                         moveok = true;\r
1649                 }\r
1650         } while (1);\r
1651 }\r
1652 \r
1653 \r
1654 //==========================================================================\r
1655 \r
1656 \r
1657 /*\r
1658 ===================\r
1659 =\r
1660 = ShotClipMove\r
1661 =\r
1662 = Only checks corners, so the object better be less than one tile wide!\r
1663 =\r
1664 ===================\r
1665 */\r
1666 \r
1667 boolean ShotClipMove (objtype *ob, long xmove, long ymove)\r
1668 {\r
1669         int                     xl,yl,xh,yh,tx,ty,nt1,nt2,x,y;\r
1670         long            intersect,basex,basey,pointx,pointy;\r
1671         unsigned        inside,total,tile;\r
1672         objtype         *check;\r
1673         boolean         moveok;\r
1674 \r
1675 //\r
1676 // move shot and check to see if any corners are in solid tiles\r
1677 //\r
1678         basex = ob->x;\r
1679         basey = ob->y;\r
1680 \r
1681         ob->x += xmove;\r
1682         ob->y += ymove;\r
1683 \r
1684         CalcBounds (ob);\r
1685 \r
1686         xl = ob->xl>>TILESHIFT;\r
1687         yl = ob->yl>>TILESHIFT;\r
1688 \r
1689         xh = ob->xh>>TILESHIFT;\r
1690         yh = ob->yh>>TILESHIFT;\r
1691 \r
1692         for (y=yl;y<=yh;y++)\r
1693                 for (x=xl;x<=xh;x++)\r
1694                 {\r
1695                         tile = tilemap[x][y];\r
1696                         if (tile)\r
1697                         {\r
1698                                 if ((unsigned)(tile-EXPWALLSTART)<NUMEXPWALLS)\r
1699                                         ExplodeWall (x,y);\r
1700                                 goto blockmove;\r
1701                         }\r
1702                 }\r
1703         return false;           // move is OK!\r
1704 \r
1705 \r
1706 blockmove:\r
1707 \r
1708         SD_PlaySound (SHOOTWALLSND);\r
1709 \r
1710         moveok = false;\r
1711 \r
1712         do\r
1713         {\r
1714                 xmove /= 2;\r
1715                 ymove /= 2;\r
1716                 if (moveok)\r
1717                 {\r
1718                         ob->x += xmove;\r
1719                         ob->y += ymove;\r
1720                 }\r
1721                 else\r
1722                 {\r
1723                         ob->x -= xmove;\r
1724                         ob->y -= ymove;\r
1725                 }\r
1726                 CalcBounds (ob);\r
1727                 xl = ob->xl>>TILESHIFT;\r
1728                 yl = ob->yl>>TILESHIFT;\r
1729                 xh = ob->xh>>TILESHIFT;\r
1730                 yh = ob->yh>>TILESHIFT;\r
1731                 if (tilemap[xl][yl] || tilemap[xh][yl]\r
1732                 || tilemap[xh][yh] || tilemap[xl][yh] )\r
1733                 {\r
1734                         moveok = false;\r
1735                         if (xmove>=-2048 && xmove <=2048 && ymove>=-2048 && ymove <=2048)\r
1736                         {\r
1737                                 ob->x = basex;\r
1738                                 ob->y = basey;\r
1739                                 return true;\r
1740                         }\r
1741                 }\r
1742                 else\r
1743                 {\r
1744                         if (xmove>=-2048 && xmove <=2048 && ymove>=-2048 && ymove <=2048)\r
1745                                 return true;\r
1746                         moveok = true;\r
1747                 }\r
1748         } while (1);\r
1749 }\r
1750 \r
1751 \r
1752 \r
1753 /*\r
1754 =============================================================================\r
1755 \r
1756                                                    PLAYER CONTROL\r
1757 \r
1758 =============================================================================\r
1759 */\r
1760 \r
1761 \r
1762 \r
1763 void    T_Player (objtype *ob);\r
1764 \r
1765 statetype s_player = {0,0,&T_Player,&s_player};\r
1766 \r
1767 /*\r
1768 ===============\r
1769 =\r
1770 = SpawnPlayer\r
1771 =\r
1772 ===============\r
1773 */\r
1774 \r
1775 void SpawnPlayer (int tilex, int tiley, int dir)\r
1776 {\r
1777         player->obclass = playerobj;\r
1778         player->active = true;\r
1779         player->tilex = tilex;\r
1780         player->tiley = tiley;\r
1781         player->x = ((long)tilex<<TILESHIFT)+TILEGLOBAL/2;\r
1782         player->y = ((long)tiley<<TILESHIFT)+TILEGLOBAL/2;\r
1783         player->state = &s_player;\r
1784         player->angle = (1-dir)*90;\r
1785         player->size = MINDIST;\r
1786         CalcBounds (player);\r
1787         if (player->angle<0)\r
1788                 player->angle += ANGLES;\r
1789 }\r
1790 \r
1791 \r
1792 /*\r
1793 ===================\r
1794 =\r
1795 = Thrust\r
1796 =\r
1797 ===================\r
1798 */\r
1799 \r
1800 void Thrust (int angle, unsigned speed)\r
1801 {\r
1802         long xmove,ymove;\r
1803 \r
1804         if (lasttimecount>>5 != ((lasttimecount-tics)>>5) )\r
1805         {\r
1806         //\r
1807         // walk sound\r
1808         //\r
1809                 if (lasttimecount&32)\r
1810                         SD_PlaySound (WALK1SND);\r
1811                 else\r
1812                         SD_PlaySound (WALK2SND);\r
1813         }\r
1814 \r
1815         xmove = FixedByFrac(speed,costable[angle]);\r
1816         ymove = -FixedByFrac(speed,sintable[angle]);\r
1817 \r
1818         ClipMove(player,xmove,ymove);\r
1819         player->tilex = player->x >> TILESHIFT;\r
1820         player->tiley = player->y >> TILESHIFT;\r
1821 }\r
1822 \r
1823 \r
1824 \r
1825 /*\r
1826 =======================\r
1827 =\r
1828 = ControlMovement\r
1829 =\r
1830 =======================\r
1831 */\r
1832 \r
1833 void ControlMovement (objtype *ob)\r
1834 {\r
1835         int     angle;\r
1836         long    speed;\r
1837 \r
1838 \r
1839         if (c.button1)\r
1840         {\r
1841         //\r
1842         // strafing\r
1843         //\r
1844                 //\r
1845                 // side to side move\r
1846                 //\r
1847                 if (!mousexmove)\r
1848                         speed = 0;\r
1849                 else if (mousexmove<0)\r
1850                         speed = -(long)mousexmove*300;\r
1851                 else\r
1852                         speed = -(long)mousexmove*300;\r
1853 \r
1854                 if (c.xaxis == -1)\r
1855                 {\r
1856                         if (running)\r
1857                                 speed += RUNSPEED*tics;\r
1858                         else\r
1859                                 speed += PLAYERSPEED*tics;\r
1860                 }\r
1861                 else if (c.xaxis == 1)\r
1862                 {\r
1863                         if (running)\r
1864                                 speed -= RUNSPEED*tics;\r
1865                         else\r
1866                                 speed -= PLAYERSPEED*tics;\r
1867                 }\r
1868 \r
1869                 if (speed > 0)\r
1870                 {\r
1871                         if (speed >= TILEGLOBAL)\r
1872                                 speed = TILEGLOBAL-1;\r
1873                         angle = ob->angle + ANGLES/4;\r
1874                         if (angle >= ANGLES)\r
1875                                 angle -= ANGLES;\r
1876                         Thrust (angle,speed);                           // move to left\r
1877                 }\r
1878                 else if (speed < 0)\r
1879                 {\r
1880                         if (speed <= -TILEGLOBAL)\r
1881                                 speed = -TILEGLOBAL+1;\r
1882                         angle = ob->angle - ANGLES/4;\r
1883                         if (angle < 0)\r
1884                                 angle += ANGLES;\r
1885                         Thrust (angle,-speed);                          // move to right\r
1886                 }\r
1887         }\r
1888         else\r
1889         {\r
1890         //\r
1891         // not strafing\r
1892         //\r
1893 \r
1894                 //\r
1895                 // turning\r
1896                 //\r
1897                 if (c.xaxis == 1)\r
1898                 {\r
1899                         ob->angle -= tics;\r
1900                         if (running)                            // fast turn\r
1901                                 ob->angle -= tics;\r
1902                 }\r
1903                 else if (c.xaxis == -1)\r
1904                 {\r
1905                         ob->angle+= tics;\r
1906                         if (running)                            // fast turn\r
1907                                 ob->angle += tics;\r
1908                 }\r
1909 \r
1910                 ob->angle -= (mousexmove/10);\r
1911 \r
1912                 if (ob->angle >= ANGLES)\r
1913                         ob->angle -= ANGLES;\r
1914                 if (ob->angle < 0)\r
1915                         ob->angle += ANGLES;\r
1916 \r
1917         }\r
1918 \r
1919         //\r
1920         // forward/backwards move\r
1921         //\r
1922         if (!mouseymove)\r
1923                 speed = 0;\r
1924         else if (mouseymove<0)\r
1925                 speed = -(long)mouseymove*500;\r
1926         else\r
1927                 speed = -(long)mouseymove*200;\r
1928 \r
1929         if (c.yaxis == -1)\r
1930         {\r
1931                 if (running)\r
1932                         speed += RUNSPEED*tics;\r
1933                 else\r
1934                         speed += PLAYERSPEED*tics;\r
1935         }\r
1936         else if (c.yaxis == 1)\r
1937         {\r
1938                 if (running)\r
1939                         speed -= RUNSPEED*tics;\r
1940                 else\r
1941                         speed -= PLAYERSPEED*tics;\r
1942         }\r
1943 \r
1944         if (speed > 0)\r
1945         {\r
1946                 if (speed >= TILEGLOBAL)\r
1947                         speed = TILEGLOBAL-1;\r
1948                 Thrust (ob->angle,speed);                       // move forwards\r
1949         }\r
1950         else if (speed < 0)\r
1951         {\r
1952                 if (speed <= -TILEGLOBAL)\r
1953                         speed = -TILEGLOBAL+1;\r
1954                 angle = ob->angle + ANGLES/2;\r
1955                 if (angle >= ANGLES)\r
1956                         angle -= ANGLES;\r
1957                 Thrust (angle,-speed);                          // move backwards\r
1958         }\r
1959 }\r
1960 \r
1961 \r
1962 /*\r
1963 ===============\r
1964 =\r
1965 = T_Player\r
1966 =\r
1967 ===============\r
1968 */\r
1969 \r
1970 void    T_Player (objtype *ob)\r
1971 {\r
1972         int     angle,speed,scroll;\r
1973         unsigned        text,tilex,tiley;\r
1974         long    lspeed;\r
1975 \r
1976 \r
1977         ControlMovement (ob);\r
1978 \r
1979 \r
1980         //\r
1981         // firing\r
1982         //\r
1983         if (boltsleft)\r
1984         {\r
1985                 handheight+=(tics<<2);\r
1986                 if (handheight>MAXHANDHEIGHT)\r
1987                         handheight = MAXHANDHEIGHT;\r
1988 \r
1989                 ContinueBolt ();\r
1990                 lasthand = lasttimecount;\r
1991         }\r
1992         else\r
1993         {\r
1994                 if (c.button0)\r
1995                 {\r
1996                         handheight+=(tics<<2);\r
1997                         if (handheight>MAXHANDHEIGHT)\r
1998                                 handheight = MAXHANDHEIGHT;\r
1999 \r
2000                         if ((unsigned)TimeCount/FIRETIME != lastfiretime)\r
2001                                 BuildShotPower ();\r
2002                         lasthand = lasttimecount;\r
2003                 }\r
2004                 else\r
2005                 {\r
2006                         if (lasttimecount > lasthand+HANDPAUSE)\r
2007                         {\r
2008                                 handheight-=(tics<<1);\r
2009                                 if (handheight<0)\r
2010                                         handheight = 0;\r
2011                         }\r
2012 \r
2013                         if (gamestate.shotpower == MAXSHOTPOWER)\r
2014                         {\r
2015                                 lastfiretime = (unsigned)TimeCount/FIRETIME;\r
2016                                 BigShoot ();\r
2017                         }\r
2018                         else if (gamestate.shotpower)\r
2019                         {\r
2020                                 lastfiretime = (unsigned)TimeCount/FIRETIME;\r
2021                                 Shoot ();\r
2022                         }\r
2023                 }\r
2024         }\r
2025 \r
2026         //\r
2027         // special actions\r
2028         //\r
2029 \r
2030         if ( (Keyboard[sc_Space] || Keyboard[sc_H]) && gamestate.body != MAXBODY)\r
2031                 DrinkPotion ();\r
2032 \r
2033         if (Keyboard[sc_B] && !boltsleft)\r
2034                 CastBolt ();\r
2035 \r
2036         if ( (Keyboard[sc_Enter] || Keyboard[sc_N]) && TimeCount-lastnuke > NUKETIME)\r
2037                 CastNuke ();\r
2038 \r
2039         scroll = LastScan-2;\r
2040         if ( scroll>=0 && scroll<NUMSCROLLS && gamestate.scrolls[scroll])\r
2041                 ReadScroll (scroll);\r
2042 \r
2043         DrawText ();\r
2044         DrawCompass ();\r
2045 \r
2046 }\r