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