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