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
//	Moving object handling. Spawn functions.
21
//
22
//-----------------------------------------------------------------------------
23
 
24
static const char
25
rcsid[] = "$Id: p_mobj.c,v 1.5 1997/02/03 22:45:12 b1 Exp $";
26
 
27
#include "i_system.h"
28
#include "z_zone.h"
29
#include "m_random.h"
30
 
31
#include "doomdef.h"
32
#include "p_local.h"
33
#include "sounds.h"
34
 
35
#include "st_stuff.h"
36
#include "hu_stuff.h"
37
 
38
#include "s_sound.h"
39
 
40
#include "doomstat.h"
41
 
42
 
43
void G_PlayerReborn (int player);
44
void P_SpawnMapThing (mapthing_t*	mthing);
45
 
46
 
47
//
48
// P_SetMobjState
49
// Returns true if the mobj is still present.
50
//
51
int test;
52
 
53
boolean
54
P_SetMobjState
55
( mobj_t*	mobj,
56
  statenum_t	state )
57
{
58
    state_t*	st;
59
 
60
    do
61
    {
62
	if (state == S_NULL)
63
	{
64
	    mobj->state = (state_t *) S_NULL;
65
	    P_RemoveMobj (mobj);
66
	    return false;
67
	}
68
 
69
	st = &states[state];
70
	mobj->state = st;
71
	mobj->tics = st->tics;
72
	mobj->sprite = st->sprite;
73
	mobj->frame = st->frame;
74
 
75
	// Modified handling.
76
	// Call action functions when the state is set
77
	if (st->action.acp1)
78
	    st->action.acp1(mobj);
79
 
80
	state = st->nextstate;
81
    } while (!mobj->tics);
82
 
83
    return true;
84
}
85
 
86
 
87
//
88
// P_ExplodeMissile
89
//
90
void P_ExplodeMissile (mobj_t* mo)
91
{
92
    mo->momx = mo->momy = mo->momz = 0;
93
 
94
    P_SetMobjState (mo, mobjinfo[mo->type].deathstate);
95
 
96
    mo->tics -= P_Random()&3;
97
 
98
    if (mo->tics < 1)
99
	mo->tics = 1;
100
 
101
    mo->flags &= ~MF_MISSILE;
102
 
103
    if (mo->info->deathsound)
104
	S_StartSound (mo, mo->info->deathsound);
105
}
106
 
107
 
108
//
109
// P_XYMovement
110
//
111
#define STOPSPEED		0x1000
112
#define FRICTION		0xe800
113
 
114
void P_XYMovement (mobj_t* mo)
115
{
116
    fixed_t 	ptryx;
117
    fixed_t	ptryy;
118
    player_t*	player;
119
    fixed_t	xmove;
120
    fixed_t	ymove;
121
 
122
    if (!mo->momx && !mo->momy)
123
    {
124
	if (mo->flags & MF_SKULLFLY)
125
	{
126
	    // the skull slammed into something
127
	    mo->flags &= ~MF_SKULLFLY;
128
	    mo->momx = mo->momy = mo->momz = 0;
129
 
130
	    P_SetMobjState (mo, mo->info->spawnstate);
131
	}
132
	return;
133
    }
134
 
135
    player = mo->player;
136
 
137
    if (mo->momx > MAXMOVE)
138
	mo->momx = MAXMOVE;
139
    else if (mo->momx < -MAXMOVE)
140
	mo->momx = -MAXMOVE;
141
 
142
    if (mo->momy > MAXMOVE)
143
	mo->momy = MAXMOVE;
144
    else if (mo->momy < -MAXMOVE)
145
	mo->momy = -MAXMOVE;
146
 
147
    xmove = mo->momx;
148
    ymove = mo->momy;
149
 
150
    do
151
    {
152
	if (xmove > MAXMOVE/2 || ymove > MAXMOVE/2)
153
	{
154
	    ptryx = mo->x + xmove/2;
155
	    ptryy = mo->y + ymove/2;
156
	    xmove >>= 1;
157
	    ymove >>= 1;
158
	}
159
	else
160
	{
161
	    ptryx = mo->x + xmove;
162
	    ptryy = mo->y + ymove;
163
	    xmove = ymove = 0;
164
	}
165
 
166
	if (!P_TryMove (mo, ptryx, ptryy))
167
	{
168
	    // blocked move
169
	    if (mo->player)
170
	    {	// try to slide along it
171
		P_SlideMove (mo);
172
	    }
173
	    else if (mo->flags & MF_MISSILE)
174
	    {
175
		// explode a missile
176
		if (ceilingline &&
177
		    ceilingline->backsector &&
178
		    ceilingline->backsector->ceilingpic == skyflatnum)
179
		{
180
		    // Hack to prevent missiles exploding
181
		    // against the sky.
182
		    // Does not handle sky floors.
183
		    P_RemoveMobj (mo);
184
		    return;
185
		}
186
		P_ExplodeMissile (mo);
187
	    }
188
	    else
189
		mo->momx = mo->momy = 0;
190
	}
191
    } while (xmove || ymove);
192
 
193
    // slow down
194
    if (player && player->cheats & CF_NOMOMENTUM)
195
    {
196
	// debug option for no sliding at all
197
	mo->momx = mo->momy = 0;
198
	return;
199
    }
200
 
201
    if (mo->flags & (MF_MISSILE | MF_SKULLFLY) )
202
	return; 	// no friction for missiles ever
203
 
204
    if (mo->z > mo->floorz)
205
	return;		// no friction when airborne
206
 
207
    if (mo->flags & MF_CORPSE)
208
    {
209
	// do not stop sliding
210
	//  if halfway off a step with some momentum
211
	if (mo->momx > FRACUNIT/4
212
	    || mo->momx < -FRACUNIT/4
213
	    || mo->momy > FRACUNIT/4
214
	    || mo->momy < -FRACUNIT/4)
215
	{
216
	    if (mo->floorz != mo->subsector->sector->floorheight)
217
		return;
218
	}
219
    }
220
 
221
    if (mo->momx > -STOPSPEED
222
	&& mo->momx < STOPSPEED
223
	&& mo->momy > -STOPSPEED
224
	&& mo->momy < STOPSPEED
225
	&& (!player
226
	    || (player->cmd.forwardmove== 0
227
		&& player->cmd.sidemove == 0 ) ) )
228
    {
229
	// if in a walking frame, stop moving
230
	if ( player&&(unsigned)((player->mo->state - states)- S_PLAY_RUN1) < 4)
231
	    P_SetMobjState (player->mo, S_PLAY);
232
 
233
	mo->momx = 0;
234
	mo->momy = 0;
235
    }
236
    else
237
    {
238
	mo->momx = FixedMul (mo->momx, FRICTION);
239
	mo->momy = FixedMul (mo->momy, FRICTION);
240
    }
241
}
242
 
243
//
244
// P_ZMovement
245
//
246
void P_ZMovement (mobj_t* mo)
247
{
248
    fixed_t	dist;
249
    fixed_t	delta;
250
 
251
    // check for smooth step up
252
    if (mo->player && mo->z < mo->floorz)
253
    {
254
	mo->player->viewheight -= mo->floorz-mo->z;
255
 
256
	mo->player->deltaviewheight
257
	    = (VIEWHEIGHT - mo->player->viewheight)>>3;
258
    }
259
 
260
    // adjust height
261
    mo->z += mo->momz;
262
 
263
    if ( mo->flags & MF_FLOAT
264
	 && mo->target)
265
    {
266
	// float down towards target if too close
267
	if ( !(mo->flags & MF_SKULLFLY)
268
	     && !(mo->flags & MF_INFLOAT) )
269
	{
270
	    dist = P_AproxDistance (mo->x - mo->target->x,
271
				    mo->y - mo->target->y);
272
 
273
	    delta =(mo->target->z + (mo->height>>1)) - mo->z;
274
 
275
	    if (delta<0 && dist < -(delta*3) )
276
		mo->z -= FLOATSPEED;
277
	    else if (delta>0 && dist < (delta*3) )
278
		mo->z += FLOATSPEED;
279
	}
280
 
281
    }
282
 
283
    // clip movement
284
    if (mo->z <= mo->floorz)
285
    {
286
	// hit the floor
287
 
288
	// Note (id):
289
	//  somebody left this after the setting momz to 0,
290
	//  kinda useless there.
291
	if (mo->flags & MF_SKULLFLY)
292
	{
293
	    // the skull slammed into something
294
	    mo->momz = -mo->momz;
295
	}
296
 
297
	if (mo->momz < 0)
298
	{
299
	    if (mo->player
300
		&& mo->momz < -GRAVITY*8)
301
	    {
302
		// Squat down.
303
		// Decrease viewheight for a moment
304
		// after hitting the ground (hard),
305
		// and utter appropriate sound.
306
		mo->player->deltaviewheight = mo->momz>>3;
307
		S_StartSound (mo, sfx_oof);
308
	    }
309
	    mo->momz = 0;
310
	}
311
	mo->z = mo->floorz;
312
 
313
	if ( (mo->flags & MF_MISSILE)
314
	     && !(mo->flags & MF_NOCLIP) )
315
	{
316
	    P_ExplodeMissile (mo);
317
	    return;
318
	}
319
    }
320
    else if (! (mo->flags & MF_NOGRAVITY) )
321
    {
322
	if (mo->momz == 0)
323
	    mo->momz = -GRAVITY*2;
324
	else
325
	    mo->momz -= GRAVITY;
326
    }
327
 
328
    if (mo->z + mo->height > mo->ceilingz)
329
    {
330
	// hit the ceiling
331
	if (mo->momz > 0)
332
	    mo->momz = 0;
333
	{
334
	    mo->z = mo->ceilingz - mo->height;
335
	}
336
 
337
	if (mo->flags & MF_SKULLFLY)
338
	{	// the skull slammed into something
339
	    mo->momz = -mo->momz;
340
	}
341
 
342
	if ( (mo->flags & MF_MISSILE)
343
	     && !(mo->flags & MF_NOCLIP) )
344
	{
345
	    P_ExplodeMissile (mo);
346
	    return;
347
	}
348
    }
349
}
350
 
351
 
352
 
353
//
354
// P_NightmareRespawn
355
//
356
void
357
P_NightmareRespawn (mobj_t* mobj)
358
{
359
    fixed_t		x;
360
    fixed_t		y;
361
    fixed_t		z;
362
    subsector_t*	ss;
363
    mobj_t*		mo;
364
    mapthing_t*		mthing;
365
 
366
    x = mobj->spawnpoint.x << FRACBITS;
367
    y = mobj->spawnpoint.y << FRACBITS;
368
 
369
    // somthing is occupying it's position?
370
    if (!P_CheckPosition (mobj, x, y) )
371
	return;	// no respwan
372
 
373
    // spawn a teleport fog at old spot
374
    // because of removal of the body?
375
    mo = P_SpawnMobj (mobj->x,
376
		      mobj->y,
377
		      mobj->subsector->sector->floorheight , MT_TFOG);
378
    // initiate teleport sound
379
    S_StartSound (mo, sfx_telept);
380
 
381
    // spawn a teleport fog at the new spot
382
    ss = R_PointInSubsector (x,y);
383
 
384
    mo = P_SpawnMobj (x, y, ss->sector->floorheight , MT_TFOG);
385
 
386
    S_StartSound (mo, sfx_telept);
387
 
388
    // spawn the new monster
389
    mthing = &mobj->spawnpoint;
390
 
391
    // spawn it
392
    if (mobj->info->flags & MF_SPAWNCEILING)
393
	z = ONCEILINGZ;
394
    else
395
	z = ONFLOORZ;
396
 
397
    // inherit attributes from deceased one
398
    mo = P_SpawnMobj (x,y,z, mobj->type);
399
    mo->spawnpoint = mobj->spawnpoint;
400
    mo->angle = ANG45 * (mthing->angle/45);
401
 
402
    if (mthing->options & MTF_AMBUSH)
403
	mo->flags |= MF_AMBUSH;
404
 
405
    mo->reactiontime = 18;
406
 
407
    // remove the old monster,
408
    P_RemoveMobj (mobj);
409
}
410
 
411
 
412
//
413
// P_MobjThinker
414
//
415
void P_MobjThinker (mobj_t* mobj)
416
{
417
    // momentum movement
418
    if (mobj->momx
419
	|| mobj->momy
420
	|| (mobj->flags&MF_SKULLFLY) )
421
    {
422
	P_XYMovement (mobj);
423
 
424
	// FIXME: decent NOP/NULL/Nil function pointer please.
425
	if (mobj->thinker.function.acv == (actionf_v) (-1))
426
	    return;		// mobj was removed
427
    }
428
    if ( (mobj->z != mobj->floorz)
429
	 || mobj->momz )
430
    {
431
	P_ZMovement (mobj);
432
 
433
	// FIXME: decent NOP/NULL/Nil function pointer please.
434
	if (mobj->thinker.function.acv == (actionf_v) (-1))
435
	    return;		// mobj was removed
436
    }
437
 
438
 
439
    // cycle through states,
440
    // calling action functions at transitions
441
    if (mobj->tics != -1)
442
    {
443
	mobj->tics--;
444
 
445
	// you can cycle through multiple states in a tic
446
	if (!mobj->tics)
447
	    if (!P_SetMobjState (mobj, mobj->state->nextstate) )
448
		return;		// freed itself
449
    }
450
    else
451
    {
452
	// check for nightmare respawn
453
	if (! (mobj->flags & MF_COUNTKILL) )
454
	    return;
455
 
456
	if (!respawnmonsters)
457
	    return;
458
 
459
	mobj->movecount++;
460
 
461
	if (mobj->movecount < 12*35)
462
	    return;
463
 
464
	if ( leveltime&31 )
465
	    return;
466
 
467
	if (P_Random () > 4)
468
	    return;
469
 
470
	P_NightmareRespawn (mobj);
471
    }
472
 
473
}
474
 
475
 
476
//
477
// P_SpawnMobj
478
//
479
mobj_t*
480
P_SpawnMobj
481
( fixed_t	x,
482
  fixed_t	y,
483
  fixed_t	z,
484
  mobjtype_t	type )
485
{
486
    mobj_t*	mobj;
487
    state_t*	st;
488
    mobjinfo_t*	info;
489
 
490
    mobj = Z_Malloc (sizeof(*mobj), PU_LEVEL, NULL);
491
    memset (mobj, 0, sizeof (*mobj));
492
    info = &mobjinfo[type];
493
 
494
    mobj->type = type;
495
    mobj->info = info;
496
    mobj->x = x;
497
    mobj->y = y;
498
    mobj->radius = info->radius;
499
    mobj->height = info->height;
500
    mobj->flags = info->flags;
501
    mobj->health = info->spawnhealth;
502
 
503
    if (gameskill != sk_nightmare)
504
	mobj->reactiontime = info->reactiontime;
505
 
506
    mobj->lastlook = P_Random () % MAXPLAYERS;
507
    // do not set the state with P_SetMobjState,
508
    // because action routines can not be called yet
509
    st = &states[info->spawnstate];
510
 
511
    mobj->state = st;
512
    mobj->tics = st->tics;
513
    mobj->sprite = st->sprite;
514
    mobj->frame = st->frame;
515
 
516
    // set subsector and/or block links
517
    P_SetThingPosition (mobj);
518
 
519
    mobj->floorz = mobj->subsector->sector->floorheight;
520
    mobj->ceilingz = mobj->subsector->sector->ceilingheight;
521
 
522
    if (z == ONFLOORZ)
523
	mobj->z = mobj->floorz;
524
    else if (z == ONCEILINGZ)
525
	mobj->z = mobj->ceilingz - mobj->info->height;
526
    else
527
	mobj->z = z;
528
 
529
    mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker;
530
 
531
    P_AddThinker (&mobj->thinker);
532
 
533
    return mobj;
534
}
535
 
536
 
537
//
538
// P_RemoveMobj
539
//
540
mapthing_t	itemrespawnque[ITEMQUESIZE];
541
int		itemrespawntime[ITEMQUESIZE];
542
int		iquehead;
543
int		iquetail;
544
 
545
 
546
void P_RemoveMobj (mobj_t* mobj)
547
{
548
    if ((mobj->flags & MF_SPECIAL)
549
	&& !(mobj->flags & MF_DROPPED)
550
	&& (mobj->type != MT_INV)
551
	&& (mobj->type != MT_INS))
552
    {
553
	itemrespawnque[iquehead] = mobj->spawnpoint;
554
	itemrespawntime[iquehead] = leveltime;
555
	iquehead = (iquehead+1)&(ITEMQUESIZE-1);
556
 
557
	// lose one off the end?
558
	if (iquehead == iquetail)
559
	    iquetail = (iquetail+1)&(ITEMQUESIZE-1);
560
    }
561
 
562
    // unlink from sector and block lists
563
    P_UnsetThingPosition (mobj);
564
 
565
    // stop any playing sound
566
    S_StopSound (mobj);
567
 
568
    // free block
569
    P_RemoveThinker ((thinker_t*)mobj);
570
}
571
 
572
 
573
 
574
 
575
//
576
// P_RespawnSpecials
577
//
578
void P_RespawnSpecials (void)
579
{
580
    fixed_t		x;
581
    fixed_t		y;
582
    fixed_t		z;
583
 
584
    subsector_t*	ss;
585
    mobj_t*		mo;
586
    mapthing_t*		mthing;
587
 
588
    int			i;
589
 
590
    // only respawn items in deathmatch
591
    if (deathmatch != 2)
592
	return;	//
593
 
594
    // nothing left to respawn?
595
    if (iquehead == iquetail)
596
	return;
597
 
598
    // wait at least 30 seconds
599
    if (leveltime - itemrespawntime[iquetail] < 30*35)
600
	return;
601
 
602
    mthing = &itemrespawnque[iquetail];
603
 
604
    x = mthing->x << FRACBITS;
605
    y = mthing->y << FRACBITS;
606
 
607
    // spawn a teleport fog at the new spot
608
    ss = R_PointInSubsector (x,y);
609
    mo = P_SpawnMobj (x, y, ss->sector->floorheight , MT_IFOG);
610
    S_StartSound (mo, sfx_itmbk);
611
 
612
    // find which type to spawn
613
    for (i=0 ; i< NUMMOBJTYPES ; i++)
614
    {
615
	if (mthing->type == mobjinfo[i].doomednum)
616
	    break;
617
    }
618
 
619
    // spawn it
620
    if (mobjinfo[i].flags & MF_SPAWNCEILING)
621
	z = ONCEILINGZ;
622
    else
623
	z = ONFLOORZ;
624
 
625
    mo = P_SpawnMobj (x,y,z, i);
626
    mo->spawnpoint = *mthing;
627
    mo->angle = ANG45 * (mthing->angle/45);
628
 
629
    // pull it from the que
630
    iquetail = (iquetail+1)&(ITEMQUESIZE-1);
631
}
632
 
633
 
634
 
635
 
636
//
637
// P_SpawnPlayer
638
// Called when a player is spawned on the level.
639
// Most of the player structure stays unchanged
640
//  between levels.
641
//
642
void P_SpawnPlayer (mapthing_t* mthing)
643
{
644
    player_t*		p;
645
    fixed_t		x;
646
    fixed_t		y;
647
    fixed_t		z;
648
 
649
    mobj_t*		mobj;
650
 
651
    int			i;
652
 
653
    // not playing?
654
    if (!playeringame[mthing->type-1])
655
	return;
656
 
657
    p = &players[mthing->type-1];
658
 
659
    if (p->playerstate == PST_REBORN)
660
	G_PlayerReborn (mthing->type-1);
661
 
662
    x 		= mthing->x << FRACBITS;
663
    y 		= mthing->y << FRACBITS;
664
    z		= ONFLOORZ;
665
    mobj	= P_SpawnMobj (x,y,z, MT_PLAYER);
666
 
667
    // set color translations for player sprites
668
    if (mthing->type > 1)
669
	mobj->flags |= (mthing->type-1)<
670
 
671
    mobj->angle	= ANG45 * (mthing->angle/45);
672
    mobj->player = p;
673
    mobj->health = p->health;
674
 
675
    p->mo = mobj;
676
    p->playerstate = PST_LIVE;
677
    p->refire = 0;
678
    p->message = NULL;
679
    p->damagecount = 0;
680
    p->bonuscount = 0;
681
    p->extralight = 0;
682
    p->fixedcolormap = 0;
683
    p->viewheight = VIEWHEIGHT;
684
 
685
    // setup gun psprite
686
    P_SetupPsprites (p);
687
 
688
    // give all cards in death match mode
689
    if (deathmatch)
690
	for (i=0 ; i
691
	    p->cards[i] = true;
692
 
693
    if (mthing->type-1 == consoleplayer)
694
    {
695
	// wake up the status bar
696
	ST_Start ();
697
	// wake up the heads up text
698
	HU_Start ();
699
    }
700
}
701
 
702
 
703
//
704
// P_SpawnMapThing
705
// The fields of the mapthing should
706
// already be in host byte order.
707
//
708
void P_SpawnMapThing (mapthing_t* mthing)
709
{
710
    int			i;
711
    int			bit;
712
    mobj_t*		mobj;
713
    fixed_t		x;
714
    fixed_t		y;
715
    fixed_t		z;
716
 
717
    // count deathmatch start positions
718
    if (mthing->type == 11)
719
    {
720
	if (deathmatch_p < &deathmatchstarts[10])
721
	{
722
	    memcpy (deathmatch_p, mthing, sizeof(*mthing));
723
	    deathmatch_p++;
724
	}
725
	return;
726
    }
727
 
728
    // check for players specially
729
    if (mthing->type <= 4)
730
    {
731
	// save spots for respawning in network games
732
	playerstarts[mthing->type-1] = *mthing;
733
	if (!deathmatch)
734
	    P_SpawnPlayer (mthing);
735
 
736
	return;
737
    }
738
 
739
    // check for apropriate skill level
740
    if (!netgame && (mthing->options & 16) )
741
	return;
742
 
743
    if (gameskill == sk_baby)
744
	bit = 1;
745
    else if (gameskill == sk_nightmare)
746
	bit = 4;
747
    else
748
	bit = 1<<(gameskill-1);
749
 
750
    if (!(mthing->options & bit) )
751
	return;
752
 
753
    // find which type to spawn
754
    for (i=0 ; i< NUMMOBJTYPES ; i++)
755
	if (mthing->type == mobjinfo[i].doomednum)
756
	    break;
757
 
758
    if (i==NUMMOBJTYPES)
759
	I_Error ("P_SpawnMapThing: Unknown type %i at (%i, %i)",
760
		 mthing->type,
761
		 mthing->x, mthing->y);
762
 
763
    // don't spawn keycards and players in deathmatch
764
    if (deathmatch && mobjinfo[i].flags & MF_NOTDMATCH)
765
	return;
766
 
767
    // don't spawn any monsters if -nomonsters
768
    if (nomonsters
769
	&& ( i == MT_SKULL
770
	     || (mobjinfo[i].flags & MF_COUNTKILL)) )
771
    {
772
	return;
773
    }
774
 
775
    // spawn it
776
    x = mthing->x << FRACBITS;
777
    y = mthing->y << FRACBITS;
778
 
779
    if (mobjinfo[i].flags & MF_SPAWNCEILING)
780
	z = ONCEILINGZ;
781
    else
782
	z = ONFLOORZ;
783
 
784
    mobj = P_SpawnMobj (x,y,z, i);
785
    mobj->spawnpoint = *mthing;
786
 
787
    if (mobj->tics > 0)
788
	mobj->tics = 1 + (P_Random () % mobj->tics);
789
    if (mobj->flags & MF_COUNTKILL)
790
	totalkills++;
791
    if (mobj->flags & MF_COUNTITEM)
792
	totalitems++;
793
 
794
    mobj->angle = ANG45 * (mthing->angle/45);
795
    if (mthing->options & MTF_AMBUSH)
796
	mobj->flags |= MF_AMBUSH;
797
}
798
 
799
 
800
 
801
//
802
// GAME SPAWN FUNCTIONS
803
//
804
 
805
 
806
//
807
// P_SpawnPuff
808
//
809
extern fixed_t attackrange;
810
 
811
void
812
P_SpawnPuff
813
( fixed_t	x,
814
  fixed_t	y,
815
  fixed_t	z )
816
{
817
    mobj_t*	th;
818
 
819
    z += ((P_Random()-P_Random())<<10);
820
 
821
    th = P_SpawnMobj (x,y,z, MT_PUFF);
822
    th->momz = FRACUNIT;
823
    th->tics -= P_Random()&3;
824
 
825
    if (th->tics < 1)
826
	th->tics = 1;
827
 
828
    // don't make punches spark on the wall
829
    if (attackrange == MELEERANGE)
830
	P_SetMobjState (th, S_PUFF3);
831
}
832
 
833
 
834
 
835
//
836
// P_SpawnBlood
837
//
838
void
839
P_SpawnBlood
840
( fixed_t	x,
841
  fixed_t	y,
842
  fixed_t	z,
843
  int		damage )
844
{
845
    mobj_t*	th;
846
 
847
    z += ((P_Random()-P_Random())<<10);
848
    th = P_SpawnMobj (x,y,z, MT_BLOOD);
849
    th->momz = FRACUNIT*2;
850
    th->tics -= P_Random()&3;
851
 
852
    if (th->tics < 1)
853
	th->tics = 1;
854
 
855
    if (damage <= 12 && damage >= 9)
856
	P_SetMobjState (th,S_BLOOD2);
857
    else if (damage < 9)
858
	P_SetMobjState (th,S_BLOOD3);
859
}
860
 
861
 
862
 
863
//
864
// P_CheckMissileSpawn
865
// Moves the missile forward a bit
866
//  and possibly explodes it right there.
867
//
868
void P_CheckMissileSpawn (mobj_t* th)
869
{
870
    th->tics -= P_Random()&3;
871
    if (th->tics < 1)
872
	th->tics = 1;
873
 
874
    // move a little forward so an angle can
875
    // be computed if it immediately explodes
876
    th->x += (th->momx>>1);
877
    th->y += (th->momy>>1);
878
    th->z += (th->momz>>1);
879
 
880
    if (!P_TryMove (th, th->x, th->y))
881
	P_ExplodeMissile (th);
882
}
883
 
884
 
885
//
886
// P_SpawnMissile
887
//
888
mobj_t*
889
P_SpawnMissile
890
( mobj_t*	source,
891
  mobj_t*	dest,
892
  mobjtype_t	type )
893
{
894
    mobj_t*	th;
895
    angle_t	an;
896
    int		dist;
897
 
898
    th = P_SpawnMobj (source->x,
899
		      source->y,
900
		      source->z + 4*8*FRACUNIT, type);
901
 
902
    if (th->info->seesound)
903
	S_StartSound (th, th->info->seesound);
904
 
905
    th->target = source;	// where it came from
906
    an = R_PointToAngle2 (source->x, source->y, dest->x, dest->y);
907
 
908
    // fuzzy player
909
    if (dest->flags & MF_SHADOW)
910
	an += (P_Random()-P_Random())<<20;
911
 
912
    th->angle = an;
913
    an >>= ANGLETOFINESHIFT;
914
    th->momx = FixedMul (th->info->speed, finecosine[an]);
915
    th->momy = FixedMul (th->info->speed, finesine[an]);
916
 
917
    dist = P_AproxDistance (dest->x - source->x, dest->y - source->y);
918
    dist = dist / th->info->speed;
919
 
920
    if (dist < 1)
921
	dist = 1;
922
 
923
    th->momz = (dest->z - source->z) / dist;
924
    P_CheckMissileSpawn (th);
925
 
926
    return th;
927
}
928
 
929
 
930
//
931
// P_SpawnPlayerMissile
932
// Tries to aim at a nearby monster
933
//
934
void
935
P_SpawnPlayerMissile
936
( mobj_t*	source,
937
  mobjtype_t	type )
938
{
939
    mobj_t*	th;
940
    angle_t	an;
941
 
942
    fixed_t	x;
943
    fixed_t	y;
944
    fixed_t	z;
945
    fixed_t	slope;
946
 
947
    // see which target is to be aimed at
948
    an = source->angle;
949
    slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
950
 
951
    if (!linetarget)
952
    {
953
	an += 1<<26;
954
	slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
955
 
956
	if (!linetarget)
957
	{
958
	    an -= 2<<26;
959
	    slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
960
	}
961
 
962
	if (!linetarget)
963
	{
964
	    an = source->angle;
965
	    slope = 0;
966
	}
967
    }
968
 
969
    x = source->x;
970
    y = source->y;
971
    z = source->z + 4*8*FRACUNIT;
972
 
973
    th = P_SpawnMobj (x,y,z, type);
974
 
975
    if (th->info->seesound)
976
	S_StartSound (th, th->info->seesound);
977
 
978
    th->target = source;
979
    th->angle = an;
980
    th->momx = FixedMul( th->info->speed,
981
			 finecosine[an>>ANGLETOFINESHIFT]);
982
    th->momy = FixedMul( th->info->speed,
983
			 finesine[an>>ANGLETOFINESHIFT]);
984
    th->momz = FixedMul( th->info->speed, slope);
985
 
986
    P_CheckMissileSpawn (th);
987
}
988