Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
298 serge 1
// Emacs style mode select   -*- C++ -*-
2
//-----------------------------------------------------------------------------
3
//
4
// $Id:$
5
//
6
// Copyright (C) 1993-1996 by id Software, Inc.
7
//
8
// This source is available for distribution and/or modification
9
// only under the terms of the DOOM Source Code License as
10
// published by id Software. All rights reserved.
11
//
12
// The source is distributed in the hope that it will be useful,
13
// but WITHOUT ANY WARRANTY; without even the implied warranty of
14
// FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
15
// for more details.
16
//
17
// $Log:$
18
//
19
// DESCRIPTION:
20
//	Enemy thinking, AI.
21
//	Action Pointer Functions
22
//	that are associated with states/frames.
23
//
24
//-----------------------------------------------------------------------------
25
 
26
static const char
27
rcsid[] = "$Id: p_enemy.c,v 1.5 1997/02/03 22:45:11 b1 Exp $";
28
 
29
#include 
30
 
31
#include "m_random.h"
32
#include "i_system.h"
33
 
34
#include "doomdef.h"
35
#include "p_local.h"
36
 
37
#include "s_sound.h"
38
 
39
#include "g_game.h"
40
 
41
// State.
42
#include "doomstat.h"
43
#include "r_state.h"
44
 
45
// Data.
46
#include "sounds.h"
47
 
48
 
49
 
50
 
51
typedef enum
52
{
53
    DI_EAST,
54
    DI_NORTHEAST,
55
    DI_NORTH,
56
    DI_NORTHWEST,
57
    DI_WEST,
58
    DI_SOUTHWEST,
59
    DI_SOUTH,
60
    DI_SOUTHEAST,
61
    DI_NODIR,
62
    NUMDIRS
63
 
64
} dirtype_t;
65
 
66
 
67
//
68
// P_NewChaseDir related LUT.
69
//
70
dirtype_t opposite[] =
71
{
72
  DI_WEST, DI_SOUTHWEST, DI_SOUTH, DI_SOUTHEAST,
73
  DI_EAST, DI_NORTHEAST, DI_NORTH, DI_NORTHWEST, DI_NODIR
74
};
75
 
76
dirtype_t diags[] =
77
{
78
    DI_NORTHWEST, DI_NORTHEAST, DI_SOUTHWEST, DI_SOUTHEAST
79
};
80
 
81
 
82
 
83
 
84
 
85
void A_Fall (mobj_t *actor);
86
 
87
 
88
//
89
// ENEMY THINKING
90
// Enemies are allways spawned
91
// with targetplayer = -1, threshold = 0
92
// Most monsters are spawned unaware of all players,
93
// but some can be made preaware
94
//
95
 
96
 
97
//
98
// Called by P_NoiseAlert.
99
// Recursively traverse adjacent sectors,
100
// sound blocking lines cut off traversal.
101
//
102
 
103
mobj_t*		soundtarget;
104
 
105
void
106
P_RecursiveSound
107
( sector_t*	sec,
108
  int		soundblocks )
109
{
110
    int		i;
111
    line_t*	check;
112
    sector_t*	other;
113
 
114
    // wake up all monsters in this sector
115
    if (sec->validcount == validcount
116
	&& sec->soundtraversed <= soundblocks+1)
117
    {
118
	return;		// already flooded
119
    }
120
 
121
    sec->validcount = validcount;
122
    sec->soundtraversed = soundblocks+1;
123
    sec->soundtarget = soundtarget;
124
 
125
    for (i=0 ;ilinecount ; i++)
126
    {
127
	check = sec->lines[i];
128
	if (! (check->flags & ML_TWOSIDED) )
129
	    continue;
130
 
131
	P_LineOpening (check);
132
 
133
	if (openrange <= 0)
134
	    continue;	// closed door
135
 
136
	if ( sides[ check->sidenum[0] ].sector == sec)
137
	    other = sides[ check->sidenum[1] ] .sector;
138
	else
139
	    other = sides[ check->sidenum[0] ].sector;
140
 
141
	if (check->flags & ML_SOUNDBLOCK)
142
	{
143
	    if (!soundblocks)
144
		P_RecursiveSound (other, 1);
145
	}
146
	else
147
	    P_RecursiveSound (other, soundblocks);
148
    }
149
}
150
 
151
 
152
 
153
//
154
// P_NoiseAlert
155
// If a monster yells at a player,
156
// it will alert other monsters to the player.
157
//
158
void
159
P_NoiseAlert
160
( mobj_t*	target,
161
  mobj_t*	emmiter )
162
{
163
    soundtarget = target;
164
    validcount++;
165
    P_RecursiveSound (emmiter->subsector->sector, 0);
166
}
167
 
168
 
169
 
170
 
171
//
172
// P_CheckMeleeRange
173
//
174
boolean P_CheckMeleeRange (mobj_t*	actor)
175
{
176
    mobj_t*	pl;
177
    fixed_t	dist;
178
 
179
    if (!actor->target)
180
	return false;
181
 
182
    pl = actor->target;
183
    dist = P_AproxDistance (pl->x-actor->x, pl->y-actor->y);
184
 
185
    if (dist >= MELEERANGE-20*FRACUNIT+pl->info->radius)
186
	return false;
187
 
188
    if (! P_CheckSight (actor, actor->target) )
189
	return false;
190
 
191
    return true;
192
}
193
 
194
//
195
// P_CheckMissileRange
196
//
197
boolean P_CheckMissileRange (mobj_t* actor)
198
{
199
    fixed_t	dist;
200
 
201
    if (! P_CheckSight (actor, actor->target) )
202
	return false;
203
 
204
    if ( actor->flags & MF_JUSTHIT )
205
    {
206
	// the target just hit the enemy,
207
	// so fight back!
208
	actor->flags &= ~MF_JUSTHIT;
209
	return true;
210
    }
211
 
212
    if (actor->reactiontime)
213
	return false;	// do not attack yet
214
 
215
    // OPTIMIZE: get this from a global checksight
216
    dist = P_AproxDistance ( actor->x-actor->target->x,
217
			     actor->y-actor->target->y) - 64*FRACUNIT;
218
 
219
    if (!actor->info->meleestate)
220
	dist -= 128*FRACUNIT;	// no melee attack, so fire more
221
 
222
    dist >>= 16;
223
 
224
    if (actor->type == MT_VILE)
225
    {
226
	if (dist > 14*64)
227
	    return false;	// too far away
228
    }
229
 
230
 
231
    if (actor->type == MT_UNDEAD)
232
    {
233
	if (dist < 196)
234
	    return false;	// close for fist attack
235
	dist >>= 1;
236
    }
237
 
238
 
239
    if (actor->type == MT_CYBORG
240
	|| actor->type == MT_SPIDER
241
	|| actor->type == MT_SKULL)
242
    {
243
	dist >>= 1;
244
    }
245
 
246
    if (dist > 200)
247
	dist = 200;
248
 
249
    if (actor->type == MT_CYBORG && dist > 160)
250
	dist = 160;
251
 
252
    if (P_Random () < dist)
253
	return false;
254
 
255
    return true;
256
}
257
 
258
 
259
//
260
// P_Move
261
// Move in the current direction,
262
// returns false if the move is blocked.
263
//
264
fixed_t	xspeed[8] = {FRACUNIT,47000,0,-47000,-FRACUNIT,-47000,0,47000};
265
fixed_t yspeed[8] = {0,47000,FRACUNIT,47000,0,-47000,-FRACUNIT,-47000};
266
 
267
#define MAXSPECIALCROSS	8
268
 
269
extern	line_t*	spechit[MAXSPECIALCROSS];
270
extern	int	numspechit;
271
 
272
boolean P_Move (mobj_t*	actor)
273
{
274
    fixed_t	tryx;
275
    fixed_t	tryy;
276
 
277
    line_t*	ld;
278
 
279
    // warning: 'catch', 'throw', and 'try'
280
    // are all C++ reserved words
281
    boolean	try_ok;
282
    boolean	good;
283
 
284
    if (actor->movedir == DI_NODIR)
285
	return false;
286
 
287
    if ((unsigned)actor->movedir >= 8)
288
	I_Error ("Weird actor->movedir!");
289
 
290
    tryx = actor->x + actor->info->speed*xspeed[actor->movedir];
291
    tryy = actor->y + actor->info->speed*yspeed[actor->movedir];
292
 
293
    try_ok = P_TryMove (actor, tryx, tryy);
294
 
295
    if (!try_ok)
296
    {
297
	// open any specials
298
	if (actor->flags & MF_FLOAT && floatok)
299
	{
300
	    // must adjust height
301
	    if (actor->z < tmfloorz)
302
		actor->z += FLOATSPEED;
303
	    else
304
		actor->z -= FLOATSPEED;
305
 
306
	    actor->flags |= MF_INFLOAT;
307
	    return true;
308
	}
309
 
310
	if (!numspechit)
311
	    return false;
312
 
313
	actor->movedir = DI_NODIR;
314
	good = false;
315
	while (numspechit--)
316
	{
317
	    ld = spechit[numspechit];
318
	    // if the special is not a door
319
	    // that can be opened,
320
	    // return false
321
	    if (P_UseSpecialLine (actor, ld,0))
322
		good = true;
323
	}
324
	return good;
325
    }
326
    else
327
    {
328
	actor->flags &= ~MF_INFLOAT;
329
    }
330
 
331
 
332
    if (! (actor->flags & MF_FLOAT) )
333
	actor->z = actor->floorz;
334
    return true;
335
}
336
 
337
 
338
//
339
// TryWalk
340
// Attempts to move actor on
341
// in its current (ob->moveangle) direction.
342
// If blocked by either a wall or an actor
343
// returns FALSE
344
// If move is either clear or blocked only by a door,
345
// returns TRUE and sets...
346
// If a door is in the way,
347
// an OpenDoor call is made to start it opening.
348
//
349
boolean P_TryWalk (mobj_t* actor)
350
{
351
    if (!P_Move (actor))
352
    {
353
	return false;
354
    }
355
 
356
    actor->movecount = P_Random()&15;
357
    return true;
358
}
359
 
360
 
361
 
362
 
363
void P_NewChaseDir (mobj_t*	actor)
364
{
365
    fixed_t	deltax;
366
    fixed_t	deltay;
367
 
368
    dirtype_t	d[3];
369
 
370
    int		tdir;
371
    dirtype_t	olddir;
372
 
373
    dirtype_t	turnaround;
374
 
375
    if (!actor->target)
376
	I_Error ("P_NewChaseDir: called with no target");
377
 
378
    olddir = actor->movedir;
379
    turnaround=opposite[olddir];
380
 
381
    deltax = actor->target->x - actor->x;
382
    deltay = actor->target->y - actor->y;
383
 
384
    if (deltax>10*FRACUNIT)
385
	d[1]= DI_EAST;
386
    else if (deltax<-10*FRACUNIT)
387
	d[1]= DI_WEST;
388
    else
389
	d[1]=DI_NODIR;
390
 
391
    if (deltay<-10*FRACUNIT)
392
	d[2]= DI_SOUTH;
393
    else if (deltay>10*FRACUNIT)
394
	d[2]= DI_NORTH;
395
    else
396
	d[2]=DI_NODIR;
397
 
398
    // try direct route
399
    if (d[1] != DI_NODIR
400
	&& d[2] != DI_NODIR)
401
    {
402
	actor->movedir = diags[((deltay<0)<<1)+(deltax>0)];
403
	if (actor->movedir != turnaround && P_TryWalk(actor))
404
	    return;
405
    }
406
 
407
    // try other directions
408
    if (P_Random() > 200
409
	||  abs(deltay)>abs(deltax))
410
    {
411
	tdir=d[1];
412
	d[1]=d[2];
413
	d[2]=tdir;
414
    }
415
 
416
    if (d[1]==turnaround)
417
	d[1]=DI_NODIR;
418
    if (d[2]==turnaround)
419
	d[2]=DI_NODIR;
420
 
421
    if (d[1]!=DI_NODIR)
422
    {
423
	actor->movedir = d[1];
424
	if (P_TryWalk(actor))
425
	{
426
	    // either moved forward or attacked
427
	    return;
428
	}
429
    }
430
 
431
    if (d[2]!=DI_NODIR)
432
    {
433
	actor->movedir =d[2];
434
 
435
	if (P_TryWalk(actor))
436
	    return;
437
    }
438
 
439
    // there is no direct path to the player,
440
    // so pick another direction.
441
    if (olddir!=DI_NODIR)
442
    {
443
	actor->movedir =olddir;
444
 
445
	if (P_TryWalk(actor))
446
	    return;
447
    }
448
 
449
    // randomly determine direction of search
450
    if (P_Random()&1)
451
    {
452
	for ( tdir=DI_EAST;
453
	      tdir<=DI_SOUTHEAST;
454
	      tdir++ )
455
	{
456
	    if (tdir!=turnaround)
457
	    {
458
		actor->movedir =tdir;
459
 
460
		if ( P_TryWalk(actor) )
461
		    return;
462
	    }
463
	}
464
    }
465
    else
466
    {
467
	for ( tdir=DI_SOUTHEAST;
468
	      tdir != (DI_EAST-1);
469
	      tdir-- )
470
	{
471
	    if (tdir!=turnaround)
472
	    {
473
		actor->movedir =tdir;
474
 
475
		if ( P_TryWalk(actor) )
476
		    return;
477
	    }
478
	}
479
    }
480
 
481
    if (turnaround !=  DI_NODIR)
482
    {
483
	actor->movedir =turnaround;
484
	if ( P_TryWalk(actor) )
485
	    return;
486
    }
487
 
488
    actor->movedir = DI_NODIR;	// can not move
489
}
490
 
491
 
492
 
493
//
494
// P_LookForPlayers
495
// If allaround is false, only look 180 degrees in front.
496
// Returns true if a player is targeted.
497
//
498
boolean
499
P_LookForPlayers
500
( mobj_t*	actor,
501
  boolean	allaround )
502
{
503
    int		c;
504
    int		stop;
505
    player_t*	player;
506
    sector_t*	sector;
507
    angle_t	an;
508
    fixed_t	dist;
509
 
510
    sector = actor->subsector->sector;
511
 
512
    c = 0;
513
    stop = (actor->lastlook-1)&3;
514
 
515
    for ( ; ; actor->lastlook = (actor->lastlook+1)&3 )
516
    {
517
	if (!playeringame[actor->lastlook])
518
	    continue;
519
 
520
	if (c++ == 2
521
	    || actor->lastlook == stop)
522
	{
523
	    // done looking
524
	    return false;
525
	}
526
 
527
	player = &players[actor->lastlook];
528
 
529
	if (player->health <= 0)
530
	    continue;		// dead
531
 
532
	if (!P_CheckSight (actor, player->mo))
533
	    continue;		// out of sight
534
 
535
	if (!allaround)
536
	{
537
	    an = R_PointToAngle2 (actor->x,
538
				  actor->y,
539
				  player->mo->x,
540
				  player->mo->y)
541
		- actor->angle;
542
 
543
	    if (an > ANG90 && an < ANG270)
544
	    {
545
		dist = P_AproxDistance (player->mo->x - actor->x,
546
					player->mo->y - actor->y);
547
		// if real close, react anyway
548
		if (dist > MELEERANGE)
549
		    continue;	// behind back
550
	    }
551
	}
552
 
553
	actor->target = player->mo;
554
	return true;
555
    }
556
 
557
    return false;
558
}
559
 
560
 
561
//
562
// A_KeenDie
563
// DOOM II special, map 32.
564
// Uses special tag 666.
565
//
566
void A_KeenDie (mobj_t* mo)
567
{
568
    thinker_t*	th;
569
    mobj_t*	mo2;
570
    line_t	junk;
571
 
572
    A_Fall (mo);
573
 
574
    // scan the remaining thinkers
575
    // to see if all Keens are dead
576
    for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
577
    {
578
	if (th->function.acp1 != (actionf_p1)P_MobjThinker)
579
	    continue;
580
 
581
	mo2 = (mobj_t *)th;
582
	if (mo2 != mo
583
	    && mo2->type == mo->type
584
	    && mo2->health > 0)
585
	{
586
	    // other Keen not dead
587
	    return;
588
	}
589
    }
590
 
591
    junk.tag = 666;
592
    EV_DoDoor(&junk,open);
593
}
594
 
595
 
596
//
597
// ACTION ROUTINES
598
//
599
 
600
//
601
// A_Look
602
// Stay in state until a player is sighted.
603
//
604
void A_Look (mobj_t* actor)
605
{
606
    mobj_t*	targ;
607
 
608
    actor->threshold = 0;	// any shot will wake up
609
    targ = actor->subsector->sector->soundtarget;
610
 
611
    if (targ
612
	&& (targ->flags & MF_SHOOTABLE) )
613
    {
614
	actor->target = targ;
615
 
616
	if ( actor->flags & MF_AMBUSH )
617
	{
618
	    if (P_CheckSight (actor, actor->target))
619
		goto seeyou;
620
	}
621
	else
622
	    goto seeyou;
623
    }
624
 
625
 
626
    if (!P_LookForPlayers (actor, false) )
627
	return;
628
 
629
    // go into chase state
630
  seeyou:
631
    if (actor->info->seesound)
632
    {
633
	int		sound;
634
 
635
	switch (actor->info->seesound)
636
	{
637
	  case sfx_posit1:
638
	  case sfx_posit2:
639
	  case sfx_posit3:
640
	    sound = sfx_posit1+P_Random()%3;
641
	    break;
642
 
643
	  case sfx_bgsit1:
644
	  case sfx_bgsit2:
645
	    sound = sfx_bgsit1+P_Random()%2;
646
	    break;
647
 
648
	  default:
649
	    sound = actor->info->seesound;
650
	    break;
651
	}
652
 
653
	if (actor->type==MT_SPIDER
654
	    || actor->type == MT_CYBORG)
655
	{
656
	    // full volume
657
	    S_StartSound (NULL, sound);
658
	}
659
	else
660
	    S_StartSound (actor, sound);
661
    }
662
 
663
    P_SetMobjState (actor, actor->info->seestate);
664
}
665
 
666
 
667
//
668
// A_Chase
669
// Actor has a melee attack,
670
// so it tries to close as fast as possible
671
//
672
void A_Chase (mobj_t*	actor)
673
{
674
    int		delta;
675
 
676
    if (actor->reactiontime)
677
	actor->reactiontime--;
678
 
679
 
680
    // modify target threshold
681
    if  (actor->threshold)
682
    {
683
	if (!actor->target
684
	    || actor->target->health <= 0)
685
	{
686
	    actor->threshold = 0;
687
	}
688
	else
689
	    actor->threshold--;
690
    }
691
 
692
    // turn towards movement direction if not there yet
693
    if (actor->movedir < 8)
694
    {
695
	actor->angle &= (7<<29);
696
	delta = actor->angle - (actor->movedir << 29);
697
 
698
	if (delta > 0)
699
	    actor->angle -= ANG90/2;
700
	else if (delta < 0)
701
	    actor->angle += ANG90/2;
702
    }
703
 
704
    if (!actor->target
705
	|| !(actor->target->flags&MF_SHOOTABLE))
706
    {
707
	// look for a new target
708
	if (P_LookForPlayers(actor,true))
709
	    return; 	// got a new target
710
 
711
	P_SetMobjState (actor, actor->info->spawnstate);
712
	return;
713
    }
714
 
715
    // do not attack twice in a row
716
    if (actor->flags & MF_JUSTATTACKED)
717
    {
718
	actor->flags &= ~MF_JUSTATTACKED;
719
	if (gameskill != sk_nightmare && !fastparm)
720
	    P_NewChaseDir (actor);
721
	return;
722
    }
723
 
724
    // check for melee attack
725
    if (actor->info->meleestate
726
	&& P_CheckMeleeRange (actor))
727
    {
728
	if (actor->info->attacksound)
729
	    S_StartSound (actor, actor->info->attacksound);
730
 
731
	P_SetMobjState (actor, actor->info->meleestate);
732
	return;
733
    }
734
 
735
    // check for missile attack
736
    if (actor->info->missilestate)
737
    {
738
	if (gameskill < sk_nightmare
739
	    && !fastparm && actor->movecount)
740
	{
741
	    goto nomissile;
742
	}
743
 
744
	if (!P_CheckMissileRange (actor))
745
	    goto nomissile;
746
 
747
	P_SetMobjState (actor, actor->info->missilestate);
748
	actor->flags |= MF_JUSTATTACKED;
749
	return;
750
    }
751
 
752
    // ?
753
  nomissile:
754
    // possibly choose another target
755
    if (netgame
756
	&& !actor->threshold
757
	&& !P_CheckSight (actor, actor->target) )
758
    {
759
	if (P_LookForPlayers(actor,true))
760
	    return;	// got a new target
761
    }
762
 
763
    // chase towards player
764
    if (--actor->movecount<0
765
	|| !P_Move (actor))
766
    {
767
	P_NewChaseDir (actor);
768
    }
769
 
770
    // make active sound
771
    if (actor->info->activesound
772
	&& P_Random () < 3)
773
    {
774
	S_StartSound (actor, actor->info->activesound);
775
    }
776
}
777
 
778
 
779
//
780
// A_FaceTarget
781
//
782
void A_FaceTarget (mobj_t* actor)
783
{
784
    if (!actor->target)
785
	return;
786
 
787
    actor->flags &= ~MF_AMBUSH;
788
 
789
    actor->angle = R_PointToAngle2 (actor->x,
790
				    actor->y,
791
				    actor->target->x,
792
				    actor->target->y);
793
 
794
    if (actor->target->flags & MF_SHADOW)
795
	actor->angle += (P_Random()-P_Random())<<21;
796
}
797
 
798
 
799
//
800
// A_PosAttack
801
//
802
void A_PosAttack (mobj_t* actor)
803
{
804
    int		angle;
805
    int		damage;
806
    int		slope;
807
 
808
    if (!actor->target)
809
	return;
810
 
811
    A_FaceTarget (actor);
812
    angle = actor->angle;
813
    slope = P_AimLineAttack (actor, angle, MISSILERANGE);
814
 
815
    S_StartSound (actor, sfx_pistol);
816
    angle += (P_Random()-P_Random())<<20;
817
    damage = ((P_Random()%5)+1)*3;
818
    P_LineAttack (actor, angle, MISSILERANGE, slope, damage);
819
}
820
 
821
void A_SPosAttack (mobj_t* actor)
822
{
823
    int		i;
824
    int		angle;
825
    int		bangle;
826
    int		damage;
827
    int		slope;
828
 
829
    if (!actor->target)
830
	return;
831
 
832
    S_StartSound (actor, sfx_shotgn);
833
    A_FaceTarget (actor);
834
    bangle = actor->angle;
835
    slope = P_AimLineAttack (actor, bangle, MISSILERANGE);
836
 
837
    for (i=0 ; i<3 ; i++)
838
    {
839
	angle = bangle + ((P_Random()-P_Random())<<20);
840
	damage = ((P_Random()%5)+1)*3;
841
	P_LineAttack (actor, angle, MISSILERANGE, slope, damage);
842
    }
843
}
844
 
845
void A_CPosAttack (mobj_t* actor)
846
{
847
    int		angle;
848
    int		bangle;
849
    int		damage;
850
    int		slope;
851
 
852
    if (!actor->target)
853
	return;
854
 
855
    S_StartSound (actor, sfx_shotgn);
856
    A_FaceTarget (actor);
857
    bangle = actor->angle;
858
    slope = P_AimLineAttack (actor, bangle, MISSILERANGE);
859
 
860
    angle = bangle + ((P_Random()-P_Random())<<20);
861
    damage = ((P_Random()%5)+1)*3;
862
    P_LineAttack (actor, angle, MISSILERANGE, slope, damage);
863
}
864
 
865
void A_CPosRefire (mobj_t* actor)
866
{
867
    // keep firing unless target got out of sight
868
    A_FaceTarget (actor);
869
 
870
    if (P_Random () < 40)
871
	return;
872
 
873
    if (!actor->target
874
	|| actor->target->health <= 0
875
	|| !P_CheckSight (actor, actor->target) )
876
    {
877
	P_SetMobjState (actor, actor->info->seestate);
878
    }
879
}
880
 
881
 
882
void A_SpidRefire (mobj_t* actor)
883
{
884
    // keep firing unless target got out of sight
885
    A_FaceTarget (actor);
886
 
887
    if (P_Random () < 10)
888
	return;
889
 
890
    if (!actor->target
891
	|| actor->target->health <= 0
892
	|| !P_CheckSight (actor, actor->target) )
893
    {
894
	P_SetMobjState (actor, actor->info->seestate);
895
    }
896
}
897
 
898
void A_BspiAttack (mobj_t *actor)
899
{
900
    if (!actor->target)
901
	return;
902
 
903
    A_FaceTarget (actor);
904
 
905
    // launch a missile
906
    P_SpawnMissile (actor, actor->target, MT_ARACHPLAZ);
907
}
908
 
909
 
910
//
911
// A_TroopAttack
912
//
913
void A_TroopAttack (mobj_t* actor)
914
{
915
    int		damage;
916
 
917
    if (!actor->target)
918
	return;
919
 
920
    A_FaceTarget (actor);
921
    if (P_CheckMeleeRange (actor))
922
    {
923
	S_StartSound (actor, sfx_claw);
924
	damage = (P_Random()%8+1)*3;
925
	P_DamageMobj (actor->target, actor, actor, damage);
926
	return;
927
    }
928
 
929
 
930
    // launch a missile
931
    P_SpawnMissile (actor, actor->target, MT_TROOPSHOT);
932
}
933
 
934
 
935
void A_SargAttack (mobj_t* actor)
936
{
937
    int		damage;
938
 
939
    if (!actor->target)
940
	return;
941
 
942
    A_FaceTarget (actor);
943
    if (P_CheckMeleeRange (actor))
944
    {
945
	damage = ((P_Random()%10)+1)*4;
946
	P_DamageMobj (actor->target, actor, actor, damage);
947
    }
948
}
949
 
950
void A_HeadAttack (mobj_t* actor)
951
{
952
    int		damage;
953
 
954
    if (!actor->target)
955
	return;
956
 
957
    A_FaceTarget (actor);
958
    if (P_CheckMeleeRange (actor))
959
    {
960
	damage = (P_Random()%6+1)*10;
961
	P_DamageMobj (actor->target, actor, actor, damage);
962
	return;
963
    }
964
 
965
    // launch a missile
966
    P_SpawnMissile (actor, actor->target, MT_HEADSHOT);
967
}
968
 
969
void A_CyberAttack (mobj_t* actor)
970
{
971
    if (!actor->target)
972
	return;
973
 
974
    A_FaceTarget (actor);
975
    P_SpawnMissile (actor, actor->target, MT_ROCKET);
976
}
977
 
978
 
979
void A_BruisAttack (mobj_t* actor)
980
{
981
    int		damage;
982
 
983
    if (!actor->target)
984
	return;
985
 
986
    if (P_CheckMeleeRange (actor))
987
    {
988
	S_StartSound (actor, sfx_claw);
989
	damage = (P_Random()%8+1)*10;
990
	P_DamageMobj (actor->target, actor, actor, damage);
991
	return;
992
    }
993
 
994
    // launch a missile
995
    P_SpawnMissile (actor, actor->target, MT_BRUISERSHOT);
996
}
997
 
998
 
999
//
1000
// A_SkelMissile
1001
//
1002
void A_SkelMissile (mobj_t* actor)
1003
{
1004
    mobj_t*	mo;
1005
 
1006
    if (!actor->target)
1007
	return;
1008
 
1009
    A_FaceTarget (actor);
1010
    actor->z += 16*FRACUNIT;	// so missile spawns higher
1011
    mo = P_SpawnMissile (actor, actor->target, MT_TRACER);
1012
    actor->z -= 16*FRACUNIT;	// back to normal
1013
 
1014
    mo->x += mo->momx;
1015
    mo->y += mo->momy;
1016
    mo->tracer = actor->target;
1017
}
1018
 
1019
int	TRACEANGLE = 0xc000000;
1020
 
1021
void A_Tracer (mobj_t* actor)
1022
{
1023
    angle_t	exact;
1024
    fixed_t	dist;
1025
    fixed_t	slope;
1026
    mobj_t*	dest;
1027
    mobj_t*	th;
1028
 
1029
    if (gametic & 3)
1030
	return;
1031
 
1032
    // spawn a puff of smoke behind the rocket
1033
    P_SpawnPuff (actor->x, actor->y, actor->z);
1034
 
1035
    th = P_SpawnMobj (actor->x-actor->momx,
1036
		      actor->y-actor->momy,
1037
		      actor->z, MT_SMOKE);
1038
 
1039
    th->momz = FRACUNIT;
1040
    th->tics -= P_Random()&3;
1041
    if (th->tics < 1)
1042
	th->tics = 1;
1043
 
1044
    // adjust direction
1045
    dest = actor->tracer;
1046
 
1047
    if (!dest || dest->health <= 0)
1048
	return;
1049
 
1050
    // change angle
1051
    exact = R_PointToAngle2 (actor->x,
1052
			     actor->y,
1053
			     dest->x,
1054
			     dest->y);
1055
 
1056
    if (exact != actor->angle)
1057
    {
1058
	if (exact - actor->angle > 0x80000000)
1059
	{
1060
	    actor->angle -= TRACEANGLE;
1061
	    if (exact - actor->angle < 0x80000000)
1062
		actor->angle = exact;
1063
	}
1064
	else
1065
	{
1066
	    actor->angle += TRACEANGLE;
1067
	    if (exact - actor->angle > 0x80000000)
1068
		actor->angle = exact;
1069
	}
1070
    }
1071
 
1072
    exact = actor->angle>>ANGLETOFINESHIFT;
1073
    actor->momx = FixedMul (actor->info->speed, finecosine[exact]);
1074
    actor->momy = FixedMul (actor->info->speed, finesine[exact]);
1075
 
1076
    // change slope
1077
    dist = P_AproxDistance (dest->x - actor->x,
1078
			    dest->y - actor->y);
1079
 
1080
    dist = dist / actor->info->speed;
1081
 
1082
    if (dist < 1)
1083
	dist = 1;
1084
    slope = (dest->z+40*FRACUNIT - actor->z) / dist;
1085
 
1086
    if (slope < actor->momz)
1087
	actor->momz -= FRACUNIT/8;
1088
    else
1089
	actor->momz += FRACUNIT/8;
1090
}
1091
 
1092
 
1093
void A_SkelWhoosh (mobj_t*	actor)
1094
{
1095
    if (!actor->target)
1096
	return;
1097
    A_FaceTarget (actor);
1098
    S_StartSound (actor,sfx_skeswg);
1099
}
1100
 
1101
void A_SkelFist (mobj_t*	actor)
1102
{
1103
    int		damage;
1104
 
1105
    if (!actor->target)
1106
	return;
1107
 
1108
    A_FaceTarget (actor);
1109
 
1110
    if (P_CheckMeleeRange (actor))
1111
    {
1112
	damage = ((P_Random()%10)+1)*6;
1113
	S_StartSound (actor, sfx_skepch);
1114
	P_DamageMobj (actor->target, actor, actor, damage);
1115
    }
1116
}
1117
 
1118
 
1119
 
1120
//
1121
// PIT_VileCheck
1122
// Detect a corpse that could be raised.
1123
//
1124
mobj_t*		corpsehit;
1125
mobj_t*		vileobj;
1126
fixed_t		viletryx;
1127
fixed_t		viletryy;
1128
 
1129
boolean PIT_VileCheck (mobj_t*	thing)
1130
{
1131
    int		maxdist;
1132
    boolean	check;
1133
 
1134
    if (!(thing->flags & MF_CORPSE) )
1135
	return true;	// not a monster
1136
 
1137
    if (thing->tics != -1)
1138
	return true;	// not lying still yet
1139
 
1140
    if (thing->info->raisestate == S_NULL)
1141
	return true;	// monster doesn't have a raise state
1142
 
1143
    maxdist = thing->info->radius + mobjinfo[MT_VILE].radius;
1144
 
1145
    if ( abs(thing->x - viletryx) > maxdist
1146
	 || abs(thing->y - viletryy) > maxdist )
1147
	return true;		// not actually touching
1148
 
1149
    corpsehit = thing;
1150
    corpsehit->momx = corpsehit->momy = 0;
1151
    corpsehit->height <<= 2;
1152
    check = P_CheckPosition (corpsehit, corpsehit->x, corpsehit->y);
1153
    corpsehit->height >>= 2;
1154
 
1155
    if (!check)
1156
	return true;		// doesn't fit here
1157
 
1158
    return false;		// got one, so stop checking
1159
}
1160
 
1161
 
1162
 
1163
//
1164
// A_VileChase
1165
// Check for ressurecting a body
1166
//
1167
void A_VileChase (mobj_t* actor)
1168
{
1169
    int			xl;
1170
    int			xh;
1171
    int			yl;
1172
    int			yh;
1173
 
1174
    int			bx;
1175
    int			by;
1176
 
1177
    mobjinfo_t*		info;
1178
    mobj_t*		temp;
1179
 
1180
    if (actor->movedir != DI_NODIR)
1181
    {
1182
	// check for corpses to raise
1183
	viletryx =
1184
	    actor->x + actor->info->speed*xspeed[actor->movedir];
1185
	viletryy =
1186
	    actor->y + actor->info->speed*yspeed[actor->movedir];
1187
 
1188
	xl = (viletryx - bmaporgx - MAXRADIUS*2)>>MAPBLOCKSHIFT;
1189
	xh = (viletryx - bmaporgx + MAXRADIUS*2)>>MAPBLOCKSHIFT;
1190
	yl = (viletryy - bmaporgy - MAXRADIUS*2)>>MAPBLOCKSHIFT;
1191
	yh = (viletryy - bmaporgy + MAXRADIUS*2)>>MAPBLOCKSHIFT;
1192
 
1193
	vileobj = actor;
1194
	for (bx=xl ; bx<=xh ; bx++)
1195
	{
1196
	    for (by=yl ; by<=yh ; by++)
1197
	    {
1198
		// Call PIT_VileCheck to check
1199
		// whether object is a corpse
1200
		// that canbe raised.
1201
		if (!P_BlockThingsIterator(bx,by,PIT_VileCheck))
1202
		{
1203
		    // got one!
1204
		    temp = actor->target;
1205
		    actor->target = corpsehit;
1206
		    A_FaceTarget (actor);
1207
		    actor->target = temp;
1208
 
1209
		    P_SetMobjState (actor, S_VILE_HEAL1);
1210
		    S_StartSound (corpsehit, sfx_slop);
1211
		    info = corpsehit->info;
1212
 
1213
		    P_SetMobjState (corpsehit,info->raisestate);
1214
		    corpsehit->height <<= 2;
1215
		    corpsehit->flags = info->flags;
1216
		    corpsehit->health = info->spawnhealth;
1217
		    corpsehit->target = NULL;
1218
 
1219
		    return;
1220
		}
1221
	    }
1222
	}
1223
    }
1224
 
1225
    // Return to normal attack.
1226
    A_Chase (actor);
1227
}
1228
 
1229
 
1230
//
1231
// A_VileStart
1232
//
1233
void A_VileStart (mobj_t* actor)
1234
{
1235
    S_StartSound (actor, sfx_vilatk);
1236
}
1237
 
1238
 
1239
//
1240
// A_Fire
1241
// Keep fire in front of player unless out of sight
1242
//
1243
void A_Fire (mobj_t* actor);
1244
 
1245
void A_StartFire (mobj_t* actor)
1246
{
1247
    S_StartSound(actor,sfx_flamst);
1248
    A_Fire(actor);
1249
}
1250
 
1251
void A_FireCrackle (mobj_t* actor)
1252
{
1253
    S_StartSound(actor,sfx_flame);
1254
    A_Fire(actor);
1255
}
1256
 
1257
void A_Fire (mobj_t* actor)
1258
{
1259
    mobj_t*	dest;
1260
    unsigned	an;
1261
 
1262
    dest = actor->tracer;
1263
    if (!dest)
1264
	return;
1265
 
1266
    // don't move it if the vile lost sight
1267
    if (!P_CheckSight (actor->target, dest) )
1268
	return;
1269
 
1270
    an = dest->angle >> ANGLETOFINESHIFT;
1271
 
1272
    P_UnsetThingPosition (actor);
1273
    actor->x = dest->x + FixedMul (24*FRACUNIT, finecosine[an]);
1274
    actor->y = dest->y + FixedMul (24*FRACUNIT, finesine[an]);
1275
    actor->z = dest->z;
1276
    P_SetThingPosition (actor);
1277
}
1278
 
1279
 
1280
 
1281
//
1282
// A_VileTarget
1283
// Spawn the hellfire
1284
//
1285
void A_VileTarget (mobj_t*	actor)
1286
{
1287
    mobj_t*	fog;
1288
 
1289
    if (!actor->target)
1290
	return;
1291
 
1292
    A_FaceTarget (actor);
1293
 
1294
    fog = P_SpawnMobj (actor->target->x,
1295
		       actor->target->x,
1296
		       actor->target->z, MT_FIRE);
1297
 
1298
    actor->tracer = fog;
1299
    fog->target = actor;
1300
    fog->tracer = actor->target;
1301
    A_Fire (fog);
1302
}
1303
 
1304
 
1305
 
1306
 
1307
//
1308
// A_VileAttack
1309
//
1310
void A_VileAttack (mobj_t* actor)
1311
{
1312
    mobj_t*	fire;
1313
    int		an;
1314
 
1315
    if (!actor->target)
1316
	return;
1317
 
1318
    A_FaceTarget (actor);
1319
 
1320
    if (!P_CheckSight (actor, actor->target) )
1321
	return;
1322
 
1323
    S_StartSound (actor, sfx_barexp);
1324
    P_DamageMobj (actor->target, actor, actor, 20);
1325
    actor->target->momz = 1000*FRACUNIT/actor->target->info->mass;
1326
 
1327
    an = actor->angle >> ANGLETOFINESHIFT;
1328
 
1329
    fire = actor->tracer;
1330
 
1331
    if (!fire)
1332
	return;
1333
 
1334
    // move the fire between the vile and the player
1335
    fire->x = actor->target->x - FixedMul (24*FRACUNIT, finecosine[an]);
1336
    fire->y = actor->target->y - FixedMul (24*FRACUNIT, finesine[an]);
1337
    P_RadiusAttack (fire, actor, 70 );
1338
}
1339
 
1340
 
1341
 
1342
 
1343
//
1344
// Mancubus attack,
1345
// firing three missiles (bruisers)
1346
// in three different directions?
1347
// Doesn't look like it.
1348
//
1349
#define	FATSPREAD	(ANG90/8)
1350
 
1351
void A_FatRaise (mobj_t *actor)
1352
{
1353
    A_FaceTarget (actor);
1354
    S_StartSound (actor, sfx_manatk);
1355
}
1356
 
1357
 
1358
void A_FatAttack1 (mobj_t* actor)
1359
{
1360
    mobj_t*	mo;
1361
    int		an;
1362
 
1363
    A_FaceTarget (actor);
1364
    // Change direction  to ...
1365
    actor->angle += FATSPREAD;
1366
    P_SpawnMissile (actor, actor->target, MT_FATSHOT);
1367
 
1368
    mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT);
1369
    mo->angle += FATSPREAD;
1370
    an = mo->angle >> ANGLETOFINESHIFT;
1371
    mo->momx = FixedMul (mo->info->speed, finecosine[an]);
1372
    mo->momy = FixedMul (mo->info->speed, finesine[an]);
1373
}
1374
 
1375
void A_FatAttack2 (mobj_t* actor)
1376
{
1377
    mobj_t*	mo;
1378
    int		an;
1379
 
1380
    A_FaceTarget (actor);
1381
    // Now here choose opposite deviation.
1382
    actor->angle -= FATSPREAD;
1383
    P_SpawnMissile (actor, actor->target, MT_FATSHOT);
1384
 
1385
    mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT);
1386
    mo->angle -= FATSPREAD*2;
1387
    an = mo->angle >> ANGLETOFINESHIFT;
1388
    mo->momx = FixedMul (mo->info->speed, finecosine[an]);
1389
    mo->momy = FixedMul (mo->info->speed, finesine[an]);
1390
}
1391
 
1392
void A_FatAttack3 (mobj_t*	actor)
1393
{
1394
    mobj_t*	mo;
1395
    int		an;
1396
 
1397
    A_FaceTarget (actor);
1398
 
1399
    mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT);
1400
    mo->angle -= FATSPREAD/2;
1401
    an = mo->angle >> ANGLETOFINESHIFT;
1402
    mo->momx = FixedMul (mo->info->speed, finecosine[an]);
1403
    mo->momy = FixedMul (mo->info->speed, finesine[an]);
1404
 
1405
    mo = P_SpawnMissile (actor, actor->target, MT_FATSHOT);
1406
    mo->angle += FATSPREAD/2;
1407
    an = mo->angle >> ANGLETOFINESHIFT;
1408
    mo->momx = FixedMul (mo->info->speed, finecosine[an]);
1409
    mo->momy = FixedMul (mo->info->speed, finesine[an]);
1410
}
1411
 
1412
 
1413
//
1414
// SkullAttack
1415
// Fly at the player like a missile.
1416
//
1417
#define	SKULLSPEED		(20*FRACUNIT)
1418
 
1419
void A_SkullAttack (mobj_t* actor)
1420
{
1421
    mobj_t*		dest;
1422
    angle_t		an;
1423
    int			dist;
1424
 
1425
    if (!actor->target)
1426
	return;
1427
 
1428
    dest = actor->target;
1429
    actor->flags |= MF_SKULLFLY;
1430
 
1431
    S_StartSound (actor, actor->info->attacksound);
1432
    A_FaceTarget (actor);
1433
    an = actor->angle >> ANGLETOFINESHIFT;
1434
    actor->momx = FixedMul (SKULLSPEED, finecosine[an]);
1435
    actor->momy = FixedMul (SKULLSPEED, finesine[an]);
1436
    dist = P_AproxDistance (dest->x - actor->x, dest->y - actor->y);
1437
    dist = dist / SKULLSPEED;
1438
 
1439
    if (dist < 1)
1440
	dist = 1;
1441
    actor->momz = (dest->z+(dest->height>>1) - actor->z) / dist;
1442
}
1443
 
1444
 
1445
//
1446
// A_PainShootSkull
1447
// Spawn a lost soul and launch it at the target
1448
//
1449
void
1450
A_PainShootSkull
1451
( mobj_t*	actor,
1452
  angle_t	angle )
1453
{
1454
    fixed_t	x;
1455
    fixed_t	y;
1456
    fixed_t	z;
1457
 
1458
    mobj_t*	newmobj;
1459
    angle_t	an;
1460
    int		prestep;
1461
    int		count;
1462
    thinker_t*	currentthinker;
1463
 
1464
    // count total number of skull currently on the level
1465
    count = 0;
1466
 
1467
    currentthinker = thinkercap.next;
1468
    while (currentthinker != &thinkercap)
1469
    {
1470
	if (   (currentthinker->function.acp1 == (actionf_p1)P_MobjThinker)
1471
	    && ((mobj_t *)currentthinker)->type == MT_SKULL)
1472
	    count++;
1473
	currentthinker = currentthinker->next;
1474
    }
1475
 
1476
    // if there are allready 20 skulls on the level,
1477
    // don't spit another one
1478
    if (count > 20)
1479
	return;
1480
 
1481
 
1482
    // okay, there's playe for another one
1483
    an = angle >> ANGLETOFINESHIFT;
1484
 
1485
    prestep =
1486
	4*FRACUNIT
1487
	+ 3*(actor->info->radius + mobjinfo[MT_SKULL].radius)/2;
1488
 
1489
    x = actor->x + FixedMul (prestep, finecosine[an]);
1490
    y = actor->y + FixedMul (prestep, finesine[an]);
1491
    z = actor->z + 8*FRACUNIT;
1492
 
1493
    newmobj = P_SpawnMobj (x , y, z, MT_SKULL);
1494
 
1495
    // Check for movements.
1496
    if (!P_TryMove (newmobj, newmobj->x, newmobj->y))
1497
    {
1498
	// kill it immediately
1499
	P_DamageMobj (newmobj,actor,actor,10000);
1500
	return;
1501
    }
1502
 
1503
    newmobj->target = actor->target;
1504
    A_SkullAttack (newmobj);
1505
}
1506
 
1507
 
1508
//
1509
// A_PainAttack
1510
// Spawn a lost soul and launch it at the target
1511
//
1512
void A_PainAttack (mobj_t* actor)
1513
{
1514
    if (!actor->target)
1515
	return;
1516
 
1517
    A_FaceTarget (actor);
1518
    A_PainShootSkull (actor, actor->angle);
1519
}
1520
 
1521
 
1522
void A_PainDie (mobj_t* actor)
1523
{
1524
    A_Fall (actor);
1525
    A_PainShootSkull (actor, actor->angle+ANG90);
1526
    A_PainShootSkull (actor, actor->angle+ANG180);
1527
    A_PainShootSkull (actor, actor->angle+ANG270);
1528
}
1529
 
1530
 
1531
 
1532
 
1533
 
1534
 
1535
void A_Scream (mobj_t* actor)
1536
{
1537
    int		sound;
1538
 
1539
    switch (actor->info->deathsound)
1540
    {
1541
      case 0:
1542
	return;
1543
 
1544
      case sfx_podth1:
1545
      case sfx_podth2:
1546
      case sfx_podth3:
1547
	sound = sfx_podth1 + P_Random ()%3;
1548
	break;
1549
 
1550
      case sfx_bgdth1:
1551
      case sfx_bgdth2:
1552
	sound = sfx_bgdth1 + P_Random ()%2;
1553
	break;
1554
 
1555
      default:
1556
	sound = actor->info->deathsound;
1557
	break;
1558
    }
1559
 
1560
    // Check for bosses.
1561
    if (actor->type==MT_SPIDER
1562
	|| actor->type == MT_CYBORG)
1563
    {
1564
	// full volume
1565
	S_StartSound (NULL, sound);
1566
    }
1567
    else
1568
	S_StartSound (actor, sound);
1569
}
1570
 
1571
 
1572
void A_XScream (mobj_t* actor)
1573
{
1574
    S_StartSound (actor, sfx_slop);
1575
}
1576
 
1577
void A_Pain (mobj_t* actor)
1578
{
1579
    if (actor->info->painsound)
1580
	S_StartSound (actor, actor->info->painsound);
1581
}
1582
 
1583
 
1584
 
1585
void A_Fall (mobj_t *actor)
1586
{
1587
    // actor is on ground, it can be walked over
1588
    actor->flags &= ~MF_SOLID;
1589
 
1590
    // So change this if corpse objects
1591
    // are meant to be obstacles.
1592
}
1593
 
1594
 
1595
//
1596
// A_Explode
1597
//
1598
void A_Explode (mobj_t* thingy)
1599
{
1600
    P_RadiusAttack ( thingy, thingy->target, 128 );
1601
}
1602
 
1603
 
1604
//
1605
// A_BossDeath
1606
// Possibly trigger special effects
1607
// if on first boss level
1608
//
1609
void A_BossDeath (mobj_t* mo)
1610
{
1611
    thinker_t*	th;
1612
    mobj_t*	mo2;
1613
    line_t	junk;
1614
    int		i;
1615
 
1616
    if ( gamemode == commercial)
1617
    {
1618
	if (gamemap != 7)
1619
	    return;
1620
 
1621
	if ((mo->type != MT_FATSO)
1622
	    && (mo->type != MT_BABY))
1623
	    return;
1624
    }
1625
    else
1626
    {
1627
	switch(gameepisode)
1628
	{
1629
	  case 1:
1630
	    if (gamemap != 8)
1631
		return;
1632
 
1633
	    if (mo->type != MT_BRUISER)
1634
		return;
1635
	    break;
1636
 
1637
	  case 2:
1638
	    if (gamemap != 8)
1639
		return;
1640
 
1641
	    if (mo->type != MT_CYBORG)
1642
		return;
1643
	    break;
1644
 
1645
	  case 3:
1646
	    if (gamemap != 8)
1647
		return;
1648
 
1649
	    if (mo->type != MT_SPIDER)
1650
		return;
1651
 
1652
	    break;
1653
 
1654
	  case 4:
1655
	    switch(gamemap)
1656
	    {
1657
	      case 6:
1658
		if (mo->type != MT_CYBORG)
1659
		    return;
1660
		break;
1661
 
1662
	      case 8:
1663
		if (mo->type != MT_SPIDER)
1664
		    return;
1665
		break;
1666
 
1667
	      default:
1668
		return;
1669
		break;
1670
	    }
1671
	    break;
1672
 
1673
	  default:
1674
	    if (gamemap != 8)
1675
		return;
1676
	    break;
1677
	}
1678
 
1679
    }
1680
 
1681
 
1682
    // make sure there is a player alive for victory
1683
    for (i=0 ; i
1684
	if (playeringame[i] && players[i].health > 0)
1685
	    break;
1686
 
1687
    if (i==MAXPLAYERS)
1688
	return;	// no one left alive, so do not end game
1689
 
1690
    // scan the remaining thinkers to see
1691
    // if all bosses are dead
1692
    for (th = thinkercap.next ; th != &thinkercap ; th=th->next)
1693
    {
1694
	if (th->function.acp1 != (actionf_p1)P_MobjThinker)
1695
	    continue;
1696
 
1697
	mo2 = (mobj_t *)th;
1698
	if (mo2 != mo
1699
	    && mo2->type == mo->type
1700
	    && mo2->health > 0)
1701
	{
1702
	    // other boss not dead
1703
	    return;
1704
	}
1705
    }
1706
 
1707
    // victory!
1708
    if ( gamemode == commercial)
1709
    {
1710
	if (gamemap == 7)
1711
	{
1712
	    if (mo->type == MT_FATSO)
1713
	    {
1714
		junk.tag = 666;
1715
		EV_DoFloor(&junk,lowerFloorToLowest);
1716
		return;
1717
	    }
1718
 
1719
	    if (mo->type == MT_BABY)
1720
	    {
1721
		junk.tag = 667;
1722
		EV_DoFloor(&junk,raiseToTexture);
1723
		return;
1724
	    }
1725
	}
1726
    }
1727
    else
1728
    {
1729
	switch(gameepisode)
1730
	{
1731
	  case 1:
1732
	    junk.tag = 666;
1733
	    EV_DoFloor (&junk, lowerFloorToLowest);
1734
	    return;
1735
	    break;
1736
 
1737
	  case 4:
1738
	    switch(gamemap)
1739
	    {
1740
	      case 6:
1741
		junk.tag = 666;
1742
		EV_DoDoor (&junk, blazeOpen);
1743
		return;
1744
		break;
1745
 
1746
	      case 8:
1747
		junk.tag = 666;
1748
		EV_DoFloor (&junk, lowerFloorToLowest);
1749
		return;
1750
		break;
1751
	    }
1752
	}
1753
    }
1754
 
1755
    G_ExitLevel ();
1756
}
1757
 
1758
 
1759
void A_Hoof (mobj_t* mo)
1760
{
1761
    S_StartSound (mo, sfx_hoof);
1762
    A_Chase (mo);
1763
}
1764
 
1765
void A_Metal (mobj_t* mo)
1766
{
1767
    S_StartSound (mo, sfx_metal);
1768
    A_Chase (mo);
1769
}
1770
 
1771
void A_BabyMetal (mobj_t* mo)
1772
{
1773
    S_StartSound (mo, sfx_bspwlk);
1774
    A_Chase (mo);
1775
}
1776
 
1777
void
1778
A_OpenShotgun2
1779
( player_t*	player,
1780
  pspdef_t*	psp )
1781
{
1782
    S_StartSound (player->mo, sfx_dbopn);
1783
}
1784
 
1785
void
1786
A_LoadShotgun2
1787
( player_t*	player,
1788
  pspdef_t*	psp )
1789
{
1790
    S_StartSound (player->mo, sfx_dbload);
1791
}
1792
 
1793
void
1794
A_ReFire
1795
( player_t*	player,
1796
  pspdef_t*	psp );
1797
 
1798
void
1799
A_CloseShotgun2
1800
( player_t*	player,
1801
  pspdef_t*	psp )
1802
{
1803
    S_StartSound (player->mo, sfx_dbcls);
1804
    A_ReFire(player,psp);
1805
}
1806
 
1807
 
1808
 
1809
mobj_t*		braintargets[32];
1810
int		numbraintargets;
1811
int		braintargeton;
1812
 
1813
void A_BrainAwake (mobj_t* mo)
1814
{
1815
    thinker_t*	thinker;
1816
    mobj_t*	m;
1817
 
1818
    // find all the target spots
1819
    numbraintargets = 0;
1820
    braintargeton = 0;
1821
 
1822
    thinker = thinkercap.next;
1823
    for (thinker = thinkercap.next ;
1824
	 thinker != &thinkercap ;
1825
	 thinker = thinker->next)
1826
    {
1827
	if (thinker->function.acp1 != (actionf_p1)P_MobjThinker)
1828
	    continue;	// not a mobj
1829
 
1830
	m = (mobj_t *)thinker;
1831
 
1832
	if (m->type == MT_BOSSTARGET )
1833
	{
1834
	    braintargets[numbraintargets] = m;
1835
	    numbraintargets++;
1836
	}
1837
    }
1838
 
1839
    S_StartSound (NULL,sfx_bossit);
1840
}
1841
 
1842
 
1843
void A_BrainPain (mobj_t*	mo)
1844
{
1845
    S_StartSound (NULL,sfx_bospn);
1846
}
1847
 
1848
 
1849
void A_BrainScream (mobj_t*	mo)
1850
{
1851
    int		x;
1852
    int		y;
1853
    int		z;
1854
    mobj_t*	th;
1855
 
1856
    for (x=mo->x - 196*FRACUNIT ; x< mo->x + 320*FRACUNIT ; x+= FRACUNIT*8)
1857
    {
1858
	y = mo->y - 320*FRACUNIT;
1859
	z = 128 + P_Random()*2*FRACUNIT;
1860
	th = P_SpawnMobj (x,y,z, MT_ROCKET);
1861
	th->momz = P_Random()*512;
1862
 
1863
	P_SetMobjState (th, S_BRAINEXPLODE1);
1864
 
1865
	th->tics -= P_Random()&7;
1866
	if (th->tics < 1)
1867
	    th->tics = 1;
1868
    }
1869
 
1870
    S_StartSound (NULL,sfx_bosdth);
1871
}
1872
 
1873
 
1874
 
1875
void A_BrainExplode (mobj_t* mo)
1876
{
1877
    int		x;
1878
    int		y;
1879
    int		z;
1880
    mobj_t*	th;
1881
 
1882
    x = mo->x + (P_Random () - P_Random ())*2048;
1883
    y = mo->y;
1884
    z = 128 + P_Random()*2*FRACUNIT;
1885
    th = P_SpawnMobj (x,y,z, MT_ROCKET);
1886
    th->momz = P_Random()*512;
1887
 
1888
    P_SetMobjState (th, S_BRAINEXPLODE1);
1889
 
1890
    th->tics -= P_Random()&7;
1891
    if (th->tics < 1)
1892
	th->tics = 1;
1893
}
1894
 
1895
 
1896
void A_BrainDie (mobj_t*	mo)
1897
{
1898
    G_ExitLevel ();
1899
}
1900
 
1901
void A_BrainSpit (mobj_t*	mo)
1902
{
1903
    mobj_t*	targ;
1904
    mobj_t*	newmobj;
1905
 
1906
    static int	easy = 0;
1907
 
1908
    easy ^= 1;
1909
    if (gameskill <= sk_easy && (!easy))
1910
	return;
1911
 
1912
    // shoot a cube at current target
1913
    targ = braintargets[braintargeton];
1914
    braintargeton = (braintargeton+1)%numbraintargets;
1915
 
1916
    // spawn brain missile
1917
    newmobj = P_SpawnMissile (mo, targ, MT_SPAWNSHOT);
1918
    newmobj->target = targ;
1919
    newmobj->reactiontime =
1920
	((targ->y - mo->y)/newmobj->momy) / newmobj->state->tics;
1921
 
1922
    S_StartSound(NULL, sfx_bospit);
1923
}
1924
 
1925
 
1926
 
1927
void A_SpawnFly (mobj_t* mo);
1928
 
1929
// travelling cube sound
1930
void A_SpawnSound (mobj_t* mo)
1931
{
1932
    S_StartSound (mo,sfx_boscub);
1933
    A_SpawnFly(mo);
1934
}
1935
 
1936
void A_SpawnFly (mobj_t* mo)
1937
{
1938
    mobj_t*	newmobj;
1939
    mobj_t*	fog;
1940
    mobj_t*	targ;
1941
    int		r;
1942
    mobjtype_t	type;
1943
 
1944
    if (--mo->reactiontime)
1945
	return;	// still flying
1946
 
1947
    targ = mo->target;
1948
 
1949
    // First spawn teleport fog.
1950
    fog = P_SpawnMobj (targ->x, targ->y, targ->z, MT_SPAWNFIRE);
1951
    S_StartSound (fog, sfx_telept);
1952
 
1953
    // Randomly select monster to spawn.
1954
    r = P_Random ();
1955
 
1956
    // Probability distribution (kind of :),
1957
    // decreasing likelihood.
1958
    if ( r<50 )
1959
	type = MT_TROOP;
1960
    else if (r<90)
1961
	type = MT_SERGEANT;
1962
    else if (r<120)
1963
	type = MT_SHADOWS;
1964
    else if (r<130)
1965
	type = MT_PAIN;
1966
    else if (r<160)
1967
	type = MT_HEAD;
1968
    else if (r<162)
1969
	type = MT_VILE;
1970
    else if (r<172)
1971
	type = MT_UNDEAD;
1972
    else if (r<192)
1973
	type = MT_BABY;
1974
    else if (r<222)
1975
	type = MT_FATSO;
1976
    else if (r<246)
1977
	type = MT_KNIGHT;
1978
    else
1979
	type = MT_BRUISER;
1980
 
1981
    newmobj	= P_SpawnMobj (targ->x, targ->y, targ->z, type);
1982
    if (P_LookForPlayers (newmobj, true) )
1983
	P_SetMobjState (newmobj, newmobj->info->seestate);
1984
 
1985
    // telefrag anything in this spot
1986
    P_TeleportMove (newmobj, newmobj->x, newmobj->y);
1987
 
1988
    // remove self (i.e., cube).
1989
    P_RemoveMobj (mo);
1990
}
1991
 
1992
 
1993
 
1994
void A_PlayerScream (mobj_t* mo)
1995
{
1996
    // Default death sound.
1997
    int		sound = sfx_pldeth;
1998
 
1999
    if ( (gamemode == commercial)
2000
	&& 	(mo->health < -50))
2001
    {
2002
	// IF THE PLAYER DIES
2003
	// LESS THAN -50% WITHOUT GIBBING
2004
	sound = sfx_pdiehi;
2005
    }
2006
 
2007
    S_StartSound (mo, sound);
2008
}