aboutsummaryrefslogtreecommitdiff
path: root/src/p_mobj.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/p_mobj.c')
-rw-r--r--src/p_mobj.c1526
1 files changed, 1526 insertions, 0 deletions
diff --git a/src/p_mobj.c b/src/p_mobj.c
new file mode 100644
index 0000000..0f8c8e3
--- /dev/null
+++ b/src/p_mobj.c
@@ -0,0 +1,1526 @@
1/* Emacs style mode select -*- C++ -*-
2 *-----------------------------------------------------------------------------
3 *
4 *
5 * PrBoom: a Doom port merged with LxDoom and LSDLDoom
6 * based on BOOM, a modified and improved DOOM engine
7 * Copyright (C) 1999 by
8 * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
9 * Copyright (C) 1999-2004 by
10 * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
11 * Copyright 2005, 2006 by
12 * Florian Schulze, Colin Phipps, Neil Stevens, Andrey Budko
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
27 * 02111-1307, USA.
28 *
29 * DESCRIPTION:
30 * Moving object handling. Spawn functions.
31 *
32 *-----------------------------------------------------------------------------*/
33
34#include "doomdef.h"
35#include "doomstat.h"
36#include "m_random.h"
37#include "r_main.h"
38#include "p_maputl.h"
39#include "p_map.h"
40#include "p_tick.h"
41#include "sounds.h"
42#include "st_stuff.h"
43#include "hu_stuff.h"
44#include "s_sound.h"
45#include "info.h"
46#include "g_game.h"
47#include "p_inter.h"
48#include "lprintf.h"
49#include "r_demo.h"
50
51//
52// P_SetMobjState
53// Returns true if the mobj is still present.
54//
55
56boolean P_SetMobjState(mobj_t* mobj,statenum_t state)
57 {
58 state_t* st;
59
60 // killough 4/9/98: remember states seen, to detect cycles:
61
62 static statenum_t seenstate_tab[NUMSTATES]; // fast transition table
63 statenum_t *seenstate = seenstate_tab; // pointer to table
64 static int recursion; // detects recursion
65 statenum_t i = state; // initial state
66 boolean ret = true; // return value
67 statenum_t tempstate[NUMSTATES]; // for use with recursion
68
69 if (recursion++) // if recursion detected,
70 memset(seenstate=tempstate,0,sizeof tempstate); // clear state table
71
72 do
73 {
74 if (state == S_NULL)
75 {
76 mobj->state = (state_t *) S_NULL;
77 P_RemoveMobj (mobj);
78 ret = false;
79 break; // killough 4/9/98
80 }
81
82 st = &states[state];
83 mobj->state = st;
84 mobj->tics = st->tics;
85 mobj->sprite = st->sprite;
86 mobj->frame = st->frame;
87
88 // Modified handling.
89 // Call action functions when the state is set
90
91 if (st->action)
92 st->action(mobj);
93
94 seenstate[state] = 1 + st->nextstate; // killough 4/9/98
95
96 state = st->nextstate;
97 } while (!mobj->tics && !seenstate[state]); // killough 4/9/98
98
99 if (ret && !mobj->tics) // killough 4/9/98: detect state cycles
100 doom_printf("Warning: State Cycle Detected");
101
102 if (!--recursion)
103 for (;(state=seenstate[i]);i=state-1)
104 seenstate[i] = 0; // killough 4/9/98: erase memory of states
105
106 return ret;
107 }
108
109
110//
111// P_ExplodeMissile
112//
113
114void P_ExplodeMissile (mobj_t* mo)
115 {
116 mo->momx = mo->momy = mo->momz = 0;
117
118 P_SetMobjState (mo, mobjinfo[mo->type].deathstate);
119
120 mo->tics -= P_Random(pr_explode)&3;
121
122 if (mo->tics < 1)
123 mo->tics = 1;
124
125 mo->flags &= ~MF_MISSILE;
126
127 if (mo->info->deathsound)
128 S_StartSound (mo, mo->info->deathsound);
129 }
130
131
132//
133// P_XYMovement
134//
135// Attempts to move something if it has momentum.
136//
137
138static void P_XYMovement (mobj_t* mo)
139 {
140 player_t *player;
141 fixed_t xmove, ymove;
142
143 //e6y
144 fixed_t oldx,oldy; // phares 9/10/98: reducing bobbing/momentum on ice
145
146#if 0
147 fixed_t ptryx;
148 fixed_t ptryy;
149 fixed_t xmove;
150 fixed_t ymove;
151 fixed_t oldx,oldy; // phares 9/10/98: reducing bobbing/momentum on ice
152 // when up against walls
153#endif
154 if (!(mo->momx | mo->momy)) // Any momentum?
155 {
156 if (mo->flags & MF_SKULLFLY)
157 {
158
159 // the skull slammed into something
160
161 mo->flags &= ~MF_SKULLFLY;
162 mo->momz = 0;
163
164 P_SetMobjState (mo, mo->info->spawnstate);
165 }
166 return;
167 }
168
169 player = mo->player;
170
171 if (mo->momx > MAXMOVE)
172 mo->momx = MAXMOVE;
173 else if (mo->momx < -MAXMOVE)
174 mo->momx = -MAXMOVE;
175
176 if (mo->momy > MAXMOVE)
177 mo->momy = MAXMOVE;
178 else if (mo->momy < -MAXMOVE)
179 mo->momy = -MAXMOVE;
180
181 xmove = mo->momx;
182 ymove = mo->momy;
183
184 oldx = mo->x; // phares 9/10/98: new code to reduce bobbing/momentum
185 oldy = mo->y; // when on ice & up against wall. These will be compared
186 // to your x,y values later to see if you were able to move
187
188 do
189 {
190 fixed_t ptryx, ptryy;
191 // killough 8/9/98: fix bug in original Doom source:
192 // Large negative displacements were never considered.
193 // This explains the tendency for Mancubus fireballs
194 // to pass through walls.
195 // CPhipps - compatibility optioned
196
197 if (xmove > MAXMOVE/2 || ymove > MAXMOVE/2 ||
198 (!comp[comp_moveblock]
199 && (xmove < -MAXMOVE/2 || ymove < -MAXMOVE/2)))
200 {
201 ptryx = mo->x + xmove/2;
202 ptryy = mo->y + ymove/2;
203 xmove >>= 1;
204 ymove >>= 1;
205 }
206 else
207 {
208 ptryx = mo->x + xmove;
209 ptryy = mo->y + ymove;
210 xmove = ymove = 0;
211 }
212
213 // killough 3/15/98: Allow objects to drop off
214
215 if (!P_TryMove (mo, ptryx, ptryy, true))
216 {
217 // blocked move
218
219 // killough 8/11/98: bouncing off walls
220 // killough 10/98:
221 // Add ability for objects other than players to bounce on ice
222
223 if (!(mo->flags & MF_MISSILE) &&
224 mbf_features &&
225 (mo->flags & MF_BOUNCES ||
226 (!player && blockline &&
227 variable_friction && mo->z <= mo->floorz &&
228 P_GetFriction(mo, NULL) > ORIG_FRICTION)))
229 {
230 if (blockline)
231 {
232 fixed_t r = ((blockline->dx >> FRACBITS) * mo->momx +
233 (blockline->dy >> FRACBITS) * mo->momy) /
234 ((blockline->dx >> FRACBITS)*(blockline->dx >> FRACBITS)+
235 (blockline->dy >> FRACBITS)*(blockline->dy >> FRACBITS));
236 fixed_t x = FixedMul(r, blockline->dx);
237 fixed_t y = FixedMul(r, blockline->dy);
238
239 // reflect momentum away from wall
240
241 mo->momx = x*2 - mo->momx;
242 mo->momy = y*2 - mo->momy;
243
244 // if under gravity, slow down in
245 // direction perpendicular to wall.
246
247 if (!(mo->flags & MF_NOGRAVITY))
248 {
249 mo->momx = (mo->momx + x)/2;
250 mo->momy = (mo->momy + y)/2;
251 }
252 }
253 else
254 mo->momx = mo->momy = 0;
255 }
256 else
257 if (player) // try to slide along it
258 P_SlideMove (mo);
259 else
260 if (mo->flags & MF_MISSILE)
261 {
262 // explode a missile
263
264 if (ceilingline &&
265 ceilingline->backsector &&
266 ceilingline->backsector->ceilingpic == skyflatnum)
267 if (demo_compatibility || // killough
268 mo->z > ceilingline->backsector->ceilingheight)
269 {
270 // Hack to prevent missiles exploding
271 // against the sky.
272 // Does not handle sky floors.
273
274 P_RemoveMobj (mo);
275 return;
276 }
277 P_ExplodeMissile (mo);
278 }
279 else // whatever else it is, it is now standing still in (x,y)
280 mo->momx = mo->momy = 0;
281 }
282 } while (xmove || ymove);
283
284 // slow down
285
286#if 0 /* killough 10/98: this is unused code (except maybe in .deh files?) */
287 if (player && player->cheats & CF_NOMOMENTUM)
288 {
289 // debug option for no sliding at all
290 mo->momx = mo->momy = 0;
291 player->momx = player->momy = 0; /* killough 10/98 */
292 return;
293 }
294#endif
295
296 /* no friction for missiles or skulls ever, no friction when airborne */
297 if (mo->flags & (MF_MISSILE | MF_SKULLFLY) || mo->z > mo->floorz)
298 return;
299
300 /* killough 8/11/98: add bouncers
301 * killough 9/15/98: add objects falling off ledges
302 * killough 11/98: only include bouncers hanging off ledges
303 */
304 if (((mo->flags & MF_BOUNCES && mo->z > mo->dropoffz) ||
305 mo->flags & MF_CORPSE || mo->intflags & MIF_FALLING) &&
306 (mo->momx > FRACUNIT/4 || mo->momx < -FRACUNIT/4 ||
307 mo->momy > FRACUNIT/4 || mo->momy < -FRACUNIT/4) &&
308 mo->floorz != mo->subsector->sector->floorheight)
309 return; // do not stop sliding if halfway off a step with some momentum
310
311 // killough 11/98:
312 // Stop voodoo dolls that have come to rest, despite any
313 // moving corresponding player, except in old demos:
314
315 if (mo->momx > -STOPSPEED && mo->momx < STOPSPEED &&
316 mo->momy > -STOPSPEED && mo->momy < STOPSPEED &&
317 (!player || !(player->cmd.forwardmove | player->cmd.sidemove) ||
318 (player->mo != mo && compatibility_level >= lxdoom_1_compatibility)))
319 {
320 // if in a walking frame, stop moving
321
322 // killough 10/98:
323 // Don't affect main player when voodoo dolls stop, except in old demos:
324
325// if ( player&&(unsigned)((player->mo->state - states)- S_PLAY_RUN1) < 4)
326// P_SetMobjState (player->mo, S_PLAY);
327 if (player && (unsigned)(player->mo->state - states - S_PLAY_RUN1) < 4
328 && (player->mo == mo || compatibility_level >= lxdoom_1_compatibility))
329 P_SetMobjState(player->mo, S_PLAY);
330
331 mo->momx = mo->momy = 0;
332
333 /* killough 10/98: kill any bobbing momentum too (except in voodoo dolls)
334 * cph - DEMOSYNC - needs compatibility check?
335 */
336 if (player && player->mo == mo)
337 player->momx = player->momy = 0;
338 }
339 else
340 {
341 /* phares 3/17/98
342 *
343 * Friction will have been adjusted by friction thinkers for
344 * icy or muddy floors. Otherwise it was never touched and
345 * remained set at ORIG_FRICTION
346 *
347 * killough 8/28/98: removed inefficient thinker algorithm,
348 * instead using touching_sectorlist in P_GetFriction() to
349 * determine friction (and thus only when it is needed).
350 *
351 * killough 10/98: changed to work with new bobbing method.
352 * Reducing player momentum is no longer needed to reduce
353 * bobbing, so ice works much better now.
354 *
355 * cph - DEMOSYNC - need old code for Boom demos?
356 */
357
358 //e6y
359 if (compatibility_level <= boom_201_compatibility)
360 {
361 // phares 3/17/98
362 // Friction will have been adjusted by friction thinkers for icy
363 // or muddy floors. Otherwise it was never touched and
364 // remained set at ORIG_FRICTION
365 mo->momx = FixedMul(mo->momx,mo->friction);
366 mo->momy = FixedMul(mo->momy,mo->friction);
367 mo->friction = ORIG_FRICTION; // reset to normal for next tic
368 }
369 else if (compatibility_level <= lxdoom_1_compatibility)
370 {
371 // phares 9/10/98: reduce bobbing/momentum when on ice & up against wall
372
373 if ((oldx == mo->x) && (oldy == mo->y)) // Did you go anywhere?
374 { // No. Use original friction. This allows you to not bob so much
375 // if you're on ice, but keeps enough momentum around to break free
376 // when you're mildly stuck in a wall.
377 mo->momx = FixedMul(mo->momx,ORIG_FRICTION);
378 mo->momy = FixedMul(mo->momy,ORIG_FRICTION);
379 }
380 else
381 { // Yes. Use stored friction.
382 mo->momx = FixedMul(mo->momx,mo->friction);
383 mo->momy = FixedMul(mo->momy,mo->friction);
384 }
385 mo->friction = ORIG_FRICTION; // reset to normal for next tic
386 }
387 else
388 {
389
390 fixed_t friction = P_GetFriction(mo, NULL);
391
392 mo->momx = FixedMul(mo->momx, friction);
393 mo->momy = FixedMul(mo->momy, friction);
394
395 /* killough 10/98: Always decrease player bobbing by ORIG_FRICTION.
396 * This prevents problems with bobbing on ice, where it was not being
397 * reduced fast enough, leading to all sorts of kludges being developed.
398 */
399
400 if (player && player->mo == mo) /* Not voodoo dolls */
401 {
402 player->momx = FixedMul(player->momx, ORIG_FRICTION);
403 player->momy = FixedMul(player->momy, ORIG_FRICTION);
404 }
405
406 }
407
408 }
409 }
410
411
412//
413// P_ZMovement
414//
415// Attempt vertical movement.
416
417static void P_ZMovement (mobj_t* mo)
418{
419 /* killough 7/11/98:
420 * BFG fireballs bounced on floors and ceilings in Pre-Beta Doom
421 * killough 8/9/98: added support for non-missile objects bouncing
422 * (e.g. grenade, mine, pipebomb)
423 */
424
425 if (mo->flags & MF_BOUNCES && mo->momz) {
426 mo->z += mo->momz;
427 if (mo->z <= mo->floorz) { /* bounce off floors */
428 mo->z = mo->floorz;
429 if (mo->momz < 0) {
430 mo->momz = -mo->momz;
431 if (!(mo->flags & MF_NOGRAVITY)) { /* bounce back with decay */
432 mo->momz = mo->flags & MF_FLOAT ? // floaters fall slowly
433 mo->flags & MF_DROPOFF ? // DROPOFF indicates rate
434 FixedMul(mo->momz, (fixed_t)(FRACUNIT*.85)) :
435 FixedMul(mo->momz, (fixed_t)(FRACUNIT*.70)) :
436 FixedMul(mo->momz, (fixed_t)(FRACUNIT*.45)) ;
437
438 /* Bring it to rest below a certain speed */
439 if (D_abs(mo->momz) <= mo->info->mass*(GRAVITY*4/256))
440 mo->momz = 0;
441 }
442
443 /* killough 11/98: touchy objects explode on impact */
444 if (mo->flags & MF_TOUCHY && mo->intflags & MIF_ARMED
445 && mo->health > 0)
446 P_DamageMobj(mo, NULL, NULL, mo->health);
447 else if (mo->flags & MF_FLOAT && sentient(mo))
448 goto floater;
449 return;
450 }
451 } else if (mo->z >= mo->ceilingz - mo->height) {
452 /* bounce off ceilings */
453 mo->z = mo->ceilingz - mo->height;
454 if (mo->momz > 0) {
455 if (mo->subsector->sector->ceilingpic != skyflatnum)
456 mo->momz = -mo->momz; /* always bounce off non-sky ceiling */
457 else if (mo->flags & MF_MISSILE)
458 P_RemoveMobj(mo); /* missiles don't bounce off skies */
459 else if (mo->flags & MF_NOGRAVITY)
460 mo->momz = -mo->momz; // bounce unless under gravity
461
462 if (mo->flags & MF_FLOAT && sentient(mo))
463 goto floater;
464
465 return;
466 }
467 } else {
468 if (!(mo->flags & MF_NOGRAVITY)) /* free-fall under gravity */
469 mo->momz -= mo->info->mass*(GRAVITY/256);
470
471 if (mo->flags & MF_FLOAT && sentient(mo)) goto floater;
472 return;
473 }
474
475 /* came to a stop */
476 mo->momz = 0;
477
478 if (mo->flags & MF_MISSILE) {
479 if (ceilingline &&
480 ceilingline->backsector &&
481 ceilingline->backsector->ceilingpic == skyflatnum &&
482 mo->z > ceilingline->backsector->ceilingheight)
483 P_RemoveMobj(mo); /* don't explode on skies */
484 else
485 P_ExplodeMissile(mo);
486 }
487
488 if (mo->flags & MF_FLOAT && sentient(mo)) goto floater;
489 return;
490 }
491
492 /* killough 8/9/98: end bouncing object code */
493
494 // check for smooth step up
495
496 if (mo->player &&
497 mo->player->mo == mo && // killough 5/12/98: exclude voodoo dolls
498 mo->z < mo->floorz)
499 {
500 mo->player->viewheight -= mo->floorz-mo->z;
501 mo->player->deltaviewheight = (VIEWHEIGHT - mo->player->viewheight)>>3;
502 }
503
504 // adjust altitude
505
506 mo->z += mo->momz;
507
508floater:
509 if ((mo->flags & MF_FLOAT) && mo->target)
510
511 // float down towards target if too close
512
513 if (!((mo->flags ^ MF_FLOAT) & (MF_FLOAT | MF_SKULLFLY | MF_INFLOAT)) &&
514 mo->target) /* killough 11/98: simplify */
515 {
516 fixed_t delta;
517 if (P_AproxDistance(mo->x - mo->target->x, mo->y - mo->target->y) <
518 D_abs(delta = mo->target->z + (mo->height>>1) - mo->z)*3)
519 mo->z += delta < 0 ? -FLOATSPEED : FLOATSPEED;
520 }
521
522 // clip movement
523
524 if (mo->z <= mo->floorz)
525 {
526 // hit the floor
527
528 /* Note (id):
529 * somebody left this after the setting momz to 0,
530 * kinda useless there.
531 * cph - This was the a bug in the linuxdoom-1.10 source which
532 * caused it not to sync Doom 2 v1.9 demos. Someone
533 * added the above comment and moved up the following code. So
534 * demos would desync in close lost soul fights.
535 * cph - revised 2001/04/15 -
536 * This was a bug in the Doom/Doom 2 source; the following code
537 * is meant to make charging lost souls bounce off of floors, but it
538 * was incorrectly placed after momz was set to 0.
539 * However, this bug was fixed in Doom95, Final/Ultimate Doom, and
540 * the v1.10 source release (which is one reason why it failed to sync
541 * some Doom2 v1.9 demos)
542 * I've added a comp_soul compatibility option to make this behavior
543 * selectable for PrBoom v2.3+. For older demos, we do this here only
544 * if we're in a compatibility level above Doom 2 v1.9 (in which case we
545 * mimic the bug and do it further down instead)
546 */
547
548 if (mo->flags & MF_SKULLFLY &&
549 (!comp[comp_soul] ||
550 (compatibility_level > doom2_19_compatibility &&
551 compatibility_level < prboom_4_compatibility)
552 ))
553 mo->momz = -mo->momz; // the skull slammed into something
554
555 if (mo->momz < 0)
556 {
557 /* killough 11/98: touchy objects explode on impact */
558 if (mo->flags & MF_TOUCHY && mo->intflags & MIF_ARMED && mo->health > 0)
559 P_DamageMobj(mo, NULL, NULL, mo->health);
560 else
561 if (mo->player && /* killough 5/12/98: exclude voodoo dolls */
562 mo->player->mo == mo && mo->momz < -GRAVITY*8)
563 {
564 // Squat down.
565 // Decrease viewheight for a moment
566 // after hitting the ground (hard),
567 // and utter appropriate sound.
568
569 mo->player->deltaviewheight = mo->momz>>3;
570 if (mo->health > 0) /* cph - prevent "oof" when dead */
571 S_StartSound (mo, sfx_oof);
572 }
573 mo->momz = 0;
574 }
575 mo->z = mo->floorz;
576
577 /* cph 2001/04/15 -
578 * This is the buggy lost-soul bouncing code referenced above.
579 * We've already set momz = 0 normally by this point, so it's useless.
580 * However we might still have upward momentum, in which case this will
581 * incorrectly reverse it, so we might still need this for demo sync
582 */
583 if (mo->flags & MF_SKULLFLY &&
584 compatibility_level <= doom2_19_compatibility)
585 mo->momz = -mo->momz; // the skull slammed into something
586
587 if ( (mo->flags & MF_MISSILE) && !(mo->flags & MF_NOCLIP) )
588 {
589 P_ExplodeMissile (mo);
590 return;
591 }
592 }
593 else // still above the floor // phares
594 if (!(mo->flags & MF_NOGRAVITY))
595 {
596 if (!mo->momz)
597 mo->momz = -GRAVITY;
598 mo->momz -= GRAVITY;
599 }
600
601 if (mo->z + mo->height > mo->ceilingz)
602 {
603 /* cph 2001/04/15 -
604 * Lost souls were meant to bounce off of ceilings;
605 * new comp_soul compatibility option added
606 */
607 if (!comp[comp_soul] && mo->flags & MF_SKULLFLY)
608 mo->momz = -mo->momz; // the skull slammed into something
609
610 // hit the ceiling
611
612 if (mo->momz > 0)
613 mo->momz = 0;
614
615 mo->z = mo->ceilingz - mo->height;
616
617 /* cph 2001/04/15 -
618 * We might have hit a ceiling but had downward momentum (e.g. ceiling is
619 * lowering on us), so for old demos we must still do the buggy
620 * momentum reversal here
621 */
622 if (comp[comp_soul] && mo->flags & MF_SKULLFLY)
623 mo->momz = -mo->momz; // the skull slammed into something
624
625 if ( (mo->flags & MF_MISSILE) && !(mo->flags & MF_NOCLIP) )
626 {
627 P_ExplodeMissile (mo);
628 return;
629 }
630 }
631 }
632
633//
634// P_NightmareRespawn
635//
636
637static void P_NightmareRespawn(mobj_t* mobj)
638 {
639 fixed_t x;
640 fixed_t y;
641 fixed_t z;
642 subsector_t* ss;
643 mobj_t* mo;
644 mapthing_t* mthing;
645
646 x = mobj->spawnpoint.x << FRACBITS;
647 y = mobj->spawnpoint.y << FRACBITS;
648
649 /* haleyjd: stupid nightmare respawning bug fix
650 *
651 * 08/09/00: compatibility added, time to ramble :)
652 * This fixes the notorious nightmare respawning bug that causes monsters
653 * that didn't spawn at level startup to respawn at the point (0,0)
654 * regardless of that point's nature. SMMU and Eternity need this for
655 * script-spawned things like Halif Swordsmythe, as well.
656 *
657 * cph - copied from eternity, except comp_respawnfix becomes comp_respawn
658 * and the logic is reversed (i.e. like the rest of comp_ it *disables*
659 * the fix)
660 */
661 if(!comp[comp_respawn] && !x && !y)
662 {
663 // spawnpoint was zeroed out, so use point of death instead
664 x = mobj->x;
665 y = mobj->y;
666 }
667
668 // something is occupying its position?
669
670 if (!P_CheckPosition (mobj, x, y) )
671 return; // no respwan
672
673 // spawn a teleport fog at old spot
674 // because of removal of the body?
675
676 mo = P_SpawnMobj (mobj->x,
677 mobj->y,
678 mobj->subsector->sector->floorheight,
679 MT_TFOG);
680
681 // initiate teleport sound
682
683 S_StartSound (mo, sfx_telept);
684
685 // spawn a teleport fog at the new spot
686
687 ss = R_PointInSubsector (x,y);
688
689 mo = P_SpawnMobj (x, y, ss->sector->floorheight , MT_TFOG);
690
691 S_StartSound (mo, sfx_telept);
692
693 // spawn the new monster
694
695 mthing = &mobj->spawnpoint;
696 if (mobj->info->flags & MF_SPAWNCEILING)
697 z = ONCEILINGZ;
698 else
699 z = ONFLOORZ;
700
701 // inherit attributes from deceased one
702
703 mo = P_SpawnMobj (x,y,z, mobj->type);
704 mo->spawnpoint = mobj->spawnpoint;
705 mo->angle = ANG45 * (mthing->angle/45);
706
707 if (mthing->options & MTF_AMBUSH)
708 mo->flags |= MF_AMBUSH;
709
710 /* killough 11/98: transfer friendliness from deceased */
711 mo->flags = (mo->flags & ~MF_FRIEND) | (mobj->flags & MF_FRIEND);
712
713 mo->reactiontime = 18;
714
715 // remove the old monster,
716
717 P_RemoveMobj (mobj);
718 }
719
720
721//
722// P_MobjThinker
723//
724
725void P_MobjThinker (mobj_t* mobj)
726 {
727 // killough 11/98:
728 // removed old code which looked at target references
729 // (we use pointer reference counting now)
730
731 mobj->PrevX = mobj->x;
732 mobj->PrevY = mobj->y;
733 mobj->PrevZ = mobj->z;
734
735 // momentum movement
736 if (mobj->momx | mobj->momy || mobj->flags & MF_SKULLFLY)
737 {
738 P_XYMovement(mobj);
739 if (mobj->thinker.function != P_MobjThinker) // cph - Must've been removed
740 return; // killough - mobj was removed
741 }
742
743 if (mobj->z != mobj->floorz || mobj->momz)
744 {
745 P_ZMovement(mobj);
746 if (mobj->thinker.function != P_MobjThinker) // cph - Must've been removed
747 return; // killough - mobj was removed
748 }
749 else
750 if (!(mobj->momx | mobj->momy) && !sentient(mobj))
751 { // non-sentient objects at rest
752 mobj->intflags |= MIF_ARMED; // arm a mine which has come to rest
753
754 // killough 9/12/98: objects fall off ledges if they are hanging off
755 // slightly push off of ledge if hanging more than halfway off
756
757 if (mobj->z > mobj->dropoffz && // Only objects contacting dropoff
758 !(mobj->flags & MF_NOGRAVITY) && // Only objects which fall
759 !comp[comp_falloff]) // Not in old demos
760 P_ApplyTorque(mobj); // Apply torque
761 else
762 mobj->intflags &= ~MIF_FALLING, mobj->gear = 0; // Reset torque
763 }
764
765 // cycle through states,
766 // calling action functions at transitions
767
768 if (mobj->tics != -1)
769 {
770 mobj->tics--;
771
772 // you can cycle through multiple states in a tic
773
774 if (!mobj->tics)
775 if (!P_SetMobjState (mobj, mobj->state->nextstate) )
776 return; // freed itself
777 }
778 else
779 {
780
781 // check for nightmare respawn
782
783 if (! (mobj->flags & MF_COUNTKILL) )
784 return;
785
786 if (!respawnmonsters)
787 return;
788
789 mobj->movecount++;
790
791 if (mobj->movecount < 12*35)
792 return;
793
794 if (leveltime & 31)
795 return;
796
797 if (P_Random (pr_respawn) > 4)
798 return;
799
800 P_NightmareRespawn (mobj);
801 }
802
803 }
804
805
806//
807// P_SpawnMobj
808//
809mobj_t* P_SpawnMobj(fixed_t x,fixed_t y,fixed_t z,mobjtype_t type)
810 {
811 mobj_t* mobj;
812 state_t* st;
813 mobjinfo_t* info;
814
815 mobj = Z_Malloc (sizeof(*mobj), PU_LEVEL, NULL);
816 memset (mobj, 0, sizeof (*mobj));
817 info = &mobjinfo[type];
818 mobj->type = type;
819 mobj->info = info;
820 mobj->x = x;
821 mobj->y = y;
822 mobj->radius = info->radius;
823 mobj->height = info->height; // phares
824 mobj->flags = info->flags;
825
826 /* killough 8/23/98: no friends, bouncers, or touchy things in old demos */
827 if (!mbf_features)
828 mobj->flags &= ~(MF_BOUNCES | MF_FRIEND | MF_TOUCHY);
829 else
830 if (type == MT_PLAYER) // Except in old demos, players
831 mobj->flags |= MF_FRIEND; // are always friends.
832
833 mobj->health = info->spawnhealth;
834
835 if (gameskill != sk_nightmare)
836 mobj->reactiontime = info->reactiontime;
837
838 mobj->lastlook = P_Random (pr_lastlook) % MAXPLAYERS;
839
840 // do not set the state with P_SetMobjState,
841 // because action routines can not be called yet
842
843 st = &states[info->spawnstate];
844
845 mobj->state = st;
846 mobj->tics = st->tics;
847 mobj->sprite = st->sprite;
848 mobj->frame = st->frame;
849 mobj->touching_sectorlist = NULL; // NULL head of sector list // phares 3/13/98
850
851 // set subsector and/or block links
852
853 P_SetThingPosition (mobj);
854
855 mobj->dropoffz = /* killough 11/98: for tracking dropoffs */
856 mobj->floorz = mobj->subsector->sector->floorheight;
857 mobj->ceilingz = mobj->subsector->sector->ceilingheight;
858
859 mobj->z = z == ONFLOORZ ? mobj->floorz : z == ONCEILINGZ ?
860 mobj->ceilingz - mobj->height : z;
861
862 mobj->PrevX = mobj->x;
863 mobj->PrevY = mobj->y;
864 mobj->PrevZ = mobj->z;
865
866 mobj->thinker.function = P_MobjThinker;
867
868 //e6y
869 mobj->friction = ORIG_FRICTION; // phares 3/17/98
870
871 mobj->target = mobj->tracer = mobj->lastenemy = NULL;
872 P_AddThinker (&mobj->thinker);
873 if (!((mobj->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL)))
874 totallive++;
875 return mobj;
876 }
877
878
879static mapthing_t itemrespawnque[ITEMQUESIZE];
880static int itemrespawntime[ITEMQUESIZE];
881int iquehead;
882int iquetail;
883
884
885//
886// P_RemoveMobj
887//
888
889void P_RemoveMobj (mobj_t* mobj)
890{
891 if ((mobj->flags & MF_SPECIAL)
892 && !(mobj->flags & MF_DROPPED)
893 && (mobj->type != MT_INV)
894 && (mobj->type != MT_INS))
895 {
896 itemrespawnque[iquehead] = mobj->spawnpoint;
897 itemrespawntime[iquehead] = leveltime;
898 iquehead = (iquehead+1)&(ITEMQUESIZE-1);
899
900 // lose one off the end?
901
902 if (iquehead == iquetail)
903 iquetail = (iquetail+1)&(ITEMQUESIZE-1);
904 }
905
906 // unlink from sector and block lists
907
908 P_UnsetThingPosition (mobj);
909
910 // Delete all nodes on the current sector_list phares 3/16/98
911
912 if (sector_list)
913 {
914 P_DelSeclist(sector_list);
915 sector_list = NULL;
916 }
917
918 // stop any playing sound
919
920 S_StopSound (mobj);
921
922 // killough 11/98:
923 //
924 // Remove any references to other mobjs.
925 //
926 // Older demos might depend on the fields being left alone, however,
927 // if multiple thinkers reference each other indirectly before the
928 // end of the current tic.
929 // CPhipps - only leave dead references in old demos; I hope lxdoom_1 level
930 // demos are rare and don't rely on this. I hope.
931
932 if ((compatibility_level >= lxdoom_1_compatibility) ||
933 (!demorecording && !demoplayback)) {
934 P_SetTarget(&mobj->target, NULL);
935 P_SetTarget(&mobj->tracer, NULL);
936 P_SetTarget(&mobj->lastenemy, NULL);
937 }
938 // free block
939
940 P_RemoveThinker (&mobj->thinker);
941}
942
943
944/*
945 * P_FindDoomedNum
946 *
947 * Finds a mobj type with a matching doomednum
948 *
949 * killough 8/24/98: rewrote to use hashing
950 */
951
952static PUREFUNC int P_FindDoomedNum(unsigned type)
953{
954 static struct { int first, next; } *hash;
955 register int i;
956
957 if (!hash)
958 {
959 hash = Z_Malloc(sizeof *hash * NUMMOBJTYPES, PU_CACHE, (void **) &hash);
960 for (i=0; i<NUMMOBJTYPES; i++)
961 hash[i].first = NUMMOBJTYPES;
962 for (i=0; i<NUMMOBJTYPES; i++)
963 if (mobjinfo[i].doomednum != -1)
964 {
965 unsigned h = (unsigned) mobjinfo[i].doomednum % NUMMOBJTYPES;
966 hash[i].next = hash[h].first;
967 hash[h].first = i;
968 }
969 }
970
971 i = hash[type % NUMMOBJTYPES].first;
972 while ((i < NUMMOBJTYPES) && ((unsigned)mobjinfo[i].doomednum != type))
973 i = hash[i].next;
974 return i;
975}
976
977//
978// P_RespawnSpecials
979//
980
981void P_RespawnSpecials (void)
982 {
983 fixed_t x;
984 fixed_t y;
985 fixed_t z;
986 subsector_t* ss;
987 mobj_t* mo;
988 mapthing_t* mthing;
989 int i;
990
991 // only respawn items in deathmatch
992
993 if (deathmatch != 2)
994 return;
995
996 // nothing left to respawn?
997
998 if (iquehead == iquetail)
999 return;
1000
1001 // wait at least 30 seconds
1002
1003 if (leveltime - itemrespawntime[iquetail] < 30*35)
1004 return;
1005
1006 mthing = &itemrespawnque[iquetail];
1007
1008 x = mthing->x << FRACBITS;
1009 y = mthing->y << FRACBITS;
1010
1011 // spawn a teleport fog at the new spot
1012
1013 ss = R_PointInSubsector (x,y);
1014 mo = P_SpawnMobj (x, y, ss->sector->floorheight , MT_IFOG);
1015 S_StartSound (mo, sfx_itmbk);
1016
1017 // find which type to spawn
1018
1019 /* killough 8/23/98: use table for faster lookup */
1020 i = P_FindDoomedNum(mthing->type);
1021
1022 // spawn it
1023
1024 if (mobjinfo[i].flags & MF_SPAWNCEILING)
1025 z = ONCEILINGZ;
1026 else
1027 z = ONFLOORZ;
1028
1029 mo = P_SpawnMobj (x,y,z, i);
1030 mo->spawnpoint = *mthing;
1031 mo->angle = ANG45 * (mthing->angle/45);
1032
1033 // pull it from the queue
1034
1035 iquetail = (iquetail+1)&(ITEMQUESIZE-1);
1036 }
1037
1038//
1039// P_SpawnPlayer
1040// Called when a player is spawned on the level.
1041// Most of the player structure stays unchanged
1042// between levels.
1043//
1044
1045extern byte playernumtotrans[MAXPLAYERS];
1046
1047void P_SpawnPlayer (int n, const mapthing_t* mthing)
1048 {
1049 player_t* p;
1050 fixed_t x;
1051 fixed_t y;
1052 fixed_t z;
1053 mobj_t* mobj;
1054 int i;
1055
1056 // not playing?
1057
1058 if (!playeringame[n])
1059 return;
1060
1061 p = &players[n];
1062
1063 if (p->playerstate == PST_REBORN)
1064 G_PlayerReborn (mthing->type-1);
1065
1066 /* cph 2001/08/14 - use the options field of memorised player starts to
1067 * indicate whether the start really exists in the level.
1068 */
1069 if (!mthing->options)
1070 I_Error("P_SpawnPlayer: attempt to spawn player at unavailable start point");
1071
1072 x = mthing->x << FRACBITS;
1073 y = mthing->y << FRACBITS;
1074 z = ONFLOORZ;
1075 mobj = P_SpawnMobj (x,y,z, MT_PLAYER);
1076
1077 // set color translations for player sprites
1078
1079 mobj->flags |= playernumtotrans[n]<<MF_TRANSSHIFT;
1080
1081 mobj->angle = ANG45 * (mthing->angle/45);
1082 mobj->player = p;
1083 mobj->health = p->health;
1084
1085 p->mo = mobj;
1086 p->playerstate = PST_LIVE;
1087 p->refire = 0;
1088 p->message = NULL;
1089 p->damagecount = 0;
1090 p->bonuscount = 0;
1091 p->extralight = 0;
1092 p->fixedcolormap = 0;
1093 p->viewheight = VIEWHEIGHT;
1094
1095 p->momx = p->momy = 0; // killough 10/98: initialize bobbing to 0.
1096
1097 // setup gun psprite
1098
1099 P_SetupPsprites (p);
1100
1101 // give all cards in death match mode
1102
1103 if (deathmatch)
1104 for (i = 0 ; i < NUMCARDS ; i++)
1105 p->cards[i] = true;
1106
1107 if (mthing->type-1 == consoleplayer)
1108 {
1109 ST_Start(); // wake up the status bar
1110 HU_Start(); // wake up the heads up text
1111 }
1112 R_SmoothPlaying_Reset(p); // e6y
1113 }
1114
1115/*
1116 * P_IsDoomnumAllowed()
1117 * Based on code taken from P_LoadThings() in src/p_setup.c Return TRUE
1118 * if the thing in question is expected to be available in the gamemode used.
1119 */
1120
1121boolean P_IsDoomnumAllowed(int doomnum)
1122{
1123 // Do not spawn cool, new monsters if !commercial
1124 if (gamemode != commercial)
1125 switch(doomnum)
1126 {
1127 case 64: // Archvile
1128 case 65: // Former Human Commando
1129 case 66: // Revenant
1130 case 67: // Mancubus
1131 case 68: // Arachnotron
1132 case 69: // Hell Knight
1133 case 71: // Pain Elemental
1134 case 84: // Wolf SS
1135 case 88: // Boss Brain
1136 case 89: // Boss Shooter
1137 return false;
1138 }
1139
1140 return true;
1141}
1142
1143//
1144// P_SpawnMapThing
1145// The fields of the mapthing should
1146// already be in host byte order.
1147//
1148
1149void P_SpawnMapThing (const mapthing_t* mthing)
1150 {
1151 int i;
1152 //int bit;
1153 mobj_t* mobj;
1154 fixed_t x;
1155 fixed_t y;
1156 fixed_t z;
1157 int options = mthing->options; /* cph 2001/07/07 - make writable copy */
1158
1159 // killough 2/26/98: Ignore type-0 things as NOPs
1160 // phares 5/14/98: Ignore Player 5-8 starts (for now)
1161
1162 switch(mthing->type)
1163 {
1164 case 0:
1165 case DEN_PLAYER5:
1166 case DEN_PLAYER6:
1167 case DEN_PLAYER7:
1168 case DEN_PLAYER8:
1169 return;
1170 }
1171
1172 // killough 11/98: clear flags unused by Doom
1173 //
1174 // We clear the flags unused in Doom if we see flag mask 256 set, since
1175 // it is reserved to be 0 under the new scheme. A 1 in this reserved bit
1176 // indicates it's a Doom wad made by a Doom editor which puts 1's in
1177 // bits that weren't used in Doom (such as HellMaker wads). So we should
1178 // then simply ignore all upper bits.
1179
1180 if (demo_compatibility ||
1181 (compatibility_level >= lxdoom_1_compatibility &&
1182 options & MTF_RESERVED)) {
1183 if (!demo_compatibility) // cph - Add warning about bad thing flags
1184 lprintf(LO_WARN, "P_SpawnMapThing: correcting bad flags (%u) (thing type %d)\n",
1185 options, mthing->type);
1186 options &= MTF_EASY|MTF_NORMAL|MTF_HARD|MTF_AMBUSH|MTF_NOTSINGLE;
1187 }
1188
1189 // count deathmatch start positions
1190
1191 // doom2.exe has at most 10 deathmatch starts
1192 if (mthing->type == 11)
1193 {
1194 if (!(!compatibility || deathmatch_p-deathmatchstarts < 10)) {
1195 return;
1196 } else {
1197 // 1/11/98 killough -- new code removes limit on deathmatch starts:
1198
1199 size_t offset = deathmatch_p - deathmatchstarts;
1200
1201 if (offset >= num_deathmatchstarts)
1202 {
1203 num_deathmatchstarts = num_deathmatchstarts ?
1204 num_deathmatchstarts*2 : 16;
1205 deathmatchstarts = realloc(deathmatchstarts,
1206 num_deathmatchstarts *
1207 sizeof(*deathmatchstarts));
1208 deathmatch_p = deathmatchstarts + offset;
1209 }
1210 memcpy(deathmatch_p++, mthing, sizeof(*mthing));
1211 (deathmatch_p-1)->options = 1;
1212 return;
1213 }
1214 }
1215
1216 // check for players specially
1217
1218 if (mthing->type <= 4 && mthing->type > 0) // killough 2/26/98 -- fix crashes
1219 {
1220#ifdef DOGS
1221 // killough 7/19/98: Marine's best friend :)
1222 if (!netgame && mthing->type > 1 && mthing->type <= dogs+1 &&
1223 !players[mthing->type-1].secretcount)
1224 { // use secretcount to avoid multiple dogs in case of multiple starts
1225 players[mthing->type-1].secretcount = 1;
1226
1227 // killough 10/98: force it to be a friend
1228 options |= MTF_FRIEND;
1229 if(HelperThing != -1) // haleyjd 9/22/99: deh substitution
1230 {
1231 int type = HelperThing - 1;
1232 if(type >= 0 && type < NUMMOBJTYPES)
1233 {
1234 i = type;
1235 }
1236 else
1237 {
1238 doom_printf("Invalid value %i for helper, ignored.", HelperThing);
1239 i = MT_DOGS;
1240 }
1241 }
1242 else {
1243 i = MT_DOGS;
1244 }
1245 goto spawnit;
1246 }
1247#endif
1248
1249 // save spots for respawning in coop games
1250 playerstarts[mthing->type-1] = *mthing;
1251 /* cph 2006/07/24 - use the otherwise-unused options field to flag that
1252 * this start is present (so we know which elements of the array are filled
1253 * in, in effect). Also note that the call below to P_SpawnPlayer must use
1254 * the playerstarts version with this field set */
1255 playerstarts[mthing->type-1].options = 1;
1256
1257 if (!deathmatch)
1258 P_SpawnPlayer (mthing->type-1, &playerstarts[mthing->type-1]);
1259 return;
1260 }
1261
1262 // check for apropriate skill level
1263
1264 /* jff "not single" thing flag */
1265 if (!netgame && options & MTF_NOTSINGLE)
1266 return;
1267
1268 //jff 3/30/98 implement "not deathmatch" thing flag
1269
1270 if (netgame && deathmatch && options & MTF_NOTDM)
1271 return;
1272
1273 //jff 3/30/98 implement "not cooperative" thing flag
1274
1275 if (netgame && !deathmatch && options & MTF_NOTCOOP)
1276 return;
1277
1278 // killough 11/98: simplify
1279 if (gameskill == sk_baby || gameskill == sk_easy ?
1280 !(options & MTF_EASY) :
1281 gameskill == sk_hard || gameskill == sk_nightmare ?
1282 !(options & MTF_HARD) : !(options & MTF_NORMAL))
1283 return;
1284
1285 // find which type to spawn
1286
1287 // killough 8/23/98: use table for faster lookup
1288 i = P_FindDoomedNum(mthing->type);
1289
1290 // phares 5/16/98:
1291 // Do not abort because of an unknown thing. Ignore it, but post a
1292 // warning message for the player.
1293
1294 if (i == NUMMOBJTYPES)
1295 {
1296 doom_printf("Unknown Thing type %i at (%i, %i)",mthing->type,mthing->x,mthing->y);
1297 return;
1298 }
1299
1300 // don't spawn keycards and players in deathmatch
1301
1302 if (deathmatch && mobjinfo[i].flags & MF_NOTDMATCH)
1303 return;
1304
1305 // don't spawn any monsters if -nomonsters
1306
1307 if (nomonsters && (i == MT_SKULL || (mobjinfo[i].flags & MF_COUNTKILL)))
1308 return;
1309
1310 // spawn it
1311#ifdef DOGS
1312spawnit:
1313#endif
1314
1315 x = mthing->x << FRACBITS;
1316 y = mthing->y << FRACBITS;
1317
1318 if (mobjinfo[i].flags & MF_SPAWNCEILING)
1319 z = ONCEILINGZ;
1320 else
1321 z = ONFLOORZ;
1322
1323 mobj = P_SpawnMobj (x,y,z, i);
1324 mobj->spawnpoint = *mthing;
1325
1326 if (mobj->tics > 0)
1327 mobj->tics = 1 + (P_Random (pr_spawnthing) % mobj->tics);
1328
1329 if (!(mobj->flags & MF_FRIEND) &&
1330 options & MTF_FRIEND &&
1331 mbf_features)
1332 {
1333 mobj->flags |= MF_FRIEND; // killough 10/98:
1334 P_UpdateThinker(&mobj->thinker); // transfer friendliness flag
1335 }
1336
1337 /* killough 7/20/98: exclude friends */
1338 if (!((mobj->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL)))
1339 totalkills++;
1340
1341 if (mobj->flags & MF_COUNTITEM)
1342 totalitems++;
1343
1344 mobj->angle = ANG45 * (mthing->angle/45);
1345 if (options & MTF_AMBUSH)
1346 mobj->flags |= MF_AMBUSH;
1347 }
1348
1349
1350//
1351// GAME SPAWN FUNCTIONS
1352//
1353
1354//
1355// P_SpawnPuff
1356//
1357
1358extern fixed_t attackrange;
1359
1360void P_SpawnPuff(fixed_t x,fixed_t y,fixed_t z)
1361 {
1362 mobj_t* th;
1363 // killough 5/5/98: remove dependence on order of evaluation:
1364 int t = P_Random(pr_spawnpuff);
1365 z += (t - P_Random(pr_spawnpuff))<<10;
1366
1367 th = P_SpawnMobj (x,y,z, MT_PUFF);
1368 th->momz = FRACUNIT;
1369 th->tics -= P_Random(pr_spawnpuff)&3;
1370
1371 if (th->tics < 1)
1372 th->tics = 1;
1373
1374 // don't make punches spark on the wall
1375
1376 if (attackrange == MELEERANGE)
1377 P_SetMobjState (th, S_PUFF3);
1378 }
1379
1380
1381//
1382// P_SpawnBlood
1383//
1384void P_SpawnBlood(fixed_t x,fixed_t y,fixed_t z,int damage)
1385 {
1386 mobj_t* th;
1387 // killough 5/5/98: remove dependence on order of evaluation:
1388 int t = P_Random(pr_spawnblood);
1389 z += (t - P_Random(pr_spawnblood))<<10;
1390 th = P_SpawnMobj(x,y,z, MT_BLOOD);
1391 th->momz = FRACUNIT*2;
1392 th->tics -= P_Random(pr_spawnblood)&3;
1393
1394 if (th->tics < 1)
1395 th->tics = 1;
1396
1397 if (damage <= 12 && damage >= 9)
1398 P_SetMobjState (th,S_BLOOD2);
1399 else if (damage < 9)
1400 P_SetMobjState (th,S_BLOOD3);
1401 }
1402
1403
1404//
1405// P_CheckMissileSpawn
1406// Moves the missile forward a bit
1407// and possibly explodes it right there.
1408//
1409
1410void P_CheckMissileSpawn (mobj_t* th)
1411 {
1412 th->tics -= P_Random(pr_missile)&3;
1413 if (th->tics < 1)
1414 th->tics = 1;
1415
1416 // move a little forward so an angle can
1417 // be computed if it immediately explodes
1418
1419 th->x += (th->momx>>1);
1420 th->y += (th->momy>>1);
1421 th->z += (th->momz>>1);
1422
1423 // killough 8/12/98: for non-missile objects (e.g. grenades)
1424 if (!(th->flags & MF_MISSILE) && mbf_features)
1425 return;
1426
1427 // killough 3/15/98: no dropoff (really = don't care for missiles)
1428
1429 if (!P_TryMove (th, th->x, th->y, false))
1430 P_ExplodeMissile (th);
1431 }
1432
1433
1434//
1435// P_SpawnMissile
1436//
1437
1438mobj_t* P_SpawnMissile(mobj_t* source,mobj_t* dest,mobjtype_t type)
1439 {
1440 mobj_t* th;
1441 angle_t an;
1442 int dist;
1443
1444 th = P_SpawnMobj (source->x,source->y,source->z + 4*8*FRACUNIT,type);
1445
1446 if (th->info->seesound)
1447 S_StartSound (th, th->info->seesound);
1448
1449 P_SetTarget(&th->target, source); // where it came from
1450 an = R_PointToAngle2 (source->x, source->y, dest->x, dest->y);
1451
1452 // fuzzy player
1453
1454 if (dest->flags & MF_SHADOW)
1455 { // killough 5/5/98: remove dependence on order of evaluation:
1456 int t = P_Random(pr_shadow);
1457 an += (t - P_Random(pr_shadow))<<20;
1458 }
1459
1460 th->angle = an;
1461 an >>= ANGLETOFINESHIFT;
1462 th->momx = FixedMul (th->info->speed, finecosine[an]);
1463 th->momy = FixedMul (th->info->speed, finesine[an]);
1464
1465 dist = P_AproxDistance (dest->x - source->x, dest->y - source->y);
1466 dist = dist / th->info->speed;
1467
1468 if (dist < 1)
1469 dist = 1;
1470
1471 th->momz = (dest->z - source->z) / dist;
1472 P_CheckMissileSpawn (th);
1473
1474 return th;
1475 }
1476
1477
1478//
1479// P_SpawnPlayerMissile
1480// Tries to aim at a nearby monster
1481//
1482
1483void P_SpawnPlayerMissile(mobj_t* source,mobjtype_t type)
1484{
1485 mobj_t *th;
1486 fixed_t x, y, z, slope = 0;
1487
1488 // see which target is to be aimed at
1489
1490 angle_t an = source->angle;
1491
1492 // killough 7/19/98: autoaiming was not in original beta
1493 {
1494 // killough 8/2/98: prefer autoaiming at enemies
1495 uint_64_t mask = mbf_features ? MF_FRIEND : 0;
1496
1497 do
1498 {
1499 slope = P_AimLineAttack(source, an, 16*64*FRACUNIT, mask);
1500 if (!linetarget)
1501 slope = P_AimLineAttack(source, an += 1<<26, 16*64*FRACUNIT, mask);
1502 if (!linetarget)
1503 slope = P_AimLineAttack(source, an -= 2<<26, 16*64*FRACUNIT, mask);
1504 if (!linetarget)
1505 an = source->angle, slope = 0;
1506 }
1507 while (mask && (mask=0, !linetarget)); // killough 8/2/98
1508 }
1509
1510 x = source->x;
1511 y = source->y;
1512 z = source->z + 4*8*FRACUNIT;
1513
1514 th = P_SpawnMobj (x,y,z, type);
1515
1516 if (th->info->seesound)
1517 S_StartSound (th, th->info->seesound);
1518
1519 P_SetTarget(&th->target, source);
1520 th->angle = an;
1521 th->momx = FixedMul(th->info->speed,finecosine[an>>ANGLETOFINESHIFT]);
1522 th->momy = FixedMul(th->info->speed,finesine[an>>ANGLETOFINESHIFT]);
1523 th->momz = FixedMul(th->info->speed,slope);
1524
1525 P_CheckMissileSpawn(th);
1526 }