summaryrefslogtreecommitdiff
path: root/apps/plugins/doom/p_mobj.c
diff options
context:
space:
mode:
authorDave Chapman <dave@dchapman.com>2006-03-28 15:44:01 +0000
committerDave Chapman <dave@dchapman.com>2006-03-28 15:44:01 +0000
commit47f4a458d636a889e955e68f896708f1276febc0 (patch)
tree99f770c02ef606f0abbdcd332ac39e69830d8007 /apps/plugins/doom/p_mobj.c
parentfff7d6157d56f233cad5c2003475e47a5ff809a7 (diff)
downloadrockbox-47f4a458d636a889e955e68f896708f1276febc0.zip
rockbox-47f4a458d636a889e955e68f896708f1276febc0.tar.gz
rockbox-47f4a458d636a889e955e68f896708f1276febc0.tar.bz2
rockbox-47f4a458d636a889e955e68f896708f1276febc0.tar.xz
Patch #2969 - Doom! Currently only working on the H300.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@9312 a1c6a512-1295-4272-9138-f99709370657
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 0000000..3aaaf45
--- /dev/null
+++ b/apps/plugins/doom/p_mobj.c
@@ -0,0 +1,1394 @@
+/* Emacs style mode select -*- C++ -*-
+ *-----------------------------------------------------------------------------
+ *
+ *
+ * PrBoom a Doom port merged with LxDoom and LSDLDoom
+ * based on BOOM, a modified and improved DOOM engine
+ * Copyright (C) 1999 by
+ * id Software, Chi Hoang, Lee Killough, Jim Flynn, Rand Phares, Ty Halderman
+ * Copyright (C) 1999-2000 by
+ * Jess Haas, Nicolas Kalkhof, Colin Phipps, Florian Schulze
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * DESCRIPTION:
+ * Moving object handling. Spawn functions.
+ *
+ *-----------------------------------------------------------------------------*/
+
+#include "doomdef.h"
+#include "doomstat.h"
+#include "m_random.h"
+#include "r_main.h"
+#include "p_maputl.h"
+#include "p_map.h"
+#include "p_tick.h"
+#include "sounds.h"
+#include "st_stuff.h"
+#include "hu_stuff.h"
+#include "s_sound.h"
+#include "info.h"
+#include "g_game.h"
+#include "p_inter.h"
+#include "rockmacros.h"
+//
+// P_SetMobjState
+// Returns true if the mobj is still present.
+//
+
+statenum_t i IBSS_ATTR; // initial state
+statenum_t seenstate_tab[NUMSTATES] IBSS_ATTR; // fast transition table
+
+boolean P_SetMobjState(mobj_t* mobj,statenum_t state)
+{
+ state_t* st;
+ // killough 4/9/98: remember states seen, to detect cycles:
+ statenum_t *seenstate = seenstate_tab; // pointer to table
+ static int recursion; // detects recursion
+ i = state;
+ boolean ret = true; // return value
+
+ if (recursion++) // if recursion detected,
+ memset(seenstate,0,sizeof(seenstate_tab)); // clear state table
+
+ do
+ {
+ if (state == S_NULL)
+ {
+ mobj->state = (state_t *) S_NULL;
+ P_RemoveMobj (mobj);
+ ret = false;
+ break; // killough 4/9/98
+ }
+
+ st = &states[state];
+ mobj->state = st;
+ mobj->tics = st->tics;
+ mobj->sprite = st->sprite;
+ mobj->frame = st->frame;
+
+ // Modified handling.
+ // Call action functions when the state is set
+
+ if (st->action)
+ st->action(mobj);
+
+ seenstate[state] = 1 + st->nextstate; // killough 4/9/98
+
+ state = st->nextstate;
+ } while (!mobj->tics && !seenstate[state]); // killough 4/9/98
+
+ if (ret && !mobj->tics) // killough 4/9/98: detect state cycles
+ doom_printf("Warning: State Cycle Detected");
+
+ if (!--recursion)
+ for (;(state=seenstate[i]);i=state-1)
+ seenstate[i] = 0; // killough 4/9/98: erase memory of states
+
+ return ret;
+}
+
+
+//
+// P_ExplodeMissile
+//
+
+void P_ExplodeMissile (mobj_t* mo)
+{
+ mo->momx = mo->momy = mo->momz = 0;
+
+ P_SetMobjState (mo, mobjinfo[mo->type].deathstate);
+
+ mo->tics -= P_Random(pr_explode)&3;
+
+ if (mo->tics < 1)
+ mo->tics = 1;
+
+ mo->flags &= ~MF_MISSILE;
+
+ if (mo->info->deathsound)
+ S_StartSound (mo, mo->info->deathsound);
+}
+
+
+//
+// P_XYMovement
+//
+// Attempts to move something if it has momentum.
+//
+
+void P_XYMovement (mobj_t* mo)
+{
+ player_t *player;
+ fixed_t xmove, ymove;
+#if 0
+ fixed_t ptryx;
+ fixed_t ptryy;
+ fixed_t xmove;
+ fixed_t ymove;
+ fixed_t oldx,oldy; // phares 9/10/98: reducing bobbing/momentum on ice
+ // when up against walls
+#endif
+ if (!(mo->momx | mo->momy)) // Any momentum?
+ {
+ if (mo->flags & MF_SKULLFLY)
+ {
+
+ // the skull slammed into something
+
+ mo->flags &= ~MF_SKULLFLY;
+ mo->momz = 0;
+
+ P_SetMobjState (mo, mo->info->spawnstate);
+ }
+ return;
+ }
+
+ player = mo->player;
+
+ if (mo->momx > MAXMOVE)
+ mo->momx = MAXMOVE;
+ else if (mo->momx < -MAXMOVE)
+ mo->momx = -MAXMOVE;
+
+ if (mo->momy > MAXMOVE)
+ mo->momy = MAXMOVE;
+ else if (mo->momy < -MAXMOVE)
+ mo->momy = -MAXMOVE;
+
+ xmove = mo->momx;
+ ymove = mo->momy;
+
+#if 0
+ oldx = mo->x; // phares 9/10/98: new code to reduce bobbing/momentum
+ oldy = mo->y; // when on ice & up against wall. These will be compared
+ // to your x,y values later to see if you were able to move
+#endif
+
+ do
+ {
+ fixed_t ptryx, ptryy;
+ // killough 8/9/98: fix bug in original Doom source:
+ // Large negative displacements were never considered.
+ // This explains the tendency for Mancubus fireballs
+ // to pass through walls.
+ // CPhipps - compatibility optioned
+
+ if (xmove > MAXMOVE/2 || ymove > MAXMOVE/2 ||
+ (!comp[comp_moveblock]
+ && (xmove < -MAXMOVE/2 || ymove < -MAXMOVE/2)))
+ {
+ ptryx = mo->x + xmove/2;
+ ptryy = mo->y + ymove/2;
+ xmove >>= 1;
+ ymove >>= 1;
+ }
+ else
+ {
+ ptryx = mo->x + xmove;
+ ptryy = mo->y + ymove;
+ xmove = ymove = 0;
+ }
+
+ // killough 3/15/98: Allow objects to drop off
+
+ if (!P_TryMove (mo, ptryx, ptryy, true))
+ {
+ // blocked move
+
+ // killough 8/11/98: bouncing off walls
+ // killough 10/98:
+ // Add ability for objects other than players to bounce on ice
+
+ if (!(mo->flags & MF_MISSILE) &&
+ mbf_features &&
+ (mo->flags & MF_BOUNCES ||
+ (!player && blockline &&
+ variable_friction && mo->z <= mo->floorz &&
+ P_GetFriction(mo, NULL) > ORIG_FRICTION)))
+ {
+ if (blockline)
+ {
+ fixed_t r = ((blockline->dx >> FRACBITS) * mo->momx +
+ (blockline->dy >> FRACBITS) * mo->momy) /
+ ((blockline->dx >> FRACBITS)*(blockline->dx >> FRACBITS)+
+ (blockline->dy >> FRACBITS)*(blockline->dy >> FRACBITS));
+ fixed_t x = FixedMul(r, blockline->dx);
+ fixed_t y = FixedMul(r, blockline->dy);
+
+ // reflect momentum away from wall
+
+ mo->momx = x*2 - mo->momx;
+ mo->momy = y*2 - mo->momy;
+
+ // if under gravity, slow down in
+ // direction perpendicular to wall.
+
+ if (!(mo->flags & MF_NOGRAVITY))
+ {
+ mo->momx = (mo->momx + x)/2;
+ mo->momy = (mo->momy + y)/2;
+ }
+ }
+ else
+ mo->momx = mo->momy = 0;
+ }
+ else
+ if (player) // try to slide along it
+ P_SlideMove (mo);
+ else
+ if (mo->flags & MF_MISSILE)
+ {
+ // explode a missile
+
+ if (ceilingline &&
+ ceilingline->backsector &&
+ ceilingline->backsector->ceilingpic == skyflatnum)
+ if (demo_compatibility || // killough
+ mo->z > ceilingline->backsector->ceilingheight)
+ {
+ // Hack to prevent missiles exploding
+ // against the sky.
+ // Does not handle sky floors.
+
+ P_RemoveMobj (mo);
+ return;
+ }
+ P_ExplodeMissile (mo);
+ }
+ else // whatever else it is, it is now standing still in (x,y)
+ mo->momx = mo->momy = 0;
+ }
+ } while (xmove || ymove);
+
+ // slow down
+
+#if 0 /* killough 10/98: this is unused code (except maybe in .deh files?) */
+ if (player && player->cheats & CF_NOMOMENTUM)
+ {
+ // debug option for no sliding at all
+ mo->momx = mo->momy = 0;
+ player->momx = player->momy = 0; /* killough 10/98 */
+ return;
+ }
+#endif
+
+ /* no friction for missiles or skulls ever, no friction when airborne */
+ if (mo->flags & (MF_MISSILE | MF_SKULLFLY) || mo->z > mo->floorz)
+ return;
+
+ /* killough 8/11/98: add bouncers
+ * killough 9/15/98: add objects falling off ledges
+ * killough 11/98: only include bouncers hanging off ledges
+ */
+ if (((mo->flags & MF_BOUNCES && mo->z > mo->dropoffz) ||
+ mo->flags & MF_CORPSE || mo->intflags & MIF_FALLING) &&
+ (mo->momx > FRACUNIT/4 || mo->momx < -FRACUNIT/4 ||
+ mo->momy > FRACUNIT/4 || mo->momy < -FRACUNIT/4) &&
+ mo->floorz != mo->subsector->sector->floorheight)
+ return; // do not stop sliding if halfway off a step with some momentum
+
+ // killough 11/98:
+ // Stop voodoo dolls that have come to rest, despite any
+ // moving corresponding player, except in old demos:
+
+ if (mo->momx > -STOPSPEED && mo->momx < STOPSPEED &&
+ mo->momy > -STOPSPEED && mo->momy < STOPSPEED &&
+ (!player || !(player->cmd.forwardmove | player->cmd.sidemove) ||
+ (player->mo != mo && compatibility_level >= lxdoom_1_compatibility)))
+ {
+ // if in a walking frame, stop moving
+
+ // killough 10/98:
+ // Don't affect main player when voodoo dolls stop, except in old demos:
+
+ if (player && (unsigned)(player->mo->state - states - S_PLAY_RUN1) < 4
+ && (player->mo == mo || compatibility_level >= lxdoom_1_compatibility))
+ P_SetMobjState(player->mo, S_PLAY);
+
+ mo->momx = mo->momy = 0;
+
+ /* killough 10/98: kill any bobbing momentum too (except in voodoo dolls)
+ * cph - DEMOSYNC - needs compatibility check?
+ */
+ if (player && player->mo == mo)
+ player->momx = player->momy = 0;
+ }
+ else
+ {
+ /* phares 3/17/98
+ *
+ * Friction will have been adjusted by friction thinkers for
+ * icy or muddy floors. Otherwise it was never touched and
+ * remained set at ORIG_FRICTION
+ *
+ * killough 8/28/98: removed inefficient thinker algorithm,
+ * instead using touching_sectorlist in P_GetFriction() to
+ * determine friction (and thus only when it is needed).
+ *
+ * killough 10/98: changed to work with new bobbing method.
+ * Reducing player momentum is no longer needed to reduce
+ * bobbing, so ice works much better now.
+ *
+ * cph - DEMOSYNC - need old code for Boom demos?
+ */
+
+ fixed_t friction = P_GetFriction(mo, NULL);
+
+ mo->momx = FixedMul(mo->momx, friction);
+ mo->momy = FixedMul(mo->momy, friction);
+
+ /* killough 10/98: Always decrease player bobbing by ORIG_FRICTION.
+ * This prevents problems with bobbing on ice, where it was not being
+ * reduced fast enough, leading to all sorts of kludges being developed.
+ */
+
+ if (player && player->mo == mo) /* Not voodoo dolls */
+ {
+ player->momx = FixedMul(player->momx, ORIG_FRICTION);
+ player->momy = FixedMul(player->momy, ORIG_FRICTION);
+ }
+
+ }
+}
+
+
+//
+// P_ZMovement
+//
+// Attempt vertical movement.
+
+static void P_ZMovement (mobj_t* mo)
+{
+ /* killough 7/11/98:
+ * BFG fireballs bounced on floors and ceilings in Pre-Beta Doom
+ * killough 8/9/98: added support for non-missile objects bouncing
+ * (e.g. grenade, mine, pipebomb)
+ */
+
+ if (mo->flags & MF_BOUNCES && mo->momz) {
+ mo->z += mo->momz;
+ if (mo->z <= mo->floorz) { /* bounce off floors */
+ mo->z = mo->floorz;
+ if (mo->momz < 0) {
+ mo->momz = -mo->momz;
+ if (!(mo->flags & MF_NOGRAVITY)) { /* bounce back with decay */
+ mo->momz = mo->flags & MF_FLOAT ? // floaters fall slowly
+ mo->flags & MF_DROPOFF ? // DROPOFF indicates rate
+ FixedMul(mo->momz, (fixed_t)(FRACUNIT*.85)) :
+ FixedMul(mo->momz, (fixed_t)(FRACUNIT*.70)) :
+ FixedMul(mo->momz, (fixed_t)(FRACUNIT*.45)) ;
+
+ /* Bring it to rest below a certain speed */
+ if (abs(mo->momz) <= mo->info->mass*(GRAVITY*4/256))
+ mo->momz = 0;
+ }
+
+ /* killough 11/98: touchy objects explode on impact */
+ if (mo->flags & MF_TOUCHY && mo->intflags & MIF_ARMED
+ && mo->health > 0)
+ P_DamageMobj(mo, NULL, NULL, mo->health);
+ else if (mo->flags & MF_FLOAT && sentient(mo))
+ goto floater;
+ return;
+ }
+} else if (mo->z >= mo->ceilingz - mo->height) {
+ /* bounce off ceilings */
+ mo->z = mo->ceilingz - mo->height;
+ if (mo->momz > 0) {
+ if (mo->subsector->sector->ceilingpic != skyflatnum)
+ mo->momz = -mo->momz; /* always bounce off non-sky ceiling */
+ else if (mo->flags & MF_MISSILE)
+ P_RemoveMobj(mo); /* missiles don't bounce off skies */
+ else if (mo->flags & MF_NOGRAVITY)
+ mo->momz = -mo->momz; // bounce unless under gravity
+
+ if (mo->flags & MF_FLOAT && sentient(mo))
+ goto floater;
+
+ return;
+ }
+ } else {
+ if (!(mo->flags & MF_NOGRAVITY)) /* free-fall under gravity */
+ mo->momz -= mo->info->mass*(GRAVITY/256);
+
+ if (mo->flags & MF_FLOAT && sentient(mo)) goto floater;
+ return;
+ }
+
+ /* came to a stop */
+ mo->momz = 0;
+
+ if (mo->flags & MF_MISSILE) {
+ if (ceilingline &&
+ ceilingline->backsector &&
+ ceilingline->backsector->ceilingpic == skyflatnum &&
+ mo->z > ceilingline->backsector->ceilingheight)
+ P_RemoveMobj(mo); /* don't explode on skies */
+ else
+ P_ExplodeMissile(mo);
+ }
+
+ if (mo->flags & MF_FLOAT && sentient(mo)) goto floater;
+ return;
+ }
+
+ /* killough 8/9/98: end bouncing object code */
+
+ // check for smooth step up
+
+ if (mo->player &&
+ mo->player->mo == mo && // killough 5/12/98: exclude voodoo dolls
+ mo->z < mo->floorz)
+ {
+ mo->player->viewheight -= mo->floorz-mo->z;
+ mo->player->deltaviewheight = (VIEWHEIGHT - mo->player->viewheight)>>3;
+ }
+
+ // adjust altitude
+
+ mo->z += mo->momz;
+
+floater:
+ if ((mo->flags & MF_FLOAT) && mo->target)
+
+ // float down towards target if too close
+
+ if (!((mo->flags ^ MF_FLOAT) & (MF_FLOAT | MF_SKULLFLY | MF_INFLOAT)) &&
+ mo->target) /* killough 11/98: simplify */
+ {
+ fixed_t delta;
+ if (P_AproxDistance(mo->x - mo->target->x, mo->y - mo->target->y) <
+ abs(delta = mo->target->z + (mo->height>>1) - mo->z)*3)
+ mo->z += delta < 0 ? -FLOATSPEED : FLOATSPEED;
+ }
+
+ // clip movement
+
+ if (mo->z <= mo->floorz)
+ {
+ // hit the floor
+
+ /* Note (id):
+ * somebody left this after the setting momz to 0,
+ * kinda useless there.
+ * cph - This was the a bug in the linuxdoom-1.10 source which
+ * caused it not to sync Doom 2 v1.9 demos. Someone
+ * added the above comment and moved up the following code. So
+ * demos would desync in close lost soul fights.
+ * Note that this only applies to original Doom 1 or Doom2 demos -
+ * Final Doom and Ultimate Doom. So we test demo_compatibility *and*
+ * gamemission. (Note we assume that Doom1 is always Ult Doom, which
+ * seems to hold for most published demos.)
+ */
+ int correct_lost_soul_bounce = !demo_compatibility || (gamemission != doom2);
+
+ if (correct_lost_soul_bounce && mo->flags & MF_SKULLFLY)
+ mo->momz = -mo->momz; // the skull slammed into something
+
+ if (mo->momz < 0)
+ {
+ /* killough 11/98: touchy objects explode on impact */
+ if (mo->flags & MF_TOUCHY && mo->intflags & MIF_ARMED && mo->health > 0)
+ P_DamageMobj(mo, NULL, NULL, mo->health);
+ else
+ if (mo->player && /* killough 5/12/98: exclude voodoo dolls */
+ mo->player->mo == mo && mo->momz < -GRAVITY*8)
+ {
+ // Squat down.
+ // Decrease viewheight for a moment
+ // after hitting the ground (hard),
+ // and utter appropriate sound.
+
+ mo->player->deltaviewheight = mo->momz>>3;
+ if (mo->health) /* cph - prevent "oof" when dead */
+ S_StartSound (mo, sfx_oof);
+ }
+ mo->momz = 0;
+ }
+ mo->z = mo->floorz;
+
+ /* cph 2001/05/26 -
+ * See lost soul bouncing comment above. We need this here for bug
+ * compatibility with original Doom2 v1.9 - if a soul is charging and
+ * hit by a raising floor this incorrectly reverses its Y momentum.
+ */
+ if (!correct_lost_soul_bounce && mo->flags & MF_SKULLFLY)
+ mo->momz = -mo->momz; // the skull slammed into something
+
+ if ( (mo->flags & MF_MISSILE) && !(mo->flags & MF_NOCLIP) )
+ {
+ P_ExplodeMissile (mo);
+ return;
+ }
+ }
+ else // still above the floor // phares
+ if (!(mo->flags & MF_NOGRAVITY))
+ {
+ if (!mo->momz)
+ mo->momz = -GRAVITY;
+ mo->momz -= GRAVITY;
+ }
+
+ if (mo->z + mo->height > mo->ceilingz)
+ {
+
+ // hit the ceiling
+
+ if (mo->momz > 0)
+ mo->momz = 0;
+
+ mo->z = mo->ceilingz - mo->height;
+
+ if (mo->flags & MF_SKULLFLY)
+ mo->momz = -mo->momz; // the skull slammed into something
+
+ if ( (mo->flags & MF_MISSILE) && !(mo->flags & MF_NOCLIP) )
+ {
+ P_ExplodeMissile (mo);
+ return;
+ }
+ }
+}
+
+//
+// P_NightmareRespawn
+//
+
+void P_NightmareRespawn(mobj_t* mobj)
+{
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ subsector_t* ss;
+ mobj_t* mo;
+ mapthing_t* mthing;
+
+ x = mobj->spawnpoint.x << FRACBITS;
+ y = mobj->spawnpoint.y << FRACBITS;
+
+ /* haleyjd: stupid nightmare respawning bug fix
+ *
+ * 08/09/00: compatibility added, time to ramble :)
+ * This fixes the notorious nightmare respawning bug that causes monsters
+ * that didn't spawn at level startup to respawn at the point (0,0)
+ * regardless of that point's nature. SMMU and Eternity need this for
+ * script-spawned things like Halif Swordsmythe, as well.
+ *
+ * cph - copied from eternity, except comp_respawnfix becomes comp_respawn
+ * and the logic is reversed (i.e. like the rest of comp_ it *disables*
+ * the fix)
+ */
+ if(!comp[comp_respawn] && !x && !y)
+ {
+ // spawnpoint was zeroed out, so use point of death instead
+ x = mobj->x;
+ y = mobj->y;
+ }
+
+ // something is occupying its position?
+
+ if (!P_CheckPosition (mobj, x, y) )
+ return; // no respwan
+
+ // spawn a teleport fog at old spot
+ // because of removal of the body?
+
+ mo = P_SpawnMobj (mobj->x,
+ mobj->y,
+ mobj->subsector->sector->floorheight,
+ MT_TFOG);
+
+ // initiate teleport sound
+
+ S_StartSound (mo, sfx_telept);
+
+ // spawn a teleport fog at the new spot
+
+ ss = R_PointInSubsector (x,y);
+
+ mo = P_SpawnMobj (x, y, ss->sector->floorheight , MT_TFOG);
+
+ S_StartSound (mo, sfx_telept);
+
+ // spawn the new monster
+
+ mthing = &mobj->spawnpoint;
+ if (mobj->info->flags & MF_SPAWNCEILING)
+ z = ONCEILINGZ;
+ else
+ z = ONFLOORZ;
+
+ // inherit attributes from deceased one
+
+ mo = P_SpawnMobj (x,y,z, mobj->type);
+ mo->spawnpoint = mobj->spawnpoint;
+ mo->angle = ANG45 * (mthing->angle/45);
+
+ if (mthing->options & MTF_AMBUSH)
+ mo->flags |= MF_AMBUSH;
+
+ /* killough 11/98: transfer friendliness from deceased */
+ mo->flags = (mo->flags & ~MF_FRIEND) | (mobj->flags & MF_FRIEND);
+
+ mo->reactiontime = 18;
+
+ // remove the old monster,
+
+ P_RemoveMobj (mobj);
+}
+
+
+//
+// P_MobjThinker
+//
+
+void P_MobjThinker (mobj_t* mobj)
+{
+ // killough 11/98:
+ // removed old code which looked at target references
+ // (we use pointer reference counting now)
+
+ // momentum movement
+ if (mobj->momx | mobj->momy || mobj->flags & MF_SKULLFLY)
+ {
+ P_XYMovement(mobj);
+ if (mobj->thinker.function != P_MobjThinker) // cph - Must've been removed
+ return; // killough - mobj was removed
+ }
+
+ if (mobj->z != mobj->floorz || mobj->momz)
+ {
+ P_ZMovement(mobj);
+ if (mobj->thinker.function != P_MobjThinker) // cph - Must've been removed
+ return; // killough - mobj was removed
+ }
+ else
+ if (!(mobj->momx | mobj->momy) && !sentient(mobj))
+ { // non-sentient objects at rest
+ mobj->intflags |= MIF_ARMED; // arm a mine which has come to rest
+
+ // killough 9/12/98: objects fall off ledges if they are hanging off
+ // slightly push off of ledge if hanging more than halfway off
+
+ if (mobj->z > mobj->dropoffz && // Only objects contacting dropoff
+ !(mobj->flags & MF_NOGRAVITY) && // Only objects which fall
+ !comp[comp_falloff]) // Not in old demos
+ P_ApplyTorque(mobj); // Apply torque
+ else
+ mobj->intflags &= ~MIF_FALLING, mobj->gear = 0; // Reset torque
+ }
+
+ // cycle through states,
+ // calling action functions at transitions
+
+ if (mobj->tics != -1)
+ {
+ mobj->tics--;
+
+ // you can cycle through multiple states in a tic
+
+ if (!mobj->tics)
+ if (!P_SetMobjState (mobj, mobj->state->nextstate) )
+ return; // freed itself
+ }
+ else
+ {
+
+ // check for nightmare respawn
+
+ if (! (mobj->flags & MF_COUNTKILL) )
+ return;
+
+ if (!respawnmonsters)
+ return;
+
+ mobj->movecount++;
+
+ if (mobj->movecount < 12*35)
+ return;
+
+ if (leveltime & 31)
+ return;
+
+ if (P_Random (pr_respawn) > 4)
+ return;
+
+ P_NightmareRespawn (mobj);
+ }
+
+}
+
+
+//
+// P_SpawnMobj
+//
+mobj_t* P_SpawnMobj(fixed_t x,fixed_t y,fixed_t z,mobjtype_t type)
+{
+ mobj_t* mobj;
+ state_t* st;
+ mobjinfo_t* info;
+
+ mobj = Z_Malloc (sizeof(*mobj), PU_LEVEL, NULL);
+ memset (mobj, 0, sizeof (*mobj));
+ info = &mobjinfo[type];
+ mobj->type = type;
+ mobj->info = info;
+ mobj->x = x;
+ mobj->y = y;
+ mobj->radius = info->radius;
+ mobj->height = info->height; // phares
+ mobj->flags = info->flags;
+
+ /* killough 8/23/98: no friends, bouncers, or touchy things in old demos */
+ if (!mbf_features)
+ mobj->flags &= ~(MF_BOUNCES | MF_FRIEND | MF_TOUCHY);
+ else
+ if (type == MT_PLAYER) // Except in old demos, players
+ mobj->flags |= MF_FRIEND; // are always friends.
+
+ mobj->health = info->spawnhealth;
+
+ if (gameskill != sk_nightmare)
+ mobj->reactiontime = info->reactiontime;
+
+ mobj->lastlook = P_Random (pr_lastlook) % MAXPLAYERS;
+
+ // do not set the state with P_SetMobjState,
+ // because action routines can not be called yet
+
+ st = &states[info->spawnstate];
+
+ mobj->state = st;
+ mobj->tics = st->tics;
+ mobj->sprite = st->sprite;
+ mobj->frame = st->frame;
+ mobj->touching_sectorlist = NULL; // NULL head of sector list // phares 3/13/98
+
+ // set subsector and/or block links
+
+ P_SetThingPosition (mobj);
+
+ mobj->dropoffz = /* killough 11/98: for tracking dropoffs */
+ mobj->floorz = mobj->subsector->sector->floorheight;
+ mobj->ceilingz = mobj->subsector->sector->ceilingheight;
+
+ mobj->z = z == ONFLOORZ ? mobj->floorz : z == ONCEILINGZ ?
+ mobj->ceilingz - mobj->height : z;
+
+ mobj->thinker.function = P_MobjThinker;
+ mobj->above_thing = 0; // phares
+ mobj->below_thing = 0; // phares
+
+ mobj->target = mobj->tracer = mobj->lastenemy = NULL;
+ P_AddThinker (&mobj->thinker);
+ if (!((mobj->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL)))
+ totallive++;
+ return mobj;
+}
+
+
+mapthing_t itemrespawnque[ITEMQUESIZE];
+int itemrespawntime[ITEMQUESIZE];
+int iquehead;
+int iquetail;
+
+
+//
+// P_RemoveMobj
+//
+
+void P_RemoveMobj (mobj_t* mobj)
+{
+ if ((mobj->flags & MF_SPECIAL)
+ && !(mobj->flags & MF_DROPPED)
+ && (mobj->type != MT_INV)
+ && (mobj->type != MT_INS))
+ {
+ itemrespawnque[iquehead] = mobj->spawnpoint;
+ itemrespawntime[iquehead] = leveltime;
+ iquehead = (iquehead+1)&(ITEMQUESIZE-1);
+
+ // lose one off the end?
+
+ if (iquehead == iquetail)
+ iquetail = (iquetail+1)&(ITEMQUESIZE-1);
+ }
+
+ // unlink from sector and block lists
+
+ P_UnsetThingPosition (mobj);
+
+ // Delete all nodes on the current sector_list phares 3/16/98
+
+ if (sector_list)
+ {
+ P_DelSeclist(sector_list);
+ sector_list = NULL;
+ }
+
+ // stop any playing sound
+
+ S_StopSound (mobj);
+
+ // killough 11/98:
+ //
+ // Remove any references to other mobjs.
+ //
+ // Older demos might depend on the fields being left alone, however,
+ // if multiple thinkers reference each other indirectly before the
+ // end of the current tic.
+ // CPhipps - only leave dead references in old demos; I hope lxdoom_1 level
+ // demos are rare and don't rely on this. I hope.
+
+ if ((compatibility_level >= lxdoom_1_compatibility) ||
+ (!demorecording && !demoplayback)) {
+ P_SetTarget(&mobj->target, NULL);
+ P_SetTarget(&mobj->tracer, NULL);
+ P_SetTarget(&mobj->lastenemy, NULL);
+ }
+ // free block
+
+ // P_RemoveThinker ((thinker_t*)mobj);
+ P_RemoveThinker (&mobj->thinker);
+}
+
+
+/*
+ * P_FindDoomedNum
+ *
+ * Finds a mobj type with a matching doomednum
+ *
+ * killough 8/24/98: rewrote to use hashing
+ */
+
+int P_FindDoomedNum(unsigned type)
+{
+ static struct { int first, next; } *hash;
+ register int i;
+
+ if (!hash)
+ {
+ hash = Z_Malloc(sizeof (*hash) * NUMMOBJTYPES, PU_CACHE, (void*)(void*) &hash);
+ for (i=0; i<NUMMOBJTYPES; i++)
+ hash[i].first = NUMMOBJTYPES;
+ for (i=0; i<NUMMOBJTYPES; i++)
+ if (mobjinfo[i].doomednum != -1)
+ {
+ unsigned h = (unsigned) mobjinfo[i].doomednum % NUMMOBJTYPES;
+ hash[i].next = hash[h].first;
+ hash[h].first = i;
+ }
+ }
+
+ i = hash[type % NUMMOBJTYPES].first;
+ while ((i < NUMMOBJTYPES) && ((unsigned)mobjinfo[i].doomednum != type))
+ i = hash[i].next;
+ return i;
+}
+
+//
+// P_RespawnSpecials
+//
+
+void P_RespawnSpecials (void)
+{
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ subsector_t* ss;
+ mobj_t* mo;
+ mapthing_t* mthing;
+ int i;
+
+ // only respawn items in deathmatch
+
+ if (deathmatch != 2)
+ return;
+
+ // nothing left to respawn?
+
+ if (iquehead == iquetail)
+ return;
+
+ // wait at least 30 seconds
+
+ if (leveltime - itemrespawntime[iquetail] < 30*35)
+ return;
+
+ mthing = &itemrespawnque[iquetail];
+
+ x = mthing->x << FRACBITS;
+ y = mthing->y << FRACBITS;
+
+ // spawn a teleport fog at the new spot
+
+ ss = R_PointInSubsector (x,y);
+ mo = P_SpawnMobj (x, y, ss->sector->floorheight , MT_IFOG);
+ S_StartSound (mo, sfx_itmbk);
+
+ // find which type to spawn
+
+ /* killough 8/23/98: use table for faster lookup */
+ i = P_FindDoomedNum(mthing->type);
+
+ // spawn it
+
+ if (mobjinfo[i].flags & MF_SPAWNCEILING)
+ z = ONCEILINGZ;
+ else
+ z = ONFLOORZ;
+
+ mo = P_SpawnMobj (x,y,z, i);
+ mo->spawnpoint = *mthing;
+ mo->angle = ANG45 * (mthing->angle/45);
+
+ // pull it from the queue
+
+ iquetail = (iquetail+1)&(ITEMQUESIZE-1);
+}
+
+//
+// P_SpawnPlayer
+// Called when a player is spawned on the level.
+// Most of the player structure stays unchanged
+// between levels.
+//
+
+extern byte playernumtotrans[MAXPLAYERS];
+
+void P_SpawnPlayer (mapthing_t* mthing)
+{
+ player_t* p;
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ mobj_t* mobj;
+ int i;
+
+ // not playing?
+
+ if (!playeringame[mthing->type-1])
+ return;
+
+ p = &players[mthing->type-1];
+
+ if (p->playerstate == PST_REBORN)
+ G_PlayerReborn (mthing->type-1);
+
+ x = mthing->x << FRACBITS;
+ y = mthing->y << FRACBITS;
+ z = ONFLOORZ;
+ mobj = P_SpawnMobj (x,y,z, MT_PLAYER);
+
+ // set color translations for player sprites
+
+ if (mthing->type > 0)
+ mobj->flags |= playernumtotrans[mthing->type-1]<<MF_TRANSSHIFT;
+
+ mobj->angle = ANG45 * (mthing->angle/45);
+ mobj->player = p;
+ mobj->health = p->health;
+
+ p->mo = mobj;
+ p->playerstate = PST_LIVE;
+ p->refire = 0;
+ p->message = NULL;
+ p->damagecount = 0;
+ p->bonuscount = 0;
+ p->extralight = 0;
+ p->fixedcolormap = 0;
+ p->viewheight = VIEWHEIGHT;
+
+ p->momx = p->momy = 0; // killough 10/98: initialize bobbing to 0.
+
+ // setup gun psprite
+
+ P_SetupPsprites (p);
+
+ // give all cards in death match mode
+
+ if (deathmatch)
+ for (i = 0 ; i < NUMCARDS ; i++)
+ p->cards[i] = true;
+
+ if (mthing->type-1 == consoleplayer)
+ {
+ ST_Start(); // wake up the status bar
+ HU_Start(); // wake up the heads up text
+ }
+}
+
+
+//
+// P_SpawnMapThing
+// The fields of the mapthing should
+// already be in host byte order.
+//
+
+void P_SpawnMapThing (mapthing_t* mthing)
+{
+ int i;
+ //int bit;
+ mobj_t* mobj;
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+
+ // killough 2/26/98: Ignore type-0 things as NOPs
+ // phares 5/14/98: Ignore Player 5-8 starts (for now)
+
+ switch(mthing->type)
+ {
+ case 0:
+ case DEN_PLAYER5:
+ case DEN_PLAYER6:
+ case DEN_PLAYER7:
+ case DEN_PLAYER8:
+ return;
+ }
+
+ // killough 11/98: clear flags unused by Doom
+ //
+ // We clear the flags unused in Doom if we see flag mask 256 set, since
+ // it is reserved to be 0 under the new scheme. A 1 in this reserved bit
+ // indicates it's a Doom wad made by a Doom editor which puts 1's in
+ // bits that weren't used in Doom (such as HellMaker wads). So we should
+ // then simply ignore all upper bits.
+
+ if (demo_compatibility ||
+ (compatibility_level >= lxdoom_1_compatibility &&
+ mthing->options & MTF_RESERVED)) {
+ if (!demo_compatibility) // cph - Add warning about bad thing flags
+ printf("P_SpawnMapThing: correcting bad flags (%u) (thing type %d)\n",
+ mthing->options, mthing->type);
+ mthing->options &= MTF_EASY|MTF_NORMAL|MTF_HARD|MTF_AMBUSH|MTF_NOTSINGLE;
+ }
+
+ // count deathmatch start positions
+
+ // doom2.exe has at most 10 deathmatch starts
+ if (mthing->type == 11 && (!compatibility || deathmatch_p-deathmatchstarts < 10))
+ {
+ // 1/11/98 killough -- new code removes limit on deathmatch starts:
+
+ size_t offset = deathmatch_p - deathmatchstarts;
+
+ if (offset >= num_deathmatchstarts)
+ {
+ num_deathmatchstarts = num_deathmatchstarts ?
+ num_deathmatchstarts*2 : 16;
+ deathmatchstarts = realloc(deathmatchstarts,
+ num_deathmatchstarts *
+ sizeof(*deathmatchstarts));
+ deathmatch_p = deathmatchstarts + offset;
+ }
+ memcpy(deathmatch_p++, mthing, sizeof(*mthing));
+ return;
+ }
+
+ // check for players specially
+
+ if (mthing->type <= 4 && mthing->type > 0) // killough 2/26/98 -- fix crashes
+ {
+#ifdef DOGS
+ // killough 7/19/98: Marine's best friend :)
+ if (!netgame && mthing->type > 1 && mthing->type <= dogs+1 &&
+ !players[mthing->type-1].secretcount)
+ { // use secretcount to avoid multiple dogs in case of multiple starts
+ players[mthing->type-1].secretcount = 1;
+
+ // killough 10/98: force it to be a friend
+ mthing->options |= MTF_FRIEND;
+ i = MT_DOGS;
+ goto spawnit;
+ }
+#endif
+
+
+ // save spots for respawning in network games
+
+ playerstarts[mthing->type-1] = *mthing;
+ if (!deathmatch)
+ P_SpawnPlayer (mthing);
+ return;
+ }
+
+ // check for apropriate skill level
+
+ /* jff "not single" thing flag */
+ if (!netgame && mthing->options & MTF_NOTSINGLE)
+ return;
+
+ //jff 3/30/98 implement "not deathmatch" thing flag
+
+ if (netgame && deathmatch && mthing->options & MTF_NOTDM)
+ return;
+
+ //jff 3/30/98 implement "not cooperative" thing flag
+
+ if (netgame && !deathmatch && mthing->options & MTF_NOTCOOP)
+ return;
+
+ // killough 11/98: simplify
+ if (gameskill == sk_baby || gameskill == sk_easy ?
+ !(mthing->options & MTF_EASY) :
+ gameskill == sk_hard || gameskill == sk_nightmare ?
+ !(mthing->options & MTF_HARD) : !(mthing->options & MTF_NORMAL))
+ return;
+
+ // find which type to spawn
+
+ // killough 8/23/98: use table for faster lookup
+ i = P_FindDoomedNum(mthing->type);
+
+ // phares 5/16/98:
+ // Do not abort because of an unknown thing. Ignore it, but post a
+ // warning message for the player.
+
+ if (i == NUMMOBJTYPES)
+ {
+ doom_printf("Unknown Thing type %i at (%i, %i)",mthing->type,mthing->x,mthing->y);
+ return;
+ }
+
+ // don't spawn keycards and players in deathmatch
+
+ if (deathmatch && mobjinfo[i].flags & MF_NOTDMATCH)
+ return;
+
+ // don't spawn any monsters if -nomonsters
+
+ if (nomonsters && (i == MT_SKULL || (mobjinfo[i].flags & MF_COUNTKILL)))
+ return;
+
+ // spawn it
+#ifdef DOGS
+spawnit:
+#endif
+
+ x = mthing->x << FRACBITS;
+ y = mthing->y << FRACBITS;
+
+ if (mobjinfo[i].flags & MF_SPAWNCEILING)
+ z = ONCEILINGZ;
+ else
+ z = ONFLOORZ;
+
+ mobj = P_SpawnMobj (x,y,z, i);
+ mobj->spawnpoint = *mthing;
+
+ if (mobj->tics > 0)
+ mobj->tics = 1 + (P_Random (pr_spawnthing) % mobj->tics);
+
+ if (!(mobj->flags & MF_FRIEND) &&
+ mthing->options & MTF_FRIEND &&
+ mbf_features)
+ {
+ mobj->flags |= MF_FRIEND; // killough 10/98:
+ P_UpdateThinker(&mobj->thinker); // transfer friendliness flag
+ }
+
+ /* killough 7/20/98: exclude friends */
+ if (!((mobj->flags ^ MF_COUNTKILL) & (MF_FRIEND | MF_COUNTKILL)))
+ totalkills++;
+
+ if (mobj->flags & MF_COUNTITEM)
+ totalitems++;
+
+ mobj->angle = ANG45 * (mthing->angle/45);
+ if (mthing->options & MTF_AMBUSH)
+ mobj->flags |= MF_AMBUSH;
+}
+
+
+//
+// GAME SPAWN FUNCTIONS
+//
+
+//
+// P_SpawnPuff
+//
+
+extern fixed_t attackrange;
+
+void P_SpawnPuff(fixed_t x,fixed_t y,fixed_t z)
+{
+ mobj_t* th;
+ // killough 5/5/98: remove dependence on order of evaluation:
+ int t = P_Random(pr_spawnpuff);
+ z += (t - P_Random(pr_spawnpuff))<<10;
+
+ th = P_SpawnMobj (x,y,z, MT_PUFF);
+ th->momz = FRACUNIT;
+ th->tics -= P_Random(pr_spawnpuff)&3;
+
+ if (th->tics < 1)
+ th->tics = 1;
+
+ // don't make punches spark on the wall
+
+ if (attackrange == MELEERANGE)
+ P_SetMobjState (th, S_PUFF3);
+}
+
+
+//
+// P_SpawnBlood
+//
+void P_SpawnBlood(fixed_t x,fixed_t y,fixed_t z,int damage)
+{
+ mobj_t* th;
+ // killough 5/5/98: remove dependence on order of evaluation:
+ int t = P_Random(pr_spawnblood);
+ z += (t - P_Random(pr_spawnblood))<<10;
+ th = P_SpawnMobj(x,y,z, MT_BLOOD);
+ th->momz = FRACUNIT*2;
+ th->tics -= P_Random(pr_spawnblood)&3;
+
+ if (th->tics < 1)
+ th->tics = 1;
+
+ if (damage <= 12 && damage >= 9)
+ P_SetMobjState (th,S_BLOOD2);
+ else if (damage < 9)
+ P_SetMobjState (th,S_BLOOD3);
+}
+
+
+//
+// P_CheckMissileSpawn
+// Moves the missile forward a bit
+// and possibly explodes it right there.
+//
+
+void P_CheckMissileSpawn (mobj_t* th)
+{
+ th->tics -= P_Random(pr_missile)&3;
+ if (th->tics < 1)
+ th->tics = 1;
+
+ // move a little forward so an angle can
+ // be computed if it immediately explodes
+
+ th->x += (th->momx>>1);
+ th->y += (th->momy>>1);
+ th->z += (th->momz>>1);
+
+ // killough 8/12/98: for non-missile objects (e.g. grenades)
+ if (!(th->flags & MF_MISSILE) && mbf_features)
+ return;
+
+ // killough 3/15/98: no dropoff (really = don't care for missiles)
+
+ if (!P_TryMove (th, th->x, th->y, false))
+ P_ExplodeMissile (th);
+}
+
+
+//
+// P_SpawnMissile
+//
+
+mobj_t* P_SpawnMissile(mobj_t* source,mobj_t* dest,mobjtype_t type)
+{
+ mobj_t* th;
+ angle_t an;
+ int dist;
+
+ th = P_SpawnMobj (source->x,source->y,source->z + 4*8*FRACUNIT,type);
+
+ if (th->info->seesound)
+ S_StartSound (th, th->info->seesound);
+
+ P_SetTarget(&th->target, source); // where it came from
+ an = R_PointToAngle2 (source->x, source->y, dest->x, dest->y);
+
+ // fuzzy player
+
+ if (dest->flags & MF_SHADOW)
+ { // killough 5/5/98: remove dependence on order of evaluation:
+ int t = P_Random(pr_shadow);
+ an += (t - P_Random(pr_shadow))<<20;
+ }
+
+ th->angle = an;
+ an >>= ANGLETOFINESHIFT;
+ th->momx = FixedMul (th->info->speed, finecosine[an]);
+ th->momy = FixedMul (th->info->speed, finesine[an]);
+
+ dist = P_AproxDistance (dest->x - source->x, dest->y - source->y);
+ dist = dist / th->info->speed;
+
+ if (dist < 1)
+ dist = 1;
+
+ th->momz = (dest->z - source->z) / dist;
+ P_CheckMissileSpawn (th);
+
+ return th;
+}
+
+
+//
+// P_SpawnPlayerMissile
+// Tries to aim at a nearby monster
+//
+
+void P_SpawnPlayerMissile(mobj_t* source,mobjtype_t type)
+{
+ mobj_t *th;
+ fixed_t x, y, z, slope = 0;
+
+ // see which target is to be aimed at
+
+ angle_t an = source->angle;
+
+ // killough 7/19/98: autoaiming was not in original beta
+ {
+ // killough 8/2/98: prefer autoaiming at enemies
+ uint_64_t mask = mbf_features ? MF_FRIEND : 0;
+
+ do
+ {
+ slope = P_AimLineAttack(source, an, 16*64*FRACUNIT, mask);
+ if (!linetarget)
+ slope = P_AimLineAttack(source, an += 1<<26, 16*64*FRACUNIT, mask);
+ if (!linetarget)
+ slope = P_AimLineAttack(source, an -= 2<<26, 16*64*FRACUNIT, mask);
+ if (!linetarget)
+ an = source->angle, slope = 0;
+ }
+ while (mask && (mask=0, !linetarget)); // killough 8/2/98
+ }
+
+ x = source->x;
+ y = source->y;
+ z = source->z + 4*8*FRACUNIT;
+
+ th = P_SpawnMobj (x,y,z, type);
+
+ if (th->info->seesound)
+ S_StartSound (th, th->info->seesound);
+
+ P_SetTarget(&th->target, source);
+ th->angle = an;
+ th->momx = FixedMul(th->info->speed,finecosine[an>>ANGLETOFINESHIFT]);
+ th->momy = FixedMul(th->info->speed,finesine[an>>ANGLETOFINESHIFT]);
+ th->momz = FixedMul(th->info->speed,slope);
+
+ P_CheckMissileSpawn(th);
+}