]> 4ch.mooo.com Git - 16.git/blob - src/core/wl_agent.c
cannot do more
[16.git] / src / core / wl_agent.c
1 // WL_AGENT.C\r
2 \r
3 #include "WL_DEF.H"\r
4 #pragma hdrstop\r
5 \r
6 \r
7 /*\r
8 =============================================================================\r
9 \r
10                                                  LOCAL CONSTANTS\r
11 \r
12 =============================================================================\r
13 */\r
14 \r
15 #define MAXMOUSETURN    10\r
16 \r
17 \r
18 #define MOVESCALE               150l\r
19 #define BACKMOVESCALE   100l\r
20 #define ANGLESCALE              20\r
21 \r
22 /*\r
23 =============================================================================\r
24 \r
25                                                  GLOBAL VARIABLES\r
26 \r
27 =============================================================================\r
28 */\r
29 \r
30 \r
31 \r
32 //\r
33 // player state info\r
34 //\r
35 boolean         running;\r
36 long            thrustspeed;\r
37 \r
38 unsigned        plux,pluy;                      // player coordinates scaled to unsigned\r
39 \r
40 int                     anglefrac;\r
41 int                     gotgatgun;      // JR\r
42 \r
43 objtype         *LastAttacker;\r
44 \r
45 /*\r
46 =============================================================================\r
47 \r
48                                                  LOCAL VARIABLES\r
49 \r
50 =============================================================================\r
51 */\r
52 \r
53 \r
54 void    T_Player (objtype *ob);\r
55 void    T_Attack (objtype *ob);\r
56 \r
57 statetype s_player = {false,0,0,T_Player,NULL,NULL};\r
58 statetype s_attack = {false,0,0,T_Attack,NULL,NULL};\r
59 \r
60 \r
61 long    playerxmove,playerymove;\r
62 \r
63 struct atkinf\r
64 {\r
65         char    tics,attack,frame;              // attack is 1 for gun, 2 for knife\r
66 } attackinfo[4][14] =\r
67 \r
68 {\r
69 { {6,0,1},{6,2,2},{6,0,3},{6,-1,4} },\r
70 { {6,0,1},{6,1,2},{6,0,3},{6,-1,4} },\r
71 { {6,0,1},{6,1,2},{6,3,3},{6,-1,4} },\r
72 { {6,0,1},{6,1,2},{6,4,3},{6,-1,4} },\r
73 };\r
74 \r
75 \r
76 int     strafeangle[9] = {0,90,180,270,45,135,225,315,0};\r
77 \r
78 void DrawWeapon (void);\r
79 void GiveWeapon (int weapon);\r
80 void    GiveAmmo (int ammo);\r
81 \r
82 //===========================================================================\r
83 \r
84 //----------\r
85 \r
86 void Attack (void);\r
87 void Use (void);\r
88 void Search (objtype *ob);\r
89 void SelectWeapon (void);\r
90 void SelectItem (void);\r
91 \r
92 //----------\r
93 \r
94 boolean TryMove (objtype *ob);\r
95 void T_Player (objtype *ob);\r
96 \r
97 void ClipMove (objtype *ob, long xmove, long ymove);\r
98 \r
99 /*\r
100 =============================================================================\r
101 \r
102                                                 CONTROL STUFF\r
103 \r
104 =============================================================================\r
105 */\r
106 \r
107 /*\r
108 ======================\r
109 =\r
110 = CheckWeaponChange\r
111 =\r
112 = Keys 1-4 change weapons\r
113 =\r
114 ======================\r
115 */\r
116 \r
117 void CheckWeaponChange (void)\r
118 {\r
119         int     i,buttons;\r
120 \r
121         if (!gamestate.ammo)            // must use knife with no ammo\r
122                 return;\r
123 \r
124         for (i=wp_knife ; i<=gamestate.bestweapon ; i++)\r
125                 if (buttonstate[bt_readyknife+i-wp_knife])\r
126                 {\r
127                         gamestate.weapon = gamestate.chosenweapon = i;\r
128                         DrawWeapon ();\r
129                         return;\r
130                 }\r
131 }\r
132 \r
133 \r
134 /*\r
135 =======================\r
136 =\r
137 = ControlMovement\r
138 =\r
139 = Takes controlx,controly, and buttonstate[bt_strafe]\r
140 =\r
141 = Changes the player's angle and position\r
142 =\r
143 = There is an angle hack because when going 70 fps, the roundoff becomes\r
144 = significant\r
145 =\r
146 =======================\r
147 */\r
148 \r
149 void ControlMovement (objtype *ob)\r
150 {\r
151         long    oldx,oldy;\r
152         int             angle,maxxmove;\r
153         int             angleunits;\r
154         long    speed;\r
155 \r
156         thrustspeed = 0;\r
157 \r
158         oldx = player->x;\r
159         oldy = player->y;\r
160 \r
161 //\r
162 // side to side move\r
163 //\r
164         if (buttonstate[bt_strafe])\r
165         {\r
166         //\r
167         // strafing\r
168         //\r
169         //\r
170                 if (controlx > 0)\r
171                 {\r
172                         angle = ob->angle - ANGLES/4;\r
173                         if (angle < 0)\r
174                                 angle += ANGLES;\r
175                         Thrust (angle,controlx*MOVESCALE);      // move to left\r
176                 }\r
177                 else if (controlx < 0)\r
178                 {\r
179                         angle = ob->angle + ANGLES/4;\r
180                         if (angle >= ANGLES)\r
181                                 angle -= ANGLES;\r
182                         Thrust (angle,-controlx*MOVESCALE);     // move to right\r
183                 }\r
184         }\r
185         else\r
186         {\r
187         //\r
188         // not strafing\r
189         //\r
190                 anglefrac += controlx;\r
191                 angleunits = anglefrac/ANGLESCALE;\r
192                 anglefrac -= angleunits*ANGLESCALE;\r
193                 ob->angle -= angleunits;\r
194 \r
195                 if (ob->angle >= ANGLES)\r
196                         ob->angle -= ANGLES;\r
197                 if (ob->angle < 0)\r
198                         ob->angle += ANGLES;\r
199 \r
200         }\r
201 \r
202 //\r
203 // forward/backwards move\r
204 //\r
205         if (controly < 0)\r
206         {\r
207                 Thrust (ob->angle,-controly*MOVESCALE); // move forwards\r
208         }\r
209         else if (controly > 0)\r
210         {\r
211                 angle = ob->angle + ANGLES/2;\r
212                 if (angle >= ANGLES)\r
213                         angle -= ANGLES;\r
214                 Thrust (angle,controly*BACKMOVESCALE);          // move backwards\r
215         }\r
216 \r
217         if (gamestate.victoryflag)              // watching the BJ actor\r
218                 return;\r
219 \r
220 //\r
221 // calculate total move\r
222 //\r
223         playerxmove = player->x - oldx;\r
224         playerymove = player->y - oldy;\r
225 }\r
226 \r
227 /*\r
228 =============================================================================\r
229 \r
230                                         STATUS WINDOW STUFF\r
231 \r
232 =============================================================================\r
233 */\r
234 \r
235 \r
236 /*\r
237 ==================\r
238 =\r
239 = StatusDrawPic\r
240 =\r
241 ==================\r
242 */\r
243 \r
244 void StatusDrawPic (unsigned x, unsigned y, unsigned picnum)\r
245 {\r
246         unsigned        temp;\r
247 \r
248         temp = bufferofs;\r
249         bufferofs = 0;\r
250 \r
251         bufferofs = PAGE1START+(200-STATUSLINES)*SCREENWIDTH;\r
252         LatchDrawPic (x,y,picnum);\r
253         bufferofs = PAGE2START+(200-STATUSLINES)*SCREENWIDTH;\r
254         LatchDrawPic (x,y,picnum);\r
255         bufferofs = PAGE3START+(200-STATUSLINES)*SCREENWIDTH;\r
256         LatchDrawPic (x,y,picnum);\r
257 \r
258         bufferofs = temp;\r
259 }\r
260 \r
261 \r
262 /*\r
263 ==================\r
264 =\r
265 = DrawFace\r
266 =\r
267 ==================\r
268 */\r
269 \r
270 void DrawFace (void)\r
271 {\r
272         if (gamestate.health)\r
273         {\r
274                 #ifdef SPEAR\r
275                 if (godmode)\r
276                         StatusDrawPic (17,4,GODMODEFACE1PIC+gamestate.faceframe);\r
277                 else\r
278                 #endif\r
279                 StatusDrawPic (17,4,FACE1APIC+3*((100-gamestate.health)/16)+gamestate.faceframe);\r
280         }\r
281         else\r
282         {\r
283 #ifndef SPEAR\r
284          if (LastAttacker->obclass == needleobj)\r
285            StatusDrawPic (17,4,MUTANTBJPIC);\r
286          else\r
287 #endif\r
288            StatusDrawPic (17,4,FACE8APIC);\r
289         }\r
290 }\r
291 \r
292 \r
293 /*\r
294 ===============\r
295 =\r
296 = UpdateFace\r
297 =\r
298 = Calls draw face if time to change\r
299 =\r
300 ===============\r
301 */\r
302 \r
303 #define FACETICS        70\r
304 \r
305 int     facecount;\r
306 \r
307 void    UpdateFace (void)\r
308 {\r
309 \r
310         if (SD_SoundPlaying() == GETGATLINGSND)\r
311           return;\r
312 \r
313         facecount += tics;\r
314         if (facecount > US_RndT())\r
315         {\r
316                 gamestate.faceframe = (US_RndT()>>6);\r
317                 if (gamestate.faceframe==3)\r
318                         gamestate.faceframe = 1;\r
319 \r
320                 facecount = 0;\r
321                 DrawFace ();\r
322         }\r
323 }\r
324 \r
325 \r
326 \r
327 /*\r
328 ===============\r
329 =\r
330 = LatchNumber\r
331 =\r
332 = right justifies and pads with blanks\r
333 =\r
334 ===============\r
335 */\r
336 \r
337 void    LatchNumber (int x, int y, int width, long number)\r
338 {\r
339         unsigned        length,c;\r
340         char    str[20];\r
341 \r
342         ltoa (number,str,10);\r
343 \r
344         length = strlen (str);\r
345 \r
346         while (length<width)\r
347         {\r
348                 StatusDrawPic (x,y,N_BLANKPIC);\r
349                 x++;\r
350                 width--;\r
351         }\r
352 \r
353         c= length <= width ? 0 : length-width;\r
354 \r
355         while (c<length)\r
356         {\r
357                 StatusDrawPic (x,y,str[c]-'0'+ N_0PIC);\r
358                 x++;\r
359                 c++;\r
360         }\r
361 }\r
362 \r
363 \r
364 /*\r
365 ===============\r
366 =\r
367 = DrawHealth\r
368 =\r
369 ===============\r
370 */\r
371 \r
372 void    DrawHealth (void)\r
373 {\r
374         LatchNumber (21,16,3,gamestate.health);\r
375 }\r
376 \r
377 \r
378 /*\r
379 ===============\r
380 =\r
381 = TakeDamage\r
382 =\r
383 ===============\r
384 */\r
385 \r
386 void    TakeDamage (int points,objtype *attacker)\r
387 {\r
388         LastAttacker = attacker;\r
389 \r
390         if (gamestate.victoryflag)\r
391                 return;\r
392         if (gamestate.difficulty==gd_baby)\r
393           points>>=2;\r
394 \r
395         if (!godmode)\r
396                 gamestate.health -= points;\r
397 \r
398         if (gamestate.health<=0)\r
399         {\r
400                 gamestate.health = 0;\r
401                 playstate = ex_died;\r
402                 killerobj = attacker;\r
403         }\r
404 \r
405         StartDamageFlash (points);\r
406 \r
407         gotgatgun=0;\r
408 \r
409         DrawHealth ();\r
410         DrawFace ();\r
411 \r
412         //\r
413         // MAKE BJ'S EYES BUG IF MAJOR DAMAGE!\r
414         //\r
415         #ifdef SPEAR\r
416         if (points > 30 && gamestate.health!=0 && !godmode)\r
417         {\r
418                 StatusDrawPic (17,4,BJOUCHPIC);\r
419                 facecount = 0;\r
420         }\r
421         #endif\r
422 \r
423 }\r
424 \r
425 \r
426 /*\r
427 ===============\r
428 =\r
429 = HealSelf\r
430 =\r
431 ===============\r
432 */\r
433 \r
434 void    HealSelf (int points)\r
435 {\r
436         gamestate.health += points;\r
437         if (gamestate.health>100)\r
438                 gamestate.health = 100;\r
439 \r
440         DrawHealth ();\r
441         gotgatgun = 0;  // JR\r
442         DrawFace ();\r
443 }\r
444 \r
445 \r
446 //===========================================================================\r
447 \r
448 \r
449 /*\r
450 ===============\r
451 =\r
452 = DrawLevel\r
453 =\r
454 ===============\r
455 */\r
456 \r
457 void    DrawLevel (void)\r
458 {\r
459 #ifdef SPEAR\r
460         if (gamestate.mapon == 20)\r
461                 LatchNumber (2,16,2,18);\r
462         else\r
463 #endif\r
464         LatchNumber (2,16,2,gamestate.mapon+1);\r
465 }\r
466 \r
467 //===========================================================================\r
468 \r
469 \r
470 /*\r
471 ===============\r
472 =\r
473 = DrawLives\r
474 =\r
475 ===============\r
476 */\r
477 \r
478 void    DrawLives (void)\r
479 {\r
480         LatchNumber (14,16,1,gamestate.lives);\r
481 }\r
482 \r
483 \r
484 /*\r
485 ===============\r
486 =\r
487 = GiveExtraMan\r
488 =\r
489 ===============\r
490 */\r
491 \r
492 void    GiveExtraMan (void)\r
493 {\r
494         if (gamestate.lives<9)\r
495                 gamestate.lives++;\r
496         DrawLives ();\r
497         SD_PlaySound (BONUS1UPSND);\r
498 }\r
499 \r
500 //===========================================================================\r
501 \r
502 /*\r
503 ===============\r
504 =\r
505 = DrawScore\r
506 =\r
507 ===============\r
508 */\r
509 \r
510 void    DrawScore (void)\r
511 {\r
512         LatchNumber (6,16,6,gamestate.score);\r
513 }\r
514 \r
515 /*\r
516 ===============\r
517 =\r
518 = GivePoints\r
519 =\r
520 ===============\r
521 */\r
522 \r
523 void    GivePoints (long points)\r
524 {\r
525         gamestate.score += points;\r
526         while (gamestate.score >= gamestate.nextextra)\r
527         {\r
528                 gamestate.nextextra += EXTRAPOINTS;\r
529                 GiveExtraMan ();\r
530         }\r
531         DrawScore ();\r
532 }\r
533 \r
534 //===========================================================================\r
535 \r
536 /*\r
537 ==================\r
538 =\r
539 = DrawWeapon\r
540 =\r
541 ==================\r
542 */\r
543 \r
544 void DrawWeapon (void)\r
545 {\r
546         StatusDrawPic (32,8,KNIFEPIC+gamestate.weapon);\r
547 }\r
548 \r
549 \r
550 /*\r
551 ==================\r
552 =\r
553 = DrawKeys\r
554 =\r
555 ==================\r
556 */\r
557 \r
558 void DrawKeys (void)\r
559 {\r
560         if (gamestate.keys & 1)\r
561                 StatusDrawPic (30,4,GOLDKEYPIC);\r
562         else\r
563                 StatusDrawPic (30,4,NOKEYPIC);\r
564 \r
565         if (gamestate.keys & 2)\r
566                 StatusDrawPic (30,20,SILVERKEYPIC);\r
567         else\r
568                 StatusDrawPic (30,20,NOKEYPIC);\r
569 }\r
570 \r
571 \r
572 \r
573 /*\r
574 ==================\r
575 =\r
576 = GiveWeapon\r
577 =\r
578 ==================\r
579 */\r
580 \r
581 void GiveWeapon (int weapon)\r
582 {\r
583         GiveAmmo (6);\r
584 \r
585         if (gamestate.bestweapon<weapon)\r
586                 gamestate.bestweapon = gamestate.weapon\r
587                 = gamestate.chosenweapon = weapon;\r
588 \r
589         DrawWeapon ();\r
590 }\r
591 \r
592 \r
593 //===========================================================================\r
594 \r
595 /*\r
596 ===============\r
597 =\r
598 = DrawAmmo\r
599 =\r
600 ===============\r
601 */\r
602 \r
603 void    DrawAmmo (void)\r
604 {\r
605         LatchNumber (27,16,2,gamestate.ammo);\r
606 }\r
607 \r
608 \r
609 /*\r
610 ===============\r
611 =\r
612 = GiveAmmo\r
613 =\r
614 ===============\r
615 */\r
616 \r
617 void    GiveAmmo (int ammo)\r
618 {\r
619         if (!gamestate.ammo)                            // knife was out\r
620         {\r
621                 if (!gamestate.attackframe)\r
622                 {\r
623                         gamestate.weapon = gamestate.chosenweapon;\r
624                         DrawWeapon ();\r
625                 }\r
626         }\r
627         gamestate.ammo += ammo;\r
628         if (gamestate.ammo > 99)\r
629                 gamestate.ammo = 99;\r
630         DrawAmmo ();\r
631 }\r
632 \r
633 //===========================================================================\r
634 \r
635 /*\r
636 ==================\r
637 =\r
638 = GiveKey\r
639 =\r
640 ==================\r
641 */\r
642 \r
643 void GiveKey (int key)\r
644 {\r
645         gamestate.keys |= (1<<key);\r
646         DrawKeys ();\r
647 }\r
648 \r
649 \r
650 \r
651 /*\r
652 =============================================================================\r
653 \r
654                                                         MOVEMENT\r
655 \r
656 =============================================================================\r
657 */\r
658 \r
659 \r
660 /*\r
661 ===================\r
662 =\r
663 = GetBonus\r
664 =\r
665 ===================\r
666 */\r
667 void GetBonus (statobj_t *check)\r
668 {\r
669         switch (check->itemnumber)\r
670         {\r
671         case    bo_firstaid:\r
672                 if (gamestate.health == 100)\r
673                         return;\r
674 \r
675                 SD_PlaySound (HEALTH2SND);\r
676                 HealSelf (25);\r
677                 break;\r
678 \r
679         case    bo_key1:\r
680         case    bo_key2:\r
681         case    bo_key3:\r
682         case    bo_key4:\r
683                 GiveKey (check->itemnumber - bo_key1);\r
684                 SD_PlaySound (GETKEYSND);\r
685                 break;\r
686 \r
687         case    bo_cross:\r
688                 SD_PlaySound (BONUS1SND);\r
689                 GivePoints (100);\r
690                 gamestate.treasurecount++;\r
691                 break;\r
692         case    bo_chalice:\r
693                 SD_PlaySound (BONUS2SND);\r
694                 GivePoints (500);\r
695                 gamestate.treasurecount++;\r
696                 break;\r
697         case    bo_bible:\r
698                 SD_PlaySound (BONUS3SND);\r
699                 GivePoints (1000);\r
700                 gamestate.treasurecount++;\r
701                 break;\r
702         case    bo_crown:\r
703                 SD_PlaySound (BONUS4SND);\r
704                 GivePoints (5000);\r
705                 gamestate.treasurecount++;\r
706                 break;\r
707 \r
708         case    bo_clip:\r
709                 if (gamestate.ammo == 99)\r
710                         return;\r
711 \r
712                 SD_PlaySound (GETAMMOSND);\r
713                 GiveAmmo (8);\r
714                 break;\r
715         case    bo_clip2:\r
716                 if (gamestate.ammo == 99)\r
717                         return;\r
718 \r
719                 SD_PlaySound (GETAMMOSND);\r
720                 GiveAmmo (4);\r
721                 break;\r
722 \r
723 #ifdef SPEAR\r
724         case    bo_25clip:\r
725                 if (gamestate.ammo == 99)\r
726                   return;\r
727 \r
728                 SD_PlaySound (GETAMMOBOXSND);\r
729                 GiveAmmo (25);\r
730                 break;\r
731 #endif\r
732 \r
733         case    bo_machinegun:\r
734                 SD_PlaySound (GETMACHINESND);\r
735                 GiveWeapon (wp_machinegun);\r
736                 break;\r
737         case    bo_chaingun:\r
738                 SD_PlaySound (GETGATLINGSND);\r
739                 GiveWeapon (wp_chaingun);\r
740 \r
741                 StatusDrawPic (17,4,GOTGATLINGPIC);\r
742                 facecount = 0;\r
743                 gotgatgun = 1;\r
744                 break;\r
745 \r
746         case    bo_fullheal:\r
747                 SD_PlaySound (BONUS1UPSND);\r
748                 HealSelf (99);\r
749                 GiveAmmo (25);\r
750                 GiveExtraMan ();\r
751                 gamestate.treasurecount++;\r
752                 break;\r
753 \r
754         case    bo_food:\r
755                 if (gamestate.health == 100)\r
756                         return;\r
757 \r
758                 SD_PlaySound (HEALTH1SND);\r
759                 HealSelf (10);\r
760                 break;\r
761 \r
762         case    bo_alpo:\r
763                 if (gamestate.health == 100)\r
764                         return;\r
765 \r
766                 SD_PlaySound (HEALTH1SND);\r
767                 HealSelf (4);\r
768                 break;\r
769 \r
770         case    bo_gibs:\r
771                 if (gamestate.health >10)\r
772                         return;\r
773 \r
774                 SD_PlaySound (SLURPIESND);\r
775                 HealSelf (1);\r
776                 break;\r
777 \r
778         case    bo_spear:\r
779                 spearflag = true;\r
780                 spearx = player->x;\r
781                 speary = player->y;\r
782                 spearangle = player->angle;\r
783                 playstate = ex_completed;\r
784         }\r
785 \r
786         StartBonusFlash ();\r
787         check->shapenum = -1;                   // remove from list\r
788 }\r
789 \r
790 \r
791 /*\r
792 ===================\r
793 =\r
794 = TryMove\r
795 =\r
796 = returns true if move ok\r
797 = debug: use pointers to optimize\r
798 ===================\r
799 */\r
800 \r
801 boolean TryMove (objtype *ob)\r
802 {\r
803         int                     xl,yl,xh,yh,x,y;\r
804         objtype         *check;\r
805         long            deltax,deltay;\r
806 \r
807         xl = (ob->x-PLAYERSIZE) >>TILESHIFT;\r
808         yl = (ob->y-PLAYERSIZE) >>TILESHIFT;\r
809 \r
810         xh = (ob->x+PLAYERSIZE) >>TILESHIFT;\r
811         yh = (ob->y+PLAYERSIZE) >>TILESHIFT;\r
812 \r
813 //\r
814 // check for solid walls\r
815 //\r
816         for (y=yl;y<=yh;y++)\r
817                 for (x=xl;x<=xh;x++)\r
818                 {\r
819                         check = actorat[x][y];\r
820                         if (check && check<objlist)\r
821                                 return false;\r
822                 }\r
823 \r
824 //\r
825 // check for actors\r
826 //\r
827         if (yl>0)\r
828                 yl--;\r
829         if (yh<MAPSIZE-1)\r
830                 yh++;\r
831         if (xl>0)\r
832                 xl--;\r
833         if (xh<MAPSIZE-1)\r
834                 xh++;\r
835 \r
836         for (y=yl;y<=yh;y++)\r
837                 for (x=xl;x<=xh;x++)\r
838                 {\r
839                         check = actorat[x][y];\r
840                         if (check > objlist\r
841                         && (check->flags & FL_SHOOTABLE) )\r
842                         {\r
843                                 deltax = ob->x - check->x;\r
844                                 if (deltax < -MINACTORDIST || deltax > MINACTORDIST)\r
845                                         continue;\r
846                                 deltay = ob->y - check->y;\r
847                                 if (deltay < -MINACTORDIST || deltay > MINACTORDIST)\r
848                                         continue;\r
849 \r
850                                 return false;\r
851                         }\r
852                 }\r
853 \r
854         return true;\r
855 }\r
856 \r
857 \r
858 /*\r
859 ===================\r
860 =\r
861 = ClipMove\r
862 =\r
863 ===================\r
864 */\r
865 \r
866 void ClipMove (objtype *ob, long xmove, long ymove)\r
867 {\r
868         long    basex,basey;\r
869 \r
870         basex = ob->x;\r
871         basey = ob->y;\r
872 \r
873         ob->x = basex+xmove;\r
874         ob->y = basey+ymove;\r
875         if (TryMove (ob))\r
876                 return;\r
877 \r
878         if (noclip && ob->x > 2*TILEGLOBAL && ob->y > 2*TILEGLOBAL &&\r
879         ob->x < (((long)(mapwidth-1))<<TILESHIFT)\r
880         && ob->y < (((long)(mapheight-1))<<TILESHIFT) )\r
881                 return;         // walk through walls\r
882 \r
883         if (!SD_SoundPlaying())\r
884                 SD_PlaySound (HITWALLSND);\r
885 \r
886         ob->x = basex+xmove;\r
887         ob->y = basey;\r
888         if (TryMove (ob))\r
889                 return;\r
890 \r
891         ob->x = basex;\r
892         ob->y = basey+ymove;\r
893         if (TryMove (ob))\r
894                 return;\r
895 \r
896         ob->x = basex;\r
897         ob->y = basey;\r
898 }\r
899 \r
900 //==========================================================================\r
901 \r
902 /*\r
903 ===================\r
904 =\r
905 = VictoryTile\r
906 =\r
907 ===================\r
908 */\r
909 \r
910 void VictoryTile (void)\r
911 {\r
912 #ifndef SPEAR\r
913         SpawnBJVictory ();\r
914 #endif\r
915 \r
916         gamestate.victoryflag = true;\r
917 }\r
918 \r
919 \r
920 /*\r
921 ===================\r
922 =\r
923 = Thrust\r
924 =\r
925 ===================\r
926 */\r
927 \r
928 void Thrust (int angle, long speed)\r
929 {\r
930         long xmove,ymove;\r
931         long    slowmax;\r
932         unsigned        offset;\r
933 \r
934 \r
935         //\r
936         // ZERO FUNNY COUNTER IF MOVED!\r
937         //\r
938         #ifdef SPEAR\r
939         if (speed)\r
940                 funnyticount = 0;\r
941         #endif\r
942 \r
943         thrustspeed += speed;\r
944 //\r
945 // moving bounds speed\r
946 //\r
947         if (speed >= MINDIST*2)\r
948                 speed = MINDIST*2-1;\r
949 \r
950         xmove = FixedByFrac(speed,costable[angle]);\r
951         ymove = -FixedByFrac(speed,sintable[angle]);\r
952 \r
953         ClipMove(player,xmove,ymove);\r
954 \r
955         player->tilex = player->x >> TILESHIFT;         // scale to tile values\r
956         player->tiley = player->y >> TILESHIFT;\r
957 \r
958         offset = farmapylookup[player->tiley]+player->tilex;\r
959         player->areanumber = *(mapsegs[0] + offset) -AREATILE;\r
960 \r
961         if (*(mapsegs[1] + offset) == EXITTILE)\r
962                 VictoryTile ();\r
963 }\r
964 \r
965 \r
966 /*\r
967 =============================================================================\r
968 \r
969                                                                 ACTIONS\r
970 \r
971 =============================================================================\r
972 */\r
973 \r
974 \r
975 /*\r
976 ===============\r
977 =\r
978 = Cmd_Fire\r
979 =\r
980 ===============\r
981 */\r
982 \r
983 void Cmd_Fire (void)\r
984 {\r
985         buttonheld[bt_attack] = true;\r
986 \r
987         gamestate.weaponframe = 0;\r
988 \r
989         player->state = &s_attack;\r
990 \r
991         gamestate.attackframe = 0;\r
992         gamestate.attackcount =\r
993                 attackinfo[gamestate.weapon][gamestate.attackframe].tics;\r
994         gamestate.weaponframe =\r
995                 attackinfo[gamestate.weapon][gamestate.attackframe].frame;\r
996 }\r
997 \r
998 //===========================================================================\r
999 \r
1000 /*\r
1001 ===============\r
1002 =\r
1003 = Cmd_Use\r
1004 =\r
1005 ===============\r
1006 */\r
1007 \r
1008 void Cmd_Use (void)\r
1009 {\r
1010         objtype         *check;\r
1011         int                     checkx,checky,doornum,dir;\r
1012         boolean         elevatorok;\r
1013 \r
1014 \r
1015 //\r
1016 // find which cardinal direction the player is facing\r
1017 //\r
1018         if (player->angle < ANGLES/8 || player->angle > 7*ANGLES/8)\r
1019         {\r
1020                 checkx = player->tilex + 1;\r
1021                 checky = player->tiley;\r
1022                 dir = di_east;\r
1023                 elevatorok = true;\r
1024         }\r
1025         else if (player->angle < 3*ANGLES/8)\r
1026         {\r
1027                 checkx = player->tilex;\r
1028                 checky = player->tiley-1;\r
1029                 dir = di_north;\r
1030                 elevatorok = false;\r
1031         }\r
1032         else if (player->angle < 5*ANGLES/8)\r
1033         {\r
1034                 checkx = player->tilex - 1;\r
1035                 checky = player->tiley;\r
1036                 dir = di_west;\r
1037                 elevatorok = true;\r
1038         }\r
1039         else\r
1040         {\r
1041                 checkx = player->tilex;\r
1042                 checky = player->tiley + 1;\r
1043                 dir = di_south;\r
1044                 elevatorok = false;\r
1045         }\r
1046 \r
1047         doornum = tilemap[checkx][checky];\r
1048         if (*(mapsegs[1]+farmapylookup[checky]+checkx) == PUSHABLETILE)\r
1049         {\r
1050         //\r
1051         // pushable wall\r
1052         //\r
1053 \r
1054                 PushWall (checkx,checky,dir);\r
1055                 return;\r
1056         }\r
1057         if (!buttonheld[bt_use] && doornum == ELEVATORTILE && elevatorok)\r
1058         {\r
1059         //\r
1060         // use elevator\r
1061         //\r
1062                 buttonheld[bt_use] = true;\r
1063 \r
1064                 tilemap[checkx][checky]++;              // flip switch\r
1065                 if (*(mapsegs[0]+farmapylookup[player->tiley]+player->tilex) == ALTELEVATORTILE)\r
1066                         playstate = ex_secretlevel;\r
1067                 else\r
1068                         playstate = ex_completed;\r
1069                 SD_PlaySound (LEVELDONESND);\r
1070                 SD_WaitSoundDone();\r
1071         }\r
1072         else if (!buttonheld[bt_use] && doornum & 0x80)\r
1073         {\r
1074                 buttonheld[bt_use] = true;\r
1075                 OperateDoor (doornum & ~0x80);\r
1076         }\r
1077         else\r
1078                 SD_PlaySound (DONOTHINGSND);\r
1079 \r
1080 }\r
1081 \r
1082 /*\r
1083 =============================================================================\r
1084 \r
1085                                                    PLAYER CONTROL\r
1086 \r
1087 =============================================================================\r
1088 */\r
1089 \r
1090 \r
1091 \r
1092 /*\r
1093 ===============\r
1094 =\r
1095 = SpawnPlayer\r
1096 =\r
1097 ===============\r
1098 */\r
1099 \r
1100 void SpawnPlayer (int tilex, int tiley, int dir)\r
1101 {\r
1102         player->obclass = playerobj;\r
1103         player->active = true;\r
1104         player->tilex = tilex;\r
1105         player->tiley = tiley;\r
1106         player->areanumber =\r
1107                 *(mapsegs[0] + farmapylookup[player->tiley]+player->tilex);\r
1108         player->x = ((long)tilex<<TILESHIFT)+TILEGLOBAL/2;\r
1109         player->y = ((long)tiley<<TILESHIFT)+TILEGLOBAL/2;\r
1110         player->state = &s_player;\r
1111         player->angle = (1-dir)*90;\r
1112         if (player->angle<0)\r
1113                 player->angle += ANGLES;\r
1114         player->flags = FL_NEVERMARK;\r
1115         Thrust (0,0);                           // set some variables\r
1116 \r
1117         InitAreas ();\r
1118 }\r
1119 \r
1120 \r
1121 //===========================================================================\r
1122 \r
1123 /*\r
1124 ===============\r
1125 =\r
1126 = T_KnifeAttack\r
1127 =\r
1128 = Update player hands, and try to do damage when the proper frame is reached\r
1129 =\r
1130 ===============\r
1131 */\r
1132 \r
1133 void    KnifeAttack (objtype *ob)\r
1134 {\r
1135         objtype *check,*closest;\r
1136         long    dist;\r
1137 \r
1138         SD_PlaySound (ATKKNIFESND);\r
1139 // actually fire\r
1140         dist = 0x7fffffff;\r
1141         closest = NULL;\r
1142         for (check=ob->next ; check ; check=check->next)\r
1143                 if ( (check->flags & FL_SHOOTABLE)\r
1144                 && (check->flags & FL_VISABLE)\r
1145                 && abs (check->viewx-centerx) < shootdelta\r
1146                 )\r
1147                 {\r
1148                         if (check->transx < dist)\r
1149                         {\r
1150                                 dist = check->transx;\r
1151                                 closest = check;\r
1152                         }\r
1153                 }\r
1154 \r
1155         if (!closest || dist> 0x18000l)\r
1156         {\r
1157         // missed\r
1158 \r
1159                 return;\r
1160         }\r
1161 \r
1162 // hit something\r
1163         DamageActor (closest,US_RndT() >> 4);\r
1164 }\r
1165 \r
1166 \r
1167 \r
1168 void    GunAttack (objtype *ob)\r
1169 {\r
1170         objtype *check,*closest,*oldclosest;\r
1171         int             damage;\r
1172         int             dx,dy,dist;\r
1173         long    viewdist;\r
1174 \r
1175         switch (gamestate.weapon)\r
1176         {\r
1177         case wp_pistol:\r
1178                 SD_PlaySound (ATKPISTOLSND);\r
1179                 break;\r
1180         case wp_machinegun:\r
1181                 SD_PlaySound (ATKMACHINEGUNSND);\r
1182                 break;\r
1183         case wp_chaingun:\r
1184                 SD_PlaySound (ATKGATLINGSND);\r
1185                 break;\r
1186         }\r
1187 \r
1188         madenoise = true;\r
1189 \r
1190 //\r
1191 // find potential targets\r
1192 //\r
1193         viewdist = 0x7fffffffl;\r
1194         closest = NULL;\r
1195 \r
1196         while (1)\r
1197         {\r
1198                 oldclosest = closest;\r
1199 \r
1200                 for (check=ob->next ; check ; check=check->next)\r
1201                         if ( (check->flags & FL_SHOOTABLE)\r
1202                         && (check->flags & FL_VISABLE)\r
1203                         && abs (check->viewx-centerx) < shootdelta\r
1204                         )\r
1205                         {\r
1206                                 if (check->transx < viewdist)\r
1207                                 {\r
1208                                         viewdist = check->transx;\r
1209                                         closest = check;\r
1210                                 }\r
1211                         }\r
1212 \r
1213                 if (closest == oldclosest)\r
1214                         return;                                         // no more targets, all missed\r
1215 \r
1216         //\r
1217         // trace a line from player to enemey\r
1218         //\r
1219                 if (CheckLine(closest))\r
1220                         break;\r
1221 \r
1222         }\r
1223 \r
1224 //\r
1225 // hit something\r
1226 //\r
1227         dx = abs(closest->tilex - player->tilex);\r
1228         dy = abs(closest->tiley - player->tiley);\r
1229         dist = dx>dy ? dx:dy;\r
1230 \r
1231         if (dist<2)\r
1232                 damage = US_RndT() / 4;\r
1233         else if (dist<4)\r
1234                 damage = US_RndT() / 6;\r
1235         else\r
1236         {\r
1237                 if ( (US_RndT() / 12) < dist)           // missed\r
1238                         return;\r
1239                 damage = US_RndT() / 6;\r
1240         }\r
1241 \r
1242         DamageActor (closest,damage);\r
1243 }\r
1244 \r
1245 //===========================================================================\r
1246 \r
1247 /*\r
1248 ===============\r
1249 =\r
1250 = VictorySpin\r
1251 =\r
1252 ===============\r
1253 */\r
1254 \r
1255 void VictorySpin (void)\r
1256 {\r
1257         long    desty;\r
1258 \r
1259         if (player->angle > 270)\r
1260         {\r
1261                 player->angle -= tics * 3;\r
1262                 if (player->angle < 270)\r
1263                         player->angle = 270;\r
1264         }\r
1265         else if (player->angle < 270)\r
1266         {\r
1267                 player->angle += tics * 3;\r
1268                 if (player->angle > 270)\r
1269                         player->angle = 270;\r
1270         }\r
1271 \r
1272         desty = (((long)player->tiley-5)<<TILESHIFT)-0x3000;\r
1273 \r
1274         if (player->y > desty)\r
1275         {\r
1276                 player->y -= tics*4096;\r
1277                 if (player->y < desty)\r
1278                         player->y = desty;\r
1279         }\r
1280 }\r
1281 \r
1282 \r
1283 //===========================================================================\r
1284 \r
1285 /*\r
1286 ===============\r
1287 =\r
1288 = T_Attack\r
1289 =\r
1290 ===============\r
1291 */\r
1292 \r
1293 void    T_Attack (objtype *ob)\r
1294 {\r
1295         struct  atkinf  *cur;\r
1296 \r
1297         UpdateFace ();\r
1298 \r
1299         if (gamestate.victoryflag)              // watching the BJ actor\r
1300         {\r
1301                 VictorySpin ();\r
1302                 return;\r
1303         }\r
1304 \r
1305         if ( buttonstate[bt_use] && !buttonheld[bt_use] )\r
1306                 buttonstate[bt_use] = false;\r
1307 \r
1308         if ( buttonstate[bt_attack] && !buttonheld[bt_attack])\r
1309                 buttonstate[bt_attack] = false;\r
1310 \r
1311         ControlMovement (ob);\r
1312         if (gamestate.victoryflag)              // watching the BJ actor\r
1313                 return;\r
1314 \r
1315         plux = player->x >> UNSIGNEDSHIFT;                      // scale to fit in unsigned\r
1316         pluy = player->y >> UNSIGNEDSHIFT;\r
1317         player->tilex = player->x >> TILESHIFT;         // scale to tile values\r
1318         player->tiley = player->y >> TILESHIFT;\r
1319 \r
1320 //\r
1321 // change frame and fire\r
1322 //\r
1323         gamestate.attackcount -= tics;\r
1324         while (gamestate.attackcount <= 0)\r
1325         {\r
1326                 cur = &attackinfo[gamestate.weapon][gamestate.attackframe];\r
1327                 switch (cur->attack)\r
1328                 {\r
1329                 case -1:\r
1330                         ob->state = &s_player;\r
1331                         if (!gamestate.ammo)\r
1332                         {\r
1333                                 gamestate.weapon = wp_knife;\r
1334                                 DrawWeapon ();\r
1335                         }\r
1336                         else\r
1337                         {\r
1338                                 if (gamestate.weapon != gamestate.chosenweapon)\r
1339                                 {\r
1340                                         gamestate.weapon = gamestate.chosenweapon;\r
1341                                         DrawWeapon ();\r
1342                                 }\r
1343                         };\r
1344                         gamestate.attackframe = gamestate.weaponframe = 0;\r
1345                         return;\r
1346 \r
1347                 case 4:\r
1348                         if (!gamestate.ammo)\r
1349                                 break;\r
1350                         if (buttonstate[bt_attack])\r
1351                                 gamestate.attackframe -= 2;\r
1352                 case 1:\r
1353                         if (!gamestate.ammo)\r
1354                         {       // can only happen with chain gun\r
1355                                 gamestate.attackframe++;\r
1356                                 break;\r
1357                         }\r
1358                         GunAttack (ob);\r
1359                         gamestate.ammo--;\r
1360                         DrawAmmo ();\r
1361                         break;\r
1362 \r
1363                 case 2:\r
1364                         KnifeAttack (ob);\r
1365                         break;\r
1366 \r
1367                 case 3:\r
1368                         if (gamestate.ammo && buttonstate[bt_attack])\r
1369                                 gamestate.attackframe -= 2;\r
1370                         break;\r
1371                 }\r
1372 \r
1373                 gamestate.attackcount += cur->tics;\r
1374                 gamestate.attackframe++;\r
1375                 gamestate.weaponframe =\r
1376                         attackinfo[gamestate.weapon][gamestate.attackframe].frame;\r
1377         }\r
1378 \r
1379 }\r
1380 \r
1381 \r
1382 \r
1383 //===========================================================================\r
1384 \r
1385 /*\r
1386 ===============\r
1387 =\r
1388 = T_Player\r
1389 =\r
1390 ===============\r
1391 */\r
1392 \r
1393 void    T_Player (objtype *ob)\r
1394 {\r
1395         if (gamestate.victoryflag)              // watching the BJ actor\r
1396         {\r
1397                 VictorySpin ();\r
1398                 return;\r
1399         }\r
1400 \r
1401         UpdateFace ();\r
1402         CheckWeaponChange ();\r
1403 \r
1404         if ( buttonstate[bt_use] )\r
1405                 Cmd_Use ();\r
1406 \r
1407         if ( buttonstate[bt_attack] && !buttonheld[bt_attack])\r
1408                 Cmd_Fire ();\r
1409 \r
1410         ControlMovement (ob);\r
1411         if (gamestate.victoryflag)              // watching the BJ actor\r
1412                 return;\r
1413 \r
1414 \r
1415         plux = player->x >> UNSIGNEDSHIFT;                      // scale to fit in unsigned\r
1416         pluy = player->y >> UNSIGNEDSHIFT;\r
1417         player->tilex = player->x >> TILESHIFT;         // scale to tile values\r
1418         player->tiley = player->y >> TILESHIFT;\r
1419 }\r
1420 \r
1421 \r