doom

a minimalistic implementation of doom
git clone git://ssnf.xyz/doom
Log | Files | Refs

p_mobj.c (15234B)


      1 #include "i_system.h"
      2 #include "z_zone.h"
      3 #include "m_random.h"
      4 
      5 #include "doomdef.h"
      6 #include "p_local.h"
      7 #include "sounds.h"
      8 
      9 #include "st_stuff.h"
     10 #include "hu_stuff.h"
     11 
     12 #include "s_sound.h"
     13 
     14 #include "doomstat.h"
     15 
     16 
     17 void G_PlayerReborn (int player);
     18 void P_SpawnMapThing (mapthing_t*	mthing);
     19 
     20 
     21 
     22 
     23 
     24 
     25 int test;
     26 
     27 boolean
     28 P_SetMobjState
     29 ( mobj_t*	mobj,
     30   statenum_t	state )
     31 {
     32     state_t*	st;
     33 
     34     do
     35     {
     36 	if (state == S_NULL)
     37 	{
     38 	    mobj->state = (state_t *) S_NULL;
     39 	    P_RemoveMobj (mobj);
     40 	    return false;
     41 	}
     42 
     43 	st = &states[state];
     44 	mobj->state = st;
     45 	mobj->tics = st->tics;
     46 	mobj->sprite = st->sprite;
     47 	mobj->frame = st->frame;
     48 
     49 	
     50 	
     51 	if (st->action.acp1)		
     52 	    st->action.acp1(mobj);	
     53 	
     54 	state = st->nextstate;
     55     } while (!mobj->tics);
     56 				
     57     return true;
     58 }
     59 
     60 
     61 
     62 
     63 
     64 void P_ExplodeMissile (mobj_t* mo)
     65 {
     66     mo->momx = mo->momy = mo->momz = 0;
     67 
     68     P_SetMobjState (mo, mobjinfo[mo->type].deathstate);
     69 
     70     mo->tics -= P_Random()&3;
     71 
     72     if (mo->tics < 1)
     73 	mo->tics = 1;
     74 
     75     mo->flags &= ~MF_MISSILE;
     76 
     77     if (mo->info->deathsound)
     78 	S_StartSound (mo, mo->info->deathsound);
     79 }
     80 
     81 
     82 
     83 
     84 
     85 #define STOPSPEED		0x1000
     86 #define FRICTION		0xe800
     87 
     88 void P_XYMovement (mobj_t* mo) 
     89 { 	
     90     fixed_t 	ptryx;
     91     fixed_t	ptryy;
     92     player_t*	player;
     93     fixed_t	xmove;
     94     fixed_t	ymove;
     95 			
     96     if (!mo->momx && !mo->momy)
     97     {
     98 	if (mo->flags & MF_SKULLFLY)
     99 	{
    100 	    
    101 	    mo->flags &= ~MF_SKULLFLY;
    102 	    mo->momx = mo->momy = mo->momz = 0;
    103 
    104 	    P_SetMobjState (mo, mo->info->spawnstate);
    105 	}
    106 	return;
    107     }
    108 	
    109     player = mo->player;
    110 		
    111     if (mo->momx > MAXMOVE)
    112 	mo->momx = MAXMOVE;
    113     else if (mo->momx < -MAXMOVE)
    114 	mo->momx = -MAXMOVE;
    115 
    116     if (mo->momy > MAXMOVE)
    117 	mo->momy = MAXMOVE;
    118     else if (mo->momy < -MAXMOVE)
    119 	mo->momy = -MAXMOVE;
    120 		
    121     xmove = mo->momx;
    122     ymove = mo->momy;
    123 	
    124     do
    125     {
    126 	if (xmove > MAXMOVE/2 || ymove > MAXMOVE/2)
    127 	{
    128 	    ptryx = mo->x + xmove/2;
    129 	    ptryy = mo->y + ymove/2;
    130 	    xmove >>= 1;
    131 	    ymove >>= 1;
    132 	}
    133 	else
    134 	{
    135 	    ptryx = mo->x + xmove;
    136 	    ptryy = mo->y + ymove;
    137 	    xmove = ymove = 0;
    138 	}
    139 		
    140 	if (!P_TryMove (mo, ptryx, ptryy))
    141 	{
    142 	    
    143 	    if (mo->player)
    144 	    {	
    145 		P_SlideMove (mo);
    146 	    }
    147 	    else if (mo->flags & MF_MISSILE)
    148 	    {
    149 		
    150 		if (ceilingline &&
    151 		    ceilingline->backsector &&
    152 		    ceilingline->backsector->ceilingpic == skyflatnum)
    153 		{
    154 		    
    155 		    
    156 		    
    157 		    P_RemoveMobj (mo);
    158 		    return;
    159 		}
    160 		P_ExplodeMissile (mo);
    161 	    }
    162 	    else
    163 		mo->momx = mo->momy = 0;
    164 	}
    165     } while (xmove || ymove);
    166     
    167     
    168     if (player && player->cheats & CF_NOMOMENTUM)
    169     {
    170 	
    171 	mo->momx = mo->momy = 0;
    172 	return;
    173     }
    174 
    175     if (mo->flags & (MF_MISSILE | MF_SKULLFLY) )
    176 	return; 	
    177 		
    178     if (mo->z > mo->floorz)
    179 	return;		
    180 
    181     if (mo->flags & MF_CORPSE)
    182     {
    183 	
    184 	
    185 	if (mo->momx > FRACUNIT/4
    186 	    || mo->momx < -FRACUNIT/4
    187 	    || mo->momy > FRACUNIT/4
    188 	    || mo->momy < -FRACUNIT/4)
    189 	{
    190 	    if (mo->floorz != mo->subsector->sector->floorheight)
    191 		return;
    192 	}
    193     }
    194 
    195     if (mo->momx > -STOPSPEED
    196 	&& mo->momx < STOPSPEED
    197 	&& mo->momy > -STOPSPEED
    198 	&& mo->momy < STOPSPEED
    199 	&& (!player
    200 	    || (player->cmd.forwardmove== 0
    201 		&& player->cmd.sidemove == 0 ) ) )
    202     {
    203 	
    204 	if ( player&&(unsigned)((player->mo->state - states)- S_PLAY_RUN1) < 4)
    205 	    P_SetMobjState (player->mo, S_PLAY);
    206 	
    207 	mo->momx = 0;
    208 	mo->momy = 0;
    209     }
    210     else
    211     {
    212 	mo->momx = FixedMul (mo->momx, FRICTION);
    213 	mo->momy = FixedMul (mo->momy, FRICTION);
    214     }
    215 }
    216 
    217 
    218 
    219 
    220 void P_ZMovement (mobj_t* mo)
    221 {
    222     fixed_t	dist;
    223     fixed_t	delta;
    224     
    225     
    226     if (mo->player && mo->z < mo->floorz)
    227     {
    228 	mo->player->viewheight -= mo->floorz-mo->z;
    229 
    230 	mo->player->deltaviewheight
    231 	    = (VIEWHEIGHT - mo->player->viewheight)>>3;
    232     }
    233     
    234     
    235     mo->z += mo->momz;
    236 	
    237     if ( mo->flags & MF_FLOAT
    238 	 && mo->target)
    239     {
    240 	
    241 	if ( !(mo->flags & MF_SKULLFLY)
    242 	     && !(mo->flags & MF_INFLOAT) )
    243 	{
    244 	    dist = P_AproxDistance (mo->x - mo->target->x,
    245 				    mo->y - mo->target->y);
    246 	    
    247 	    delta =(mo->target->z + (mo->height>>1)) - mo->z;
    248 
    249 	    if (delta<0 && dist < -(delta*3) )
    250 		mo->z -= FLOATSPEED;
    251 	    else if (delta>0 && dist < (delta*3) )
    252 		mo->z += FLOATSPEED;			
    253 	}
    254 	
    255     }
    256     
    257     
    258     if (mo->z <= mo->floorz)
    259     {
    260 	
    261 
    262 	
    263 	
    264 	
    265 	if (mo->flags & MF_SKULLFLY)
    266 	{
    267 	    
    268 	    mo->momz = -mo->momz;
    269 	}
    270 	
    271 	if (mo->momz < 0)
    272 	{
    273 	    if (mo->player
    274 		&& mo->momz < -GRAVITY*8)	
    275 	    {
    276 		
    277 		
    278 		
    279 		
    280 		mo->player->deltaviewheight = mo->momz>>3;
    281 		S_StartSound (mo, sfx_oof);
    282 	    }
    283 	    mo->momz = 0;
    284 	}
    285 	mo->z = mo->floorz;
    286 
    287 	if ( (mo->flags & MF_MISSILE)
    288 	     && !(mo->flags & MF_NOCLIP) )
    289 	{
    290 	    P_ExplodeMissile (mo);
    291 	    return;
    292 	}
    293     }
    294     else if (! (mo->flags & MF_NOGRAVITY) )
    295     {
    296 	if (mo->momz == 0)
    297 	    mo->momz = -GRAVITY*2;
    298 	else
    299 	    mo->momz -= GRAVITY;
    300     }
    301 	
    302     if (mo->z + mo->height > mo->ceilingz)
    303     {
    304 	
    305 	if (mo->momz > 0)
    306 	    mo->momz = 0;
    307 	{
    308 	    mo->z = mo->ceilingz - mo->height;
    309 	}
    310 
    311 	if (mo->flags & MF_SKULLFLY)
    312 	{	
    313 	    mo->momz = -mo->momz;
    314 	}
    315 	
    316 	if ( (mo->flags & MF_MISSILE)
    317 	     && !(mo->flags & MF_NOCLIP) )
    318 	{
    319 	    P_ExplodeMissile (mo);
    320 	    return;
    321 	}
    322     }
    323 } 
    324 
    325 
    326 
    327 
    328 
    329 
    330 void
    331 P_NightmareRespawn (mobj_t* mobj)
    332 {
    333     fixed_t		x;
    334     fixed_t		y;
    335     fixed_t		z; 
    336     subsector_t*	ss; 
    337     mobj_t*		mo;
    338     mapthing_t*		mthing;
    339 		
    340     x = mobj->spawnpoint.x << FRACBITS; 
    341     y = mobj->spawnpoint.y << FRACBITS; 
    342 
    343     
    344     if (!P_CheckPosition (mobj, x, y) ) 
    345 	return;	
    346 
    347     
    348     
    349     mo = P_SpawnMobj (mobj->x,
    350 		      mobj->y,
    351 		      mobj->subsector->sector->floorheight , MT_TFOG); 
    352     
    353     S_StartSound (mo, sfx_telept);
    354 
    355     
    356     ss = R_PointInSubsector (x,y); 
    357 
    358     mo = P_SpawnMobj (x, y, ss->sector->floorheight , MT_TFOG); 
    359 
    360     S_StartSound (mo, sfx_telept);
    361 
    362     
    363     mthing = &mobj->spawnpoint;
    364 	
    365     
    366     if (mobj->info->flags & MF_SPAWNCEILING)
    367 	z = ONCEILINGZ;
    368     else
    369 	z = ONFLOORZ;
    370 
    371     
    372     mo = P_SpawnMobj (x,y,z, mobj->type);
    373     mo->spawnpoint = mobj->spawnpoint;	
    374     mo->angle = ANG45 * (mthing->angle/45);
    375 
    376     if (mthing->options & MTF_AMBUSH)
    377 	mo->flags |= MF_AMBUSH;
    378 
    379     mo->reactiontime = 18;
    380 	
    381     
    382     P_RemoveMobj (mobj);
    383 }
    384 
    385 
    386 
    387 
    388 
    389 void P_MobjThinker (mobj_t* mobj)
    390 {
    391     
    392     if (mobj->momx
    393 	|| mobj->momy
    394 	|| (mobj->flags&MF_SKULLFLY) )
    395     {
    396 	P_XYMovement (mobj);
    397 
    398 	
    399 	if (mobj->thinker.function.acv == (actionf_v) (-1))
    400 	    return;		
    401     }
    402     if ( (mobj->z != mobj->floorz)
    403 	 || mobj->momz )
    404     {
    405 	P_ZMovement (mobj);
    406 	
    407 	
    408 	if (mobj->thinker.function.acv == (actionf_v) (-1))
    409 	    return;		
    410     }
    411 
    412     
    413     
    414     
    415     if (mobj->tics != -1)
    416     {
    417 	mobj->tics--;
    418 		
    419 	
    420 	if (!mobj->tics)
    421 	    if (!P_SetMobjState (mobj, mobj->state->nextstate) )
    422 		return;		
    423     }
    424     else
    425     {
    426 	
    427 	if (! (mobj->flags & MF_COUNTKILL) )
    428 	    return;
    429 
    430 	if (!respawnmonsters)
    431 	    return;
    432 
    433 	mobj->movecount++;
    434 
    435 	if (mobj->movecount < 12*35)
    436 	    return;
    437 
    438 	if ( leveltime&31 )
    439 	    return;
    440 
    441 	if (P_Random () > 4)
    442 	    return;
    443 
    444 	P_NightmareRespawn (mobj);
    445     }
    446 
    447 }
    448 
    449 
    450 
    451 
    452 
    453 mobj_t*
    454 P_SpawnMobj
    455 ( fixed_t	x,
    456   fixed_t	y,
    457   fixed_t	z,
    458   mobjtype_t	type )
    459 {
    460     mobj_t*	mobj;
    461     state_t*	st;
    462     mobjinfo_t*	info;
    463 	
    464     mobj = Z_Malloc (sizeof(*mobj), PU_LEVEL, NULL);
    465     memset (mobj, 0, sizeof (*mobj));
    466     info = &mobjinfo[type];
    467 	
    468     mobj->type = type;
    469     mobj->info = info;
    470     mobj->x = x;
    471     mobj->y = y;
    472     mobj->radius = info->radius;
    473     mobj->height = info->height;
    474     mobj->flags = info->flags;
    475     mobj->health = info->spawnhealth;
    476 
    477     if (gameskill != sk_nightmare)
    478 	mobj->reactiontime = info->reactiontime;
    479     
    480     mobj->lastlook = P_Random () % MAXPLAYERS;
    481     
    482     
    483     st = &states[info->spawnstate];
    484 
    485     mobj->state = st;
    486     mobj->tics = st->tics;
    487     mobj->sprite = st->sprite;
    488     mobj->frame = st->frame;
    489 
    490     
    491     P_SetThingPosition (mobj);
    492 	
    493     mobj->floorz = mobj->subsector->sector->floorheight;
    494     mobj->ceilingz = mobj->subsector->sector->ceilingheight;
    495 
    496     if (z == ONFLOORZ)
    497 	mobj->z = mobj->floorz;
    498     else if (z == ONCEILINGZ)
    499 	mobj->z = mobj->ceilingz - mobj->info->height;
    500     else 
    501 	mobj->z = z;
    502 
    503     mobj->thinker.function.acp1 = (actionf_p1)P_MobjThinker;
    504 	
    505     P_AddThinker (&mobj->thinker);
    506 
    507     return mobj;
    508 }
    509 
    510 
    511 
    512 
    513 
    514 mapthing_t	itemrespawnque[ITEMQUESIZE];
    515 int		itemrespawntime[ITEMQUESIZE];
    516 int		iquehead;
    517 int		iquetail;
    518 
    519 
    520 void P_RemoveMobj (mobj_t* mobj)
    521 {
    522     if ((mobj->flags & MF_SPECIAL)
    523 	&& !(mobj->flags & MF_DROPPED)
    524 	&& (mobj->type != MT_INV)
    525 	&& (mobj->type != MT_INS))
    526     {
    527 	itemrespawnque[iquehead] = mobj->spawnpoint;
    528 	itemrespawntime[iquehead] = leveltime;
    529 	iquehead = (iquehead+1)&(ITEMQUESIZE-1);
    530 
    531 	
    532 	if (iquehead == iquetail)
    533 	    iquetail = (iquetail+1)&(ITEMQUESIZE-1);
    534     }
    535 	
    536     
    537     P_UnsetThingPosition (mobj);
    538     
    539     
    540     S_StopSound (mobj);
    541     
    542     
    543     P_RemoveThinker ((thinker_t*)mobj);
    544 }
    545 
    546 
    547 
    548 
    549 
    550 
    551 
    552 void P_RespawnSpecials (void)
    553 {
    554     fixed_t		x;
    555     fixed_t		y;
    556     fixed_t		z;
    557     
    558     subsector_t*	ss; 
    559     mobj_t*		mo;
    560     mapthing_t*		mthing;
    561     
    562     int			i;
    563 
    564     
    565     if (deathmatch != 2)
    566 	return;	
    567 
    568     
    569     if (iquehead == iquetail)
    570 	return;		
    571 
    572     
    573     if (leveltime - itemrespawntime[iquetail] < 30*35)
    574 	return;			
    575 
    576     mthing = &itemrespawnque[iquetail];
    577 	
    578     x = mthing->x << FRACBITS; 
    579     y = mthing->y << FRACBITS; 
    580 	  
    581     
    582     ss = R_PointInSubsector (x,y); 
    583     mo = P_SpawnMobj (x, y, ss->sector->floorheight , MT_IFOG); 
    584     S_StartSound (mo, sfx_itmbk);
    585 
    586     
    587     for (i=0 ; i< NUMMOBJTYPES ; i++)
    588     {
    589 	if (mthing->type == mobjinfo[i].doomednum)
    590 	    break;
    591     }
    592     
    593     
    594     if (mobjinfo[i].flags & MF_SPAWNCEILING)
    595 	z = ONCEILINGZ;
    596     else
    597 	z = ONFLOORZ;
    598 
    599     mo = P_SpawnMobj (x,y,z, i);
    600     mo->spawnpoint = *mthing;	
    601     mo->angle = ANG45 * (mthing->angle/45);
    602 
    603     
    604     iquetail = (iquetail+1)&(ITEMQUESIZE-1);
    605 }
    606 
    607 
    608 
    609 
    610 
    611 
    612 
    613 
    614 
    615 
    616 void P_SpawnPlayer (mapthing_t* mthing)
    617 {
    618     player_t*		p;
    619     fixed_t		x;
    620     fixed_t		y;
    621     fixed_t		z;
    622 
    623     mobj_t*		mobj;
    624 
    625     int			i;
    626 
    627     
    628     if (!playeringame[mthing->type-1])
    629 	return;					
    630 		
    631     p = &players[mthing->type-1];
    632 
    633     if (p->playerstate == PST_REBORN)
    634 	G_PlayerReborn (mthing->type-1);
    635 
    636     x 		= mthing->x << FRACBITS;
    637     y 		= mthing->y << FRACBITS;
    638     z		= ONFLOORZ;
    639     mobj	= P_SpawnMobj (x,y,z, MT_PLAYER);
    640 
    641     
    642     if (mthing->type > 1)		
    643 	mobj->flags |= (mthing->type-1)<<MF_TRANSSHIFT;
    644 		
    645     mobj->angle	= ANG45 * (mthing->angle/45);
    646     mobj->player = p;
    647     mobj->health = p->health;
    648 
    649     p->mo = mobj;
    650     p->playerstate = PST_LIVE;	
    651     p->refire = 0;
    652     p->message = NULL;
    653     p->damagecount = 0;
    654     p->bonuscount = 0;
    655     p->extralight = 0;
    656     p->fixedcolormap = 0;
    657     p->viewheight = VIEWHEIGHT;
    658 
    659     
    660     P_SetupPsprites (p);
    661     
    662     
    663     if (deathmatch)
    664 	for (i=0 ; i<NUMCARDS ; i++)
    665 	    p->cards[i] = true;
    666 			
    667     if (mthing->type-1 == consoleplayer)
    668     {
    669 	
    670 	ST_Start ();
    671 	
    672 	HU_Start ();		
    673     }
    674 }
    675 
    676 
    677 
    678 
    679 
    680 
    681 
    682 void P_SpawnMapThing (mapthing_t* mthing)
    683 {
    684     int			i;
    685     int			bit;
    686     mobj_t*		mobj;
    687     fixed_t		x;
    688     fixed_t		y;
    689     fixed_t		z;
    690 		
    691     
    692     if (mthing->type == 11)
    693     {
    694 	if (deathmatch_p < &deathmatchstarts[10])
    695 	{
    696 	    memcpy (deathmatch_p, mthing, sizeof(*mthing));
    697 	    deathmatch_p++;
    698 	}
    699 	return;
    700     }
    701 	
    702     
    703     if (mthing->type <= 4)
    704     {
    705 	
    706 	playerstarts[mthing->type-1] = *mthing;
    707 	if (!deathmatch)
    708 	    P_SpawnPlayer (mthing);
    709 
    710 	return;
    711     }
    712 
    713     
    714     if (!netgame && (mthing->options & 16) )
    715 	return;
    716 		
    717     if (gameskill == sk_baby)
    718 	bit = 1;
    719     else if (gameskill == sk_nightmare)
    720 	bit = 4;
    721     else
    722 	bit = 1<<(gameskill-1);
    723 
    724     if (!(mthing->options & bit) )
    725 	return;
    726 	
    727     
    728     for (i=0 ; i< NUMMOBJTYPES ; i++)
    729 	if (mthing->type == mobjinfo[i].doomednum)
    730 	    break;
    731 	
    732     if (i==NUMMOBJTYPES)
    733 	I_Error ("P_SpawnMapThing: Unknown type %i at (%i, %i)",
    734 		 mthing->type,
    735 		 mthing->x, mthing->y);
    736 		
    737     
    738     if (deathmatch && mobjinfo[i].flags & MF_NOTDMATCH)
    739 	return;
    740 		
    741     
    742     if (nomonsters
    743 	&& ( i == MT_SKULL
    744 	     || (mobjinfo[i].flags & MF_COUNTKILL)) )
    745     {
    746 	return;
    747     }
    748     
    749     
    750     x = mthing->x << FRACBITS;
    751     y = mthing->y << FRACBITS;
    752 
    753     if (mobjinfo[i].flags & MF_SPAWNCEILING)
    754 	z = ONCEILINGZ;
    755     else
    756 	z = ONFLOORZ;
    757     
    758     mobj = P_SpawnMobj (x,y,z, i);
    759     mobj->spawnpoint = *mthing;
    760 
    761     if (mobj->tics > 0)
    762 	mobj->tics = 1 + (P_Random () % mobj->tics);
    763     if (mobj->flags & MF_COUNTKILL)
    764 	totalkills++;
    765     if (mobj->flags & MF_COUNTITEM)
    766 	totalitems++;
    767 		
    768     mobj->angle = ANG45 * (mthing->angle/45);
    769     if (mthing->options & MTF_AMBUSH)
    770 	mobj->flags |= MF_AMBUSH;
    771 }
    772 
    773 
    774 
    775 
    776 
    777 
    778 
    779 
    780 
    781 
    782 
    783 extern fixed_t attackrange;
    784 
    785 void
    786 P_SpawnPuff
    787 ( fixed_t	x,
    788   fixed_t	y,
    789   fixed_t	z )
    790 {
    791     mobj_t*	th;
    792 	
    793     z += ((P_Random()-P_Random())<<10);
    794 
    795     th = P_SpawnMobj (x,y,z, MT_PUFF);
    796     th->momz = FRACUNIT;
    797     th->tics -= P_Random()&3;
    798 
    799     if (th->tics < 1)
    800 	th->tics = 1;
    801 	
    802     
    803     if (attackrange == MELEERANGE)
    804 	P_SetMobjState (th, S_PUFF3);
    805 }
    806 
    807 
    808 
    809 
    810 
    811 
    812 void
    813 P_SpawnBlood
    814 ( fixed_t	x,
    815   fixed_t	y,
    816   fixed_t	z,
    817   int		damage )
    818 {
    819     mobj_t*	th;
    820 	
    821     z += ((P_Random()-P_Random())<<10);
    822     th = P_SpawnMobj (x,y,z, MT_BLOOD);
    823     th->momz = FRACUNIT*2;
    824     th->tics -= P_Random()&3;
    825 
    826     if (th->tics < 1)
    827 	th->tics = 1;
    828 		
    829     if (damage <= 12 && damage >= 9)
    830 	P_SetMobjState (th,S_BLOOD2);
    831     else if (damage < 9)
    832 	P_SetMobjState (th,S_BLOOD3);
    833 }
    834 
    835 
    836 
    837 
    838 
    839 
    840 
    841 
    842 void P_CheckMissileSpawn (mobj_t* th)
    843 {
    844     th->tics -= P_Random()&3;
    845     if (th->tics < 1)
    846 	th->tics = 1;
    847     
    848     
    849     
    850     th->x += (th->momx>>1);
    851     th->y += (th->momy>>1);
    852     th->z += (th->momz>>1);
    853 
    854     if (!P_TryMove (th, th->x, th->y))
    855 	P_ExplodeMissile (th);
    856 }
    857 
    858 
    859 
    860 
    861 
    862 mobj_t*
    863 P_SpawnMissile
    864 ( mobj_t*	source,
    865   mobj_t*	dest,
    866   mobjtype_t	type )
    867 {
    868     mobj_t*	th;
    869     angle_t	an;
    870     int		dist;
    871 
    872     th = P_SpawnMobj (source->x,
    873 		      source->y,
    874 		      source->z + 4*8*FRACUNIT, type);
    875     
    876     if (th->info->seesound)
    877 	S_StartSound (th, th->info->seesound);
    878 
    879     th->target = source;	
    880     an = R_PointToAngle2 (source->x, source->y, dest->x, dest->y);	
    881 
    882     
    883     if (dest->flags & MF_SHADOW)
    884 	an += (P_Random()-P_Random())<<20;	
    885 
    886     th->angle = an;
    887     an >>= ANGLETOFINESHIFT;
    888     th->momx = FixedMul (th->info->speed, finecosine[an]);
    889     th->momy = FixedMul (th->info->speed, finesine[an]);
    890 	
    891     dist = P_AproxDistance (dest->x - source->x, dest->y - source->y);
    892     dist = dist / th->info->speed;
    893 
    894     if (dist < 1)
    895 	dist = 1;
    896 
    897     th->momz = (dest->z - source->z) / dist;
    898     P_CheckMissileSpawn (th);
    899 	
    900     return th;
    901 }
    902 
    903 
    904 
    905 
    906 
    907 
    908 void
    909 P_SpawnPlayerMissile
    910 ( mobj_t*	source,
    911   mobjtype_t	type )
    912 {
    913     mobj_t*	th;
    914     angle_t	an;
    915     
    916     fixed_t	x;
    917     fixed_t	y;
    918     fixed_t	z;
    919     fixed_t	slope;
    920     
    921     
    922     an = source->angle;
    923     slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
    924     
    925     if (!linetarget)
    926     {
    927 	an += 1<<26;
    928 	slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
    929 
    930 	if (!linetarget)
    931 	{
    932 	    an -= 2<<26;
    933 	    slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
    934 	}
    935 
    936 	if (!linetarget)
    937 	{
    938 	    an = source->angle;
    939 	    slope = 0;
    940 	}
    941     }
    942 		
    943     x = source->x;
    944     y = source->y;
    945     z = source->z + 4*8*FRACUNIT;
    946 	
    947     th = P_SpawnMobj (x,y,z, type);
    948 
    949     if (th->info->seesound)
    950 	S_StartSound (th, th->info->seesound);
    951 
    952     th->target = source;
    953     th->angle = an;
    954     th->momx = FixedMul( th->info->speed,
    955 			 finecosine[an>>ANGLETOFINESHIFT]);
    956     th->momy = FixedMul( th->info->speed,
    957 			 finesine[an>>ANGLETOFINESHIFT]);
    958     th->momz = FixedMul( th->info->speed, slope);
    959 
    960     P_CheckMissileSpawn (th);
    961 }
    962