/* Emacs style mode select   -*- C++ -*- */
/*----------------------------------------------------------------------------- */
/* */
/* $Id:$ */
/* */
/* Copyright (C) 1993-1996 by id Software, Inc. */
/* */
/* 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. */
/* */
/* $Log:$ */
/* */
/* DESCRIPTION: */
/*	Moving object handling. Spawn functions. */
/* */
/*----------------------------------------------------------------------------- */

static const char
        rcsid[] = "$Id: p_mobj.c,v 1.5 1997/02/03 22:45:12 b1 Exp $";

#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"


void G_PlayerReborn (int player);
void P_SpawnMapThing (mapthing_t*       mthing);


/* */
/* P_SetMobjState */
/* Returns true if the mobj is still present. */
/* */
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 */
/* */
void P_ExplodeMissile (mobj_t* mo)
{
	mo->momx = mo->momy = mo->momz = 0;

	P_SetMobjState (mo, mobjinfo[mo->type].deathstate);

	mo->tics -= P_Random()&3;

	if (mo->tics < 1)
		mo->tics = 1;

	mo->flags &= ~MF_MISSILE;

	if (mo->info->deathsound)
		S_StartSound (mo, mo->info->deathsound);
}


/* */
/* P_XYMovement */
/* */
#define STOPSPEED               0x1000
#define FRICTION                0xe800

void P_XYMovement (mobj_t* mo)
{
	fixed_t ptryx;
	fixed_t ptryy;
	player_t*   player;
	fixed_t xmove;
	fixed_t ymove;

	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);
			}
			else if (mo->flags & MF_MISSILE)
			{
				/* 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;
	}

	if (mo->flags & (MF_MISSILE | MF_SKULLFLY) )
		return; /* no friction for missiles ever */

	if (mo->z > mo->floorz)
		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 */
		if ( player&&(unsigned)((player->mo->state - states)- S_PLAY_RUN1) < 4)
			P_SetMobjState (player->mo, S_PLAY);

		mo->momx = 0;
		mo->momy = 0;
	}
	else
	{
		mo->momx = FixedMul (mo->momx, FRICTION);
		mo->momy = FixedMul (mo->momy, FRICTION);
	}
}

/* */
/* P_ZMovement */
/* */
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 */
	mo->z += mo->momz;

	if ( mo->flags & MF_FLOAT
	     && mo->target)
	{
		/* float down towards target if too close */
		if ( !(mo->flags & MF_SKULLFLY)
		     && !(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 */

		/* Note (id): */
		/*  somebody left this after the setting momz to 0, */
		/*  kinda useless there. */
		if (mo->flags & MF_SKULLFLY)
		{
			/* the skull slammed into something */
			mo->momz = -mo->momz;
		}

		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;
				S_StartSound (mo, sfx_oof);
			}
			mo->momz = 0;
		}
		mo->z = mo->floorz;

		if ( (mo->flags & MF_MISSILE)
		     && !(mo->flags & MF_NOCLIP) )
		{
			P_ExplodeMissile (mo);
			return;
		}
	}
	else if (!(mo->flags & MF_NOGRAVITY) )
	{
		if (mo->momz == 0)
			mo->momz = -GRAVITY*2;
		else
			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)
		{ /* the skull slammed into something */
			mo->momz = -mo->momz;
		}

		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;

	/* 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);

	mo = P_SpawnMobj (x, y, ss->sector->floorheight, 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;

	mo->reactiontime = 18;

	/* remove the old monster, */
	P_RemoveMobj (mobj);
}


/* */
/* P_MobjThinker */
/* */
void P_MobjThinker (mobj_t* mobj)
{
	/* momentum movement */
	if (mobj->momx
	    || mobj->momy
	    || (mobj->flags&MF_SKULLFLY) )
	{
		P_XYMovement (mobj);

		/* FIXME: decent NOP/NULL/Nil function pointer please. */
		if (mobj->thinker.function.acv == (actionf_v) (-1))
			return; /* mobj was removed */
	}
	if ( (mobj->z != mobj->floorz)
	     || 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 */
	}


	/* 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 () > 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;
	mobj->flags = info->flags;
	mobj->health = info->spawnhealth;

	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;
	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 */
/* */
mapthing_t itemrespawnque[ITEMQUESIZE];
int itemrespawntime[ITEMQUESIZE];
int iquehead;
int iquetail;


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);

	/* stop any playing sound */
	S_StopSound (mobj);

	/* free block */
	P_RemoveThinker ((thinker_t*)mobj);
}




/* */
/* 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 */
	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. */
/* */
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 > 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);

	/* give all cards in death match mode */
	if (deathmatch)
		for (i=0; i<NUMCARDS; i++)
			p->cards[i] = true;

	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. */
/* */
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;
	}

	/* check for players specially */
	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);

	/* 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 */
	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++;
	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;

	z += ((P_Random()-P_Random())<<10);

	th = P_SpawnMobj (x,y,z, MT_PUFF);
	th->momz = FRACUNIT;
	th->tics -= P_Random()&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;

	z += ((P_Random()-P_Random())<<10);
	th = P_SpawnMobj (x,y,z, MT_BLOOD);
	th->momz = FRACUNIT*2;
	th->tics -= P_Random()&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()&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);

	if (!P_TryMove (th, th->x, th->y))
		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);

	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)
		an += (P_Random()-P_Random())<<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;
	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;
			slope = 0;
		}
	}

	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);

	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);
}

