forked from len0rd/rockbox
		
	git-svn-id: svn://svn.rockbox.org/rockbox/trunk@9312 a1c6a512-1295-4272-9138-f99709370657
		
			
				
	
	
		
			1394 lines
		
	
	
	
		
			38 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1394 lines
		
	
	
	
		
			38 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* 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);
 | |
| }
 |