]> icculus.org git repositories - theoddone33/hheretic.git/blob - base/p_mobj.c
Optimized blit functions.
[theoddone33/hheretic.git] / base / p_mobj.c
1
2 // P_mobj.c
3
4 #include "doomdef.h"
5 #include "p_local.h"
6 #include "sounds.h"
7 #include "soundst.h"
8
9 void G_PlayerReborn (int player);
10 void P_SpawnMapThing (mapthing_t *mthing);
11
12 mobjtype_t PuffType;
13 mobj_t *MissileMobj;
14
15 static fixed_t FloatBobOffsets[64] =
16 {
17         0, 51389, 102283, 152192,
18         200636, 247147, 291278, 332604,
19         370727, 405280, 435929, 462380,
20         484378, 501712, 514213, 521763,
21         524287, 521763, 514213, 501712,
22         484378, 462380, 435929, 405280,
23         370727, 332604, 291278, 247147,
24         200636, 152192, 102283, 51389,
25         -1, -51390, -102284, -152193,
26         -200637, -247148, -291279, -332605,
27         -370728, -405281, -435930, -462381,
28         -484380, -501713, -514215, -521764,
29         -524288, -521764, -514214, -501713,
30         -484379, -462381, -435930, -405280,
31         -370728, -332605, -291279, -247148,
32         -200637, -152193, -102284, -51389
33 };
34
35 //----------------------------------------------------------------------------
36 //
37 // FUNC P_SetMobjState
38 //
39 // Returns true if the mobj is still present.
40 //
41 //----------------------------------------------------------------------------
42
43 boolean P_SetMobjState(mobj_t *mobj, statenum_t state)
44 {
45         state_t *st;
46
47         if(state == S_NULL)
48         { // Remove mobj
49                 mobj->state = S_NULL;
50                 P_RemoveMobj(mobj);
51                 return(false);
52         }
53         st = &states[state];
54         mobj->state = st;
55         mobj->tics = st->tics;
56         mobj->sprite = st->sprite;
57         mobj->frame = st->frame;
58         if(st->action)
59         { // Call action function
60                 st->action(mobj);
61         }
62         return(true);
63 }
64
65 //----------------------------------------------------------------------------
66 //
67 // FUNC P_SetMobjStateNF
68 //
69 // Same as P_SetMobjState, but does not call the state function.
70 //
71 //----------------------------------------------------------------------------
72
73 boolean P_SetMobjStateNF(mobj_t *mobj, statenum_t state)
74 {
75         state_t *st;
76
77         if(state == S_NULL)
78         { // Remove mobj
79                 mobj->state = S_NULL;
80                 P_RemoveMobj(mobj);
81                 return(false);
82         }
83         st = &states[state];
84         mobj->state = st;
85         mobj->tics = st->tics;
86         mobj->sprite = st->sprite;
87         mobj->frame = st->frame;
88         return(true);
89 }
90
91 //----------------------------------------------------------------------------
92 //
93 // PROC P_ExplodeMissile
94 //
95 //----------------------------------------------------------------------------
96
97 void P_ExplodeMissile(mobj_t *mo)
98 {
99         if(mo->type == MT_WHIRLWIND)
100         {
101                 if(++mo->special2 < 60)
102                 {
103                         return;
104                 }
105         }
106         mo->momx = mo->momy = mo->momz = 0;
107         P_SetMobjState(mo, mobjinfo[mo->type].deathstate);
108         //mo->tics -= P_Random()&3;
109         mo->flags &= ~MF_MISSILE;
110         if(mo->info->deathsound)
111         {
112                 S_StartSound(mo, mo->info->deathsound);
113         }
114 }
115
116 //----------------------------------------------------------------------------
117 //
118 // PROC P_FloorBounceMissile
119 //
120 //----------------------------------------------------------------------------
121
122 void P_FloorBounceMissile(mobj_t *mo)
123 {
124         mo->momz = -mo->momz;
125         P_SetMobjState(mo, mobjinfo[mo->type].deathstate);
126 }
127
128 //----------------------------------------------------------------------------
129 //
130 // PROC P_ThrustMobj
131 //
132 //----------------------------------------------------------------------------
133
134 void P_ThrustMobj(mobj_t *mo, angle_t angle, fixed_t move)
135 {
136         angle >>= ANGLETOFINESHIFT;
137         mo->momx += FixedMul(move, finecosine[angle]);
138         mo->momy += FixedMul(move, finesine[angle]);
139 }
140
141 //----------------------------------------------------------------------------
142 //
143 // FUNC P_FaceMobj
144 //
145 // Returns 1 if 'source' needs to turn clockwise, or 0 if 'source' needs
146 // to turn counter clockwise.  'delta' is set to the amount 'source'
147 // needs to turn.
148 //
149 //----------------------------------------------------------------------------
150
151 int P_FaceMobj(mobj_t *source, mobj_t *target, angle_t *delta)
152 {
153         angle_t diff;
154         angle_t angle1;
155         angle_t angle2;
156
157         angle1 = source->angle;
158         angle2 = R_PointToAngle2(source->x, source->y, target->x, target->y);
159         if(angle2 > angle1)
160         {
161                 diff = angle2-angle1;
162                 if(diff > ANGLE_180)
163                 {
164                         *delta = ANGLE_MAX-diff;
165                         return(0);
166                 }
167                 else
168                 {
169                         *delta = diff;
170                         return(1);
171                 }
172         }
173         else
174         {
175                 diff = angle1-angle2;
176                 if(diff > ANGLE_180)
177                 {
178                         *delta = ANGLE_MAX-diff;
179                         return(1);
180                 }
181                 else
182                 {
183                         *delta = diff;
184                         return(0);
185                 }
186         }
187 }
188
189 //----------------------------------------------------------------------------
190 //
191 // FUNC P_SeekerMissile
192 //
193 // The missile special1 field must be mobj_t *target.  Returns true if
194 // target was tracked, false if not.
195 //
196 //----------------------------------------------------------------------------
197
198 boolean P_SeekerMissile(mobj_t *actor, angle_t thresh, angle_t turnMax)
199 {
200         int dir;
201         int dist;
202         angle_t delta;
203         angle_t angle;
204         mobj_t *target;
205
206         target = (mobj_t *)actor->special1;
207         if(target == NULL)
208         {
209                 return(false);
210         }
211         if(!(target->flags&MF_SHOOTABLE))
212         { // Target died
213                 actor->special1 = 0;
214                 return(false);
215         }
216         dir = P_FaceMobj(actor, target, &delta);
217         if(delta > thresh)
218         {
219                 delta >>= 1;
220                 if(delta > turnMax)
221                 {
222                         delta = turnMax;
223                 }
224         }
225         if(dir)
226         { // Turn clockwise
227                 actor->angle += delta;
228         }
229         else
230         { // Turn counter clockwise
231                 actor->angle -= delta;
232         }
233         angle = actor->angle>>ANGLETOFINESHIFT;
234         actor->momx = FixedMul(actor->info->speed, finecosine[angle]);
235         actor->momy = FixedMul(actor->info->speed, finesine[angle]);
236         if(actor->z+actor->height < target->z ||
237                 target->z+target->height < actor->z)
238         { // Need to seek vertically
239                 dist = P_AproxDistance(target->x-actor->x, target->y-actor->y);
240                 dist = dist/actor->info->speed;
241                 if(dist < 1)
242                 {
243                         dist = 1;
244                 }
245                 actor->momz = (target->z-actor->z)/dist;
246         }
247         return(true);
248 }
249
250 //----------------------------------------------------------------------------
251 //
252 // PROC P_XYMovement
253 //
254 //----------------------------------------------------------------------------
255
256 #define STOPSPEED                       0x1000
257 #define FRICTION_NORMAL         0xe800
258 #define FRICTION_LOW            0xf900
259 #define FRICTION_FLY            0xeb00
260
261 void P_XYMovement(mobj_t *mo)
262 {
263         fixed_t ptryx, ptryy;
264         player_t *player;
265         fixed_t xmove, ymove;
266         int special;
267         static int windTab[3] = {2048*5, 2048*10, 2048*25};
268
269         if(!mo->momx && !mo->momy)
270         {
271                 if(mo->flags&MF_SKULLFLY)
272                 { // A flying mobj slammed into something
273                         mo->flags &= ~MF_SKULLFLY;
274                         mo->momx = mo->momy = mo->momz = 0;
275                         P_SetMobjState(mo, mo->info->seestate);
276                 }
277                 return;
278         }
279         special = mo->subsector->sector->special;
280         if(mo->flags2&MF2_WINDTHRUST)
281         {
282                 switch(special)
283                 {
284                         case 40: case 41: case 42: // Wind_East
285                                 P_ThrustMobj(mo, 0, windTab[special-40]);
286                                 break;
287                         case 43: case 44: case 45: // Wind_North
288                                 P_ThrustMobj(mo, ANG90, windTab[special-43]);
289                                 break;
290                         case 46: case 47: case 48: // Wind_South
291                                 P_ThrustMobj(mo, ANG270, windTab[special-46]);
292                                 break;
293                         case 49: case 50: case 51: // Wind_West
294                                 P_ThrustMobj(mo, ANG180, windTab[special-49]);
295                                 break;
296                 }
297         }
298         player = mo->player;
299         if(mo->momx > MAXMOVE)
300         {
301                 mo->momx = MAXMOVE;
302         }
303         else if(mo->momx < -MAXMOVE)
304         {
305                 mo->momx = -MAXMOVE;
306         }
307         if(mo->momy > MAXMOVE)
308         {
309                 mo->momy = MAXMOVE;
310         }
311         else if(mo->momy < -MAXMOVE)
312         {
313                 mo->momy = -MAXMOVE;
314         }
315         xmove = mo->momx;
316         ymove = mo->momy;
317         do
318         {
319                 if(xmove > MAXMOVE/2 || ymove > MAXMOVE/2)
320                 {
321                         ptryx = mo->x+xmove/2;
322                         ptryy = mo->y+ymove/2;
323                         xmove >>= 1;
324                         ymove >>= 1;
325                 }
326                 else
327                 {
328                         ptryx = mo->x + xmove;
329                         ptryy = mo->y + ymove;
330                         xmove = ymove = 0;
331                 }
332                 if(!P_TryMove(mo, ptryx, ptryy))
333                 { // Blocked move
334                         if(mo->flags2&MF2_SLIDE)
335                         { // Try to slide along it
336                                 P_SlideMove(mo);
337                         }
338                         else if(mo->flags&MF_MISSILE)
339                         { // Explode a missile
340                                 if(ceilingline && ceilingline->backsector
341                                         && ceilingline->backsector->ceilingpic == skyflatnum)
342                                 { // Hack to prevent missiles exploding against the sky
343                                         if(mo->type == MT_BLOODYSKULL)
344                                         {
345                                                 mo->momx = mo->momy = 0;
346                                                 mo->momz = -FRACUNIT;
347                                         }
348                                         else
349                                         {
350                                                 P_RemoveMobj(mo);
351                                         }
352                                         return;
353                                 }
354                                 P_ExplodeMissile(mo);
355                         }
356                         //else if(mo->info->crashstate)
357                         //{
358                         //      mo->momx = mo->momy = 0;
359                         //      P_SetMobjState(mo, mo->info->crashstate);
360                         //      return;
361                         //}
362                         else
363                         {
364                                 mo->momx = mo->momy = 0;
365                         }
366                 }
367         } while(xmove || ymove);
368
369         // Friction
370
371         if(player && player->cheats&CF_NOMOMENTUM)
372         { // Debug option for no sliding at all
373                 mo->momx = mo->momy = 0;
374                 return;
375         }
376         if(mo->flags&(MF_MISSILE|MF_SKULLFLY))
377         { // No friction for missiles
378                 return;
379         }
380         if(mo->z > mo->floorz && !(mo->flags2&MF2_FLY) && !(mo->flags2&MF2_ONMOBJ))
381         { // No friction when falling
382                 return;
383         }
384         if(mo->flags&MF_CORPSE)
385         { // Don't stop sliding if halfway off a step with some momentum
386                 if(mo->momx > FRACUNIT/4 || mo->momx < -FRACUNIT/4
387                         || mo->momy > FRACUNIT/4 || mo->momy < -FRACUNIT/4)
388                 {
389                         if(mo->floorz != mo->subsector->sector->floorheight)
390                         {
391                                 return;
392                         }
393                 }
394         }
395         if(mo->momx > -STOPSPEED && mo->momx < STOPSPEED
396                 && mo->momy > -STOPSPEED && mo->momy < STOPSPEED
397                 && (!player || (player->cmd.forwardmove == 0
398                 && player->cmd.sidemove == 0)))
399         { // If in a walking frame, stop moving
400                 if(player)
401                 {
402                         if(player->chickenTics)
403                         {
404                                 if((unsigned)((player->mo->state-states)
405                                         -S_CHICPLAY_RUN1) < 4)
406                                 {
407                                         P_SetMobjState(player->mo, S_CHICPLAY);
408                                 }
409                         }
410                         else
411                         {
412                                 if((unsigned)((player->mo->state-states)
413                                         -S_PLAY_RUN1) < 4)
414                                 {
415                                         P_SetMobjState(player->mo, S_PLAY);
416                                 }
417                         }
418                 }
419                 mo->momx = 0;
420                 mo->momy = 0;
421         }
422         else
423         {
424                 if(mo->flags2&MF2_FLY && !(mo->z <= mo->floorz)
425                         &&!(mo->flags2&MF2_ONMOBJ))
426                 {
427                         mo->momx = FixedMul(mo->momx, FRICTION_FLY);
428                         mo->momy = FixedMul(mo->momy, FRICTION_FLY);
429                 }
430                 else if(special == 15) // Friction_Low
431                 {
432                         mo->momx = FixedMul(mo->momx, FRICTION_LOW);
433                         mo->momy = FixedMul(mo->momy, FRICTION_LOW);
434                 }
435                 else
436                 {
437                         mo->momx = FixedMul(mo->momx, FRICTION_NORMAL);
438                         mo->momy = FixedMul(mo->momy, FRICTION_NORMAL);
439                 }
440         }
441 }
442
443
444 /*
445 ===============
446 =
447 = P_ZMovement
448 =
449 ===============
450 */
451
452 void P_ZMovement(mobj_t *mo)
453 {
454         int dist;
455         int delta;
456 //
457 // check for smooth step up
458 //
459         if (mo->player && mo->z < mo->floorz)
460         {
461                 mo->player->viewheight -= mo->floorz-mo->z;
462                 mo->player->deltaviewheight = (VIEWHEIGHT - mo->player->viewheight)>>3;
463         }
464 //
465 // adjust height
466 //
467         mo->z += mo->momz;
468         if(mo->flags&MF_FLOAT && mo->target)
469         {       // float down towards target if too close
470                 if(!(mo->flags&MF_SKULLFLY) && !(mo->flags&MF_INFLOAT))
471                 {
472                         dist = P_AproxDistance(mo->x-mo->target->x, mo->y-mo->target->y);
473                         delta =( mo->target->z+(mo->height>>1))-mo->z;
474                         if (delta < 0 && dist < -(delta*3))
475                                 mo->z -= FLOATSPEED;
476                         else if (delta > 0 && dist < (delta*3))
477                                 mo->z += FLOATSPEED;
478                 }
479         }
480         if(mo->player && mo->flags2&MF2_FLY && !(mo->z <= mo->floorz)
481                 && leveltime&2)
482         {
483                 mo->z += finesine[(FINEANGLES/20*leveltime>>2)&FINEMASK];
484         }
485
486 //
487 // clip movement
488 //
489         if(mo->z <= mo->floorz)
490         { // Hit the floor
491                 if(mo->flags&MF_MISSILE)
492                 {
493                         mo->z = mo->floorz;
494                         if(mo->flags2&MF2_FLOORBOUNCE)
495                         {
496                                 P_FloorBounceMissile(mo);
497                                 return;
498                         }
499                         else if(mo->type == MT_MNTRFX2)
500                         { // Minotaur floor fire can go up steps
501                                 return;
502                         }
503                         else
504                         {
505                                 P_ExplodeMissile(mo);
506                                 return;
507                         }
508                 }
509                 if(mo->z-mo->momz > mo->floorz)
510                 { // Spawn splashes, etc.
511                         P_HitFloor(mo);
512                 }
513                 mo->z = mo->floorz;
514                 if(mo->momz < 0)
515                 {
516                         if(mo->player && mo->momz < -GRAVITY*8
517                                 && !(mo->flags2&MF2_FLY))       // squat down
518                         {
519                                 mo->player->deltaviewheight = mo->momz>>3;
520                                 S_StartSound(mo, sfx_plroof);
521 #ifdef __WATCOMC__
522                                 if(!useexterndriver)
523                                 {
524                                         mo->player->centering = true;
525                                 }
526 #else
527                                 mo->player->centering = true;
528 #endif
529                         }
530                         mo->momz = 0;
531                 }
532                 if(mo->flags&MF_SKULLFLY)
533                 { // The skull slammed into something
534                         mo->momz = -mo->momz;
535                 }
536                 if(mo->info->crashstate && (mo->flags&MF_CORPSE))
537                 {
538                         P_SetMobjState(mo, mo->info->crashstate);
539                         return;
540                 }
541         }
542         else if(mo->flags2&MF2_LOGRAV)
543         {
544                 if(mo->momz == 0)
545                         mo->momz = -(GRAVITY>>3)*2;
546                 else
547                         mo->momz -= GRAVITY>>3;
548         }
549         else if (! (mo->flags & MF_NOGRAVITY) )
550         {
551                 if (mo->momz == 0)
552                         mo->momz = -GRAVITY*2;
553                 else
554                         mo->momz -= GRAVITY;
555         }
556
557         if (mo->z + mo->height > mo->ceilingz)
558         {       // hit the ceiling
559                 if (mo->momz > 0)
560                         mo->momz = 0;
561                 mo->z = mo->ceilingz - mo->height;
562                 if (mo->flags & MF_SKULLFLY)
563                 {       // the skull slammed into something
564                         mo->momz = -mo->momz;
565                 }
566                 if (mo->flags & MF_MISSILE)
567                 {
568                         if(mo->subsector->sector->ceilingpic == skyflatnum)
569                         {
570                                 if(mo->type == MT_BLOODYSKULL)
571                                 {
572                                         mo->momx = mo->momy = 0;
573                                         mo->momz = -FRACUNIT;
574                                 }
575                                 else
576                                 {
577                                         P_RemoveMobj(mo);
578                                 }
579                                 return;
580                         }
581                         P_ExplodeMissile(mo);
582                         return;
583                 }
584         }
585 }
586
587
588 /*
589 ================
590 =
591 = P_NightmareRespawn
592 =
593 ================
594 */
595
596 void P_NightmareRespawn (mobj_t *mobj)
597 {
598         fixed_t         x,y,z;
599         subsector_t     *ss;
600         mobj_t                  *mo;
601         mapthing_t              *mthing;
602                 
603         x = mobj->spawnpoint.x << FRACBITS;
604         y = mobj->spawnpoint.y << FRACBITS;
605         
606         if (!P_CheckPosition (mobj, x, y) )
607                 return; // somthing is occupying it's position
608
609
610 // spawn a teleport fog at old spot
611
612         mo = P_SpawnMobj (mobj->x, mobj->y,
613                 mobj->subsector->sector->floorheight+TELEFOGHEIGHT, MT_TFOG);
614         S_StartSound (mo, sfx_telept);
615
616 // spawn a teleport fog at the new spot
617         ss = R_PointInSubsector (x,y);
618         mo = P_SpawnMobj (x, y, ss->sector->floorheight+TELEFOGHEIGHT, MT_TFOG);
619         S_StartSound (mo, sfx_telept);
620
621 // spawn the new monster
622         mthing = &mobj->spawnpoint;
623         
624 // spawn it
625         if (mobj->info->flags & MF_SPAWNCEILING)
626                 z = ONCEILINGZ;
627         else
628                 z = ONFLOORZ;
629         mo = P_SpawnMobj (x,y,z, mobj->type);
630         mo->spawnpoint = mobj->spawnpoint;      
631         mo->angle = ANG45 * (mthing->angle/45);
632         if (mthing->options & MTF_AMBUSH)
633                 mo->flags |= MF_AMBUSH;
634
635         mo->reactiontime = 18;
636         
637 // remove the old monster
638         P_RemoveMobj (mobj);
639 }
640
641 //----------------------------------------------------------------------------
642 //
643 // PROC P_BlasterMobjThinker
644 //
645 // Thinker for the ultra-fast blaster PL2 ripper-spawning missile.
646 //
647 //----------------------------------------------------------------------------
648
649 void P_BlasterMobjThinker(mobj_t *mobj)
650 {
651         int i;
652         fixed_t xfrac;
653         fixed_t yfrac;
654         fixed_t zfrac;
655         fixed_t z;
656         boolean changexy;
657
658         // Handle movement
659         if(mobj->momx || mobj->momy ||
660                 (mobj->z != mobj->floorz) || mobj->momz)
661         {
662                 xfrac = mobj->momx>>3;
663                 yfrac = mobj->momy>>3;
664                 zfrac = mobj->momz>>3;
665                 changexy = xfrac || yfrac;
666                 for(i = 0; i < 8; i++)
667                 {
668                         if(changexy)
669                         {
670                                 if(!P_TryMove(mobj, mobj->x+xfrac, mobj->y+yfrac))
671                                 { // Blocked move
672                                         P_ExplodeMissile(mobj);
673                                         return;
674                                 }
675                         }
676                         mobj->z += zfrac;
677                         if(mobj->z <= mobj->floorz)
678                         { // Hit the floor
679                                 mobj->z = mobj->floorz;
680                                 P_HitFloor(mobj);
681                                 P_ExplodeMissile(mobj);
682                                 return;
683                         }
684                         if(mobj->z+mobj->height > mobj->ceilingz)
685                         { // Hit the ceiling
686                                 mobj->z = mobj->ceilingz-mobj->height;
687                                 P_ExplodeMissile(mobj);
688                                 return;
689                         }
690                         if(changexy && (P_Random() < 64))
691                         {
692                                 z = mobj->z-8*FRACUNIT;
693                                 if(z < mobj->floorz)
694                                 {
695                                         z = mobj->floorz;
696                                 }
697                                 P_SpawnMobj(mobj->x, mobj->y, z, MT_BLASTERSMOKE);
698                         }
699                 }
700         }
701         // Advance the state
702         if(mobj->tics != -1)
703         {
704                 mobj->tics--;
705                 while(!mobj->tics)
706                 {
707                         if(!P_SetMobjState(mobj, mobj->state->nextstate))
708                         { // mobj was removed
709                                 return;
710                         }
711                 }
712         }
713 }
714
715 //----------------------------------------------------------------------------
716 //
717 // PROC P_MobjThinker
718 //
719 //----------------------------------------------------------------------------
720
721 void P_MobjThinker(mobj_t *mobj)
722 {
723         mobj_t *onmo;
724         
725         // Handle X and Y momentums
726         if(mobj->momx || mobj->momy || (mobj->flags&MF_SKULLFLY))
727         {
728                 P_XYMovement(mobj);
729                 if(mobj->thinker.function == (think_t)-1)
730                 { // mobj was removed
731                         return;
732                 }
733         }
734         if(mobj->flags2&MF2_FLOATBOB)
735         { // Floating item bobbing motion
736                 mobj->z = mobj->floorz+FloatBobOffsets[(mobj->health++)&63];
737         }
738         else if((mobj->z != mobj->floorz) || mobj->momz)
739         { // Handle Z momentum and gravity
740                 if(mobj->flags2&MF2_PASSMOBJ)
741                 {
742                         if(!(onmo = P_CheckOnmobj(mobj)))
743                         {
744                                 P_ZMovement(mobj);
745                         }
746                         else
747                         {
748                                 if(mobj->player && mobj->momz < 0)
749                                 {
750                                         mobj->flags2 |= MF2_ONMOBJ;
751                                         mobj->momz = 0;
752                                 }
753                                 if(mobj->player && (onmo->player || onmo->type == MT_POD))
754                                 {
755                                         mobj->momx = onmo->momx;
756                                         mobj->momy = onmo->momy;
757                                         if(onmo->z < onmo->floorz)
758                                         {
759                                                 mobj->z += onmo->floorz-onmo->z;
760                                                 if(onmo->player)
761                                                 {
762                                                         onmo->player->viewheight -= onmo->floorz-onmo->z;
763                                                         onmo->player->deltaviewheight = (VIEWHEIGHT-
764                                                                 onmo->player->viewheight)>>3;
765                                                 }
766                                                 onmo->z = onmo->floorz;
767                                         }
768                                 }
769                         }
770                 }
771                 else
772                 {
773                         P_ZMovement(mobj);
774                 }
775                 if(mobj->thinker.function == (think_t)-1)
776                 { // mobj was removed
777                         return;
778                 }
779         }
780
781 //
782 // cycle through states, calling action functions at transitions
783 //
784         if(mobj->tics != -1)
785         {
786                 mobj->tics--;
787                 // you can cycle through multiple states in a tic
788                 while(!mobj->tics)
789                 {
790                         if(!P_SetMobjState(mobj, mobj->state->nextstate))
791                         { // mobj was removed
792                                 return;
793                         }
794                 }
795         }
796         else
797         { // Check for monster respawn
798                 if(!(mobj->flags&MF_COUNTKILL))
799                 {
800                         return;
801                 }
802                 if(!respawnmonsters)
803                 {
804                         return;
805                 }
806                 mobj->movecount++;
807                 if(mobj->movecount < 12*35)
808                 {
809                         return;
810                 }
811                 if(leveltime&31)
812                 {
813                         return;
814                 }
815                 if(P_Random() > 4)
816                 {
817                         return;
818                 }
819                 P_NightmareRespawn(mobj);
820         }
821 }
822
823 /*
824 ===============
825 =
826 = P_SpawnMobj
827 =
828 ===============
829 */
830
831 mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
832 {
833         mobj_t *mobj;
834         state_t *st;
835         mobjinfo_t *info;
836         fixed_t space;
837
838         mobj = Z_Malloc(sizeof(*mobj), PU_LEVEL, NULL);
839         memset(mobj, 0, sizeof(*mobj));
840         info = &mobjinfo[type];
841         mobj->type = type;
842         mobj->info = info;
843         mobj->x = x;
844         mobj->y = y;
845         mobj->radius = info->radius;
846         mobj->height = info->height;
847         mobj->flags = info->flags;
848         mobj->flags2 = info->flags2;
849         mobj->damage = info->damage;
850         mobj->health = info->spawnhealth;
851         if(gameskill != sk_nightmare)
852         {
853                 mobj->reactiontime = info->reactiontime;
854         }
855         mobj->lastlook = P_Random()%MAXPLAYERS;
856
857         // Set the state, but do not use P_SetMobjState, because action
858         // routines can't be called yet.  If the spawnstate has an action
859         // routine, it will not be called.
860         st = &states[info->spawnstate];
861         mobj->state = st;
862         mobj->tics = st->tics;
863         mobj->sprite = st->sprite;
864         mobj->frame = st->frame;
865
866         // Set subsector and/or block links.
867         P_SetThingPosition(mobj);
868         mobj->floorz = mobj->subsector->sector->floorheight;
869         mobj->ceilingz = mobj->subsector->sector->ceilingheight;
870         if(z == ONFLOORZ)
871         {
872                 mobj->z = mobj->floorz;
873         }
874         else if(z == ONCEILINGZ)
875         {
876                 mobj->z = mobj->ceilingz-mobj->info->height;
877         }
878         else if(z == FLOATRANDZ)
879         {
880                 space = ((mobj->ceilingz)-(mobj->info->height))-mobj->floorz;
881                 if(space > 48*FRACUNIT)
882                 {
883                         space -= 40*FRACUNIT;
884                         mobj->z = ((space*P_Random())>>8)+mobj->floorz+40*FRACUNIT;
885                 }
886                 else
887                 {
888                         mobj->z = mobj->floorz;
889                 }
890         }
891         else
892         {
893                 mobj->z = z;
894         }
895         if(mobj->flags2&MF2_FOOTCLIP && P_GetThingFloorType(mobj) != FLOOR_SOLID
896                 && mobj->floorz == mobj->subsector->sector->floorheight)
897         {
898                 mobj->flags2 |= MF2_FEETARECLIPPED;
899         }
900         else
901         {
902                 mobj->flags2 &= ~MF2_FEETARECLIPPED;
903         }
904
905         mobj->thinker.function = P_MobjThinker;
906         P_AddThinker(&mobj->thinker);
907         return(mobj);
908 }
909
910 /*
911 ===============
912 =
913 = P_RemoveMobj
914 =
915 ===============
916 */
917
918 void P_RemoveMobj(mobj_t *mobj)
919 {
920 // unlink from sector and block lists
921         P_UnsetThingPosition (mobj);
922 // stop any playing sound
923         S_StopSound(mobj);
924 // free block
925         P_RemoveThinker((thinker_t *)mobj);
926 }
927
928 //=============================================================================
929
930
931 /*
932 ============
933 =
934 = P_SpawnPlayer
935 =
936 = Called when a player is spawned on the level 
937 = Most of the player structure stays unchanged between levels
938 ============
939 */
940
941 void P_SpawnPlayer(mapthing_t *mthing)
942 {
943         player_t        *p;
944         fixed_t         x,y,z;
945         mobj_t          *mobj;
946         int                     i;
947         extern int playerkeys;
948
949         if (!playeringame[mthing->type-1])
950                 return;                                         // not playing
951                 
952         p = &players[mthing->type-1];
953
954         if (p->playerstate == PST_REBORN)
955                 G_PlayerReborn (mthing->type-1);
956
957         x = mthing->x << FRACBITS;
958         y = mthing->y << FRACBITS;
959
960         z = ONFLOORZ;
961         mobj = P_SpawnMobj (x,y,z, MT_PLAYER);
962         if (mthing->type > 1)           // set color translations for player sprites
963                 mobj->flags |= (mthing->type-1)<<MF_TRANSSHIFT;
964                 
965         mobj->angle = ANG45 * (mthing->angle/45);
966         mobj->player = p;
967         mobj->health = p->health;
968         p->mo = mobj;
969         p->playerstate = PST_LIVE;      
970         p->refire = 0;
971         p->message = NULL;
972         p->damagecount = 0;
973         p->bonuscount = 0;
974         p->chickenTics = 0;
975         p->rain1 = NULL;
976         p->rain2 = NULL;
977         p->extralight = 0;
978         p->fixedcolormap = 0;
979         p->viewheight = VIEWHEIGHT;
980         P_SetupPsprites(p); // setup gun psprite        
981         if(deathmatch)
982         { // Give all keys in death match mode
983                 for(i = 0; i < NUMKEYS; i++)
984                 {
985                         p->keys[i] = true;
986                         if(p == &players[consoleplayer])
987                         {
988                                 playerkeys = 7;
989                                 UpdateState |= I_STATBAR;
990                         }
991                 }
992         }
993         else if(p == &players[consoleplayer])
994         {
995                 playerkeys = 0;
996                 UpdateState |= I_STATBAR;
997         }               
998 }
999
1000 //----------------------------------------------------------------------------
1001 //
1002 // PROC P_SpawnMapThing
1003 //
1004 // The fields of the mapthing should already be in host byte order.
1005 //
1006 //----------------------------------------------------------------------------
1007
1008 void P_SpawnMapThing(mapthing_t *mthing)
1009 {
1010         int i;
1011         int bit;
1012         mobj_t *mobj;
1013         fixed_t x, y, z;
1014
1015 // count deathmatch start positions
1016         if(mthing->type == 11)
1017         {
1018                 if(deathmatch_p < &deathmatchstarts[10])
1019                 {
1020                         memcpy(deathmatch_p, mthing, sizeof(*mthing));
1021                         deathmatch_p++;
1022                 }
1023                 return;
1024         }
1025         
1026 // check for players specially
1027         if(mthing->type <= 4)
1028         {
1029                 // save spots for respawning in network games
1030                 playerstarts[mthing->type-1] = *mthing;
1031                 if(!deathmatch)
1032                 {
1033                         P_SpawnPlayer(mthing);
1034                 }
1035                 return;
1036         }
1037
1038         // Ambient sound sequences
1039         if(mthing->type >= 1200 && mthing->type < 1300)
1040         {
1041                 P_AddAmbientSfx(mthing->type-1200);
1042                 return;
1043         }
1044
1045         // Check for boss spots
1046         if(mthing->type == 56) // Monster_BossSpot
1047         {
1048                 P_AddBossSpot(mthing->x<<FRACBITS, mthing->y<<FRACBITS,
1049                         ANG45*(mthing->angle/45));
1050                 return;
1051         }
1052
1053 // check for apropriate skill level
1054         if (!netgame && (mthing->options & 16) )
1055                 return;
1056                 
1057         if (gameskill == sk_baby)
1058                 bit = 1;
1059         else if (gameskill == sk_nightmare)
1060                 bit = 4;
1061         else
1062                 bit = 1<<(gameskill-1);
1063         if (!(mthing->options & bit) )
1064                 return;
1065         
1066 // find which type to spawn
1067         for (i=0 ; i< NUMMOBJTYPES ; i++)
1068                 if (mthing->type == mobjinfo[i].doomednum)
1069                         break;
1070         
1071         if (i==NUMMOBJTYPES)
1072                 I_Error ("P_SpawnMapThing: Unknown type %i at (%i, %i)",mthing->type
1073                 , mthing->x, mthing->y);
1074                 
1075 // don't spawn keys and players in deathmatch
1076         if (deathmatch && mobjinfo[i].flags & MF_NOTDMATCH)
1077                 return;
1078                 
1079 // don't spawn any monsters if -nomonsters
1080         if (nomonsters && (mobjinfo[i].flags & MF_COUNTKILL) )
1081                 return;
1082
1083 // spawn it
1084         switch(i)
1085         { // Special stuff
1086                 case MT_WSKULLROD:
1087                 case MT_WPHOENIXROD:
1088                 case MT_AMSKRDWIMPY:
1089                 case MT_AMSKRDHEFTY:
1090                 case MT_AMPHRDWIMPY:
1091                 case MT_AMPHRDHEFTY:
1092                 case MT_AMMACEWIMPY:
1093                 case MT_AMMACEHEFTY:
1094                 case MT_ARTISUPERHEAL:
1095                 case MT_ARTITELEPORT:
1096                 case MT_ITEMSHIELD2:
1097                         if(shareware)
1098                         { // Don't place on map in shareware version
1099                                 return;
1100                         }
1101                         break;
1102                 case MT_WMACE:
1103                         if(!shareware)
1104                         { // Put in the mace spot list
1105                                 P_AddMaceSpot(mthing);
1106                                 return;
1107                         }
1108                         return;
1109                 default:
1110                         break;
1111         }
1112         x = mthing->x<<FRACBITS;
1113         y = mthing->y<<FRACBITS;
1114         if(mobjinfo[i].flags&MF_SPAWNCEILING)
1115         {
1116                 z = ONCEILINGZ;
1117         }
1118         else if(mobjinfo[i].flags2&MF2_SPAWNFLOAT)
1119         {
1120                 z = FLOATRANDZ;
1121         }
1122         else
1123         {
1124                 z = ONFLOORZ;
1125         }
1126         mobj = P_SpawnMobj(x, y, z, i);
1127         if(mobj->flags2&MF2_FLOATBOB)
1128         { // Seed random starting index for bobbing motion
1129                 mobj->health = P_Random();
1130         }
1131         if(mobj->tics > 0)
1132         {
1133                 mobj->tics = 1+(P_Random()%mobj->tics);
1134         }
1135         if(mobj->flags&MF_COUNTKILL)
1136         {
1137                 totalkills++;
1138                 mobj->spawnpoint = *mthing;
1139         }
1140         if(mobj->flags&MF_COUNTITEM)
1141         {
1142                 totalitems++;
1143         }
1144         mobj->angle = ANG45*(mthing->angle/45);
1145         if(mthing->options&MTF_AMBUSH)
1146         {
1147                 mobj->flags |= MF_AMBUSH;
1148         }
1149 }
1150
1151 /*
1152 ===============================================================================
1153
1154                                                 GAME SPAWN FUNCTIONS
1155
1156 ===============================================================================
1157 */
1158
1159 //---------------------------------------------------------------------------
1160 //
1161 // PROC P_SpawnPuff
1162 //
1163 //---------------------------------------------------------------------------
1164
1165 extern fixed_t attackrange;
1166
1167 void P_SpawnPuff(fixed_t x, fixed_t y, fixed_t z)
1168 {
1169         mobj_t *puff;
1170
1171         z += ((P_Random()-P_Random())<<10);
1172         puff = P_SpawnMobj(x, y, z, PuffType);
1173         if(puff->info->attacksound)
1174         {
1175                 S_StartSound(puff, puff->info->attacksound);
1176         }
1177         switch(PuffType)
1178         {
1179                 case MT_BEAKPUFF:
1180                 case MT_STAFFPUFF:
1181                         puff->momz = FRACUNIT;
1182                         break;
1183                 case MT_GAUNTLETPUFF1:
1184                 case MT_GAUNTLETPUFF2:
1185                         puff->momz = .8*FRACUNIT;
1186                 default:
1187                         break;
1188         }
1189 }
1190
1191 /*
1192 ================
1193 =
1194 = P_SpawnBlood
1195 =
1196 ================
1197 */
1198
1199 /*
1200 void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, int damage)
1201 {
1202         mobj_t  *th;
1203         
1204         z += ((P_Random()-P_Random())<<10);
1205         th = P_SpawnMobj (x,y,z, MT_BLOOD);
1206         th->momz = FRACUNIT*2;
1207         th->tics -= P_Random()&3;
1208
1209         if (damage <= 12 && damage >= 9)
1210                 P_SetMobjState (th,S_BLOOD2);
1211         else if (damage < 9)
1212                 P_SetMobjState (th,S_BLOOD3);
1213 }
1214 */
1215
1216 //---------------------------------------------------------------------------
1217 //
1218 // PROC P_BloodSplatter
1219 //
1220 //---------------------------------------------------------------------------
1221
1222 void P_BloodSplatter(fixed_t x, fixed_t y, fixed_t z, mobj_t *originator)
1223 {
1224         mobj_t *mo;
1225
1226         mo = P_SpawnMobj(x, y, z, MT_BLOODSPLATTER);
1227         mo->target = originator;
1228         mo->momx = (P_Random()-P_Random())<<9;
1229         mo->momy = (P_Random()-P_Random())<<9;
1230         mo->momz = FRACUNIT*2;
1231 }
1232
1233 //---------------------------------------------------------------------------
1234 //
1235 // PROC P_RipperBlood
1236 //
1237 //---------------------------------------------------------------------------
1238
1239 void P_RipperBlood(mobj_t *mo)
1240 {
1241         mobj_t *th;
1242         fixed_t x, y, z;
1243
1244         x = mo->x+((P_Random()-P_Random())<<12);
1245         y = mo->y+((P_Random()-P_Random())<<12);
1246         z = mo->z+((P_Random()-P_Random())<<12);
1247         th = P_SpawnMobj(x, y, z, MT_BLOOD);
1248         th->flags |= MF_NOGRAVITY;
1249         th->momx = mo->momx>>1;
1250         th->momy = mo->momy>>1;
1251         th->tics += P_Random()&3;
1252 }
1253
1254 //---------------------------------------------------------------------------
1255 //
1256 // FUNC P_GetThingFloorType
1257 //
1258 //---------------------------------------------------------------------------
1259
1260 int P_GetThingFloorType(mobj_t *thing)
1261 {
1262         return(TerrainTypes[thing->subsector->sector->floorpic]);
1263 /*
1264         if(thing->subsector->sector->floorpic
1265                 == W_GetNumForName("FLTWAWA1")-firstflat)
1266         {
1267                 return(FLOOR_WATER);
1268         }
1269         else
1270         {
1271                 return(FLOOR_SOLID);
1272         }
1273 */
1274 }
1275
1276 //---------------------------------------------------------------------------
1277 //
1278 // FUNC P_HitFloor
1279 //
1280 //---------------------------------------------------------------------------
1281
1282 int P_HitFloor(mobj_t *thing)
1283 {
1284         mobj_t *mo;
1285
1286         if(thing->floorz != thing->subsector->sector->floorheight)
1287         { // don't splash if landing on the edge above water/lava/etc....
1288                 return(FLOOR_SOLID);
1289         }
1290         switch(P_GetThingFloorType(thing))
1291         {
1292                 case FLOOR_WATER:
1293                         P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SPLASHBASE);
1294                         mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SPLASH);
1295                         mo->target = thing;
1296                         mo->momx = (P_Random()-P_Random())<<8;
1297                         mo->momy = (P_Random()-P_Random())<<8;
1298                         mo->momz = 2*FRACUNIT+(P_Random()<<8);
1299                         S_StartSound(mo, sfx_gloop);
1300                         return(FLOOR_WATER);
1301                 case FLOOR_LAVA:
1302                         P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_LAVASPLASH);
1303                         mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_LAVASMOKE);
1304                         mo->momz = FRACUNIT+(P_Random()<<7);
1305                         S_StartSound(mo, sfx_burn);
1306                         return(FLOOR_LAVA);
1307                 case FLOOR_SLUDGE:
1308                         P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SLUDGESPLASH);
1309                         mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SLUDGECHUNK);
1310                         mo->target = thing;
1311                         mo->momx = (P_Random()-P_Random())<<8;
1312                         mo->momy = (P_Random()-P_Random())<<8;
1313                         mo->momz = FRACUNIT+(P_Random()<<8);
1314                         return(FLOOR_SLUDGE);
1315         }
1316         return(FLOOR_SOLID);
1317 }
1318
1319 //---------------------------------------------------------------------------
1320 //
1321 // FUNC P_CheckMissileSpawn
1322 //
1323 // Returns true if the missile is at a valid spawn point, otherwise
1324 // explodes it and returns false.
1325 //
1326 //---------------------------------------------------------------------------
1327
1328 boolean P_CheckMissileSpawn(mobj_t *missile)
1329 {
1330         //missile->tics -= P_Random()&3;
1331
1332         // move a little forward so an angle can be computed if it
1333         // immediately explodes
1334         missile->x += (missile->momx>>1);
1335         missile->y += (missile->momy>>1);
1336         missile->z += (missile->momz>>1);
1337         if(!P_TryMove(missile, missile->x, missile->y))
1338         {
1339                 P_ExplodeMissile(missile);
1340                 return(false);
1341         }
1342         return(true);
1343 }
1344
1345 //---------------------------------------------------------------------------
1346 //
1347 // FUNC P_SpawnMissile
1348 //
1349 // Returns NULL if the missile exploded immediately, otherwise returns
1350 // a mobj_t pointer to the missile.
1351 //
1352 //---------------------------------------------------------------------------
1353
1354 mobj_t *P_SpawnMissile(mobj_t *source, mobj_t *dest, mobjtype_t type)
1355 {
1356         fixed_t z;
1357         mobj_t *th;
1358         angle_t an;
1359         int dist;
1360
1361         switch(type)
1362         {
1363                 case MT_MNTRFX1: // Minotaur swing attack missile
1364                         z = source->z+40*FRACUNIT;
1365                         break;
1366                 case MT_MNTRFX2: // Minotaur floor fire missile
1367                         z = ONFLOORZ;
1368                         break;
1369                 case MT_SRCRFX1: // Sorcerer Demon fireball
1370                         z = source->z+48*FRACUNIT;
1371                         break;
1372                 case MT_KNIGHTAXE: // Knight normal axe
1373                 case MT_REDAXE: // Knight red power axe
1374                         z = source->z+36*FRACUNIT;
1375                         break;
1376                 default:
1377                         z = source->z+32*FRACUNIT;
1378                         break;
1379         }
1380         if(source->flags2&MF2_FEETARECLIPPED)
1381         {
1382                 z -= FOOTCLIPSIZE;
1383         }
1384         th = P_SpawnMobj(source->x, source->y, z, type);
1385         if(th->info->seesound)
1386         {
1387                 S_StartSound(th, th->info->seesound);
1388         }
1389         th->target = source; // Originator
1390         an = R_PointToAngle2(source->x, source->y, dest->x, dest->y);
1391         if(dest->flags&MF_SHADOW)
1392         { // Invisible target
1393                 an += (P_Random()-P_Random())<<21;
1394         }
1395         th->angle = an;
1396         an >>= ANGLETOFINESHIFT;
1397         th->momx = FixedMul(th->info->speed, finecosine[an]);
1398         th->momy = FixedMul(th->info->speed, finesine[an]);
1399         dist = P_AproxDistance(dest->x - source->x, dest->y - source->y);
1400         dist = dist/th->info->speed;
1401         if(dist < 1)
1402         {
1403                 dist = 1;
1404         }
1405         th->momz = (dest->z-source->z)/dist;
1406         return(P_CheckMissileSpawn(th) ? th : NULL);
1407 }
1408
1409 //---------------------------------------------------------------------------
1410 //
1411 // FUNC P_SpawnMissileAngle
1412 //
1413 // Returns NULL if the missile exploded immediately, otherwise returns
1414 // a mobj_t pointer to the missile.
1415 //
1416 //---------------------------------------------------------------------------
1417
1418 mobj_t *P_SpawnMissileAngle(mobj_t *source, mobjtype_t type,
1419         angle_t angle, fixed_t momz)
1420 {
1421         fixed_t z;
1422         mobj_t *mo;
1423
1424         switch(type)
1425         {
1426                 case MT_MNTRFX1: // Minotaur swing attack missile
1427                         z = source->z+40*FRACUNIT;
1428                         break;
1429                 case MT_MNTRFX2: // Minotaur floor fire missile
1430                         z = ONFLOORZ;
1431                         break;
1432                 case MT_SRCRFX1: // Sorcerer Demon fireball
1433                         z = source->z+48*FRACUNIT;
1434                         break;
1435                 default:
1436                         z = source->z+32*FRACUNIT;
1437                         break;
1438         }
1439         if(source->flags2&MF2_FEETARECLIPPED)
1440         {
1441                 z -= FOOTCLIPSIZE;
1442         }
1443         mo = P_SpawnMobj(source->x, source->y, z, type);
1444         if(mo->info->seesound)
1445         {
1446                 S_StartSound(mo, mo->info->seesound);
1447         }
1448         mo->target = source; // Originator
1449         mo->angle = angle;
1450         angle >>= ANGLETOFINESHIFT;
1451         mo->momx = FixedMul(mo->info->speed, finecosine[angle]);
1452         mo->momy = FixedMul(mo->info->speed, finesine[angle]);
1453         mo->momz = momz;
1454         return(P_CheckMissileSpawn(mo) ? mo : NULL);
1455 }
1456
1457 /*
1458 ================
1459 =
1460 = P_SpawnPlayerMissile
1461 =
1462 = Tries to aim at a nearby monster
1463 ================
1464 */
1465
1466 mobj_t *P_SpawnPlayerMissile(mobj_t *source, mobjtype_t type)
1467 {
1468         angle_t an;
1469         fixed_t x, y, z, slope;
1470
1471         // Try to find a target
1472         an = source->angle;
1473         slope = P_AimLineAttack(source, an, 16*64*FRACUNIT);
1474         if(!linetarget)
1475         {
1476                 an += 1<<26;
1477                 slope = P_AimLineAttack(source, an, 16*64*FRACUNIT);
1478                 if(!linetarget)
1479                 {
1480                         an -= 2<<26;
1481                         slope = P_AimLineAttack(source, an, 16*64*FRACUNIT);
1482                 }
1483                 if(!linetarget)
1484                 {
1485                         an = source->angle;
1486                         slope = ((source->player->lookdir)<<FRACBITS)/173;
1487                 }
1488         }
1489         x = source->x;
1490         y = source->y;
1491         z = source->z + 4*8*FRACUNIT+((source->player->lookdir)<<FRACBITS)/173;
1492         if(source->flags2&MF2_FEETARECLIPPED)
1493         {
1494                 z -= FOOTCLIPSIZE;
1495         }
1496         MissileMobj = P_SpawnMobj(x, y, z, type);
1497         if(MissileMobj->info->seesound)
1498         {
1499                 S_StartSound(MissileMobj, MissileMobj->info->seesound);
1500         }
1501         MissileMobj->target = source;
1502         MissileMobj->angle = an;
1503         MissileMobj->momx = FixedMul(MissileMobj->info->speed,
1504                 finecosine[an>>ANGLETOFINESHIFT]);
1505         MissileMobj->momy = FixedMul(MissileMobj->info->speed,
1506                 finesine[an>>ANGLETOFINESHIFT]);
1507         MissileMobj->momz = FixedMul(MissileMobj->info->speed, slope);
1508         if(MissileMobj->type == MT_BLASTERFX1)
1509         { // Ultra-fast ripper spawning missile
1510                 MissileMobj->x += (MissileMobj->momx>>3);
1511                 MissileMobj->y += (MissileMobj->momy>>3);
1512                 MissileMobj->z += (MissileMobj->momz>>3);
1513         }
1514         else
1515         { // Normal missile
1516                 MissileMobj->x += (MissileMobj->momx>>1);
1517                 MissileMobj->y += (MissileMobj->momy>>1);
1518                 MissileMobj->z += (MissileMobj->momz>>1);
1519         }
1520         if(!P_TryMove(MissileMobj, MissileMobj->x, MissileMobj->y))
1521         { // Exploded immediately
1522                 P_ExplodeMissile(MissileMobj);
1523                 return(NULL);
1524         }
1525         return(MissileMobj);
1526 }
1527
1528 //---------------------------------------------------------------------------
1529 //
1530 // PROC P_SPMAngle
1531 //
1532 //---------------------------------------------------------------------------
1533
1534 mobj_t *P_SPMAngle(mobj_t *source, mobjtype_t type, angle_t angle)
1535 {
1536         mobj_t *th;
1537         angle_t an;
1538         fixed_t x, y, z, slope;
1539
1540 //
1541 // see which target is to be aimed at
1542 //
1543         an = angle;
1544         slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
1545         if (!linetarget)
1546         {
1547                 an += 1<<26;
1548                 slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
1549                 if (!linetarget)
1550                 {
1551                         an -= 2<<26;
1552                         slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
1553                 }
1554                 if (!linetarget)
1555                 {
1556                         an = angle;
1557                         slope = ((source->player->lookdir)<<FRACBITS)/173;
1558                 }
1559         }
1560         x = source->x;
1561         y = source->y;
1562         z = source->z + 4*8*FRACUNIT+((source->player->lookdir)<<FRACBITS)/173;
1563         if(source->flags2&MF2_FEETARECLIPPED)
1564         {
1565                 z -= FOOTCLIPSIZE;
1566         }
1567         th = P_SpawnMobj(x, y, z, type);
1568         if(th->info->seesound)
1569         {
1570                 S_StartSound(th, th->info->seesound);
1571         }
1572         th->target = source;
1573         th->angle = an;
1574         th->momx = FixedMul(th->info->speed, finecosine[an>>ANGLETOFINESHIFT]);
1575         th->momy = FixedMul(th->info->speed, finesine[an>>ANGLETOFINESHIFT]);
1576         th->momz = FixedMul(th->info->speed, slope);
1577         return(P_CheckMissileSpawn(th) ? th : NULL);
1578 }
1579
1580 //---------------------------------------------------------------------------
1581 //
1582 // PROC A_ContMobjSound
1583 //
1584 //---------------------------------------------------------------------------
1585
1586 void A_ContMobjSound(mobj_t *actor)
1587 {
1588         switch(actor->type)
1589         {
1590                 case MT_KNIGHTAXE:
1591                         S_StartSound(actor, sfx_kgtatk);
1592                         break;
1593                 case MT_MUMMYFX1:
1594                         S_StartSound(actor, sfx_mumhed);
1595                         break;  
1596                 default:
1597                         break;
1598         }
1599 }