]> icculus.org git repositories - theoddone33/hhexen.git/blob - base/a_action.c
Fix stupid wadfile problem
[theoddone33/hhexen.git] / base / a_action.c
1
2 //**************************************************************************
3 //**
4 //** a_action.c : Heretic 2 : Raven Software, Corp.
5 //**
6 //** $RCSfile$
7 //** $Revision$
8 //** $Date$
9 //** $Author$
10 //**
11 //**************************************************************************
12
13 // HEADER FILES ------------------------------------------------------------
14
15 #include "h2def.h"
16 #include "p_local.h"
17 #include "soundst.h"
18
19 // MACROS ------------------------------------------------------------------
20
21 // TYPES -------------------------------------------------------------------
22
23 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
24
25 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
26
27 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
28
29 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
30 extern fixed_t FloatBobOffsets[64];
31
32 // PUBLIC DATA DEFINITIONS -------------------------------------------------
33 int orbitTableX[256]=
34 {
35 983025, 982725, 981825, 980340, 978255, 975600, 972330, 968490,
36 964065, 959070, 953475, 947325, 940590, 933300, 925440, 917025,
37 908055, 898545, 888495, 877905, 866775, 855135, 842985, 830310,
38 817155, 803490, 789360, 774735, 759660, 744120, 728130, 711690,
39 694845, 677565, 659880, 641805, 623340, 604500, 585285, 565725,
40 545820, 525600, 505050, 484200, 463065, 441645, 419955, 398010,
41 375840, 353430, 330810, 307995, 285000, 261825, 238485, 215010,
42 191400, 167685, 143865, 119955, 95970, 71940, 47850, 23745,
43 -375, -24495, -48600, -72690, -96720, -120705, -144600, -168420,
44 -192150, -215745, -239220, -262545, -285720, -308715, -331530, -354135,
45 -376530, -398700, -420630, -442320, -463725, -484860, -505695, -526230,
46 -546450, -566340, -585885, -605085, -623925, -642375, -660435, -678105,
47 -695370, -712215, -728625, -744600, -760125, -775200, -789795, -803925,
48 -817575, -830715, -843375, -855510, -867135, -878235, -888810, -898845,
49 -908340, -917295, -925695, -933540, -940815, -947520, -953670, -959235,
50 -964215, -968625, -972450, -975690, -978330, -980400, -981870, -982740,
51 -983025, -982725, -981825, -980340, -978255, -975600, -972330, -968490,
52 -964065, -959070, -953475, -947325, -940590, -933300, -925440, -917025,
53 -908055, -898545, -888495, -877905, -866775, -855135, -842985, -830310,
54 -817155, -803490, -789360, -774735, -759660, -744120, -728130, -711690,
55 -694845, -677565, -659880, -641805, -623340, -604485, -585285, -565725,
56 -545820, -525600, -505050, -484200, -463065, -441645, -419955, -398010,
57 -375840, -353430, -330810, -307995, -285000, -261825, -238485, -215010,
58 -191400, -167685, -143865, -119955, -95970, -71940, -47850, -23745,
59 375, 24495, 48600, 72690, 96720, 120705, 144600, 168420,
60 192150, 215745, 239220, 262545, 285720, 308715, 331530, 354135,
61 376530, 398700, 420630, 442320, 463725, 484860, 505695, 526230,
62 546450, 566340, 585885, 605085, 623925, 642375, 660435, 678105,
63 695370, 712215, 728625, 744600, 760125, 775200, 789795, 803925,
64 817575, 830715, 843375, 855510, 867135, 878235, 888810, 898845,
65 908340, 917295, 925695, 933540, 940815, 947520, 953670, 959235,
66 964215, 968625, 972450, 975690, 978330, 980400, 981870, 982740
67 };
68
69 int orbitTableY[256]=
70 {
71 375, 24495, 48600, 72690, 96720, 120705, 144600, 168420,
72 192150, 215745, 239220, 262545, 285720, 308715, 331530, 354135,
73 376530, 398700, 420630, 442320, 463725, 484860, 505695, 526230,
74 546450, 566340, 585885, 605085, 623925, 642375, 660435, 678105,
75 695370, 712215, 728625, 744600, 760125, 775200, 789795, 803925,
76 817575, 830715, 843375, 855510, 867135, 878235, 888810, 898845,
77 908340, 917295, 925695, 933540, 940815, 947520, 953670, 959235,
78 964215, 968625, 972450, 975690, 978330, 980400, 981870, 982740,
79 983025, 982725, 981825, 980340, 978255, 975600, 972330, 968490,
80 964065, 959070, 953475, 947325, 940590, 933300, 925440, 917025,
81 908055, 898545, 888495, 877905, 866775, 855135, 842985, 830310,
82 817155, 803490, 789360, 774735, 759660, 744120, 728130, 711690,
83 694845, 677565, 659880, 641805, 623340, 604500, 585285, 565725,
84 545820, 525600, 505050, 484200, 463065, 441645, 419955, 398010,
85 375840, 353430, 330810, 307995, 285000, 261825, 238485, 215010,
86 191400, 167685, 143865, 119955, 95970, 71940, 47850, 23745,
87 -375, -24495, -48600, -72690, -96720, -120705, -144600, -168420,
88 -192150, -215745, -239220, -262545, -285720, -308715, -331530, -354135,
89 -376530, -398700, -420630, -442320, -463725, -484860, -505695, -526230,
90 -546450, -566340, -585885, -605085, -623925, -642375, -660435, -678105,
91 -695370, -712215, -728625, -744600, -760125, -775200, -789795, -803925,
92 -817575, -830715, -843375, -855510, -867135, -878235, -888810, -898845,
93 -908340, -917295, -925695, -933540, -940815, -947520, -953670, -959235,
94 -964215, -968625, -972450, -975690, -978330, -980400, -981870, -982740,
95 -983025, -982725, -981825, -980340, -978255, -975600, -972330, -968490,
96 -964065, -959070, -953475, -947325, -940590, -933300, -925440, -917025,
97 -908055, -898545, -888495, -877905, -866775, -855135, -842985, -830310,
98 -817155, -803490, -789360, -774735, -759660, -744120, -728130, -711690,
99 -694845, -677565, -659880, -641805, -623340, -604485, -585285, -565725,
100 -545820, -525600, -505050, -484200, -463065, -441645, -419955, -398010,
101 -375840, -353430, -330810, -307995, -285000, -261825, -238485, -215010,
102 -191400, -167685, -143865, -119955, -95970, -71940, -47850, -23745
103 };
104
105 // PRIVATE DATA DEFINITIONS ------------------------------------------------
106
107 // CODE --------------------------------------------------------------------
108
109 //--------------------------------------------------------------------------
110 //
111 // Environmental Action routines
112 //
113 //--------------------------------------------------------------------------
114
115 //==========================================================================
116 //
117 // A_DripBlood
118 //
119 //==========================================================================
120
121 /*
122 void A_DripBlood(mobj_t *actor)
123 {
124         mobj_t *mo;
125
126         mo = P_SpawnMobj(actor->x+((P_Random()-P_Random())<<11),
127                 actor->y+((P_Random()-P_Random())<<11), actor->z, MT_BLOOD);
128         mo->momx = (P_Random()-P_Random())<<10;
129         mo->momy = (P_Random()-P_Random())<<10;
130         mo->flags2 |= MF2_LOGRAV;
131 }
132 */
133
134 //============================================================================
135 //
136 // A_PotteryExplode
137 //
138 //============================================================================
139
140 void A_PotteryExplode(mobj_t *actor)
141 {
142         mobj_t *mo=NULL;
143         int i;
144
145         for(i = (P_Random()&3)+3; i; i--)
146         {
147                 mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_POTTERYBIT1);
148                 P_SetMobjState(mo, mo->info->spawnstate+(P_Random()%5));
149                 if(mo)
150                 {
151                         mo->momz = ((P_Random()&7)+5)*(3*FRACUNIT/4);
152                         mo->momx = (P_Random()-P_Random())<<(FRACBITS-6);
153                         mo->momy = (P_Random()-P_Random())<<(FRACBITS-6);
154                 }
155         }
156         S_StartSound(mo, SFX_POTTERY_EXPLODE);
157         if(actor->args[0])
158         { // Spawn an item
159                 if(!nomonsters 
160                 || !(mobjinfo[TranslateThingType[actor->args[0]]].flags&MF_COUNTKILL))
161                 { // Only spawn monsters if not -nomonsters
162                         P_SpawnMobj(actor->x, actor->y, actor->z,
163                                 TranslateThingType[actor->args[0]]);
164                 }
165         }
166         P_RemoveMobj(actor);
167 }
168
169 //============================================================================
170 //
171 // A_PotteryChooseBit
172 //
173 //============================================================================
174
175 void A_PotteryChooseBit(mobj_t *actor)
176 {
177         P_SetMobjState(actor, actor->info->deathstate+(P_Random()%5)+1);
178         actor->tics = 256+(P_Random()<<1);
179 }
180
181 //============================================================================
182 //
183 // A_PotteryCheck
184 //
185 //============================================================================
186
187 void A_PotteryCheck(mobj_t *actor)
188 {
189         int i;
190         mobj_t *pmo;
191
192         if(!netgame)
193         {
194                 pmo = players[consoleplayer].mo;
195                 if(P_CheckSight(actor, pmo) && (abs(R_PointToAngle2(pmo->x,
196                         pmo->y, actor->x, actor->y)-pmo->angle) <= ANGLE_45))
197                 { // Previous state (pottery bit waiting state)
198                         P_SetMobjState(actor, actor->state-&states[0]-1);
199                 }
200                 else
201                 {
202                         return;
203                 }
204         }
205         else
206         {
207                 for(i = 0; i < MAXPLAYERS; i++)
208                 {
209                         if(!playeringame[i])
210                         {
211                                 continue;
212                         }
213                         pmo = players[i].mo;
214                         if(P_CheckSight(actor, pmo) && (abs(R_PointToAngle2(pmo->x,
215                                 pmo->y, actor->x, actor->y)-pmo->angle) <= ANGLE_45))
216                         { // Previous state (pottery bit waiting state)
217                                 P_SetMobjState(actor, actor->state-&states[0]-1);
218                                 return;
219                         }
220                 }
221         }               
222 }
223
224 //============================================================================
225 //
226 // A_CorpseBloodDrip
227 //
228 //============================================================================
229
230 void A_CorpseBloodDrip(mobj_t *actor)
231 {
232         if(P_Random() > 128)
233         {
234                 return;
235         }
236         P_SpawnMobj(actor->x, actor->y, actor->z+actor->height/2, 
237                 MT_CORPSEBLOODDRIP);
238 }
239
240 //============================================================================
241 //
242 // A_CorpseExplode
243 //
244 //============================================================================
245
246 void A_CorpseExplode(mobj_t *actor)
247 {
248         mobj_t *mo;
249         int i;
250
251         for(i = (P_Random()&3)+3; i; i--)
252         {
253                 mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_CORPSEBIT);
254                 P_SetMobjState(mo, mo->info->spawnstate+(P_Random()%3));
255                 if(mo)
256                 {
257                         mo->momz = ((P_Random()&7)+5)*(3*FRACUNIT/4);
258                         mo->momx = (P_Random()-P_Random())<<(FRACBITS-6);
259                         mo->momy = (P_Random()-P_Random())<<(FRACBITS-6);
260                 }
261         }
262         // Spawn a skull
263         mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_CORPSEBIT);
264         P_SetMobjState(mo, S_CORPSEBIT_4);
265         if(mo)
266         {
267                 mo->momz = ((P_Random()&7)+5)*(3*FRACUNIT/4);
268                 mo->momx = (P_Random()-P_Random())<<(FRACBITS-6);
269                 mo->momy = (P_Random()-P_Random())<<(FRACBITS-6);
270                 S_StartSound(mo, SFX_FIRED_DEATH);
271         }
272         P_RemoveMobj(actor);
273 }
274
275 //============================================================================
276 //
277 // A_LeafSpawn
278 //
279 //============================================================================
280
281 void A_LeafSpawn(mobj_t *actor)
282 {
283         mobj_t *mo;
284         int i;
285
286         for(i = (P_Random()&3)+1; i; i--)
287         {
288                 mo = P_SpawnMobj(actor->x+((P_Random()-P_Random())<<14), actor->y+
289                         ((P_Random()-P_Random())<<14), actor->z+(P_Random()<<14), 
290                         MT_LEAF1+(P_Random()&1));
291                 if(mo)
292                 {
293                         P_ThrustMobj(mo, actor->angle, (P_Random()<<9)+3*FRACUNIT);
294                         mo->target = actor;
295                         mo->special1 = 0;
296                 }
297         }
298 }
299
300 //============================================================================
301 //
302 // A_LeafThrust
303 //
304 //============================================================================
305
306 void A_LeafThrust(mobj_t *actor)
307 {
308         if(P_Random() > 96)
309         {
310                 return;
311         }
312         actor->momz += (P_Random()<<9)+FRACUNIT;
313 }
314
315 //============================================================================
316 //
317 // A_LeafCheck
318 //
319 //============================================================================
320
321 void A_LeafCheck(mobj_t *actor)
322 {
323         actor->special1++;
324         if(actor->special1 >= 20)
325         {
326                 P_SetMobjState(actor, S_NULL);
327                 return;
328         }
329         if(P_Random() > 64)
330         {
331                 if(!actor->momx && !actor->momy)
332                 {
333                         P_ThrustMobj(actor, actor->target->angle,
334                                 (P_Random()<<9)+FRACUNIT);
335                 }
336                 return;
337         }
338         P_SetMobjState(actor, S_LEAF1_8);
339         actor->momz = (P_Random()<<9)+FRACUNIT;
340         P_ThrustMobj(actor, actor->target->angle, (P_Random()<<9)+2*FRACUNIT);
341         actor->flags |= MF_MISSILE;
342 }
343
344 /*
345 #define ORBIT_RADIUS    (15*FRACUNIT)
346 void GenerateOrbitTable(void)
347 {
348         int angle;
349
350         for (angle=0; angle<256; angle++)
351         {
352                 orbitTableX[angle] = FixedMul(ORBIT_RADIUS, finecosine[angle<<5]);
353                 orbitTableY[angle] = FixedMul(ORBIT_RADIUS, finesine[angle<<5]);
354         }
355
356         printf("int orbitTableX[256]=\n{\n");
357         for (angle=0; angle<256; angle+=8)
358         {
359                 printf("%d, %d, %d, %d, %d, %d, %d, %d,\n",
360                         orbitTableX[angle],
361                         orbitTableX[angle+1],
362                         orbitTableX[angle+2],
363                         orbitTableX[angle+3],
364                         orbitTableX[angle+4],
365                         orbitTableX[angle+5],
366                         orbitTableX[angle+6],
367                         orbitTableX[angle+7]);
368         }
369         printf("};\n\n");
370
371         printf("int orbitTableY[256]=\n{\n");
372         for (angle=0; angle<256; angle+=8)
373         {
374                 printf("%d, %d, %d, %d, %d, %d, %d, %d,\n",
375                         orbitTableY[angle],
376                         orbitTableY[angle+1],
377                         orbitTableY[angle+2],
378                         orbitTableY[angle+3],
379                         orbitTableY[angle+4],
380                         orbitTableY[angle+5],
381                         orbitTableY[angle+6],
382                         orbitTableY[angle+7]);
383         }
384         printf("};\n");
385 }
386 */
387
388 // New bridge stuff
389 //      Parent
390 //              special1        true == removing from world
391 //
392 //      Child
393 //              target          pointer to center mobj
394 //              args[0]         angle of ball
395
396 void A_BridgeOrbit(mobj_t *actor)
397 {
398         if (actor->target->special1)
399         {
400                 P_SetMobjState(actor, S_NULL);
401         }
402         actor->args[0]+=3;
403         actor->x = actor->target->x + orbitTableX[actor->args[0]];
404         actor->y = actor->target->y + orbitTableY[actor->args[0]];
405         actor->z = actor->target->z;
406 }
407
408
409 void A_BridgeInit(mobj_t *actor)
410 {
411         byte startangle;
412         mobj_t *ball1, *ball2, *ball3;
413         fixed_t cx,cy,cz;
414
415 //      GenerateOrbitTable();
416
417         cx = actor->x;
418         cy = actor->y;
419         cz = actor->z;
420         startangle = P_Random();
421         actor->special1 = 0;
422
423         // Spawn triad into world
424         ball1 = P_SpawnMobj(cx, cy, cz, MT_BRIDGEBALL);
425         ball1->args[0] = startangle;
426         ball1->target = actor;
427
428         ball2 = P_SpawnMobj(cx, cy, cz, MT_BRIDGEBALL);
429         ball2->args[0] = (startangle+85)&255;
430         ball2->target = actor;
431
432         ball3 = P_SpawnMobj(cx, cy, cz, MT_BRIDGEBALL);
433         ball3->args[0] = (startangle+170)&255;
434         ball3->target = actor;
435
436         A_BridgeOrbit(ball1);
437         A_BridgeOrbit(ball2);
438         A_BridgeOrbit(ball3);
439 }
440
441 void A_BridgeRemove(mobj_t *actor)
442 {
443         actor->special1 = true;         // Removing the bridge
444         actor->flags &= ~MF_SOLID;
445         P_SetMobjState(actor, S_FREE_BRIDGE1);
446 }
447
448
449 //==========================================================================
450 //
451 // A_GhostOn
452 //
453 //==========================================================================
454
455 /*
456 void A_GhostOn(mobj_t *actor)
457 {
458         actor->flags |= MF_SHADOW;
459 }
460 */
461
462 //==========================================================================
463 //
464 // A_GhostOff
465 //
466 //==========================================================================
467
468 /*
469 void A_GhostOff(mobj_t *actor)
470 {
471         actor->flags &= ~MF_SHADOW;
472 }
473 */
474
475 //==========================================================================
476 //
477 // A_HideThing
478 //
479 //==========================================================================
480
481 void A_HideThing(mobj_t *actor)
482 {
483         actor->flags2 |= MF2_DONTDRAW;
484 }
485
486 //==========================================================================
487 //
488 // A_UnHideThing
489 //
490 //==========================================================================
491
492 void A_UnHideThing(mobj_t *actor)
493 {
494         actor->flags2 &= ~MF2_DONTDRAW;
495 }
496
497 //==========================================================================
498 //
499 // A_SetShootable
500 //
501 //==========================================================================
502
503 void A_SetShootable(mobj_t *actor)
504 {
505         actor->flags2 &= ~MF2_NONSHOOTABLE;
506         actor->flags |= MF_SHOOTABLE;
507 }
508
509 //==========================================================================
510 //
511 // A_UnSetShootable
512 //
513 //==========================================================================
514
515 void A_UnSetShootable(mobj_t *actor)
516 {
517         actor->flags2 |= MF2_NONSHOOTABLE;
518         actor->flags &= ~MF_SHOOTABLE;
519 }
520
521 //==========================================================================
522 //
523 // A_SetAltShadow
524 //
525 //==========================================================================
526
527 void A_SetAltShadow(mobj_t *actor)
528 {
529         actor->flags &= ~MF_SHADOW;
530         actor->flags |= MF_ALTSHADOW;
531 }
532
533 //==========================================================================
534 //
535 // A_UnSetAltShadow
536 //
537 //==========================================================================
538
539 /*
540 void A_UnSetAltShadow(mobj_t *actor)
541 {
542         actor->flags &= ~MF_ALTSHADOW;
543 }
544 */
545
546 //--------------------------------------------------------------------------
547 //
548 // Sound Action Routines
549 //
550 //--------------------------------------------------------------------------
551
552 //==========================================================================
553 //
554 // A_ContMobjSound
555 //
556 //==========================================================================
557
558 void A_ContMobjSound(mobj_t *actor)
559 {
560         switch(actor->type)
561         {
562                 case MT_SERPENTFX:
563                         S_StartSound(actor, SFX_SERPENTFX_CONTINUOUS);
564                         break;
565                 case MT_HAMMER_MISSILE:
566                         S_StartSound(actor, SFX_FIGHTER_HAMMER_CONTINUOUS);
567                         break;
568                 case MT_QUAKE_FOCUS:
569                         S_StartSound(actor, SFX_EARTHQUAKE);
570                         break;
571                 default:
572                         break;
573         }
574 }
575
576 //==========================================================================
577 //
578 // PROC A_ESound
579 //
580 //==========================================================================
581
582 void A_ESound(mobj_t *mo)
583 {
584         int sound;
585
586         switch(mo->type)
587         {
588                 case MT_SOUNDWIND:
589                         sound = SFX_WIND;
590                         break;
591                 default:
592                         sound = SFX_NONE;
593                         break;
594         }
595         S_StartSound(mo, sound);        
596 }
597
598
599
600 //==========================================================================
601 // Summon Minotaur -- see p_enemy for variable descriptions
602 //==========================================================================
603
604
605 void A_Summon(mobj_t *actor)
606 {
607         mobj_t *mo;
608         mobj_t *master;
609
610         mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_MINOTAUR);
611         if (mo)
612         {
613                 if(P_TestMobjLocation(mo) == false || !actor->special1)
614                 { // Didn't fit - change back to artifact
615                         P_SetMobjState(mo, S_NULL);
616                         mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_SUMMONMAULATOR);
617                         if (mo) mo->flags2 |= MF2_DROPPED;
618                         return;
619                 }
620
621                 memcpy((void *)mo->args, &leveltime, sizeof(leveltime));
622                 master = (mobj_t *)actor->special1;
623                 if (master->flags&MF_CORPSE)
624                 {       // Master dead
625                         mo->special1 = 0;               // No master
626                 }
627                 else
628                 {
629                         mo->special1 = actor->special1;         // Pointer to master (mobj_t *)
630                         P_GivePower(master->player, pw_minotaur);
631                 }
632
633                 // Make smoke puff
634                 P_SpawnMobj(actor->x, actor->y, actor->z, MT_MNTRSMOKE);
635                 S_StartSound(actor, SFX_MAULATOR_ACTIVE);
636         }
637 }
638
639
640
641 //==========================================================================
642 // Fog Variables:
643 //
644 //              args[0]         Speed (0..10) of fog
645 //              args[1]         Angle of spread (0..128)
646 //              args[2]         Frequency of spawn (1..10)
647 //              args[3]         Lifetime countdown
648 //              args[4]         Boolean: fog moving?
649 //              special1                Internal:  Counter for spawn frequency
650 //              special2                Internal:  Index into floatbob table
651 //
652 //==========================================================================
653
654 void A_FogSpawn(mobj_t *actor)
655 {
656         mobj_t *mo=NULL;
657         angle_t delta;
658
659         if (actor->special1-- > 0) return;
660
661         actor->special1 = actor->args[2];               // Reset frequency count
662
663         switch(P_Random()%3)
664         {
665                 case 0:
666                         mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FOGPATCHS);
667                         break;
668                 case 1:
669                         mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FOGPATCHM);
670                         break;
671                 case 2:
672                         mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_FOGPATCHL);
673                         break;
674         }
675
676         if (mo)
677         {
678                 delta = actor->args[1];
679                 if (delta==0) delta=1;
680                 mo->angle = actor->angle + (((P_Random()%delta)-(delta>>1))<<24);
681                 mo->target = actor;
682                 if (actor->args[0] < 1) actor->args[0] = 1;
683                 mo->args[0] = (P_Random() % (actor->args[0]))+1;        // Random speed
684                 mo->args[3] = actor->args[3];                                           // Set lifetime
685                 mo->args[4] = 1;                                                                        // Set to moving
686                 mo->special2 = P_Random()&63;
687         }
688 }
689
690
691 void A_FogMove(mobj_t *actor)
692 {
693         int speed = actor->args[0]<<FRACBITS;
694         angle_t angle;
695         int weaveindex;
696
697         if (!(actor->args[4])) return;
698
699         if (actor->args[3]-- <= 0)
700         {
701                 P_SetMobjStateNF(actor, actor->info->deathstate);
702                 return;
703         }
704
705         if ((actor->args[3] % 4) == 0)
706         {
707                 weaveindex = actor->special2;
708                 actor->z += FloatBobOffsets[weaveindex]>>1;
709                 actor->special2 = (weaveindex+1)&63;
710         }
711
712         angle = actor->angle>>ANGLETOFINESHIFT;
713         actor->momx = FixedMul(speed, finecosine[angle]);
714         actor->momy = FixedMul(speed, finesine[angle]);
715 }
716
717 //===========================================================================
718 //
719 // A_PoisonBagInit
720 //
721 //===========================================================================
722
723 void A_PoisonBagInit(mobj_t *actor)
724 {
725         mobj_t *mo;
726
727         mo = P_SpawnMobj(actor->x, actor->y, actor->z+28*FRACUNIT,
728                 MT_POISONCLOUD);
729         if(!mo)
730         {
731                 return;
732         }
733         mo->momx = 1; // missile objects must move to impact other objects
734         mo->special1 = 24+(P_Random()&7);
735         mo->special2 = 0;
736         mo->target = actor->target;
737         mo->radius = 20*FRACUNIT;
738         mo->height = 30*FRACUNIT;
739         mo->flags &= ~MF_NOCLIP;
740 }
741
742 //===========================================================================
743 //
744 // A_PoisonBagCheck
745 //
746 //===========================================================================
747
748 void A_PoisonBagCheck(mobj_t *actor)
749 {
750         if(!--actor->special1)
751         {
752                 P_SetMobjState(actor, S_POISONCLOUD_X1);
753         }
754         else
755         {
756                 return;
757         }
758 }
759
760 //===========================================================================
761 //
762 // A_PoisonBagDamage
763 //
764 //===========================================================================
765
766 void A_PoisonBagDamage(mobj_t *actor)
767 {
768         int bobIndex;
769         
770         extern void A_Explode(mobj_t *actor);
771
772         A_Explode(actor);       
773
774         bobIndex = actor->special2;
775         actor->z += FloatBobOffsets[bobIndex]>>4;
776         actor->special2 = (bobIndex+1)&63;
777 }
778
779 //===========================================================================
780 //
781 // A_PoisonShroom
782 //
783 //===========================================================================
784
785 void A_PoisonShroom(mobj_t *actor)
786 {
787         actor->tics = 128+(P_Random()<<1);
788 }
789
790 //===========================================================================
791 //
792 // A_CheckThrowBomb
793 //
794 //===========================================================================
795
796 void A_CheckThrowBomb(mobj_t *actor)
797 {
798         if(abs(actor->momx) < 1.5*FRACUNIT && abs(actor->momy) < 1.5*FRACUNIT
799                 && actor->momz < 2*FRACUNIT
800                 && actor->state == &states[S_THROWINGBOMB6])
801         {
802                 P_SetMobjState(actor, S_THROWINGBOMB7);
803                 actor->z = actor->floorz;
804                 actor->momz = 0;
805                 actor->flags2 &= ~MF2_FLOORBOUNCE;
806                 actor->flags &= ~MF_MISSILE;
807         }
808         if(!--actor->health)
809         {
810                 P_SetMobjState(actor, actor->info->deathstate);
811         }
812 }
813
814 //===========================================================================
815 // Quake variables
816 //
817 //              args[0]         Intensity on richter scale (2..9)
818 //              args[1]         Duration in tics
819 //              args[2]         Radius for damage
820 //              args[3]         Radius for tremor
821 //              args[4]         TID of map thing for focus of quake
822 //
823 //===========================================================================
824
825 //===========================================================================
826 //
827 // A_LocalQuake
828 //
829 //===========================================================================
830
831 boolean A_LocalQuake(byte *args, mobj_t *actor)
832 {
833         mobj_t *focus, *target;
834         int lastfound=0;
835         int success=false;
836
837         actor=actor;    // suppress warning
838
839         // Find all quake foci
840         do
841         {
842                 target = P_FindMobjFromTID(args[4], &lastfound);
843                 if (target)
844                 {
845                         focus = P_SpawnMobj(target->x,
846                                                                 target->y,
847                                                                 target->z, MT_QUAKE_FOCUS);
848                         if (focus)
849                         {
850                                 focus->args[0] = args[0];
851                                 focus->args[1] = args[1]>>1;    // decremented every 2 tics
852                                 focus->args[2] = args[2];
853                                 focus->args[3] = args[3];
854                                 focus->args[4] = args[4];
855                                 success = true;
856                         }
857                 }
858         }while(target != NULL);
859
860         return(success);
861 }
862
863
864 //===========================================================================
865 //
866 // A_Quake
867 //
868 //===========================================================================
869 int     localQuakeHappening[MAXPLAYERS];
870
871 void A_Quake(mobj_t *actor)
872 {
873         angle_t an;
874         player_t *player;
875         mobj_t *victim;
876         int richters = actor->args[0];
877         int playnum;
878         fixed_t dist;
879
880         if (actor->args[1]-- > 0)
881         {
882                 for (playnum=0; playnum < MAXPLAYERS; playnum++)
883                 {
884                         player = &players[playnum];
885                         if (!playeringame[playnum]) continue;
886
887                         victim = player->mo;
888                         dist = P_AproxDistance(actor->x - victim->x,
889                                                 actor->y - victim->y) >> (FRACBITS+6);
890                         // Tested in tile units (64 pixels)
891                         if (dist < actor->args[3])              // In tremor radius
892                         {
893                                 localQuakeHappening[playnum] = richters;
894                         }
895                         // Check if in damage radius
896                         if ((dist < actor->args[2]) &&
897                                 (victim->z <= victim->floorz))
898                         {
899                                 if (P_Random() < 50)
900                                 {
901                                         P_DamageMobj(victim, NULL, NULL, HITDICE(1));
902                                 }
903                                 // Thrust player around
904                                 an = victim->angle + ANGLE_1*P_Random();
905                                 P_ThrustMobj(victim,an,richters<<(FRACBITS-1));
906                         }
907                 }
908         }
909         else
910         {
911                 for (playnum=0; playnum < MAXPLAYERS; playnum++)
912                 {
913                         localQuakeHappening[playnum] = false;
914                 }
915                 P_SetMobjState(actor, S_NULL);
916         }
917 }
918
919
920
921
922 //===========================================================================
923 //
924 // Teleport other stuff
925 //
926 //===========================================================================
927
928 #define TELEPORT_LIFE 1
929
930 void A_TeloSpawnA(mobj_t *actor)
931 {
932         mobj_t *mo;
933
934         mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_TELOTHER_FX2);
935         if (mo)
936         {
937                 mo->special1 = TELEPORT_LIFE;                   // Lifetime countdown
938                 mo->angle = actor->angle;
939                 mo->target = actor->target;
940                 mo->momx = actor->momx>>1;
941                 mo->momy = actor->momy>>1;
942                 mo->momz = actor->momz>>1;
943         }
944 }
945
946 void A_TeloSpawnB(mobj_t *actor)
947 {
948         mobj_t *mo;
949
950         mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_TELOTHER_FX3);
951         if (mo)
952         {
953                 mo->special1 = TELEPORT_LIFE;                   // Lifetime countdown
954                 mo->angle = actor->angle;
955                 mo->target = actor->target;
956                 mo->momx = actor->momx>>1;
957                 mo->momy = actor->momy>>1;
958                 mo->momz = actor->momz>>1;
959         }
960 }
961
962 void A_TeloSpawnC(mobj_t *actor)
963 {
964         mobj_t *mo;
965
966         mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_TELOTHER_FX4);
967         if (mo)
968         {
969                 mo->special1 = TELEPORT_LIFE;                   // Lifetime countdown
970                 mo->angle = actor->angle;
971                 mo->target = actor->target;
972                 mo->momx = actor->momx>>1;
973                 mo->momy = actor->momy>>1;
974                 mo->momz = actor->momz>>1;
975         }
976 }
977
978 void A_TeloSpawnD(mobj_t *actor)
979 {
980         mobj_t *mo;
981
982         mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_TELOTHER_FX5);
983         if (mo)
984         {
985                 mo->special1 = TELEPORT_LIFE;                   // Lifetime countdown
986                 mo->angle = actor->angle;
987                 mo->target = actor->target;
988                 mo->momx = actor->momx>>1;
989                 mo->momy = actor->momy>>1;
990                 mo->momz = actor->momz>>1;
991         }
992 }
993
994 void A_CheckTeleRing(mobj_t *actor)
995 {
996         if (actor->special1-- <= 0)
997         {
998                 P_SetMobjState(actor, actor->info->deathstate);
999         }
1000 }
1001
1002
1003
1004
1005 // Dirt stuff
1006
1007 void P_SpawnDirt(mobj_t *actor, fixed_t radius)
1008 {
1009         fixed_t x,y,z;
1010         int dtype=0;
1011         mobj_t *mo;
1012         angle_t angle;
1013
1014         angle = P_Random()<<5;          // <<24 >>19
1015         x = actor->x + FixedMul(radius,finecosine[angle]);
1016         y = actor->y + FixedMul(radius,finesine[angle]);
1017 //      x = actor->x + ((P_Random()-P_Random())%radius)<<FRACBITS;
1018 //      y = actor->y + ((P_Random()-P_Random()<<FRACBITS)%radius);
1019         z = actor->z + (P_Random()<<9) + FRACUNIT;
1020         switch(P_Random()%6)
1021         {
1022                 case 0:
1023                         dtype = MT_DIRT1;
1024                         break;
1025                 case 1:
1026                         dtype = MT_DIRT2;
1027                         break;
1028                 case 2:
1029                         dtype = MT_DIRT3;
1030                         break;
1031                 case 3:
1032                         dtype = MT_DIRT4;
1033                         break;
1034                 case 4:
1035                         dtype = MT_DIRT5;
1036                         break;
1037                 case 5:
1038                         dtype = MT_DIRT6;
1039                         break;
1040         }
1041         mo = P_SpawnMobj(x,y,z,dtype);
1042         if (mo)
1043         {
1044                 mo->momz = P_Random()<<10;
1045         }
1046 }
1047
1048
1049
1050
1051 //===========================================================================
1052 //
1053 // Thrust floor stuff
1054 //
1055 // Thrust Spike Variables
1056 //              special1                pointer to dirt clump mobj
1057 //              special2                speed of raise
1058 //              args[0]         0 = lowered,  1 = raised
1059 //              args[1]         0 = normal,   1 = bloody
1060 //===========================================================================
1061
1062 void A_ThrustInitUp(mobj_t *actor)
1063 {
1064         actor->special2 = 5;            // Raise speed
1065         actor->args[0] = 1;             // Mark as up
1066         actor->floorclip = 0;
1067         actor->flags = MF_SOLID;
1068         actor->flags2 = MF2_NOTELEPORT|MF2_FLOORCLIP;
1069         actor->special1 = 0L;
1070 }
1071
1072 void A_ThrustInitDn(mobj_t *actor)
1073 {
1074         mobj_t *mo;
1075         actor->special2 = 5;            // Raise speed
1076         actor->args[0] = 0;             // Mark as down
1077         actor->floorclip = actor->info->height;
1078         actor->flags = 0;
1079         actor->flags2 = MF2_NOTELEPORT|MF2_FLOORCLIP|MF2_DONTDRAW;
1080         mo = P_SpawnMobj(actor->x, actor->y, actor->z, MT_DIRTCLUMP);
1081         actor->special1 = (int)mo;
1082 }
1083
1084
1085 void A_ThrustRaise(mobj_t *actor)
1086 {
1087         if (A_RaiseMobj(actor))
1088         {       // Reached it's target height
1089                 actor->args[0] = 1;
1090                 if (actor->args[1])
1091                         P_SetMobjStateNF(actor, S_BTHRUSTINIT2_1);
1092                 else
1093                         P_SetMobjStateNF(actor, S_THRUSTINIT2_1);
1094         }
1095
1096         // Lose the dirt clump
1097         if ((actor->floorclip < actor->height) && actor->special1)
1098         {
1099                 P_RemoveMobj( (mobj_t *)actor->special1 );
1100                 actor->special1 = 0;
1101         }
1102
1103         // Spawn some dirt
1104         if (P_Random()<40)
1105                 P_SpawnDirt(actor, actor->radius);
1106         actor->special2++;                                                      // Increase raise speed
1107 }
1108
1109 void A_ThrustLower(mobj_t *actor)
1110 {
1111         if (A_SinkMobj(actor))
1112         {
1113                 actor->args[0] = 0;
1114                 if (actor->args[1])
1115                         P_SetMobjStateNF(actor, S_BTHRUSTINIT1_1);
1116                 else
1117                         P_SetMobjStateNF(actor, S_THRUSTINIT1_1);
1118         }
1119 }
1120
1121 void A_ThrustBlock(mobj_t *actor)
1122 {
1123         actor->flags |= MF_SOLID;
1124 }
1125
1126 void A_ThrustImpale(mobj_t *actor)
1127 {
1128         // Impale all shootables in radius
1129         PIT_ThrustSpike(actor);
1130 }
1131
1132 //===========================================================================
1133 //
1134 // A_SoAExplode - Suit of Armor Explode
1135 //
1136 //===========================================================================
1137
1138 void A_SoAExplode(mobj_t *actor)
1139 {
1140         mobj_t *mo;
1141         int i;
1142
1143         for(i = 0; i < 10; i++)
1144         {
1145                 mo = P_SpawnMobj(actor->x+((P_Random()-128)<<12), 
1146                         actor->y+((P_Random()-128)<<12), 
1147                         actor->z+(P_Random()*actor->height/256), MT_ZARMORCHUNK);
1148                 P_SetMobjState(mo, mo->info->spawnstate+i);
1149                 if(mo)
1150                 {
1151                         mo->momz = ((P_Random()&7)+5)*FRACUNIT;
1152                         mo->momx = (P_Random()-P_Random())<<(FRACBITS-6);
1153                         mo->momy = (P_Random()-P_Random())<<(FRACBITS-6);
1154                 }
1155         }
1156         if(actor->args[0])
1157         { // Spawn an item
1158                 if(!nomonsters 
1159                 || !(mobjinfo[TranslateThingType[actor->args[0]]].flags&MF_COUNTKILL))
1160                 { // Only spawn monsters if not -nomonsters
1161                         P_SpawnMobj(actor->x, actor->y, actor->z,
1162                                 TranslateThingType[actor->args[0]]);
1163                 }
1164         }
1165         S_StartSound(mo, SFX_SUITOFARMOR_BREAK);
1166         P_RemoveMobj(actor);
1167 }
1168
1169 //===========================================================================
1170 //
1171 // A_BellReset1
1172 //
1173 //===========================================================================
1174
1175 void A_BellReset1(mobj_t *actor)
1176 {
1177         actor->flags |= MF_NOGRAVITY;
1178         actor->height <<= 2;    
1179 }
1180
1181 //===========================================================================
1182 //
1183 // A_BellReset2
1184 //
1185 //===========================================================================
1186
1187 void A_BellReset2(mobj_t *actor)
1188 {
1189         actor->flags |= MF_SHOOTABLE;
1190         actor->flags &= ~MF_CORPSE;
1191         actor->health = 5;
1192 }
1193
1194
1195 //===========================================================================
1196 //
1197 // A_FlameCheck
1198 //
1199 //===========================================================================
1200
1201 void A_FlameCheck(mobj_t *actor)
1202 {
1203         if(!actor->args[0]--)           // Called every 8 tics
1204         {
1205                 P_SetMobjState(actor, S_NULL);
1206         }
1207 }
1208
1209
1210 //===========================================================================
1211 // Bat Spawner Variables
1212 //      special1        frequency counter
1213 //      special2        
1214 //      args[0]         frequency of spawn (1=fastest, 10=slowest)
1215 //      args[1]         spread angle (0..255)
1216 //      args[2]         
1217 //      args[3]         duration of bats (in octics)
1218 //      args[4]         turn amount per move (in degrees)
1219 //
1220 // Bat Variables
1221 //      special2        lifetime counter
1222 //      args[4]         turn amount per move (in degrees)
1223 //===========================================================================
1224
1225 void A_BatSpawnInit(mobj_t *actor)
1226 {
1227         actor->special1 = 0;    // Frequency count
1228 }
1229
1230 void A_BatSpawn(mobj_t *actor)
1231 {
1232         mobj_t *mo;
1233         int delta;
1234         angle_t angle;
1235
1236         // Countdown until next spawn
1237         if (actor->special1-- > 0) return;
1238         actor->special1 = actor->args[0];               // Reset frequency count
1239
1240         delta = actor->args[1];
1241         if (delta==0) delta=1;
1242         angle = actor->angle + (((P_Random()%delta)-(delta>>1))<<24);
1243         mo = P_SpawnMissileAngle(actor, MT_BAT, angle, 0);
1244         if (mo)
1245         {
1246                 mo->args[0] = P_Random()&63;                    // floatbob index
1247                 mo->args[4] = actor->args[4];                   // turn degrees
1248                 mo->special2 = actor->args[3]<<3;               // Set lifetime
1249                 mo->target = actor;
1250         }
1251 }
1252
1253
1254 void A_BatMove(mobj_t *actor)
1255 {
1256         angle_t newangle;
1257         fixed_t speed;
1258
1259         if (actor->special2 < 0)
1260         {
1261                 P_SetMobjState(actor, actor->info->deathstate);
1262         }
1263         actor->special2 -= 2;           // Called every 2 tics
1264
1265         if (P_Random()<128)
1266         {
1267                 newangle = actor->angle + ANGLE_1*actor->args[4];
1268         }
1269         else
1270         {
1271                 newangle = actor->angle - ANGLE_1*actor->args[4];
1272         }
1273
1274         // Adjust momentum vector to new direction
1275         newangle >>= ANGLETOFINESHIFT;
1276         speed = FixedMul(actor->info->speed, P_Random()<<10);
1277         actor->momx = FixedMul(speed, finecosine[newangle]);
1278         actor->momy = FixedMul(speed, finesine[newangle]);
1279
1280         if (P_Random()<15)
1281                 S_StartSound(actor, SFX_BAT_SCREAM);
1282
1283         // Handle Z movement
1284         actor->z = actor->target->z + 2*FloatBobOffsets[actor->args[0]];
1285         actor->args[0] = (actor->args[0]+3)&63; 
1286 }
1287
1288 //===========================================================================
1289 //
1290 // A_TreeDeath
1291 //
1292 //===========================================================================
1293
1294 void A_TreeDeath(mobj_t *actor)
1295 {
1296         if(!(actor->flags2&MF2_FIREDAMAGE))
1297         {
1298                 actor->height <<= 2;
1299                 actor->flags |= MF_SHOOTABLE;
1300                 actor->flags &= ~(MF_CORPSE+MF_DROPOFF);
1301                 actor->health = 35;
1302                 return;
1303         }
1304         else
1305         {
1306                 P_SetMobjState(actor, actor->info->meleestate);
1307         }
1308 }
1309
1310 //===========================================================================
1311 //
1312 // A_NoGravity
1313 //
1314 //===========================================================================
1315
1316 void A_NoGravity(mobj_t *actor)
1317 {
1318         actor->flags |= MF_NOGRAVITY;
1319 }
1320