DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

p_mobj.cpp (19826B)


      1 /*
      2 ===========================================================================
      3 
      4 Doom 3 BFG Edition GPL Source Code
      5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 
      6 
      7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").  
      8 
      9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
     10 it under the terms of the GNU General Public License as published by
     11 the Free Software Foundation, either version 3 of the License, or
     12 (at your option) any later version.
     13 
     14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
     15 but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 GNU General Public License for more details.
     18 
     19 You should have received a copy of the GNU General Public License
     20 along with Doom 3 BFG Edition Source Code.  If not, see <http://www.gnu.org/licenses/>.
     21 
     22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code.  If not, please request a copy in writing from id Software at the address below.
     23 
     24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
     25 
     26 ===========================================================================
     27 */
     28 
     29 #include "Precompiled.h"
     30 #include "globaldata.h"
     31 
     32 #include "i_system.h"
     33 #include "z_zone.h"
     34 #include "m_random.h"
     35 
     36 #include "doomdef.h"
     37 #include "p_local.h"
     38 #include "sounds.h"
     39 
     40 #include "st_stuff.h"
     41 #include "hu_stuff.h"
     42 
     43 #include "s_sound.h"
     44 
     45 #include "doomstat.h"
     46 
     47 extern bool globalNetworking;
     48 
     49 void G_PlayerReborn (int player);
     50 void P_SpawnMapThing (mapthing_t*	mthing);
     51 
     52 
     53 //
     54 // P_SetMobjState
     55 // Returns true if the mobj is still present.
     56 //
     57 
     58 qboolean
     59 P_SetMobjState
     60 ( mobj_t*	mobj,
     61  statenum_t	state )
     62 {
     63 	const state_t*	st;
     64 
     65 	do
     66 	{
     67 		if (state == S_NULL)
     68 		{
     69 			mobj->state = (const state_t *) S_NULL;
     70 			P_RemoveMobj (mobj);
     71 			return false;
     72 		}
     73 
     74 		st = &::g->states[state];
     75 		mobj->state = st;
     76 		mobj->tics = st->tics;
     77 		mobj->sprite = st->sprite;
     78 		mobj->frame = st->frame;
     79 
     80 		// Modified handling.
     81 		// Call action functions when the state is set
     82 		if (st->action)		
     83 			st->action(mobj, NULL);	
     84 
     85 		state = st->nextstate;
     86 	} while (!mobj->tics);
     87 
     88 	return true;
     89 }
     90 
     91 
     92 //
     93 // P_ExplodeMissile  
     94 //
     95 void P_ExplodeMissile (mobj_t* mo)
     96 {
     97 	mo->momx = mo->momy = mo->momz = 0;
     98 
     99 	P_SetMobjState (mo, (statenum_t)mobjinfo[mo->type].deathstate);
    100 
    101 	mo->tics -= P_Random()&3;
    102 
    103 	if (mo->tics < 1)
    104 		mo->tics = 1;
    105 
    106 	mo->flags &= ~MF_MISSILE;
    107 
    108 	if (mo->info->deathsound)
    109 		S_StartSound (mo, mo->info->deathsound);
    110 }
    111 
    112 
    113 //
    114 // P_XYMovement  
    115 //
    116 
    117 void P_XYMovement (mobj_t* mo) 
    118 { 	
    119 	fixed_t 	ptryx;
    120 	fixed_t	ptryy;
    121 	player_t*	player;
    122 	fixed_t	xmove;
    123 	fixed_t	ymove;
    124 
    125 	if (!mo->momx && !mo->momy)
    126 	{
    127 		if (mo->flags & MF_SKULLFLY)
    128 		{
    129 			// the skull slammed into something
    130 			mo->flags &= ~MF_SKULLFLY;
    131 			mo->momx = mo->momy = mo->momz = 0;
    132 
    133 			P_SetMobjState (mo, (statenum_t)mo->info->spawnstate);
    134 		}
    135 		return;
    136 	}
    137 
    138 	player = mo->player;
    139 
    140 	if (mo->momx > MAXMOVE)
    141 		mo->momx = MAXMOVE;
    142 	else if (mo->momx < -MAXMOVE)
    143 		mo->momx = -MAXMOVE;
    144 
    145 	if (mo->momy > MAXMOVE)
    146 		mo->momy = MAXMOVE;
    147 	else if (mo->momy < -MAXMOVE)
    148 		mo->momy = -MAXMOVE;
    149 
    150 	xmove = mo->momx;
    151 	ymove = mo->momy;
    152 
    153 	do
    154 	{
    155 		if (xmove > MAXMOVE/2 || ymove > MAXMOVE/2)
    156 		{
    157 			ptryx = mo->x + xmove/2;
    158 			ptryy = mo->y + ymove/2;
    159 			xmove >>= 1;
    160 			ymove >>= 1;
    161 		}
    162 		else
    163 		{
    164 			ptryx = mo->x + xmove;
    165 			ptryy = mo->y + ymove;
    166 			xmove = ymove = 0;
    167 		}
    168 
    169 		if (!P_TryMove (mo, ptryx, ptryy))
    170 		{
    171 			// blocked move
    172 			if (mo->player)
    173 			{	// try to slide along it
    174 				P_SlideMove (mo);
    175 			}
    176 			else if (mo->flags & MF_MISSILE)
    177 			{
    178 				// explode a missile
    179 				if (::g->ceilingline &&
    180 					::g->ceilingline->backsector &&
    181 					::g->ceilingline->backsector->ceilingpic == ::g->skyflatnum)
    182 				{
    183 					// Hack to prevent missiles exploding
    184 					// against the sky.
    185 					// Does not handle sky floors.
    186 					P_RemoveMobj (mo);
    187 					return;
    188 				}
    189 				P_ExplodeMissile (mo);
    190 			}
    191 			else
    192 				mo->momx = mo->momy = 0;
    193 		}
    194 	} while (xmove || ymove);
    195 
    196 	// slow down
    197 	if (player && player->cheats & CF_NOMOMENTUM)
    198 	{
    199 		// debug option for no sliding at all
    200 		mo->momx = mo->momy = 0;
    201 		return;
    202 	}
    203 
    204 	if (mo->flags & (MF_MISSILE | MF_SKULLFLY) )
    205 		return; 	// no friction for missiles ever
    206 
    207 	if (mo->z > mo->floorz)
    208 		return;		// no friction when airborne
    209 
    210 	if (mo->flags & MF_CORPSE)
    211 	{
    212 		// do not stop sliding
    213 		//  if halfway off a step with some momentum
    214 		if (mo->momx > FRACUNIT/4
    215 			|| mo->momx < -FRACUNIT/4
    216 			|| mo->momy > FRACUNIT/4
    217 			|| mo->momy < -FRACUNIT/4)
    218 		{
    219 			if (mo->floorz != mo->subsector->sector->floorheight)
    220 				return;
    221 		}
    222 	}
    223 
    224 	if (mo->momx > -STOPSPEED
    225 		&& mo->momx < STOPSPEED
    226 		&& mo->momy > -STOPSPEED
    227 		&& mo->momy < STOPSPEED
    228 		&& (!player
    229 		|| (player->cmd.forwardmove== 0
    230 		&& player->cmd.sidemove == 0 ) ) )
    231 	{
    232 		// if in a walking frame, stop moving
    233 		if ( player&&(unsigned)((player->mo->state - ::g->states)- S_PLAY_RUN1) < 4)
    234 			P_SetMobjState (player->mo, S_PLAY);
    235 
    236 		mo->momx = 0;
    237 		mo->momy = 0;
    238 	}
    239 	else
    240 	{
    241 		mo->momx = FixedMul (mo->momx, FRICTION);
    242 		mo->momy = FixedMul (mo->momy, FRICTION);
    243 	}
    244 }
    245 
    246 //
    247 // P_ZMovement
    248 //
    249 void P_ZMovement (mobj_t* mo)
    250 {
    251 	fixed_t	dist;
    252 	fixed_t	delta;
    253 
    254 	// check for smooth step up
    255 	if (mo->player && mo->z < mo->floorz)
    256 	{
    257 		mo->player->viewheight -= mo->floorz-mo->z;
    258 
    259 		mo->player->deltaviewheight
    260 			= (VIEWHEIGHT - mo->player->viewheight)>>3;
    261 	}
    262 
    263 	// adjust height
    264 	mo->z += mo->momz;
    265 
    266 	if ( mo->flags & MF_FLOAT
    267 		&& mo->target)
    268 	{
    269 		// float down towards target if too close
    270 		if ( !(mo->flags & MF_SKULLFLY)
    271 			&& !(mo->flags & MF_INFLOAT) )
    272 		{
    273 			dist = P_AproxDistance (mo->x - mo->target->x,
    274 				mo->y - mo->target->y);
    275 
    276 			delta =(mo->target->z + (mo->height>>1)) - mo->z;
    277 
    278 			if (delta<0 && dist < -(delta*3) )
    279 				mo->z -= FLOATSPEED;
    280 			else if (delta>0 && dist < (delta*3) )
    281 				mo->z += FLOATSPEED;			
    282 		}
    283 
    284 	}
    285 
    286 	// clip movement
    287 	if (mo->z <= mo->floorz)
    288 	{
    289 		// hit the floor
    290 
    291 		// Note (id):
    292 		//  somebody left this after the setting momz to 0,
    293 		//  kinda useless there.
    294 		if (mo->flags & MF_SKULLFLY)
    295 		{
    296 			// the skull slammed into something
    297 			mo->momz = -mo->momz;
    298 		}
    299 
    300 		if (mo->momz < 0)
    301 		{
    302 			if (mo->player
    303 				&& mo->momz < -GRAVITY*8)	
    304 			{
    305 				// Squat down.
    306 				// Decrease ::g->viewheight for a moment
    307 				// after hitting the ground (hard),
    308 				// and utter appropriate sound.
    309 				mo->player->deltaviewheight = mo->momz>>3;
    310 				if (globalNetworking || (mo->player == &::g->players[::g->consoleplayer]))
    311 					S_StartSound (mo, sfx_oof);
    312 			}
    313 			mo->momz = 0;
    314 		}
    315 		mo->z = mo->floorz;
    316 
    317 		if ( (mo->flags & MF_MISSILE)
    318 			&& !(mo->flags & MF_NOCLIP) )
    319 		{
    320 			P_ExplodeMissile (mo);
    321 			return;
    322 		}
    323 	}
    324 	else if (! (mo->flags & MF_NOGRAVITY) )
    325 	{
    326 		if (mo->momz == 0)
    327 			mo->momz = -GRAVITY*2;
    328 		else
    329 			mo->momz -= GRAVITY;
    330 	}
    331 
    332 	if (mo->z + mo->height > mo->ceilingz)
    333 	{
    334 		// hit the ceiling
    335 		if (mo->momz > 0)
    336 			mo->momz = 0;
    337 		{
    338 			mo->z = mo->ceilingz - mo->height;
    339 		}
    340 
    341 		if (mo->flags & MF_SKULLFLY)
    342 		{	// the skull slammed into something
    343 			mo->momz = -mo->momz;
    344 		}
    345 
    346 		if ( (mo->flags & MF_MISSILE)
    347 			&& !(mo->flags & MF_NOCLIP) )
    348 		{
    349 			P_ExplodeMissile (mo);
    350 			return;
    351 		}
    352 	}
    353 } 
    354 
    355 
    356 
    357 //
    358 // P_NightmareRespawn
    359 //
    360 void
    361 P_NightmareRespawn (mobj_t* mobj)
    362 {
    363 	fixed_t		x;
    364 	fixed_t		y;
    365 	fixed_t		z; 
    366 	subsector_t*	ss; 
    367 	mobj_t*		mo;
    368 	mapthing_t*		mthing;
    369 
    370 	x = mobj->spawnpoint.x << FRACBITS; 
    371 	y = mobj->spawnpoint.y << FRACBITS; 
    372 
    373 	// somthing is occupying it's position?
    374 	if (!P_CheckPosition (mobj, x, y) ) 
    375 		return;	// no respwan
    376 
    377 	// spawn a teleport fog at old spot
    378 	// because of removal of the body?
    379 	mo = P_SpawnMobj (mobj->x,
    380 		mobj->y,
    381 		mobj->subsector->sector->floorheight , MT_TFOG); 
    382 	// initiate teleport sound
    383 	S_StartSound (mo, sfx_telept);
    384 
    385 	// spawn a teleport fog at the new spot
    386 	ss = R_PointInSubsector (x,y); 
    387 
    388 	mo = P_SpawnMobj (x, y, ss->sector->floorheight , MT_TFOG); 
    389 
    390 	S_StartSound (mo, sfx_telept);
    391 
    392 	// spawn the new monster
    393 	mthing = &mobj->spawnpoint;
    394 
    395 	// spawn it
    396 	if (mobj->info->flags & MF_SPAWNCEILING)
    397 		z = ONCEILINGZ;
    398 	else
    399 		z = ONFLOORZ;
    400 
    401 	// inherit attributes from deceased one
    402 	mo = P_SpawnMobj (x,y,z, mobj->type);
    403 	mo->spawnpoint = mobj->spawnpoint;	
    404 	mo->angle = ANG45 * (mthing->angle/45);
    405 
    406 	if (mthing->options & MTF_AMBUSH)
    407 		mo->flags |= MF_AMBUSH;
    408 
    409 	mo->reactiontime = 18;
    410 
    411 	// remove the old monster,
    412 	P_RemoveMobj (mobj);
    413 }
    414 
    415 
    416 //
    417 // P_MobjThinker
    418 //
    419 void P_MobjThinker (mobj_t* mobj)
    420 {
    421 	// momentum movement
    422 	if (mobj->momx
    423 		|| mobj->momy
    424 		|| (mobj->flags&MF_SKULLFLY) )
    425 	{
    426 		P_XYMovement (mobj);
    427 
    428 		// FIXME: decent NOP/NULL/Nil function pointer please.
    429 		if (mobj->thinker.function.acv == (actionf_v) (-1))
    430 			return;		// mobj was removed
    431 	}
    432 	if ( (mobj->z != mobj->floorz)
    433 		|| mobj->momz )
    434 	{
    435 		P_ZMovement (mobj);
    436 
    437 		// FIXME: decent NOP/NULL/Nil function pointer please.
    438 		if (mobj->thinker.function.acv == (actionf_v) (-1))
    439 			return;		// mobj was removed
    440 	}
    441 
    442 
    443 	// cycle through states,
    444 	// calling action functions at transitions
    445 	if (mobj->tics != -1)
    446 	{
    447 		mobj->tics--;
    448 
    449 		// you can cycle through multiple states in a tic
    450 		if (!mobj->tics)
    451 			if (!P_SetMobjState (mobj, mobj->state->nextstate) )
    452 				return;		// freed itself
    453 	}
    454 	else
    455 	{
    456 		// check for nightmare respawn
    457 		if (! (mobj->flags & MF_COUNTKILL) )
    458 			return;
    459 
    460 		if (!::g->respawnmonsters)
    461 			return;
    462 
    463 		mobj->movecount++;
    464 
    465 		if (mobj->movecount < 12*TICRATE)
    466 			return;
    467 
    468 		if ( ::g->leveltime&31 )
    469 			return;
    470 
    471 		if (P_Random () > 4)
    472 			return;
    473 
    474 		P_NightmareRespawn (mobj);
    475 	}
    476 
    477 }
    478 
    479 
    480 //
    481 // P_SpawnMobj
    482 //
    483 mobj_t*
    484 P_SpawnMobj
    485 ( fixed_t	x,
    486  fixed_t	y,
    487  fixed_t	z,
    488  mobjtype_t	type )
    489 {
    490 	mobj_t*	mobj;
    491 	const state_t*	st;
    492 	const mobjinfo_t*	info;
    493 
    494 	mobj = (mobj_t*)DoomLib::Z_Malloc(sizeof(*mobj), PU_LEVEL, NULL);
    495 	memset (mobj, 0, sizeof (*mobj));
    496 	info = &mobjinfo[type];
    497 
    498 	mobj->type = type;
    499 	mobj->info = info;
    500 	mobj->x = x;
    501 	mobj->y = y;
    502 	mobj->radius = info->radius;
    503 	mobj->height = info->height;
    504 	mobj->flags = info->flags;
    505 	mobj->health = info->spawnhealth;
    506 
    507 	if (::g->gameskill != sk_nightmare)
    508 		mobj->reactiontime = info->reactiontime;
    509 
    510 	mobj->lastlook = P_Random () % MAXPLAYERS;
    511 	// do not set the state with P_SetMobjState,
    512 	// because action routines can not be called yet
    513 	st = &::g->states[info->spawnstate];
    514 
    515 	mobj->state = st;
    516 	mobj->tics = st->tics;
    517 	mobj->sprite = st->sprite;
    518 	mobj->frame = st->frame;
    519 
    520 	// set subsector and/or block links
    521 	P_SetThingPosition (mobj);
    522 
    523 	mobj->floorz = mobj->subsector->sector->floorheight;
    524 	mobj->ceilingz = mobj->subsector->sector->ceilingheight;
    525 
    526 	if (z == ONFLOORZ)
    527 		mobj->z = mobj->floorz;
    528 	else if (z == ONCEILINGZ)
    529 		mobj->z = mobj->ceilingz - mobj->info->height;
    530 	else 
    531 		mobj->z = z;
    532 
    533 	mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker;
    534 
    535 	P_AddThinker (&mobj->thinker);
    536 
    537 	return mobj;
    538 }
    539 
    540 
    541 //
    542 // P_RemoveMobj
    543 //
    544 
    545 
    546 void P_RemoveMobj (mobj_t* mobj)
    547 {
    548 	if ((mobj->flags & MF_SPECIAL)
    549 		&& !(mobj->flags & MF_DROPPED)
    550 		&& (mobj->type != MT_INV)
    551 		&& (mobj->type != MT_INS))
    552 	{
    553 		::g->itemrespawnque[::g->iquehead] = mobj->spawnpoint;
    554 		::g->itemrespawntime[::g->iquehead] = ::g->leveltime;
    555 		::g->iquehead = (::g->iquehead+1)&(ITEMQUESIZE-1);
    556 
    557 		// lose one off the end?
    558 		if (::g->iquehead == ::g->iquetail)
    559 			::g->iquetail = (::g->iquetail+1)&(ITEMQUESIZE-1);
    560 	}
    561 
    562 	// unlink from sector and block lists
    563 	P_UnsetThingPosition (mobj);
    564 
    565 	// stop any playing sound
    566 	//S_StopSound (mobj);
    567 
    568 	// free block
    569 	P_RemoveThinker ((thinker_t*)mobj);
    570 }
    571 
    572 
    573 
    574 
    575 //
    576 // P_RespawnSpecials
    577 //
    578 void P_RespawnSpecials (void)
    579 {
    580 	fixed_t		x;
    581 	fixed_t		y;
    582 	fixed_t		z;
    583 
    584 	subsector_t*	ss; 
    585 	mobj_t*		mo;
    586 	mapthing_t*		mthing;
    587 
    588 	int			i;
    589 
    590 	// only respawn items in ::g->deathmatch
    591 	if (::g->deathmatch != 2)
    592 		return;	// 
    593 
    594 	// nothing left to respawn?
    595 	if (::g->iquehead == ::g->iquetail)
    596 		return;		
    597 
    598 	// wait at least 30 seconds
    599 	if (::g->leveltime - ::g->itemrespawntime[::g->iquetail] < 30*TICRATE)
    600 		return;			
    601 
    602 	mthing = &::g->itemrespawnque[::g->iquetail];
    603 
    604 	x = mthing->x << FRACBITS; 
    605 	y = mthing->y << FRACBITS; 
    606 
    607 	// spawn a teleport fog at the new spot
    608 	ss = R_PointInSubsector (x,y); 
    609 	mo = P_SpawnMobj (x, y, ss->sector->floorheight , MT_IFOG); 
    610 	S_StartSound (mo, sfx_itmbk);
    611 
    612 	// find which type to spawn
    613 	for (i=0 ; i< NUMMOBJTYPES ; i++)
    614 	{
    615 		if (mthing->type == mobjinfo[i].doomednum)
    616 			break;
    617 	}
    618 
    619 	// spawn it
    620 	if (mobjinfo[i].flags & MF_SPAWNCEILING)
    621 		z = ONCEILINGZ;
    622 	else
    623 		z = ONFLOORZ;
    624 
    625 	mo = (mobj_t*)P_SpawnMobj (x,y,z, (mobjtype_t)i);
    626 	mo->spawnpoint = *mthing;	
    627 	mo->angle = ANG45 * (mthing->angle/45);
    628 
    629 	// pull it from the que
    630 	::g->iquetail = (::g->iquetail+1)&(ITEMQUESIZE-1);
    631 }
    632 
    633 
    634 
    635 
    636 //
    637 // P_SpawnPlayer
    638 // Called when a player is spawned on the level.
    639 // Most of the player structure stays unchanged
    640 //  between levels.
    641 //
    642 void P_SpawnPlayer (mapthing_t* mthing)
    643 {
    644 	player_t*		p;
    645 	fixed_t		x;
    646 	fixed_t		y;
    647 	fixed_t		z;
    648 
    649 	mobj_t*		mobj;
    650 
    651 	int			i;
    652 
    653 	// not playing?
    654 	if (!::g->playeringame[mthing->type-1])
    655 		return;					
    656 
    657 	p = &::g->players[mthing->type-1];
    658 
    659 	if (p->playerstate == PST_REBORN)
    660 		G_PlayerReborn (mthing->type-1);
    661 
    662 	x 		= mthing->x << FRACBITS;
    663 	y 		= mthing->y << FRACBITS;
    664 	z		= ONFLOORZ;
    665 	mobj	= P_SpawnMobj (x,y,z, MT_PLAYER);
    666 
    667 	// set color translations for player ::g->sprites
    668 	if (mthing->type > 1)		
    669 		mobj->flags |= (mthing->type-1)<<MF_TRANSSHIFT;
    670 
    671 	mobj->angle	= ANG45 * (mthing->angle/45);
    672 	mobj->player = p;
    673 	mobj->health = p->health;
    674 
    675 	p->mo = mobj;
    676 	p->playerstate = PST_LIVE;	
    677 	p->refire = 0;
    678 	p->message = NULL;
    679 	p->damagecount = 0;
    680 	p->bonuscount = 0;
    681 	p->extralight = 0;
    682 	p->fixedcolormap = 0;
    683 	p->viewheight = VIEWHEIGHT;
    684 
    685 	// setup gun psprite
    686 	P_SetupPsprites (p);
    687 
    688 	// give all cards in death match mode
    689 	if (::g->deathmatch)
    690 		for (i=0 ; i<NUMCARDS ; i++)
    691 			p->cards[i] = true;
    692 
    693 	if (mthing->type-1 == ::g->consoleplayer)
    694 	{
    695 		// wake up the status bar
    696 		ST_Start ();
    697 		// wake up the heads up text
    698 		HU_Start ();		
    699 	}
    700 
    701 	// Give him everything is Give All is on.
    702 	if( p->cheats & CF_GIVEALL ) {
    703 		 p->armorpoints = 200;
    704 		 p->armortype = 2;
    705 
    706 		int i;
    707 		for (i=0;i<NUMWEAPONS;i++)
    708 			 p->weaponowned[i] = true;
    709 
    710 		for (i=0;i<NUMAMMO;i++)
    711 			 p->ammo[i] =  p->maxammo[i];
    712 
    713 		for (i=0;i<NUMCARDS;i++)
    714 			 p->cards[i] = true;
    715 	}
    716 
    717 }
    718 
    719 
    720 //
    721 // P_SpawnMapThing
    722 // The fields of the mapthing should
    723 // already be in host byte order.
    724 //
    725 void P_SpawnMapThing (mapthing_t* mthing)
    726 {
    727 	int			i;
    728 	int			bit;
    729 	mobj_t*		mobj;
    730 	fixed_t		x;
    731 	fixed_t		y;
    732 	fixed_t		z;
    733 
    734 	// count ::g->deathmatch start positions
    735 	if (mthing->type == 11)
    736 	{
    737 		if (::g->deathmatch_p < &::g->deathmatchstarts[10])
    738 		{
    739 			memcpy (::g->deathmatch_p, mthing, sizeof(*mthing));
    740 			::g->deathmatch_p++;
    741 		}
    742 		return;
    743 	}
    744 
    745 	// check for ::g->players specially
    746 	if (mthing->type <= 4)
    747 	{
    748 		// save spots for respawning in network games
    749 		::g->playerstarts[mthing->type-1] = *mthing;
    750 		if (!::g->deathmatch)
    751 			P_SpawnPlayer (mthing);
    752 
    753 		return;
    754 	}
    755 
    756 	// check for apropriate skill level
    757 	if (!::g->netgame && (mthing->options & 16) )
    758 		return;
    759 
    760 	if (::g->gameskill == sk_baby)
    761 		bit = 1;
    762 	else if (::g->gameskill == sk_nightmare)
    763 		bit = 4;
    764 	else
    765 		bit = 1<<(::g->gameskill-1);
    766 
    767 	if (!(mthing->options & bit) )
    768 		return;
    769 
    770 	// find which type to spawn
    771 	for (i=0 ; i< NUMMOBJTYPES ; i++)
    772 		if (mthing->type == mobjinfo[i].doomednum)
    773 			break;
    774 
    775 	if ( i==NUMMOBJTYPES ) {
    776 		//printf( "P_SpawnMapThing: Unknown type %i at (%i, %i)", mthing->type, mthing->x, mthing->y);
    777 		return;
    778 		//I_Error ("P_SpawnMapThing: Unknown type %i at (%i, %i)",
    779 		//mthing->type,
    780 		//mthing->x, mthing->y);
    781 	}
    782 
    783 	// don't spawn keycards and ::g->players in ::g->deathmatch
    784 	if (::g->deathmatch && mobjinfo[i].flags & MF_NOTDMATCH)
    785 		return;
    786 
    787 	// don't spawn any monsters if -::g->nomonsters
    788 	if (::g->nomonsters
    789 		&& ( i == MT_SKULL
    790 		|| (mobjinfo[i].flags & MF_COUNTKILL)) )
    791 	{
    792 		return;
    793 	}
    794 
    795 	// spawn it
    796 	x = mthing->x << FRACBITS;
    797 	y = mthing->y << FRACBITS;
    798 
    799 	if (mobjinfo[i].flags & MF_SPAWNCEILING)
    800 		z = ONCEILINGZ;
    801 	else
    802 		z = ONFLOORZ;
    803 
    804 	mobj = (mobj_t*)P_SpawnMobj (x,y,z, (mobjtype_t)i);
    805 	mobj->spawnpoint = *mthing;
    806 
    807 	if (mobj->tics > 0)
    808 		mobj->tics = 1 + (P_Random () % mobj->tics);
    809 	if (mobj->flags & MF_COUNTKILL)
    810 		::g->totalkills++;
    811 	if (mobj->flags & MF_COUNTITEM)
    812 		::g->totalitems++;
    813 
    814 	mobj->angle = ANG45 * (mthing->angle/45);
    815 	if (mthing->options & MTF_AMBUSH)
    816 		mobj->flags |= MF_AMBUSH;
    817 }
    818 
    819 
    820 
    821 //
    822 // GAME SPAWN FUNCTIONS
    823 //
    824 
    825 
    826 //
    827 // P_SpawnPuff
    828 //
    829 
    830 void
    831 P_SpawnPuff
    832 ( fixed_t	x,
    833  fixed_t	y,
    834  fixed_t	z )
    835 {
    836 	mobj_t*	th;
    837 
    838 	z += ((P_Random()-P_Random())<<10);
    839 
    840 	th = P_SpawnMobj (x,y,z, MT_PUFF);
    841 	th->momz = FRACUNIT;
    842 	th->tics -= P_Random()&3;
    843 
    844 	if (th->tics < 1)
    845 		th->tics = 1;
    846 
    847 	// don't make punches spark on the wall
    848 	if (::g->attackrange == MELEERANGE) {
    849 
    850 		P_SetMobjState (th, S_PUFF3);
    851 		
    852 	}
    853 }
    854 
    855 
    856 
    857 //
    858 // P_SpawnBlood
    859 // 
    860 void
    861 P_SpawnBlood
    862 ( fixed_t	x,
    863  fixed_t	y,
    864  fixed_t	z,
    865  int		damage )
    866 {
    867 	mobj_t*	th;
    868 
    869 	z += ((P_Random()-P_Random())<<10);
    870 	th = P_SpawnMobj (x,y,z, MT_BLOOD);
    871 	th->momz = FRACUNIT*2;
    872 	th->tics -= P_Random()&3;
    873 
    874 	if (th->tics < 1)
    875 		th->tics = 1;
    876 
    877 	if (damage <= 12 && damage >= 9)
    878 		P_SetMobjState (th,S_BLOOD2);
    879 	else if (damage < 9)
    880 		P_SetMobjState (th,S_BLOOD3);
    881 }
    882 
    883 
    884 
    885 //
    886 // P_CheckMissileSpawn
    887 // Moves the missile forward a bit
    888 //  and possibly explodes it right there.
    889 //
    890 void P_CheckMissileSpawn (mobj_t* th)
    891 {
    892 	th->tics -= P_Random()&3;
    893 	if (th->tics < 1)
    894 		th->tics = 1;
    895 
    896 	// move a little forward so an angle can
    897 	// be computed if it immediately explodes
    898 	th->x += (th->momx>>1);
    899 	th->y += (th->momy>>1);
    900 	th->z += (th->momz>>1);
    901 
    902 	if (!P_TryMove (th, th->x, th->y))
    903 		P_ExplodeMissile (th);
    904 }
    905 
    906 
    907 //
    908 // P_SpawnMissile
    909 //
    910 mobj_t*
    911 P_SpawnMissile
    912 ( mobj_t*	source,
    913  mobj_t*	dest,
    914  mobjtype_t	type )
    915 {
    916 	mobj_t*	th;
    917 	angle_t	an;
    918 	int		dist;
    919 
    920 	th = P_SpawnMobj (source->x,
    921 		source->y,
    922 		source->z + 4*8*FRACUNIT, type);
    923 
    924 	if (th->info->seesound)
    925 		S_StartSound (th, th->info->seesound);
    926 
    927 	th->target = source;	// where it came from
    928 	an = R_PointToAngle2 (source->x, source->y, dest->x, dest->y);	
    929 
    930 	// fuzzy player
    931 	if (dest->flags & MF_SHADOW)
    932 		an += (P_Random()-P_Random())<<20;	
    933 
    934 	th->angle = an;
    935 	an >>= ANGLETOFINESHIFT;
    936 	th->momx = FixedMul (th->info->speed, finecosine[an]);
    937 	th->momy = FixedMul (th->info->speed, finesine[an]);
    938 
    939 	dist = P_AproxDistance (dest->x - source->x, dest->y - source->y);
    940 	dist = dist / th->info->speed;
    941 
    942 	if (dist < 1)
    943 		dist = 1;
    944 
    945 	th->momz = (dest->z - source->z) / dist;
    946 	P_CheckMissileSpawn (th);
    947 
    948 	return th;
    949 }
    950 
    951 
    952 //
    953 // P_SpawnPlayerMissile
    954 // Tries to aim at a nearby monster
    955 //
    956 void
    957 P_SpawnPlayerMissile
    958 ( mobj_t*	source,
    959  mobjtype_t	type )
    960 {
    961 	mobj_t*	th;
    962 	angle_t	an;
    963 
    964 	fixed_t	x;
    965 	fixed_t	y;
    966 	fixed_t	z;
    967 	fixed_t	slope;
    968 
    969 	// see which target is to be aimed at
    970 	an = source->angle;
    971 	slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
    972 
    973 	if (!::g->linetarget)
    974 	{
    975 		an += 1<<26;
    976 		slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
    977 
    978 		if (!::g->linetarget)
    979 		{
    980 			an -= 2<<26;
    981 			slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
    982 		}
    983 
    984 		if (!::g->linetarget)
    985 		{
    986 			an = source->angle;
    987 			slope = 0;
    988 		}
    989 	}
    990 
    991 	x = source->x;
    992 	y = source->y;
    993 	z = source->z + 4*8*FRACUNIT;
    994 
    995 	th = P_SpawnMobj (x,y,z, type);
    996 
    997 	if (th->info->seesound && (source->player == &::g->players[::g->consoleplayer]) ) {
    998 		S_StartSound (th, th->info->seesound);
    999 	}
   1000 
   1001 	th->target = source;
   1002 	th->angle = an;
   1003 	th->momx = FixedMul( th->info->speed,
   1004 		finecosine[an>>ANGLETOFINESHIFT]);
   1005 	th->momy = FixedMul( th->info->speed,
   1006 		finesine[an>>ANGLETOFINESHIFT]);
   1007 	th->momz = FixedMul( th->info->speed, slope);
   1008 
   1009 	P_CheckMissileSpawn (th);
   1010 }
   1011 
   1012