summaryrefslogtreecommitdiff
path: root/src/strife/p_mobj.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/strife/p_mobj.c')
-rw-r--r--src/strife/p_mobj.c1360
1 files changed, 1360 insertions, 0 deletions
diff --git a/src/strife/p_mobj.c b/src/strife/p_mobj.c
new file mode 100644
index 00000000..8d1a7f3a
--- /dev/null
+++ b/src/strife/p_mobj.c
@@ -0,0 +1,1360 @@
+// Emacs style mode select -*- C++ -*-
+//-----------------------------------------------------------------------------
+//
+// Copyright(C) 1993-1996 Id Software, Inc.
+// Copyright(C) 2005 Simon Howard
+//
+// 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 <stdio.h>
+
+#include "i_system.h"
+#include "z_zone.h"
+#include "m_random.h"
+#include "doomdef.h"
+#include "p_local.h"
+#include "sounds.h"
+#include "st_stuff.h"
+#include "hu_stuff.h"
+#include "s_sound.h"
+#include "doomstat.h"
+#include "d_main.h" // villsa [STRIFE]
+
+extern line_t *spechit[]; // haleyjd:
+extern int numspechit; // [STRIFE] - needed in P_XYMovement
+
+
+void G_PlayerReborn (int player);
+void P_SpawnMapThing (mapthing_t* mthing);
+
+
+//
+// P_SetMobjState
+// Returns true if the mobj is still present.
+//
+// [STRIFE] Verified unmodified
+//
+int test;
+
+boolean
+P_SetMobjState
+( mobj_t* mobj,
+ statenum_t state )
+{
+ state_t* st;
+
+ do
+ {
+ if (state == S_NULL)
+ {
+ mobj->state = (state_t *) S_NULL;
+ P_RemoveMobj (mobj);
+ return false;
+ }
+
+ 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.acp1)
+ st->action.acp1(mobj);
+
+ state = st->nextstate;
+ } while (!mobj->tics);
+
+ return true;
+}
+
+
+//
+// P_ExplodeMissile
+//
+// [STRIFE] Removed randomization of deathstate tics
+//
+void P_ExplodeMissile (mobj_t* mo)
+{
+ mo->momx = mo->momy = mo->momz = 0;
+
+ P_SetMobjState (mo, mobjinfo[mo->type].deathstate);
+
+ // villsa [STRIFE] removed tics randomization
+
+ mo->flags &= ~MF_MISSILE;
+
+ if (mo->info->deathsound)
+ S_StartSound (mo, mo->info->deathsound);
+}
+
+
+//
+// P_XYMovement
+//
+// [STRIFE] Modifications for:
+// * No SKULLFLY logic (replaced by BOUNCE flag)
+// * Missiles can activate G1/GR line types
+// * Player walking logic
+// * Air friction for players
+//
+#define STOPSPEED 0x1000
+#define FRICTION 0xe800
+#define AIRFRICTION 0xfff0 // [STRIFE]
+
+void P_XYMovement (mobj_t* mo)
+{
+ fixed_t ptryx;
+ fixed_t ptryy;
+ player_t* player;
+ fixed_t xmove;
+ fixed_t ymove;
+
+ // villsa [STRIFE] unused
+ /*
+ if (!mo->momx && !mo->momy)
+ {
+ if (mo->flags & MF_SKULLFLY)
+ {
+ // the skull slammed into something
+ mo->flags &= ~MF_SKULLFLY;
+ mo->momx = mo->momy = 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;
+
+ do
+ {
+ if (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;
+ }
+
+ if (!P_TryMove (mo, ptryx, ptryy))
+ {
+ // blocked move
+ if (mo->player)
+ { // try to slide along it
+ P_SlideMove (mo);
+ }
+ // villsa [STRIFE] check for bouncy missiles
+ else if(mo->flags & MF_BOUNCE)
+ {
+ mo->momx >>= 3;
+ mo->momy >>= 3;
+
+ if (P_TryMove(mo, mo->x - xmove, ymove + mo->y))
+ mo->momy = -mo->momy;
+ else
+ mo->momx = -mo->momx;
+
+ xmove = 0;
+ ymove = 0;
+ }
+ else if (mo->flags & MF_MISSILE)
+ {
+ // haley 20110203: [STRIFE]
+ // This modification allows missiles to activate shoot specials.
+ // *** BUG: In vanilla Strife the second condition is simply
+ // if(numspechit). However, numspechit can be negative, and
+ // when it is, this accesses spechit[-2]. This always causes the
+ // DOS exe to read from NULL, and the 'special' value there (in
+ // DOS 6.22 at least) is 0x70, which does nothing.
+ if(blockingline && blockingline->special)
+ P_ShootSpecialLine(mo, blockingline);
+ if(numspechit > 0)
+ P_ShootSpecialLine(mo, spechit[numspechit-1]);
+
+ // explode a missile
+ if (ceilingline &&
+ ceilingline->backsector &&
+ ceilingline->backsector->ceilingpic == skyflatnum)
+ {
+ // Hack to prevent missiles exploding
+ // against the sky.
+ // Does not handle sky floors.
+ P_RemoveMobj (mo);
+ return;
+ }
+ P_ExplodeMissile (mo);
+ }
+ else
+ mo->momx = mo->momy = 0;
+ }
+ } while (xmove || ymove);
+
+ // slow down
+ if (player && player->cheats & CF_NOMOMENTUM)
+ {
+ // debug option for no sliding at all
+ mo->momx = mo->momy = 0;
+ return;
+ }
+
+ // villsa [STRIFE] replace skullfly flag with MF_BOUNCE
+ if (mo->flags & (MF_MISSILE | MF_BOUNCE) )
+ return; // no friction for missiles ever
+
+ // haleyjd 20110224: [STRIFE] players experience friction even in the air,
+ // although less than when on the ground. With this fix, the 1.2-and-up
+ // IWAD demo is now in sync!
+ if (mo->z > mo->floorz)
+ {
+ if(player)
+ {
+ mo->momx = FixedMul (mo->momx, AIRFRICTION);
+ mo->momy = FixedMul (mo->momy, AIRFRICTION);
+ }
+ return; // no friction when airborne
+ }
+
+ if (mo->flags & MF_CORPSE)
+ {
+ // do not stop sliding
+ // if halfway off a step with some momentum
+ if (mo->momx > FRACUNIT/4
+ || mo->momx < -FRACUNIT/4
+ || mo->momy > FRACUNIT/4
+ || mo->momy < -FRACUNIT/4)
+ {
+ if (mo->floorz != mo->subsector->sector->floorheight)
+ return;
+ }
+ }
+
+ if (mo->momx > -STOPSPEED
+ && mo->momx < STOPSPEED
+ && mo->momy > -STOPSPEED
+ && mo->momy < STOPSPEED
+ && (!player
+ || (player->cmd.forwardmove == 0
+ && player->cmd.sidemove == 0 ) ) )
+ {
+ // if in a walking frame, stop moving
+ // villsa [STRIFE]: different player state (haleyjd - verified 20110202)
+ if ( player&&(unsigned)((player->mo->state - states) - S_PLAY_01) < 4)
+ P_SetMobjState (player->mo, S_PLAY_00);
+
+ mo->momx = 0;
+ mo->momy = 0;
+ }
+ else
+ {
+ mo->momx = FixedMul (mo->momx, FRICTION);
+ mo->momy = FixedMul (mo->momy, FRICTION);
+ }
+}
+
+//
+// P_ZMovement
+//
+// [STRIFE] Modifications for:
+// * 3D Object Clipping
+// * Different momz handling
+// * No SKULLFLY logic (replaced with BOUNCE)
+// * Missiles don't hit sky flats
+//
+void P_ZMovement (mobj_t* mo)
+{
+ fixed_t dist;
+ fixed_t delta;
+
+ // check for smooth step up
+ if (mo->player && mo->z < mo->floorz)
+ {
+ mo->player->viewheight -= mo->floorz-mo->z;
+
+ mo->player->deltaviewheight
+ = (VIEWHEIGHT - mo->player->viewheight)>>3;
+ }
+
+ // adjust height
+ // villsa [STRIFE] check for things standing on top of other things
+ if(!P_CheckPositionZ(mo, mo->z + mo->momz))
+ {
+ if(mo->momz >= 0)
+ mo->ceilingz = mo->height + mo->z;
+ else
+ mo->floorz = mo->z;
+ }
+
+ //mo->z += mo->momz; // villsa [STRIFE] unused
+
+ if ( mo->flags & MF_FLOAT
+ && mo->target)
+ {
+ // float down towards target if too close
+ if ( /*!(mo->flags & MF_SKULLFLY) // villsa [STRIFE] unused
+ &&*/ !(mo->flags & MF_INFLOAT) )
+ {
+ dist = P_AproxDistance (mo->x - mo->target->x,
+ mo->y - mo->target->y);
+
+ delta =(mo->target->z + (mo->height>>1)) - mo->z;
+
+ if (delta<0 && dist < -(delta*3) )
+ mo->z -= FLOATSPEED;
+ else if (delta>0 && dist < (delta*3) )
+ mo->z += FLOATSPEED;
+ }
+ }
+
+ // clip movement
+ if (mo->z <= mo->floorz)
+ {
+ // hit the floor
+
+ if (mo->flags & MF_BOUNCE)
+ {
+ // the skull slammed into something
+ // villsa [STRIFE] affect reactiontime
+ // momz is also shifted by 1
+ mo->momz = -mo->momz >> 1;
+ mo->reactiontime >>= 1;
+
+ // villsa [STRIFE] get terrain type
+ if(P_GetTerrainType(mo) != FLOOR_SOLID)
+ mo->flags &= ~MF_BOUNCE;
+ }
+
+ if (mo->momz < 0)
+ {
+ if (mo->player
+ && 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;
+
+ // villsa [STRIFE] fall damage
+ // haleyjd 09/18/10: Repaired calculation
+ if(mo->momz < -20*FRACUNIT)
+ P_DamageMobj(mo, NULL, mo, mo->momz / -25000);
+
+ // haleyjd 20110224: *Any* fall centers your view, not just
+ // damaging falls (moved outside the above if).
+ mo->player->centerview = 1;
+ 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.
+ //
+
+ // villsa [STRIFE] unused
+ /*
+ if (!correct_lost_soul_bounce && mo->flags & MF_SKULLFLY)
+ mo->momz = -mo->momz;
+ */
+
+ // villsa [STRIFE] also check for MF_BOUNCE
+ if ( (mo->flags & MF_MISSILE)
+ && !(mo->flags & (MF_NOCLIP|MF_BOUNCE)) )
+ {
+ P_ExplodeMissile (mo);
+ }
+ }
+ else // haleyjd 20110224: else here, not else if - Strife change or what?
+ {
+ if (! (mo->flags & MF_NOGRAVITY) )
+ {
+ if (mo->momz == 0)
+ mo->momz = -GRAVITY*2;
+ else
+ mo->momz -= GRAVITY;
+ }
+
+ if (mo->z + mo->height > mo->ceilingz)
+ {
+ // villsa [STRIFE] replace skullfly flag with MF_BOUNCE
+ if (mo->flags & MF_BOUNCE)
+ {
+ // villsa [STRIFE] affect reactiontime
+ // momz is also shifted by 1
+ mo->momz = -mo->momz >> 1;
+ mo->reactiontime >>= 1;
+ }
+
+ // hit the ceiling
+ if (mo->momz > 0)
+ mo->momz = 0;
+
+ mo->z = mo->ceilingz - mo->height;
+
+ // villsa [STRIFE] also check for MF_BOUNCE
+ if ( (mo->flags & MF_MISSILE)
+ && !(mo->flags & (MF_NOCLIP|MF_BOUNCE)) )
+ {
+ // villsa [STRIFE] check against skies
+ if(mo->subsector->sector->ceilingpic == skyflatnum)
+ P_RemoveMobj(mo);
+ else
+ P_ExplodeMissile (mo);
+ }
+ }
+ }
+}
+
+
+
+//
+// P_NightmareRespawn
+//
+// [STRIFE] Modifications for:
+// * Destination fog z coordinate
+// * Restoration of all Strife mapthing flags
+//
+void
+P_NightmareRespawn (mobj_t* mobj)
+{
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ mobj_t* mo;
+ mapthing_t* mthing;
+
+ x = mobj->spawnpoint.x << FRACBITS;
+ y = mobj->spawnpoint.y << FRACBITS;
+
+ // somthing is occupying it's 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);
+
+ // haleyjd [STRIFE]: Uses ONFLOORZ instead of ss->sector->floorheight
+ mo = P_SpawnMobj (x, y, ONFLOORZ , MT_TFOG);
+
+ S_StartSound (mo, sfx_telept);
+
+ // spawn the new monster
+ mthing = &mobj->spawnpoint;
+
+ // spawn it
+ 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;
+ if (mthing->options & MTF_STAND) // [STRIFE] Standing mode, for NPCs
+ mobj->flags |= MF_STAND;
+ if (mthing->options & MTF_FRIEND) // [STRIFE] Allies
+ mobj->flags |= MF_ALLY;
+ if (mthing->options & MTF_TRANSLUCENT) // [STRIFE] Translucent object
+ mobj->flags |= MF_SHADOW;
+ if (mthing->options & MTF_MVIS) // [STRIFE] Alt. Translucency
+ mobj->flags |= MF_MVIS;
+
+ mo->reactiontime = 18;
+
+ // remove the old monster,
+ P_RemoveMobj (mobj);
+}
+
+
+//
+// P_MobjThinker
+//
+// [STRIFE] Modified for:
+// * Terrain effects
+// * Stonecold cheat
+// * Altered skill 5 respawn behavior
+//
+void P_MobjThinker (mobj_t* mobj)
+{
+ // momentum movement
+ if (mobj->momx
+ || mobj->momy
+ /*|| (mobj->flags&MF_SKULLFLY)*/ ) // villsa [STRIFE] unused
+ {
+ P_XYMovement (mobj);
+
+ // FIXME: decent NOP/NULL/Nil function pointer please.
+ if (mobj->thinker.function.acv == (actionf_v) (-1))
+ return; // mobj was removed
+
+ // villsa [STRIFE] terrain clipping
+ if(P_GetTerrainType(mobj) == FLOOR_SOLID)
+ mobj->flags &= ~MF_FEETCLIPPED;
+ else
+ mobj->flags |= MF_FEETCLIPPED;
+
+ }
+ if ( (mobj->z != mobj->floorz && !(mobj->flags & MF_NOGRAVITY)) // villsa [STRIFE]
+ || mobj->momz )
+ {
+ P_ZMovement (mobj);
+
+ // FIXME: decent NOP/NULL/Nil function pointer please.
+ if (mobj->thinker.function.acv == (actionf_v) (-1))
+ return; // mobj was removed
+
+ // villsa [STRIFE] terrain clipping and sounds
+ if(P_GetTerrainType(mobj) == FLOOR_SOLID)
+ mobj->flags &= ~MF_FEETCLIPPED;
+ else
+ {
+ S_StartSound(mobj, sfx_wsplsh);
+ mobj->flags |= MF_FEETCLIPPED;
+ }
+
+ }
+
+
+ // cycle through states,
+ // calling action functions at transitions
+ if (mobj->tics != -1)
+ {
+ mobj->tics--;
+
+ // villsa [STRIFE] stonecold cheat
+ if(stonecold)
+ {
+ if(mobj->flags & MF_COUNTKILL)
+ P_DamageMobj(mobj, mobj, mobj, 10);
+ }
+
+ // 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++;
+
+ // haleyjd [STRIFE]: respawn time increased from 12 to 16
+ if (mobj->movecount < 16*TICRATE)
+ return;
+
+ if ( leveltime&31 )
+ return;
+
+ if (P_Random () > 4)
+ return;
+
+ // haleyjd [STRIFE]: NOTDMATCH things don't respawn
+ if(mobj->flags & MF_NOTDMATCH)
+ return;
+
+ P_NightmareRespawn (mobj);
+ }
+}
+
+
+//
+// P_SpawnMobj
+//
+// [STRIFE] Modifications to reactiontime and for terrain types.
+//
+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;
+ mobj->flags = info->flags;
+ mobj->health = info->spawnhealth;
+
+ // haleyjd 09/25/10: [STRIFE] Doesn't do this; messes up flamethrower
+ // and a lot of other stuff using reactiontime as a counter.
+ //if (gameskill != sk_nightmare)
+ mobj->reactiontime = info->reactiontime;
+
+ mobj->lastlook = P_Random () % 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;
+
+ // set subsector and/or block links
+ P_SetThingPosition (mobj);
+
+ mobj->floorz = mobj->subsector->sector->floorheight;
+ mobj->ceilingz = mobj->subsector->sector->ceilingheight;
+
+ if (z == ONFLOORZ)
+ {
+ mobj->z = mobj->floorz;
+
+ // villsa [STRIFE]
+ if(P_GetTerrainType(mobj) != FLOOR_SOLID)
+ mobj->flags |= MF_FEETCLIPPED;
+
+ }
+ else if (z == ONCEILINGZ)
+ mobj->z = mobj->ceilingz - mobj->info->height;
+ else
+ mobj->z = z;
+
+ mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker;
+
+ P_AddThinker (&mobj->thinker);
+
+ return mobj;
+}
+
+
+//
+// P_RemoveMobj
+//
+// [STRIFE] Modifications for item respawn timing
+//
+mapthing_t itemrespawnque[ITEMQUESIZE];
+int itemrespawntime[ITEMQUESIZE];
+int iquehead;
+int iquetail;
+
+void P_RemoveMobj (mobj_t* mobj)
+{
+ // villsa [STRIFE] removed invuln/invis. sphere exceptions
+ if ((mobj->flags & MF_SPECIAL)
+ && !(mobj->flags & MF_DROPPED))
+ {
+ itemrespawnque[iquehead] = mobj->spawnpoint;
+ itemrespawntime[iquehead] = leveltime + 30*TICRATE; // [STRIFE]
+ iquehead = (iquehead+1)&(ITEMQUESIZE-1);
+
+ // [STRIFE] FIXME/TODO: - haleyjd 20110629
+ // -random parameter affects the behavior of respawning items here.
+ // However, this requires addition of randomparm to the transmission
+ // of variables during netgame initialization, and the netcode is not
+ // functional yet - so, I haven't added this yet!
+
+ // lose one off the end?
+ if (iquehead == iquetail)
+ iquetail = (iquetail+1)&(ITEMQUESIZE-1);
+ }
+
+ // unlink from sector and block lists
+ P_UnsetThingPosition (mobj);
+
+ // stop any playing sound
+ S_StopSound (mobj);
+
+ // free block
+ P_RemoveThinker ((thinker_t*)mobj);
+}
+
+
+
+
+//
+// P_RespawnSpecials
+//
+// [STRIFE] modification to item respawn time handling
+//
+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;
+
+ // haleyjd [STRIFE]: 30 second wait is not accounted for here, see above.
+ if (leveltime < itemrespawntime[iquetail])
+ 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
+ for (i=0 ; i< NUMMOBJTYPES ; i++)
+ {
+ if (mthing->type == mobjinfo[i].doomednum)
+ break;
+ }
+
+ // 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 que
+ 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.
+//
+// [STRIFE] Modifications for:
+// * stonecold cheat, -workparm
+// * default inventory/questflags
+//
+void P_SpawnPlayer(mapthing_t* mthing)
+{
+ player_t* p;
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ mobj_t* mobj;
+
+ if(mthing->type == 0)
+ return;
+
+ // 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 > 1)
+ mobj->flags |= (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;
+
+ // setup gun psprite
+ P_SetupPsprites(p);
+
+ // villsa [STRIFE]
+ stonecold = false;
+
+ // villsa [STRIFE] what a nasty hack...
+ if(gamemap == 10)
+ p->weaponowned[wp_sigil] = true;
+
+ // villsa [STRIFE] instead of just giving cards in deathmatch mode, also
+ // set accuracy to 50 and give all quest flags
+ if(deathmatch)
+ {
+ int i;
+
+ p->accuracy = 50;
+ p->questflags = QF_ALLQUESTS; // 0x7fffffff
+
+ for(i = 0; i < NUMCARDS; i++)
+ p->cards[i] = true;
+ }
+
+ // villsa [STRIFE] set godmode?
+ if(workparm)
+ p->cheats |= CF_GODMODE;
+
+ if(mthing->type - 1 == consoleplayer)
+ {
+ // wake up the status bar
+ ST_Start ();
+ // wake up the heads up text
+ HU_Start ();
+ }
+}
+
+
+//
+// P_SpawnMapThing
+// The fields of the mapthing should
+// already be in host byte order.
+//
+// [STRIFE] Modifications for:
+// * No Lost Souls, item count
+// * New mapthing_t flag bits
+//
+// STRIFE-FIXME/STRIFE-TODO:
+// * 8-player support
+// * Restore I_Error for missing mapthings (8-player support is prerequisite)
+//
+void P_SpawnMapThing (mapthing_t* mthing)
+{
+ int i;
+ int bit;
+ mobj_t* mobj;
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+
+ // count deathmatch start positions
+ if (mthing->type == 11)
+ {
+ if (deathmatch_p < &deathmatchstarts[10])
+ {
+ memcpy (deathmatch_p, mthing, sizeof(*mthing));
+ deathmatch_p++;
+ }
+ return;
+ }
+
+ if (mthing->type <= 0)
+ {
+ // Thing type 0 is actually "player -1 start".
+ // For some reason, Vanilla Doom accepts/ignores this.
+
+ return;
+ }
+
+ // check for players specially
+ // STRIFE-TODO: Need 8 player starts
+ if (mthing->type <= 4)
+ {
+ // save spots for respawning in network games
+ playerstarts[mthing->type-1] = *mthing;
+ if (!deathmatch)
+ P_SpawnPlayer (mthing);
+
+ return;
+ }
+
+ // check for apropriate skill level
+ if (!netgame && (mthing->options & 16) )
+ return;
+
+ if (gameskill == sk_baby)
+ bit = 1;
+ else if (gameskill == sk_nightmare)
+ bit = 4;
+ else
+ bit = 1<<(gameskill-1);
+
+ if (!(mthing->options & bit) )
+ return;
+
+ // find which type to spawn
+ for (i=0 ; i< NUMMOBJTYPES ; i++)
+ if (mthing->type == mobjinfo[i].doomednum)
+ break;
+
+ /*
+ if (i==NUMMOBJTYPES)
+ I_Error ("P_SpawnMapThing: Unknown type %i at (%i, %i)",
+ mthing->type,
+ mthing->x, mthing->y);
+ */
+ // haleyjd 08/29/10: STRIFE-FIXME: Temporarily disabled I_Error for testing purposes
+ if (i == NUMMOBJTYPES)
+ return;
+
+ // don't spawn keycards and players in deathmatch
+ if (deathmatch && mobjinfo[i].flags & MF_NOTDMATCH)
+ return;
+
+ // don't spawn any monsters if -nomonsters
+ // villsa [STRIFE] Removed MT_SKULL
+ if (nomonsters && (mobjinfo[i].flags & MF_COUNTKILL))
+ return;
+
+ // spawn it
+ 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 () % mobj->tics);
+ if (mobj->flags & MF_COUNTKILL)
+ totalkills++;
+
+ // villsa [STRIFE] unused
+ /*
+ if (mobj->flags & MF_COUNTITEM)
+ totalitems++;
+ */
+
+ mobj->angle = ANG45 * (mthing->angle/45);
+ if (mthing->options & MTF_AMBUSH)
+ mobj->flags |= MF_AMBUSH;
+ if (mthing->options & MTF_STAND) // [STRIFE] Standing mode, for NPCs
+ mobj->flags |= MF_STAND;
+ if (mthing->options & MTF_FRIEND) // [STRIFE] Allies
+ mobj->flags |= MF_ALLY;
+ if (mthing->options & MTF_TRANSLUCENT) // [STRIFE] Translucent object
+ mobj->flags |= MF_SHADOW;
+ if (mthing->options & MTF_MVIS) // [STRIFE] Alt. Translucency
+ mobj->flags |= MF_MVIS;
+}
+
+
+
+//
+// GAME SPAWN FUNCTIONS
+//
+
+
+//
+// P_SpawnPuff
+//
+// [STRIFE] Modifications for:
+// * No spawn tics randomization
+// * Player melee behavior
+//
+extern fixed_t attackrange;
+
+void
+P_SpawnPuff
+( fixed_t x,
+ fixed_t y,
+ fixed_t z )
+{
+ mobj_t* th;
+ int t;
+
+ t = P_Random();
+ z += ((t - P_Random()) << 10);
+
+ // [STRIFE] removed momz and tics randomization
+
+ th = P_SpawnMobj(x, y, z, MT_STRIFEPUFF); // [STRIFE]: new type
+
+ // don't make punches spark on the wall
+ // [STRIFE] Use a separate melee attack range for the player
+ if(attackrange == PLAYERMELEERANGE)
+ P_SetMobjState(th, S_POW2_00); // 141
+
+ // villsa [STRIFE] unused
+ /*
+ if (th->tics < 1)
+ th->tics = 1;
+ */
+}
+
+//
+// P_SpawnSparkPuff
+//
+// villsa [STRIFE] new function
+//
+mobj_t* P_SpawnSparkPuff(fixed_t x, fixed_t y, fixed_t z)
+{
+ int t = P_Random();
+ return P_SpawnMobj(x, y, ((t - P_Random()) << 10) + z, MT_SPARKPUFF);
+}
+
+//
+// P_SpawnBlood
+//
+// [STRIFE] Modifications for:
+// * No spawn tics randomization
+// * Different damage ranges for state setting
+//
+void
+P_SpawnBlood
+( fixed_t x,
+ fixed_t y,
+ fixed_t z,
+ int damage )
+{
+ mobj_t* th;
+ int temp;
+
+ temp = P_Random();
+ z += (temp - P_Random()) << 10;
+ th = P_SpawnMobj(x, y, z, MT_BLOOD_DEATH);
+ th->momz = FRACUNIT*2;
+
+ // villsa [STRIFE]: removed tics randomization
+
+ // villsa [STRIFE] different checks for damage range
+ if(damage >= 10 && damage <= 13)
+ P_SetMobjState(th, S_BLOD_00);
+ else if(damage >= 7 && damage < 10)
+ P_SetMobjState(th, S_BLOD_01);
+ else if(damage < 7)
+ P_SetMobjState(th, S_BLOD_02);
+}
+
+
+
+//
+// P_CheckMissileSpawn
+// Moves the missile forward a bit
+// and possibly explodes it right there.
+//
+// [STRIFE] Modifications for:
+// * No spawn tics randomization
+//
+void P_CheckMissileSpawn (mobj_t* th)
+{
+ // villsa [STRIFE] removed tics randomization
+
+ // 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);
+
+ if (!P_TryMove (th, th->x, th->y))
+ P_ExplodeMissile (th);
+}
+
+// Certain functions assume that a mobj_t pointer is non-NULL,
+// causing a crash in some situations where it is NULL. Vanilla
+// Doom did not crash because of the lack of proper memory
+// protection. This function substitutes NULL pointers for
+// pointers to a dummy mobj, to avoid a crash.
+
+mobj_t *P_SubstNullMobj(mobj_t *mobj)
+{
+ if (mobj == NULL)
+ {
+ static mobj_t dummy_mobj;
+
+ dummy_mobj.x = 0;
+ dummy_mobj.y = 0;
+ dummy_mobj.z = 0;
+ dummy_mobj.flags = 0;
+
+ mobj = &dummy_mobj;
+ }
+
+ return mobj;
+}
+
+//
+// P_SpawnMissile
+//
+// [STRIFE] Added MVIS inaccuracy
+//
+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);
+
+ 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)
+ {
+ int t = P_Random(); // haleyjd 20110223: remove order-of-evaluation dependencies
+ an += (t - P_Random()) << 21;
+ }
+ // villsa [STRIFE] check for heavily transparent things
+ else if(dest->flags & MF_MVIS)
+ {
+ int t = P_Random();
+ an += (t - P_Random()) << 22;
+ }
+
+ 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_SpawnFacingMissile
+//
+// villsa [STRIFE] new function
+// Spawn a missile based on source's angle
+//
+mobj_t* P_SpawnFacingMissile(mobj_t* source, mobj_t* target, mobjtype_t type)
+{
+ mobj_t* th;
+ angle_t an;
+ fixed_t dist;
+
+ th = P_SpawnMobj(source->x, source->y, source->z + (32*FRACUNIT), type);
+
+ if(th->info->seesound)
+ S_StartSound(th, th->info->seesound);
+
+ th->target = source; // where it came from
+ th->angle = source->angle; // haleyjd 09/06/10: fix0red
+ an = th->angle;
+
+ // fuzzy player
+ if (target->flags & MF_SHADOW)
+ {
+ int t = P_Random();
+ an += (t - P_Random()) << 21;
+ }
+ // villsa [STRIFE] check for heavily transparent things
+ else if(target->flags & MF_MVIS)
+ {
+ int t = P_Random();
+ an += (t - P_Random()) << 22;
+ }
+
+ an >>= ANGLETOFINESHIFT;
+ th->momx = FixedMul (th->info->speed, finecosine[an]);
+ th->momy = FixedMul (th->info->speed, finesine[an]);
+
+ dist = P_AproxDistance (target->x - source->x, target->y - source->y);
+ dist = dist / th->info->speed;
+
+ if(dist < 1)
+ dist = 1;
+
+ th->momz = (target->z - source->z) / dist;
+ P_CheckMissileSpawn (th);
+
+ return th;
+}
+
+//
+// P_SpawnPlayerMissile
+//
+// Tries to aim at a nearby monster
+// villsa [STRIFE] now returns a mobj
+// * Also modified to allow up/down look, and to account for foot-clipping
+// by liquid terrain.
+//
+mobj_t* P_SpawnPlayerMissile(mobj_t* source, mobjtype_t type)
+{
+ mobj_t* th;
+ angle_t an;
+
+ fixed_t x;
+ fixed_t y;
+ fixed_t z;
+ fixed_t slope;
+
+ // see which target is to be aimed at
+ an = source->angle;
+ slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
+
+ if (!linetarget)
+ {
+ an += 1<<26;
+ slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
+
+ if (!linetarget)
+ {
+ an -= 2<<26;
+ slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
+ }
+
+ if (!linetarget)
+ {
+ an = source->angle;
+
+ // haleyjd 09/21/10: [STRIFE] Removed, for look up/down support.
+ //slope = 0;
+ }
+ }
+
+ // villsa [STRIFE]
+ if(linetarget)
+ source->target = linetarget;
+
+ x = source->x;
+ y = source->y;
+
+ // villsa [STRIFE]
+ if(!(source->flags & MF_FEETCLIPPED))
+ z = source->z + 32*FRACUNIT;
+ else
+ z = source->z + 22*FRACUNIT;
+
+ th = P_SpawnMobj (x,y,z, type);
+
+ if (th->info->seesound)
+ S_StartSound (th, th->info->seesound);
+
+ 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);
+
+ return th;
+}
+
+//
+// P_SpawnMortar
+//
+// villsa [STRIFE] new function
+// Spawn a high-arcing ballistic projectile
+//
+mobj_t* P_SpawnMortar(mobj_t *source, mobjtype_t type)
+{
+ mobj_t* th;
+ angle_t an;
+ fixed_t slope;
+
+ an = source->angle;
+
+ th = P_SpawnMobj(source->x, source->y, source->z, type);
+ th->target = source;
+ th->angle = an;
+ an >>= ANGLETOFINESHIFT;
+
+ // haleyjd 20110203: corrected order of function calls
+ th->momx = FixedMul(th->info->speed, finecosine[an]);
+ th->momy = FixedMul(th->info->speed, finesine[an]);
+
+ P_CheckMissileSpawn(th);
+
+ slope = P_AimLineAttack(source, source->angle, 1024*FRACUNIT);
+ th->momz = FixedMul(th->info->speed, slope);
+
+ return th;
+}