osezer patch 001
[theoddone33/hhexen.git] / base / p_mobj.c
1
2 //**************************************************************************
3 //**
4 //** p_mobj.c : Heretic 2 : Raven Software, Corp.
5 //**
6 //** $RCSfile$
7 //** $Revision$
8 //** $Date$
9 //** $Author$
10 //**
11 //**************************************************************************
12
13 // HEADER FILES ------------------------------------------------------------
14
15 #include "h2def.h"
16 #include "p_local.h"
17 #include "sounds.h"
18 #include "soundst.h"
19
20 // MACROS ------------------------------------------------------------------
21
22 #define MAX_TID_COUNT 200
23
24 // TYPES -------------------------------------------------------------------
25
26 // EXTERNAL FUNCTION PROTOTYPES --------------------------------------------
27
28 void G_PlayerReborn(int player);
29 void P_MarkAsLeaving(mobj_t *corpse);
30
31 // PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
32
33 void P_SpawnMapThing(mapthing_t *mthing);
34
35 // PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
36
37 static void PlayerLandedOnThing(mobj_t *mo, mobj_t *onmobj);
38
39 // EXTERNAL DATA DECLARATIONS ----------------------------------------------
40 extern boolean demorecording;
41 extern boolean demoplayback;
42 extern mobj_t LavaInflictor;
43
44 // PUBLIC DATA DEFINITIONS -------------------------------------------------
45
46 mobjtype_t PuffType;
47 mobj_t *MissileMobj;
48
49 fixed_t FloatBobOffsets[64] =
50 {
51         0, 51389, 102283, 152192,
52         200636, 247147, 291278, 332604,
53         370727, 405280, 435929, 462380,
54         484378, 501712, 514213, 521763,
55         524287, 521763, 514213, 501712,
56         484378, 462380, 435929, 405280,
57         370727, 332604, 291278, 247147,
58         200636, 152192, 102283, 51389,
59         -1, -51390, -102284, -152193,
60         -200637, -247148, -291279, -332605,
61         -370728, -405281, -435930, -462381,
62         -484380, -501713, -514215, -521764,
63         -524288, -521764, -514214, -501713,
64         -484379, -462381, -435930, -405280,
65         -370728, -332605, -291279, -247148,
66         -200637, -152193, -102284, -51389
67 };
68
69 // PRIVATE DATA DEFINITIONS ------------------------------------------------
70
71 static int TIDList[MAX_TID_COUNT+1]; // +1 for termination marker
72 static mobj_t *TIDMobj[MAX_TID_COUNT];
73
74 // CODE --------------------------------------------------------------------
75
76 //==========================================================================
77 //
78 // P_SetMobjState
79 //
80 // Returns true if the mobj is still present.
81 //
82 //==========================================================================
83
84 boolean P_SetMobjState(mobj_t *mobj, statenum_t state)
85 {
86         state_t *st;
87
88         if(state == S_NULL)
89         { // Remove mobj
90                 mobj->state = S_NULL;
91                 P_RemoveMobj(mobj);
92                 return(false);
93         }
94         st = &states[state];
95         mobj->state = st;
96         mobj->tics = st->tics;
97         mobj->sprite = st->sprite;
98         mobj->frame = st->frame;
99         if(st->action)
100         { // Call action function
101                 st->action(mobj);
102         }
103         return(true);
104 }
105
106 //==========================================================================
107 //
108 // P_SetMobjStateNF
109 //
110 // Same as P_SetMobjState, but does not call the state function.
111 //
112 //==========================================================================
113
114 boolean P_SetMobjStateNF(mobj_t *mobj, statenum_t state)
115 {
116         state_t *st;
117
118         if(state == S_NULL)
119         { // Remove mobj
120                 mobj->state = S_NULL;
121                 P_RemoveMobj(mobj);
122                 return(false);
123         }
124         st = &states[state];
125         mobj->state = st;
126         mobj->tics = st->tics;
127         mobj->sprite = st->sprite;
128         mobj->frame = st->frame;
129         return(true);
130 }
131
132 //----------------------------------------------------------------------------
133 //
134 // PROC P_ExplodeMissile
135 //
136 //----------------------------------------------------------------------------
137
138 void P_ExplodeMissile(mobj_t *mo)
139 {
140         mo->momx = mo->momy = mo->momz = 0;
141         P_SetMobjState(mo, mobjinfo[mo->type].deathstate);
142         //mo->tics -= P_Random()&3;
143         mo->flags &= ~MF_MISSILE;
144
145         switch(mo->type)
146         {
147                 case MT_SORCBALL1:
148                 case MT_SORCBALL2:
149                 case MT_SORCBALL3:
150                         S_StartSound(NULL, SFX_SORCERER_BIGBALLEXPLODE);
151                         break;
152                 case MT_SORCFX1:
153                         S_StartSound(NULL, SFX_SORCERER_HEADSCREAM);
154                         break;
155                 default:
156                         if(mo->info->deathsound)
157                         {
158                                 S_StartSound(mo, mo->info->deathsound);
159                         }
160                         break;
161         }
162 }
163
164 //----------------------------------------------------------------------------
165 //
166 // PROC P_FloorBounceMissile
167 //
168 //----------------------------------------------------------------------------
169
170 void P_FloorBounceMissile(mobj_t *mo)
171 {
172         if(P_HitFloor(mo) >= FLOOR_LIQUID)
173         {
174                 switch(mo->type)
175                 {
176                         case MT_SORCFX1:
177                         case MT_SORCBALL1:
178                         case MT_SORCBALL2:
179                         case MT_SORCBALL3:
180                                 break;
181                         default:
182                                 P_RemoveMobj(mo);
183                                 return;
184                 }
185         }
186         switch(mo->type)
187         {
188                 case MT_SORCFX1:
189                         mo->momz = -mo->momz;           // no energy absorbed
190                         break;
191                 case MT_SGSHARD1:
192                 case MT_SGSHARD2:
193                 case MT_SGSHARD3:
194                 case MT_SGSHARD4:
195                 case MT_SGSHARD5:
196                 case MT_SGSHARD6:
197                 case MT_SGSHARD7:
198                 case MT_SGSHARD8:
199                 case MT_SGSHARD9:
200                 case MT_SGSHARD0:
201                         mo->momz = FixedMul(mo->momz, -0.3*FRACUNIT);
202                         if(abs(mo->momz) < (FRACUNIT/2))
203                         {
204                                 P_SetMobjState(mo, S_NULL);
205                                 return;
206                         }
207                         break;
208                 default:
209                         mo->momz = FixedMul(mo->momz, -0.7*FRACUNIT);
210                         break;
211         }
212         mo->momx = 2*mo->momx/3;
213         mo->momy = 2*mo->momy/3;
214         if(mo->info->seesound)
215         {
216                 switch(mo->type)
217                 {
218                         case MT_SORCBALL1:
219                         case MT_SORCBALL2:
220                         case MT_SORCBALL3:
221                                 if (!mo->args[0]) S_StartSound(mo, mo->info->seesound);
222                                 break;
223                         default:
224                                 S_StartSound(mo, mo->info->seesound);
225                                 break;
226                 }
227                 S_StartSound(mo, mo->info->seesound);
228         }
229 //      P_SetMobjState(mo, mobjinfo[mo->type].deathstate);
230 }
231
232 //----------------------------------------------------------------------------
233 //
234 // PROC P_ThrustMobj
235 //
236 //----------------------------------------------------------------------------
237
238 void P_ThrustMobj(mobj_t *mo, angle_t angle, fixed_t move)
239 {
240         angle >>= ANGLETOFINESHIFT;
241         mo->momx += FixedMul(move, finecosine[angle]);
242         mo->momy += FixedMul(move, finesine[angle]);
243 }
244
245 //----------------------------------------------------------------------------
246 //
247 // FUNC P_FaceMobj
248 //
249 // Returns 1 if 'source' needs to turn clockwise, or 0 if 'source' needs
250 // to turn counter clockwise.  'delta' is set to the amount 'source'
251 // needs to turn.
252 //
253 //----------------------------------------------------------------------------
254
255 int P_FaceMobj(mobj_t *source, mobj_t *target, angle_t *delta)
256 {
257         angle_t diff;
258         angle_t angle1;
259         angle_t angle2;
260
261         angle1 = source->angle;
262         angle2 = R_PointToAngle2(source->x, source->y, target->x, target->y);
263         if(angle2 > angle1)
264         {
265                 diff = angle2-angle1;
266                 if(diff > ANGLE_180)
267                 {
268                         *delta = ANGLE_MAX-diff;
269                         return(0);
270                 }
271                 else
272                 {
273                         *delta = diff;
274                         return(1);
275                 }
276         }
277         else
278         {
279                 diff = angle1-angle2;
280                 if(diff > ANGLE_180)
281                 {
282                         *delta = ANGLE_MAX-diff;
283                         return(1);
284                 }
285                 else
286                 {
287                         *delta = diff;
288                         return(0);
289                 }
290         }
291 }
292
293 //----------------------------------------------------------------------------
294 //
295 //
296 // The missile special1 field must be mobj_t *target.  Returns true if
297 // target was tracked, false if not.
298 //
299 //----------------------------------------------------------------------------
300
301 boolean P_SeekerMissile(mobj_t *actor, angle_t thresh, angle_t turnMax)
302 {
303         int dir;
304         int dist;
305         angle_t delta;
306         angle_t angle;
307         mobj_t *target;
308
309         target = (mobj_t *)actor->special1;
310         if(target == NULL)
311         {
312                 return(false);
313         }
314         if(!(target->flags&MF_SHOOTABLE))
315         { // Target died
316                 actor->special1 = 0;
317                 return(false);
318         }
319         dir = P_FaceMobj(actor, target, &delta);
320         if(delta > thresh)
321         {
322                 delta >>= 1;
323                 if(delta > turnMax)
324                 {
325                         delta = turnMax;
326                 }
327         }
328         if(dir)
329         { // Turn clockwise
330                 actor->angle += delta;
331         }
332         else
333         { // Turn counter clockwise
334                 actor->angle -= delta;
335         }
336         angle = actor->angle>>ANGLETOFINESHIFT;
337         actor->momx = FixedMul(actor->info->speed, finecosine[angle]);
338         actor->momy = FixedMul(actor->info->speed, finesine[angle]);
339         if(actor->z+actor->height < target->z 
340                 || target->z+target->height < actor->z)
341         { // Need to seek vertically
342                 dist = P_AproxDistance(target->x-actor->x, target->y-actor->y);
343                 dist = dist/actor->info->speed;
344                 if(dist < 1)
345                 {
346                         dist = 1;
347                 }
348                 actor->momz = (target->z+(target->height>>1)
349                         -(actor->z+(actor->height>>1)))/dist;
350         }
351         return(true);
352 }
353
354 //----------------------------------------------------------------------------
355 //
356 // PROC P_XYMovement
357 //
358 //----------------------------------------------------------------------------
359
360 #define STOPSPEED                       0x1000
361 #define FRICTION_NORMAL         0xe800
362 #define FRICTION_LOW            0xf900
363 #define FRICTION_FLY            0xeb00
364
365 void P_XYMovement(mobj_t *mo)
366 {
367         fixed_t ptryx, ptryy;
368         player_t *player;
369         fixed_t xmove, ymove;
370         int special;
371         angle_t angle;
372         static int windTab[3] = {2048*5, 2048*10, 2048*25};
373
374         if(!mo->momx && !mo->momy)
375         {
376                 if(mo->flags&MF_SKULLFLY)
377                 { // A flying mobj slammed into something
378                         mo->flags &= ~MF_SKULLFLY;
379                         mo->momx = mo->momy = mo->momz = 0;
380                         P_SetMobjState(mo, mo->info->seestate);
381                 }
382                 return;
383         }
384         special = mo->subsector->sector->special;
385         if(mo->flags2&MF2_WINDTHRUST)
386         {
387                 switch(special)
388                 {
389                         case 40: case 41: case 42: // Wind_East
390                                 P_ThrustMobj(mo, 0, windTab[special-40]);
391                                 break;
392                         case 43: case 44: case 45: // Wind_North
393                                 P_ThrustMobj(mo, ANG90, windTab[special-43]);
394                                 break;
395                         case 46: case 47: case 48: // Wind_South
396                                 P_ThrustMobj(mo, ANG270, windTab[special-46]);
397                                 break;
398                         case 49: case 50: case 51: // Wind_West
399                                 P_ThrustMobj(mo, ANG180, windTab[special-49]);
400                                 break;
401                 }
402         }
403         player = mo->player;
404         if(mo->momx > MAXMOVE)
405         {
406                 mo->momx = MAXMOVE;
407         }
408         else if(mo->momx < -MAXMOVE)
409         {
410                 mo->momx = -MAXMOVE;
411         }
412         if(mo->momy > MAXMOVE)
413         {
414                 mo->momy = MAXMOVE;
415         }
416         else if(mo->momy < -MAXMOVE)
417         {
418                 mo->momy = -MAXMOVE;
419         }
420         xmove = mo->momx;
421         ymove = mo->momy;
422         do
423         {
424                 if(xmove > MAXMOVE/2 || ymove > MAXMOVE/2)
425                 {
426                         ptryx = mo->x+xmove/2;
427                         ptryy = mo->y+ymove/2;
428                         xmove >>= 1;
429                         ymove >>= 1;
430                 }
431                 else
432                 {
433                         ptryx = mo->x + xmove;
434                         ptryy = mo->y + ymove;
435                         xmove = ymove = 0;
436                 }
437                 if(!P_TryMove(mo, ptryx, ptryy))
438                 { // Blocked move
439                         if(mo->flags2&MF2_SLIDE)
440                         { // Try to slide along it
441                                 if(BlockingMobj == NULL)
442                                 { // Slide against wall
443                                         P_SlideMove(mo);
444                                 }
445                                 else
446                                 { // Slide against mobj
447                                         //if(P_TryMove(mo, mo->x, mo->y+mo->momy))
448                                         if(P_TryMove(mo, mo->x, ptryy))
449                                         {
450                                                 mo->momx = 0;
451                                         }
452                                         //else if(P_TryMove(mo, mo->x+mo->momx, mo->y))
453                                         else if(P_TryMove(mo, ptryx, mo->y))
454                                         {
455                                                 mo->momy = 0;
456                                         }
457                                         else
458                                         {
459                                                 mo->momx = mo->momy = 0;
460                                         }
461                                 }
462                         }
463                         else if(mo->flags&MF_MISSILE)
464                         { 
465                                 if(mo->flags2&MF2_FLOORBOUNCE)
466                                 {
467                                         if(BlockingMobj)
468                                         {
469                                                 if ((BlockingMobj->flags2&MF2_REFLECTIVE) ||
470                                                         ((!BlockingMobj->player) &&
471                                                         (!(BlockingMobj->flags&MF_COUNTKILL))))
472                                                 {
473                                                         fixed_t speed;
474         
475                                                         angle = R_PointToAngle2(BlockingMobj->x,
476                                                                 BlockingMobj->y, mo->x, mo->y)
477                                                                 +ANGLE_1*((P_Random()%16)-8);
478                                                         speed = P_AproxDistance(mo->momx, mo->momy);
479                                                         speed = FixedMul(speed, 0.75*FRACUNIT);
480                                                         mo->angle = angle;
481                                                         angle >>= ANGLETOFINESHIFT;
482                                                         mo->momx = FixedMul(speed, finecosine[angle]);
483                                                         mo->momy = FixedMul(speed, finesine[angle]);
484                                                         if(mo->info->seesound)
485                                                         {
486                                                                 S_StartSound(mo, mo->info->seesound);
487                                                         }
488                                                         return;
489                                                 }
490                                                 else
491                                                 { // Struck a player/creature
492                                                         P_ExplodeMissile(mo);
493                                                 }
494                                         }
495                                         else
496                                         { // Struck a wall
497                                                 P_BounceWall(mo);
498                                                 switch(mo->type)
499                                                 {
500                                                         case MT_SORCBALL1:
501                                                         case MT_SORCBALL2:
502                                                         case MT_SORCBALL3:
503                                                         case MT_SORCFX1:
504                                                                 break;
505                                                         default:
506                                                                 if(mo->info->seesound)
507                                                                 {
508                                                                         S_StartSound(mo, mo->info->seesound);
509                                                                 }
510                                                                 break;
511                                                 }
512                                                 return;
513                                         }       
514                                 }
515                                 if(BlockingMobj &&
516                                         (BlockingMobj->flags2 & MF2_REFLECTIVE))
517                                 {
518                                         angle = R_PointToAngle2(BlockingMobj->x,
519                                                                                                         BlockingMobj->y,
520                                                                                                         mo->x, mo->y);
521
522                                         // Change angle for delflection/reflection
523                                         switch(BlockingMobj->type)
524                                         {
525                                                 case MT_CENTAUR:
526                                                 case MT_CENTAURLEADER:
527                                                         if ( abs(angle-BlockingMobj->angle)>>24 > 45)
528                                                                 goto explode;
529                                                         if (mo->type == MT_HOLY_FX)
530                                                                 goto explode;
531                                                                 // Drop through to sorcerer full reflection
532                                                 case MT_SORCBOSS:
533                                                         // Deflection
534                                                         if (P_Random()<128)
535                                                                 angle += ANGLE_45;
536                                                         else
537                                                                 angle -= ANGLE_45;
538                                                         break;
539                                                 default:
540                                                         // Reflection
541                                                         angle += ANGLE_1 * ((P_Random()%16)-8);
542                                                         break;
543                                         }
544
545                                         // Reflect the missile along angle
546                                         mo->angle = angle;
547                                         angle >>= ANGLETOFINESHIFT;
548                                         mo->momx = FixedMul(mo->info->speed>>1, finecosine[angle]);
549                                         mo->momy = FixedMul(mo->info->speed>>1, finesine[angle]);
550 //                                      mo->momz = -mo->momz;
551                                         if (mo->flags2 & MF2_SEEKERMISSILE)
552                                         {
553                                                 mo->special1 = (int)(mo->target);
554                                         }
555                                         mo->target = BlockingMobj;
556                                         return;
557                                 }
558 explode:
559                                 // Explode a missile
560                                 if(ceilingline && ceilingline->backsector
561                                         && ceilingline->backsector->ceilingpic == skyflatnum)
562                                 { // Hack to prevent missiles exploding against the sky
563                                         if(mo->type == MT_BLOODYSKULL)
564                                         {
565                                                 mo->momx = mo->momy = 0;
566                                                 mo->momz = -FRACUNIT;
567                                         }
568                                         else if(mo->type == MT_HOLY_FX)
569                                         {
570                                                 P_ExplodeMissile(mo);
571                                         }
572                                         else
573                                         {
574                                                 P_RemoveMobj(mo);
575                                         }
576                                         return;
577                                 }
578                                 P_ExplodeMissile(mo);
579                         }
580                         //else if(mo->info->crashstate)
581                         //{
582                         //      mo->momx = mo->momy = 0;
583                         //      P_SetMobjState(mo, mo->info->crashstate);
584                         //      return;
585                         //}
586                         else
587                         {
588                                 mo->momx = mo->momy = 0;
589                         }
590                 }
591         } while(xmove || ymove);
592
593         // Friction
594
595         if(player && player->cheats&CF_NOMOMENTUM)
596         { // Debug option for no sliding at all
597                 mo->momx = mo->momy = 0;
598                 return;
599         }
600         if(mo->flags&(MF_MISSILE|MF_SKULLFLY))
601         { // No friction for missiles
602                 return;
603         }
604         if(mo->z > mo->floorz && !(mo->flags2&MF2_FLY) && !(mo->flags2&MF2_ONMOBJ))
605         { // No friction when falling
606                 if (mo->type != MT_BLASTEFFECT)
607                 return;
608         }
609         if(mo->flags&MF_CORPSE)
610         { // Don't stop sliding if halfway off a step with some momentum
611                 if(mo->momx > FRACUNIT/4 || mo->momx < -FRACUNIT/4
612                         || mo->momy > FRACUNIT/4 || mo->momy < -FRACUNIT/4)
613                 {
614                         if(mo->floorz != mo->subsector->sector->floorheight)
615                         {
616                                 return;
617                         }
618                 }
619         }
620         if(mo->momx > -STOPSPEED && mo->momx < STOPSPEED
621                 && mo->momy > -STOPSPEED && mo->momy < STOPSPEED
622                 && (!player || (player->cmd.forwardmove == 0
623                 && player->cmd.sidemove == 0)))
624         { // If in a walking frame, stop moving
625                 if(player)
626                 {
627                         if((unsigned)((player->mo->state-states)
628                                 -PStateRun[player->class]) < 4)
629                         {
630                                 P_SetMobjState(player->mo, PStateNormal[player->class]);
631                         }
632                 }
633                 mo->momx = 0;
634                 mo->momy = 0;
635         }
636         else
637         {
638                 if(mo->flags2&MF2_FLY && !(mo->z <= mo->floorz)
639                         &&!(mo->flags2&MF2_ONMOBJ))
640                 {
641                         mo->momx = FixedMul(mo->momx, FRICTION_FLY);
642                         mo->momy = FixedMul(mo->momy, FRICTION_FLY);
643                 }
644                 else if(P_GetThingFloorType(mo) == FLOOR_ICE)
645                 {
646                         mo->momx = FixedMul(mo->momx, FRICTION_LOW);
647                         mo->momy = FixedMul(mo->momy, FRICTION_LOW);
648                 }
649                 else
650                 {
651                         mo->momx = FixedMul(mo->momx, FRICTION_NORMAL);
652                         mo->momy = FixedMul(mo->momy, FRICTION_NORMAL);
653                 }
654         }
655 }
656
657
658 // Move this to p_inter ***
659 void P_MonsterFallingDamage(mobj_t *mo)
660 {
661         int damage;
662         int mom;
663
664         mom = abs(mo->momz);
665         if(mom > 35*FRACUNIT)
666         { // automatic death
667                 damage=10000;
668         }
669         else
670         {
671                 damage = ((mom - (23*FRACUNIT) )*6)>>FRACBITS;
672         }
673         damage=10000;   // always kill 'em
674         P_DamageMobj(mo, NULL, NULL, damage);
675 }
676
677
678
679 /*
680 ===============
681 =
682 = P_ZMovement
683 =
684 ===============
685 */
686
687 void P_ZMovement(mobj_t *mo)
688 {
689         int dist;
690         int delta;
691 //
692 // check for smooth step up
693 //
694         if (mo->player && mo->z < mo->floorz)
695         {
696                 mo->player->viewheight -= mo->floorz-mo->z;
697                 mo->player->deltaviewheight = (VIEWHEIGHT - mo->player->viewheight)>>3;
698         }       
699 //
700 // adjust height
701 //
702         mo->z += mo->momz;
703         if(mo->flags&MF_FLOAT && mo->target)
704         {       // float down towards target if too close
705                 if(!(mo->flags&MF_SKULLFLY) && !(mo->flags&MF_INFLOAT))
706                 {
707                         dist = P_AproxDistance(mo->x-mo->target->x, mo->y-mo->target->y);
708                         delta =( mo->target->z+(mo->height>>1))-mo->z;
709                         if (delta < 0 && dist < -(delta*3))
710                                 mo->z -= FLOATSPEED;
711                         else if (delta > 0 && dist < (delta*3))
712                                 mo->z += FLOATSPEED;                    
713                 }
714         }
715         if(mo->player && mo->flags2&MF2_FLY && !(mo->z <= mo->floorz)
716                 && leveltime&2)
717         {
718                 mo->z += finesine[(FINEANGLES/20*leveltime>>2)&FINEMASK];
719         }
720
721 //
722 // clip movement
723 //
724         if(mo->z <= mo->floorz)
725         {       // Hit the floor
726                 if(mo->flags&MF_MISSILE)
727                 {
728                         mo->z = mo->floorz;
729                         if(mo->flags2&MF2_FLOORBOUNCE)
730                         {
731                                 P_FloorBounceMissile(mo);
732                                 return;
733                         }
734                         else if(mo->type == MT_HOLY_FX)
735                         { // The spirit struck the ground
736                                 mo->momz = 0;
737                                 P_HitFloor(mo);
738                                 return;
739                         }
740                         else if(mo->type == MT_MNTRFX2 || mo->type == MT_LIGHTNING_FLOOR)
741                         { // Minotaur floor fire can go up steps
742                                 return;
743                         }
744                         else
745                         {
746                                 P_HitFloor(mo);
747                                 P_ExplodeMissile(mo);
748                                 return;
749                         }
750                 }
751                 if(mo->flags&MF_COUNTKILL)              // Blasted mobj falling
752                 {
753                         if(mo->momz < -(23*FRACUNIT))
754                         {
755                                 P_MonsterFallingDamage(mo);
756                         }
757                 }
758                 if(mo->z-mo->momz > mo->floorz)
759                 { // Spawn splashes, etc.
760                         P_HitFloor(mo);
761                 }
762                 mo->z = mo->floorz;
763                 if(mo->momz < 0)
764                 {
765                         if(mo->flags2&MF2_ICEDAMAGE && mo->momz < -GRAVITY*8)
766                         {
767                                 mo->tics = 1;
768                                 mo->momx = 0;
769                                 mo->momy = 0;
770                                 mo->momz = 0;
771                                 return;
772                         }       
773                         if(mo->player)
774                         {
775                                 mo->player->jumpTics = 7;// delay any jumping for a short time
776                                 if(mo->momz < -GRAVITY*8 && !(mo->flags2&MF2_FLY))
777                                 { // squat down
778                                         mo->player->deltaviewheight = mo->momz>>3;
779                                         if(mo->momz < -23*FRACUNIT)
780                                         {
781                                                 P_FallingDamage(mo->player);
782                                                 P_NoiseAlert(mo, mo);
783                                         }
784                                         else if(mo->momz < -GRAVITY*12 && !mo->player->morphTics)
785                                         {
786                                                 S_StartSound(mo, SFX_PLAYER_LAND);
787                                                 switch(mo->player->class)
788                                                 {
789                                                         case PCLASS_FIGHTER:
790                                                                 S_StartSound(mo, SFX_PLAYER_FIGHTER_GRUNT);
791                                                                 break;
792                                                         case PCLASS_CLERIC:
793                                                                 S_StartSound(mo, SFX_PLAYER_CLERIC_GRUNT);
794                                                                 break;
795                                                         case PCLASS_MAGE:
796                                                                 S_StartSound(mo, SFX_PLAYER_MAGE_GRUNT);
797                                                                 break;
798                                                         default:
799                                                                 break;
800                                                 }
801                                         }
802                                         else if ((P_GetThingFloorType(mo) < FLOOR_LIQUID) && 
803                                                 (!mo->player->morphTics))
804                                         {
805                                                 S_StartSound(mo, SFX_PLAYER_LAND);
806                                         }
807                                         if(mouselook && !demorecording && !demoplayback) {
808                                                 mo->player->centering = false;
809                                         }
810                                         else {
811                                                 mo->player->centering = true;
812                                         }
813                                 }
814                         }
815                         else if(mo->type >= MT_POTTERY1 
816                                 && mo->type <= MT_POTTERY3)
817                         {
818                                 P_DamageMobj(mo, NULL, NULL, 25);
819                         }
820                         else if(mo->flags&MF_COUNTKILL)
821                         {
822                                 if(mo->momz < -23*FRACUNIT)
823                                 {
824                                         // Doesn't get here
825                                 }
826                         }
827                         mo->momz = 0;
828                 }
829                 if(mo->flags&MF_SKULLFLY)
830                 { // The skull slammed into something
831                         mo->momz = -mo->momz;
832                 }
833                 if(mo->info->crashstate &&
834                         (mo->flags&MF_CORPSE) && 
835                         !(mo->flags2&MF2_ICEDAMAGE))
836                 {
837                         P_SetMobjState(mo, mo->info->crashstate);
838                         return;
839                 }
840         }
841         else if(mo->flags2&MF2_LOGRAV)
842         {
843                 if(mo->momz == 0)
844                         mo->momz = -(GRAVITY>>3)*2;
845                 else
846                         mo->momz -= GRAVITY>>3;
847         }
848         else if (! (mo->flags & MF_NOGRAVITY) )
849         {
850                 if (mo->momz == 0)
851                         mo->momz = -GRAVITY*2;
852                 else
853                         mo->momz -= GRAVITY;
854         }
855         
856         if (mo->z + mo->height > mo->ceilingz)
857         {       // hit the ceiling
858                 if (mo->momz > 0)
859                         mo->momz = 0;
860                 mo->z = mo->ceilingz - mo->height;
861                 if(mo->flags2&MF2_FLOORBOUNCE)
862                 {
863                         // Maybe reverse momentum here for ceiling bounce
864                         // Currently won't happen
865
866                         if(mo->info->seesound)
867                         {
868                                 S_StartSound(mo, mo->info->seesound);
869                         }
870                         return;
871                 }       
872                 if (mo->flags & MF_SKULLFLY)
873                 {       // the skull slammed into something
874                         mo->momz = -mo->momz;
875                 }
876                 if(mo->flags&MF_MISSILE)
877                 {
878                         if(mo->type == MT_LIGHTNING_CEILING)
879                         {
880                                 return;
881                         }
882                         if(mo->subsector->sector->ceilingpic == skyflatnum)
883                         {
884                                 if(mo->type == MT_BLOODYSKULL)
885                                 {
886                                         mo->momx = mo->momy = 0;
887                                         mo->momz = -FRACUNIT;
888                                 }
889                                 else if(mo->type == MT_HOLY_FX)
890                                 {
891                                         P_ExplodeMissile(mo);
892                                 }
893                                 else
894                                 {
895                                         P_RemoveMobj(mo);
896                                 }
897                                 return;
898                         }
899                         P_ExplodeMissile(mo);
900                         return;
901                 }
902         }
903 }
904
905 //----------------------------------------------------------------------------
906 //
907 // PROC P_BlasterMobjThinker
908 //
909 //
910 //----------------------------------------------------------------------------
911
912 void P_BlasterMobjThinker(mobj_t *mobj)
913 {
914         int i;
915         fixed_t xfrac;
916         fixed_t yfrac;
917         fixed_t zfrac;
918         fixed_t z;
919         boolean changexy;
920         mobj_t *mo;
921
922         // Handle movement
923         if(mobj->momx || mobj->momy ||
924                 (mobj->z != mobj->floorz) || mobj->momz)
925         {
926                 xfrac = mobj->momx>>3;
927                 yfrac = mobj->momy>>3;
928                 zfrac = mobj->momz>>3;
929                 changexy = xfrac || yfrac;
930                 for(i = 0; i < 8; i++)
931                 {
932                         if(changexy)
933                         {
934                                 if(!P_TryMove(mobj, mobj->x+xfrac, mobj->y+yfrac))
935                                 { // Blocked move
936                                         P_ExplodeMissile(mobj);
937                                         return;
938                                 }
939                         }
940                         mobj->z += zfrac;
941                         if(mobj->z <= mobj->floorz)
942                         { // Hit the floor
943                                 mobj->z = mobj->floorz;
944                                 P_HitFloor(mobj);
945                                 P_ExplodeMissile(mobj);
946                                 return;
947                         }
948                         if(mobj->z+mobj->height > mobj->ceilingz)
949                         { // Hit the ceiling
950                                 mobj->z = mobj->ceilingz-mobj->height;
951                                 P_ExplodeMissile(mobj);
952                                 return;
953                         }
954                         if(changexy)
955                         {
956                                 if(mobj->type == MT_MWAND_MISSILE && (P_Random() < 128))
957                                 {
958                                         z = mobj->z-8*FRACUNIT;
959                                         if(z < mobj->floorz)
960                                         {
961                                                 z = mobj->floorz;
962                                         }
963                                         P_SpawnMobj(mobj->x, mobj->y, z, MT_MWANDSMOKE);
964                                 }
965                                 /*
966                                 else if(!--mobj->special1)
967
968                                 jim allow other things to have BlasterMobjThinker()s (crossbow)
969
970                                 O.S: I don't need an #ifdef ASSASSIN here, I think..
971                                 */
972                                 else if((mobj->type == MT_CFLAME_MISSILE) && !--mobj->special1)
973                                 {
974                                         mobj->special1 = 4;
975                                         z = mobj->z-12*FRACUNIT;
976                                         if(z < mobj->floorz)
977                                         {
978                                                 z = mobj->floorz;
979                                         }
980                                         mo = P_SpawnMobj(mobj->x, mobj->y, z, MT_CFLAMEFLOOR);
981                                         if(mo)
982                                         {
983                                                 mo->angle = mobj->angle;
984                                         }
985                                 }
986                         }
987                 }
988         }
989         // Advance the state
990         if(mobj->tics != -1)
991         {
992                 mobj->tics--;
993                 while(!mobj->tics)
994                 {
995                         if(!P_SetMobjState(mobj, mobj->state->nextstate))
996                         { // mobj was removed
997                                 return;
998                         }
999                 }
1000         }
1001 }
1002
1003 //===========================================================================
1004 //
1005 // PlayerLandedOnThing
1006 //
1007 //===========================================================================
1008
1009 static void PlayerLandedOnThing(mobj_t *mo, mobj_t *onmobj)
1010 {
1011         mo->player->deltaviewheight = mo->momz>>3;
1012         if(mo->momz < -23*FRACUNIT)
1013         {
1014                 P_FallingDamage(mo->player);
1015                 P_NoiseAlert(mo, mo);
1016         }
1017         else if(mo->momz < -GRAVITY*12 
1018                 && !mo->player->morphTics)
1019         {
1020                 S_StartSound(mo, SFX_PLAYER_LAND);
1021                 switch(mo->player->class)
1022                 {
1023                         case PCLASS_FIGHTER:
1024                                 S_StartSound(mo, SFX_PLAYER_FIGHTER_GRUNT);
1025                                 break;
1026                         case PCLASS_CLERIC:
1027                                 S_StartSound(mo, SFX_PLAYER_CLERIC_GRUNT);
1028                                 break;
1029                         case PCLASS_MAGE:
1030                                 S_StartSound(mo, SFX_PLAYER_MAGE_GRUNT);
1031                                 break;
1032                         default:
1033                                 break;
1034                 }
1035         }
1036         else if(!mo->player->morphTics)
1037         {
1038                 S_StartSound(mo, SFX_PLAYER_LAND);
1039         }
1040         if(mouselook && !demorecording && !demoplayback) {
1041                 mo->player->centering = false;
1042         }
1043         else { mo->player->centering = true;
1044         }
1045 }
1046
1047 //----------------------------------------------------------------------------
1048 //
1049 // PROC P_MobjThinker
1050 //
1051 //----------------------------------------------------------------------------
1052
1053 void P_MobjThinker(mobj_t *mobj)
1054 {
1055         mobj_t *onmo;
1056 /*
1057         // Reset to not blasted when momentums are gone
1058         if((mobj->flags2&MF2_BLASTED) && (!(mobj->momx)) && (!(mobj->momy)))
1059                 ResetBlasted(mobj);
1060 */
1061         // Handle X and Y momentums
1062         BlockingMobj = NULL;
1063         if(mobj->momx || mobj->momy || (mobj->flags&MF_SKULLFLY))
1064         {
1065                 P_XYMovement(mobj);
1066                 if(mobj->thinker.function == (think_t)-1)
1067                 { // mobj was removed
1068                         return;
1069                 }
1070         }
1071         else if(mobj->flags2&MF2_BLASTED)
1072         { // Reset to not blasted when momentums are gone
1073                 ResetBlasted(mobj);
1074         }
1075         if(mobj->flags2&MF2_FLOATBOB)
1076         { // Floating item bobbing motion (special1 is height)
1077                 mobj->z = mobj->floorz +
1078                                         mobj->special1 +
1079                                         FloatBobOffsets[(mobj->health++)&63];
1080         }
1081         else if((mobj->z != mobj->floorz) || mobj->momz || BlockingMobj)
1082         {       // Handle Z momentum and gravity
1083                 if(mobj->flags2&MF2_PASSMOBJ)
1084                 {
1085                         if(!(onmo = P_CheckOnmobj(mobj)))
1086                         {
1087                                 P_ZMovement(mobj);
1088                                 if(mobj->player && mobj->flags&MF2_ONMOBJ)
1089                                 {
1090                                         mobj->flags2 &= ~MF2_ONMOBJ;
1091                                 }
1092                         }
1093                         else
1094                         {
1095                                 if(mobj->player)
1096                                 {
1097                                         if(mobj->momz < -GRAVITY*8 && !(mobj->flags2&MF2_FLY))
1098                                         {
1099                                                 PlayerLandedOnThing(mobj, onmo);
1100                                         }
1101                                         if(onmo->z+onmo->height-mobj->z <= 24*FRACUNIT)
1102                                         {
1103                                                 mobj->player->viewheight -= onmo->z+onmo->height
1104                                                         -mobj->z;
1105                                                 mobj->player->deltaviewheight = 
1106                                                         (VIEWHEIGHT-mobj->player->viewheight)>>3;
1107                                                 mobj->z = onmo->z+onmo->height;
1108                                                 mobj->flags2 |= MF2_ONMOBJ;
1109                                                 mobj->momz = 0;
1110                                         }                               
1111                                         else
1112                                         { // hit the bottom of the blocking mobj
1113                                                 mobj->momz = 0;
1114                                         }
1115                                 }
1116 /* Landing on another player, and mimicking his movements
1117                                 if(mobj->player && onmo->player)
1118                                 {
1119                                         mobj->momx = onmo->momx;
1120                                         mobj->momy = onmo->momy;
1121                                         if(onmo->z < onmo->floorz)
1122                                         {
1123                                                 mobj->z += onmo->floorz-onmo->z;
1124                                                 if(onmo->player)
1125                                                 {
1126                                                         onmo->player->viewheight -= onmo->floorz-onmo->z;
1127                                                         onmo->player->deltaviewheight = (VIEWHEIGHT-
1128                                                                 onmo->player->viewheight)>>3;
1129                                                 }
1130                                                 onmo->z = onmo->floorz;
1131                                         }
1132                                 }
1133 */
1134                         }
1135                 }
1136                 else
1137                 {
1138                         P_ZMovement(mobj);
1139                 }
1140                 if(mobj->thinker.function == (think_t)-1)
1141                 { // mobj was removed
1142                         return;
1143                 }
1144         }
1145
1146         // Cycle through states, calling action functions at transitions
1147         if(mobj->tics != -1)
1148         {
1149                 mobj->tics--;
1150                 // you can cycle through multiple states in a tic
1151                 while(!mobj->tics)
1152                 {
1153                         if(!P_SetMobjState(mobj, mobj->state->nextstate))
1154                         { // mobj was removed
1155                                 return;
1156                         }
1157                 }
1158         }
1159 }
1160
1161 //==========================================================================
1162 //
1163 // P_SpawnMobj
1164 //
1165 //==========================================================================
1166
1167 mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
1168 {
1169         mobj_t *mobj;
1170         state_t *st;
1171         mobjinfo_t *info;
1172         fixed_t space;
1173
1174         mobj = Z_Malloc(sizeof(*mobj), PU_LEVEL, NULL);
1175         memset(mobj, 0, sizeof(*mobj));
1176         info = &mobjinfo[type];
1177         mobj->type = type;
1178         mobj->info = info;
1179         mobj->x = x;
1180         mobj->y = y;
1181         mobj->radius = info->radius;
1182         mobj->height = info->height;
1183         mobj->flags = info->flags;
1184         mobj->flags2 = info->flags2;
1185         mobj->damage = info->damage;
1186         mobj->health = info->spawnhealth;
1187         if(gameskill != sk_nightmare)
1188         {
1189                 mobj->reactiontime = info->reactiontime;
1190         }
1191         mobj->lastlook = P_Random()%MAXPLAYERS;
1192
1193         // Set the state, but do not use P_SetMobjState, because action
1194         // routines can't be called yet.  If the spawnstate has an action
1195         // routine, it will not be called.
1196         st = &states[info->spawnstate];
1197         mobj->state = st;
1198         mobj->tics = st->tics;
1199         mobj->sprite = st->sprite;
1200         mobj->frame = st->frame;
1201
1202         // Set subsector and/or block links.
1203         P_SetThingPosition(mobj);
1204         mobj->floorz = mobj->subsector->sector->floorheight;
1205         mobj->ceilingz = mobj->subsector->sector->ceilingheight;
1206         if(z == ONFLOORZ)
1207         {
1208                 mobj->z = mobj->floorz;
1209         }
1210         else if(z == ONCEILINGZ)
1211         {
1212                 mobj->z = mobj->ceilingz-mobj->info->height;
1213         }       
1214         else if(z == FLOATRANDZ)
1215         {
1216                 space = ((mobj->ceilingz)-(mobj->info->height))-mobj->floorz;
1217                 if(space > 48*FRACUNIT)
1218                 {
1219                         space -= 40*FRACUNIT;
1220                         mobj->z = ((space*P_Random())>>8)+mobj->floorz+40*FRACUNIT;
1221                 }
1222                 else
1223                 {
1224                         mobj->z = mobj->floorz;
1225                 }
1226         }
1227         else if (mobj->flags2&MF2_FLOATBOB)
1228         {
1229                 mobj->z = mobj->floorz + z;             // artifact z passed in as height
1230         }
1231         else
1232         {
1233                 mobj->z = z;
1234         }
1235         if(mobj->flags2&MF2_FLOORCLIP && P_GetThingFloorType(mobj) >= FLOOR_LIQUID
1236                 && mobj->z == mobj->subsector->sector->floorheight)
1237         {
1238                 mobj->floorclip = 10*FRACUNIT;
1239         }
1240         else
1241         {
1242                 mobj->floorclip = 0;
1243         }
1244
1245         mobj->thinker.function = P_MobjThinker;
1246         P_AddThinker(&mobj->thinker);
1247         return(mobj);
1248 }
1249
1250 //==========================================================================
1251 //
1252 // P_RemoveMobj
1253 //
1254 //==========================================================================
1255
1256 void P_RemoveMobj(mobj_t *mobj)
1257 {
1258         // Remove from creature queue
1259         if(mobj->flags&MF_COUNTKILL &&
1260                 mobj->flags&MF_CORPSE)
1261         {
1262                 A_DeQueueCorpse(mobj);
1263         }
1264
1265         if(mobj->tid)
1266         { // Remove from TID list
1267                 P_RemoveMobjFromTIDList(mobj);
1268         }
1269
1270         // Unlink from sector and block lists
1271         P_UnsetThingPosition(mobj);
1272
1273         // Stop any playing sound
1274         S_StopSound(mobj);
1275
1276         // Free block
1277         P_RemoveThinker((thinker_t *)mobj);
1278 }
1279
1280 //==========================================================================
1281 //
1282 // P_SpawnPlayer
1283 //
1284 // Called when a player is spawned on the level.  Most of the player
1285 // structure stays unchanged between levels.
1286 //
1287 //==========================================================================
1288
1289 void P_SpawnPlayer(mapthing_t *mthing)
1290 {
1291         player_t *p;
1292         fixed_t x, y, z;
1293         mobj_t *mobj;
1294
1295         if(!playeringame[mthing->type-1])
1296         { // Not playing
1297                 return;
1298         }
1299         p = &players[mthing->type-1];
1300         if(p->playerstate == PST_REBORN)
1301         {
1302                 G_PlayerReborn(mthing->type-1);
1303         }
1304         x = mthing->x << FRACBITS;
1305         y = mthing->y << FRACBITS;
1306         z = ONFLOORZ;
1307         if(randomclass && deathmatch)
1308         {
1309                 p->class = P_Random()%3;
1310                 if(p->class == PlayerClass[mthing->type-1])
1311                 {
1312                         p->class = (p->class+1)%3;
1313                 }
1314                 PlayerClass[mthing->type-1] = p->class;
1315                 SB_SetClassData();
1316         }
1317         else
1318         {
1319                 p->class = PlayerClass[mthing->type-1];
1320         }
1321         switch(p->class)
1322         {
1323                 case PCLASS_FIGHTER:
1324                         mobj = P_SpawnMobj(x, y, z, MT_PLAYER_FIGHTER);
1325                         break;
1326                 case PCLASS_CLERIC:
1327                         mobj = P_SpawnMobj(x, y, z, MT_PLAYER_CLERIC);
1328                         break;
1329                 case PCLASS_MAGE:
1330                         mobj = P_SpawnMobj(x, y, z, MT_PLAYER_MAGE);
1331                         break;
1332 #ifdef ASSASSIN
1333                 case PCLASS_ASS:
1334                         mobj = P_SpawnMobj(x, y, z, MT_PLAYER_ASS);
1335                         break;
1336 #endif
1337                 default:
1338                         I_Error("P_SpawnPlayer: Unknown class type");
1339                         /* jim never happens but keeps gcc happy */
1340                         mobj = NULL;
1341                         break;
1342         }
1343
1344         // Set translation table data
1345         if(p->class == PCLASS_FIGHTER && (mthing->type == 1 || mthing->type == 3))
1346         { 
1347                 // The first type should be blue, and the third should be the
1348                 // Fighter's original gold color
1349                 if(mthing->type == 1)
1350                 {
1351                         mobj->flags |= 2<<MF_TRANSSHIFT;
1352                 }
1353         }
1354         else if(mthing->type > 1)
1355         { // Set color translation bits for player sprites
1356                 mobj->flags |= (mthing->type-1)<<MF_TRANSSHIFT;
1357         }
1358
1359         mobj->angle = ANG45 * (mthing->angle/45);
1360         mobj->player = p;
1361         mobj->health = p->health;
1362         p->mo = mobj;
1363         p->playerstate = PST_LIVE;
1364         p->refire = 0;
1365         P_ClearMessage(p);
1366         p->damagecount = 0;
1367         p->bonuscount = 0;
1368         p->poisoncount = 0;
1369         p->morphTics = 0;
1370         p->extralight = 0;
1371         p->fixedcolormap = 0;
1372         p->viewheight = VIEWHEIGHT;
1373         P_SetupPsprites(p);
1374         if(deathmatch)
1375         { // Give all keys in death match mode
1376                 p->keys = 2047;
1377         }
1378 }
1379
1380 //==========================================================================
1381 //
1382 // P_SpawnMapThing
1383 //
1384 // The fields of the mapthing should already be in host byte order.
1385 //
1386 //==========================================================================
1387
1388 void P_SpawnMapThing(mapthing_t *mthing)
1389 {
1390         int i;
1391         unsigned int spawnMask;
1392         mobj_t *mobj;
1393         fixed_t x, y, z;
1394         // Put in Cleric twice, since we can't have an assassin flag.
1395         static unsigned int classFlags[] =
1396         {
1397                 MTF_FIGHTER,
1398                 MTF_CLERIC,
1399                 MTF_MAGE,
1400 #ifdef ASSASSIN
1401                 MTF_CLERIC
1402 #endif
1403         };
1404
1405         // Count deathmatch start positions
1406         if(mthing->type == 11)
1407         {
1408                 if(deathmatch_p < &deathmatchstarts[MAXDEATHMATCHSTARTS])
1409                 {
1410                         memcpy(deathmatch_p, mthing, sizeof(*mthing));
1411                         deathmatch_p++;
1412                 }
1413                 return;
1414         }
1415         if(mthing->type == PO_ANCHOR_TYPE)
1416         { // Polyobj Anchor Pt.
1417                 return;
1418         }
1419         else if(mthing->type == PO_SPAWN_TYPE
1420                 || mthing->type == PO_SPAWNCRUSH_TYPE)
1421         { // Polyobj Anchor Pt.
1422                 po_NumPolyobjs++;
1423                 return;
1424         }
1425
1426         // Check for player starts 1 to 4
1427         if(mthing->type <= 4)
1428         {
1429                 playerstarts[mthing->arg1][mthing->type-1] = *mthing;
1430                 if(!deathmatch && !mthing->arg1)
1431                 {
1432                         P_SpawnPlayer(mthing);
1433                 }
1434                 return;
1435         }
1436         // Check for player starts 5 to 8
1437         if(mthing->type >= 9100 && mthing->type <= 9103)
1438         {
1439                 mthing->type = 5+mthing->type-9100; // Translate to 5 - 8
1440                 playerstarts[mthing->arg1][mthing->type-1] = *mthing;
1441                 if(!deathmatch && !mthing->arg1)
1442                 {
1443                         P_SpawnPlayer(mthing);
1444                 }
1445                 return;
1446         }
1447
1448         if(mthing->type >= 1400 && mthing->type < 1410)
1449         {
1450                 R_PointInSubsector(mthing->x<<FRACBITS, 
1451                         mthing->y<<FRACBITS)->sector->seqType = mthing->type-1400;
1452                 return;
1453         }
1454
1455         // Check current game type with spawn flags
1456         if(netgame == false)
1457         {
1458                 spawnMask = MTF_GSINGLE;
1459         }
1460         else if(deathmatch)
1461         {
1462                 spawnMask = MTF_GDEATHMATCH;
1463         }
1464         else
1465         {
1466                 spawnMask = MTF_GCOOP;
1467         }
1468         if(!(mthing->options&spawnMask))
1469         {
1470                 return;
1471         }
1472
1473         // Check current skill with spawn flags
1474         if(gameskill == sk_baby || gameskill == sk_easy)
1475         {
1476                 spawnMask = MTF_EASY;
1477         }
1478         else if(gameskill == sk_hard || gameskill == sk_nightmare)
1479         {
1480                 spawnMask = MTF_HARD;
1481         }
1482         else
1483         {
1484                 spawnMask = MTF_NORMAL;
1485         }
1486         if(!(mthing->options&spawnMask))
1487         {
1488                 return;
1489         }
1490
1491         // Check current character classes with spawn flags
1492         if(netgame == false)
1493         { // Single player
1494                 if((mthing->options&classFlags[PlayerClass[0]]) == 0)
1495                 { // Not for current class
1496                         return;
1497                 }
1498         }
1499         else if(deathmatch == false)
1500         { // Cooperative
1501                 spawnMask = 0;
1502                 for(i = 0; i < MAXPLAYERS; i++)
1503                 {
1504                         if(playeringame[i])
1505                         {
1506                                 spawnMask |= classFlags[PlayerClass[i]];
1507                         }
1508                 }
1509                 if((mthing->options&spawnMask) == 0)
1510                 {
1511                         return;
1512                 }
1513         }
1514
1515         // Find which type to spawn
1516         for(i = 0; i < NUMMOBJTYPES; i++)
1517         {
1518                 if(mthing->type == mobjinfo[i].doomednum)
1519                 {
1520                         break;
1521                 }
1522         }
1523         
1524         if(i == NUMMOBJTYPES)
1525         { // Can't find thing type
1526                 I_Error("P_SpawnMapThing: Unknown type %i at (%i, %i)",
1527                         mthing->type, mthing->x, mthing->y);
1528         }
1529
1530         // Don't spawn keys and players in deathmatch
1531         if(deathmatch && mobjinfo[i].flags&MF_NOTDMATCH)
1532         {
1533                 return;
1534         }
1535                 
1536         // Don't spawn monsters if -nomonsters
1537         if(nomonsters && (mobjinfo[i].flags&MF_COUNTKILL))
1538         {
1539                 return;
1540         }
1541
1542         x = mthing->x<<FRACBITS;
1543         y = mthing->y<<FRACBITS;
1544         if(mobjinfo[i].flags&MF_SPAWNCEILING)
1545         {
1546                 z = ONCEILINGZ;
1547         }
1548         else if(mobjinfo[i].flags2&MF2_SPAWNFLOAT)
1549         {
1550                 z = FLOATRANDZ;
1551         }
1552         else if(mobjinfo[i].flags2&MF2_FLOATBOB)
1553         {
1554                 z = mthing->height<<FRACBITS;
1555         }
1556         else
1557         {
1558                 z = ONFLOORZ;
1559         }
1560         switch(i)
1561         { // Special stuff
1562                 case MT_ZLYNCHED_NOHEART:
1563                         P_SpawnMobj(x, y, ONFLOORZ, MT_BLOODPOOL);
1564                         break;
1565                 default:
1566                         break;
1567         }
1568         mobj = P_SpawnMobj(x, y, z, i);
1569         if(z == ONFLOORZ)
1570         {
1571                 mobj->z += mthing->height<<FRACBITS;
1572         }
1573         else if(z == ONCEILINGZ)
1574         {
1575                 mobj->z -= mthing->height<<FRACBITS;
1576         }
1577         mobj->tid = mthing->tid;
1578         mobj->special = mthing->special;
1579         mobj->args[0] = mthing->arg1;
1580         mobj->args[1] = mthing->arg2;
1581         mobj->args[2] = mthing->arg3;
1582         mobj->args[3] = mthing->arg4;
1583         mobj->args[4] = mthing->arg5;
1584         if(mobj->flags2&MF2_FLOATBOB)
1585         { // Seed random starting index for bobbing motion
1586                 mobj->health = P_Random();
1587                 mobj->special1 = mthing->height<<FRACBITS;
1588         }
1589         if(mobj->tics > 0)
1590         {
1591                 mobj->tics = 1+(P_Random()%mobj->tics);
1592         }
1593 //      if(mobj->flags&MF_COUNTITEM)
1594 //      {
1595 //              totalitems++;
1596 //      }
1597         if (mobj->flags&MF_COUNTKILL)
1598         {
1599                 // Quantize angle to 45 degree increments
1600                 mobj->angle = ANG45*(mthing->angle/45);
1601         }
1602         else
1603         {
1604                 // Scale angle correctly (source is 0..359)
1605                 mobj->angle = ((mthing->angle<<8)/360)<<24;
1606         }
1607         if(mthing->options&MTF_AMBUSH)
1608         {
1609                 mobj->flags |= MF_AMBUSH;
1610         }
1611         if(mthing->options&MTF_DORMANT)
1612         {
1613                 mobj->flags2 |= MF2_DORMANT;
1614                 if(mobj->type == MT_ICEGUY)
1615                 {
1616                         P_SetMobjState(mobj, S_ICEGUY_DORMANT);
1617                 }
1618                 mobj->tics = -1;
1619         }
1620 }
1621
1622 //==========================================================================
1623 //
1624 // P_CreateTIDList
1625 //
1626 //==========================================================================
1627
1628 void P_CreateTIDList(void)
1629 {
1630         int i;
1631         mobj_t *mobj;
1632         thinker_t *t;
1633
1634         i = 0;
1635         for(t = thinkercap.next; t != &thinkercap; t = t->next)
1636         { // Search all current thinkers
1637                 if(t->function != P_MobjThinker)
1638                 { // Not a mobj thinker
1639                         continue;
1640                 }
1641                 mobj = (mobj_t *)t;
1642                 if(mobj->tid != 0)
1643                 { // Add to list
1644                         if(i == MAX_TID_COUNT)
1645                         {
1646                                 I_Error("P_CreateTIDList: MAX_TID_COUNT (%d) exceeded.",
1647                                         MAX_TID_COUNT);
1648                         }
1649                         TIDList[i] = mobj->tid;
1650                         TIDMobj[i++] = mobj;
1651                 }
1652         }
1653         // Add termination marker
1654         TIDList[i] = 0;
1655 }
1656
1657 //==========================================================================
1658 //
1659 // P_InsertMobjIntoTIDList
1660 //
1661 //==========================================================================
1662
1663 void P_InsertMobjIntoTIDList(mobj_t *mobj, int tid)
1664 {
1665         int i;
1666         int index;
1667
1668         index = -1;
1669         for(i = 0; TIDList[i] != 0; i++)
1670         {
1671                 if(TIDList[i] == -1)
1672                 { // Found empty slot
1673                         index = i;
1674                         break;
1675                 }
1676         }
1677         if(index == -1)
1678         { // Append required
1679                 if(i == MAX_TID_COUNT)
1680                 {
1681                         I_Error("P_InsertMobjIntoTIDList: MAX_TID_COUNT (%d)"
1682                                 "exceeded.", MAX_TID_COUNT);
1683                 }
1684                 index = i;
1685                 TIDList[index+1] = 0;
1686         }
1687         mobj->tid = tid;
1688         TIDList[index] = tid;
1689         TIDMobj[index] = mobj;
1690 }
1691
1692 //==========================================================================
1693 //
1694 // P_RemoveMobjFromTIDList
1695 //
1696 //==========================================================================
1697
1698 void P_RemoveMobjFromTIDList(mobj_t *mobj)
1699 {
1700         int i;
1701
1702         for(i = 0; TIDList[i] != 0; i++)
1703         {
1704                 if(TIDMobj[i] == mobj)
1705                 {
1706                         TIDList[i] = -1;
1707                         TIDMobj[i] = NULL;
1708                         mobj->tid = 0;
1709                         return;
1710                 }
1711         }
1712         mobj->tid = 0;
1713 }
1714
1715 //==========================================================================
1716 //
1717 // P_FindMobjFromTID
1718 //
1719 //==========================================================================
1720
1721 mobj_t *P_FindMobjFromTID(int tid, int *searchPosition)
1722 {
1723         int i;
1724
1725         for(i = *searchPosition+1; TIDList[i] != 0; i++)
1726         {
1727                 if(TIDList[i] == tid)
1728                 {
1729                         *searchPosition = i;
1730                         return TIDMobj[i];
1731                 }
1732         }
1733         *searchPosition = -1;
1734         return NULL;
1735 }
1736
1737 /*
1738 ===============================================================================
1739
1740                                                 GAME SPAWN FUNCTIONS
1741
1742 ===============================================================================
1743 */
1744
1745 //---------------------------------------------------------------------------
1746 //
1747 // PROC P_SpawnPuff
1748 //
1749 //---------------------------------------------------------------------------
1750
1751 extern fixed_t attackrange;
1752
1753 void P_SpawnPuff(fixed_t x, fixed_t y, fixed_t z)
1754 {
1755         mobj_t *puff;
1756
1757         z += ((P_Random()-P_Random())<<10);
1758         puff = P_SpawnMobj(x, y, z, PuffType);
1759         if(linetarget && puff->info->seesound)
1760         { // Hit thing sound
1761                 S_StartSound(puff, puff->info->seesound);
1762         }
1763         else if(puff->info->attacksound)
1764         {
1765                 S_StartSound(puff, puff->info->attacksound);
1766         }
1767         switch(PuffType)
1768         {
1769                 case MT_PUNCHPUFF:
1770                         puff->momz = FRACUNIT;
1771                         break;
1772                 case MT_HAMMERPUFF:
1773                         puff->momz = .8*FRACUNIT;
1774                         break;
1775                 default:
1776                         break;
1777         }
1778         PuffSpawned = puff;
1779 }
1780
1781 /*
1782 ================
1783 =
1784 = P_SpawnBlood
1785 =
1786 ================
1787 */
1788
1789 /*
1790 void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, int damage)
1791 {
1792         mobj_t  *th;
1793         
1794         z += ((P_Random()-P_Random())<<10);
1795         th = P_SpawnMobj (x,y,z, MT_BLOOD);
1796         th->momz = FRACUNIT*2;
1797         th->tics -= P_Random()&3;
1798
1799         if (damage <= 12 && damage >= 9)
1800                 P_SetMobjState (th,S_BLOOD2);
1801         else if (damage < 9)
1802                 P_SetMobjState (th,S_BLOOD3);
1803 }
1804 */
1805
1806 //---------------------------------------------------------------------------
1807 //
1808 // PROC P_BloodSplatter
1809 //
1810 //---------------------------------------------------------------------------
1811
1812 void P_BloodSplatter(fixed_t x, fixed_t y, fixed_t z, mobj_t *originator)
1813 {
1814         mobj_t *mo;
1815
1816         mo = P_SpawnMobj(x, y, z, MT_BLOODSPLATTER);
1817         mo->target = originator;
1818         mo->momx = (P_Random()-P_Random())<<10;
1819         mo->momy = (P_Random()-P_Random())<<10;
1820         mo->momz = 3*FRACUNIT;
1821 }
1822
1823 //===========================================================================
1824 //
1825 //  P_BloodSplatter2
1826 //
1827 //===========================================================================
1828
1829 void P_BloodSplatter2(fixed_t x, fixed_t y, fixed_t z, mobj_t *originator)
1830 {
1831         mobj_t *mo;
1832
1833         mo = P_SpawnMobj(x+((P_Random()-128)<<11), y+((P_Random()-128)<<11), z, 
1834                 MT_AXEBLOOD);
1835         mo->target = originator;
1836 }
1837
1838 //---------------------------------------------------------------------------
1839 //
1840 // PROC P_RipperBlood
1841 //
1842 //---------------------------------------------------------------------------
1843
1844 void P_RipperBlood(mobj_t *mo)
1845 {
1846         mobj_t *th;
1847         fixed_t x, y, z;
1848
1849         x = mo->x+((P_Random()-P_Random())<<12);
1850         y = mo->y+((P_Random()-P_Random())<<12);
1851         z = mo->z+((P_Random()-P_Random())<<12);
1852         th = P_SpawnMobj(x, y, z, MT_BLOOD);
1853 //      th->flags |= MF_NOGRAVITY;
1854         th->momx = mo->momx>>1;
1855         th->momy = mo->momy>>1;
1856         th->tics += P_Random()&3;
1857 }
1858
1859 //---------------------------------------------------------------------------
1860 //
1861 // FUNC P_GetThingFloorType
1862 //
1863 //---------------------------------------------------------------------------
1864
1865 int P_GetThingFloorType(mobj_t *thing)
1866 {
1867         if(thing->floorpic)
1868         {               
1869                 return(TerrainTypes[thing->floorpic]);
1870         }
1871         else
1872         {
1873                 return(TerrainTypes[thing->subsector->sector->floorpic]);
1874         }
1875 /*
1876         if(thing->subsector->sector->floorpic
1877                 == W_GetNumForName("FLTWAWA1")-firstflat)
1878         {
1879                 return(FLOOR_WATER);
1880         }
1881         else
1882         {
1883                 return(FLOOR_SOLID);
1884         }
1885 */
1886 }
1887
1888 //---------------------------------------------------------------------------
1889 //
1890 // FUNC P_HitFloor
1891 //
1892 //---------------------------------------------------------------------------
1893 #define SMALLSPLASHCLIP 12<<FRACBITS;
1894
1895 int P_HitFloor(mobj_t *thing)
1896 {
1897         mobj_t *mo;
1898         int smallsplash=false;
1899
1900         if(thing->floorz != thing->subsector->sector->floorheight)
1901         { // don't splash if landing on the edge above water/lava/etc....
1902                 return(FLOOR_SOLID);
1903         }
1904
1905         // Things that don't splash go here
1906         switch(thing->type)
1907         {
1908                 case MT_LEAF1:
1909                 case MT_LEAF2:
1910 //              case MT_BLOOD:                  // I set these to low mass -- pm
1911 //              case MT_BLOODSPLATTER:
1912                 case MT_SPLASH:
1913                 case MT_SLUDGECHUNK:
1914                         return(FLOOR_SOLID);
1915                 default:
1916                         break;
1917         }
1918
1919         // Small splash for small masses
1920         if (thing->info->mass < 10) smallsplash = true;
1921
1922         switch(P_GetThingFloorType(thing))
1923         {
1924                 case FLOOR_WATER:
1925                         if (smallsplash)
1926                         {
1927                                 mo=P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SPLASHBASE);
1928                                 if (mo) mo->floorclip += SMALLSPLASHCLIP;
1929                                 S_StartSound(mo, SFX_AMBIENT10);        // small drip
1930                         }
1931                         else
1932                         {
1933                                 mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SPLASH);
1934                                 mo->target = thing;
1935                                 mo->momx = (P_Random()-P_Random())<<8;
1936                                 mo->momy = (P_Random()-P_Random())<<8;
1937                                 mo->momz = 2*FRACUNIT+(P_Random()<<8);
1938                                 mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SPLASHBASE);
1939                                 if (thing->player) P_NoiseAlert(thing, thing);
1940                                 S_StartSound(mo, SFX_WATER_SPLASH);
1941                         }
1942                         return(FLOOR_WATER);
1943                 case FLOOR_LAVA:
1944                         if (smallsplash)
1945                         {
1946                                 mo=P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_LAVASPLASH);
1947                                 if (mo) mo->floorclip += SMALLSPLASHCLIP;
1948                         }
1949                         else
1950                         {
1951                                 mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_LAVASMOKE);
1952                                 mo->momz = FRACUNIT+(P_Random()<<7);
1953                                 mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_LAVASPLASH);
1954                                 if (thing->player) P_NoiseAlert(thing, thing);
1955                         }
1956                         S_StartSound(mo, SFX_LAVA_SIZZLE);
1957                         if(thing->player && leveltime&31)
1958                         {
1959                                 P_DamageMobj(thing, &LavaInflictor, NULL, 5);
1960                         }
1961                         return(FLOOR_LAVA);
1962                 case FLOOR_SLUDGE:
1963                         if (smallsplash)
1964                         {
1965                                 mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ,
1966                                         MT_SLUDGESPLASH);
1967                                 if (mo) mo->floorclip += SMALLSPLASHCLIP;
1968                         }
1969                         else
1970                         {
1971                                 mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SLUDGECHUNK);
1972                                 mo->target = thing;
1973                                 mo->momx = (P_Random()-P_Random())<<8;
1974                                 mo->momy = (P_Random()-P_Random())<<8;
1975                                 mo->momz = FRACUNIT+(P_Random()<<8);
1976                                 mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, 
1977                                         MT_SLUDGESPLASH);
1978                                 if (thing->player) P_NoiseAlert(thing, thing);
1979                         }
1980                         S_StartSound(mo, SFX_SLUDGE_GLOOP);
1981                         return(FLOOR_SLUDGE);
1982         }
1983         return(FLOOR_SOLID);
1984 }
1985
1986
1987 //---------------------------------------------------------------------------
1988 //
1989 // FUNC P_CheckMissileSpawn
1990 //
1991 // Returns true if the missile is at a valid spawn point, otherwise
1992 // explodes it and returns false.
1993 //
1994 //---------------------------------------------------------------------------
1995
1996 boolean P_CheckMissileSpawn(mobj_t *missile)
1997 {
1998         //missile->tics -= P_Random()&3;
1999
2000         // move a little forward so an angle can be computed if it
2001         // immediately explodes
2002   /*
2003    * jim - handle fast missiles with BlasterMobjThinker()s
2004    * assume so if momentum > MAXMOVE
2005    * this is a horrible kludge, but to be honest so is the BlasterMobjThinker
2006    *  stuff in the first place
2007    */
2008   if ((missile->momx > MAXMOVE) || (missile->momy > MAXMOVE))
2009   {
2010     missile->x += (missile->momx>>3);
2011     missile->y += (missile->momy>>3);
2012     missile->z += (missile->momz>>3);
2013   }
2014   else
2015   {
2016         missile->x += (missile->momx>>1);
2017         missile->y += (missile->momy>>1);
2018         missile->z += (missile->momz>>1);
2019   }
2020         if(!P_TryMove(missile, missile->x, missile->y))
2021         {
2022                 P_ExplodeMissile(missile);
2023                 return(false);
2024         }
2025         return(true);
2026 }
2027
2028 //---------------------------------------------------------------------------
2029 //
2030 // FUNC P_SpawnMissile
2031 //
2032 // Returns NULL if the missile exploded immediately, otherwise returns
2033 // a mobj_t pointer to the missile.
2034 //
2035 //---------------------------------------------------------------------------
2036
2037 mobj_t *P_SpawnMissile(mobj_t *source, mobj_t *dest, mobjtype_t type)
2038 {
2039         fixed_t z;
2040         mobj_t *th;
2041         angle_t an;
2042         int dist;
2043
2044         switch(type)
2045         {
2046                 case MT_MNTRFX1: // Minotaur swing attack missile
2047                         z = source->z+40*FRACUNIT;
2048                         break;
2049                 case MT_MNTRFX2: // Minotaur floor fire missile
2050                         z = ONFLOORZ+source->floorclip;
2051                         break;
2052                 case MT_CENTAUR_FX:
2053                         z = source->z+45*FRACUNIT;
2054                         break;
2055                 case MT_ICEGUY_FX:
2056                         z = source->z+40*FRACUNIT;
2057                         break;
2058                 case MT_HOLY_MISSILE:
2059                         z = source->z+40*FRACUNIT;
2060                         break;
2061                 default:
2062                         z = source->z+32*FRACUNIT;
2063                         break;
2064         }
2065         z -= source->floorclip;
2066         th = P_SpawnMobj(source->x, source->y, z, type);
2067         if(th->info->seesound)
2068         {
2069                 S_StartSound(th, th->info->seesound);
2070         }
2071         th->target = source; // Originator
2072         an = R_PointToAngle2(source->x, source->y, dest->x, dest->y);
2073         if(dest->flags&MF_SHADOW)
2074         { // Invisible target
2075                 an += (P_Random()-P_Random())<<21;
2076         }
2077         th->angle = an;
2078         an >>= ANGLETOFINESHIFT;
2079         th->momx = FixedMul(th->info->speed, finecosine[an]);
2080         th->momy = FixedMul(th->info->speed, finesine[an]);
2081         dist = P_AproxDistance(dest->x - source->x, dest->y - source->y);
2082         dist = dist/th->info->speed;
2083         if(dist < 1)
2084         {
2085                 dist = 1;
2086         }
2087         th->momz = (dest->z-source->z)/dist;
2088         return(P_CheckMissileSpawn(th) ? th : NULL);
2089 }
2090
2091 //---------------------------------------------------------------------------
2092 //
2093 // FUNC P_SpawnMissileXYZ
2094 //
2095 // Returns NULL if the missile exploded immediately, otherwise returns
2096 // a mobj_t pointer to the missile.
2097 //
2098 //---------------------------------------------------------------------------
2099
2100 mobj_t *P_SpawnMissileXYZ(fixed_t x, fixed_t y, fixed_t z,
2101         mobj_t *source, mobj_t *dest, mobjtype_t type)
2102 {
2103         mobj_t *th;
2104         angle_t an;
2105         int dist;
2106
2107         z -= source->floorclip;
2108         th = P_SpawnMobj(x, y, z, type);
2109         if(th->info->seesound)
2110         {
2111                 S_StartSound(th, th->info->seesound);
2112         }
2113         th->target = source; // Originator
2114         an = R_PointToAngle2(source->x, source->y, dest->x, dest->y);
2115         if(dest->flags&MF_SHADOW)
2116         { // Invisible target
2117                 an += (P_Random()-P_Random())<<21;
2118         }
2119         th->angle = an;
2120         an >>= ANGLETOFINESHIFT;
2121         th->momx = FixedMul(th->info->speed, finecosine[an]);
2122         th->momy = FixedMul(th->info->speed, finesine[an]);
2123         dist = P_AproxDistance(dest->x - source->x, dest->y - source->y);
2124         dist = dist/th->info->speed;
2125         if(dist < 1)
2126         {
2127                 dist = 1;
2128         }
2129         th->momz = (dest->z-source->z)/dist;
2130         return(P_CheckMissileSpawn(th) ? th : NULL);
2131 }
2132
2133 //---------------------------------------------------------------------------
2134 //
2135 // FUNC P_SpawnMissileAngle
2136 //
2137 // Returns NULL if the missile exploded immediately, otherwise returns
2138 // a mobj_t pointer to the missile.
2139 //
2140 //---------------------------------------------------------------------------
2141
2142 mobj_t *P_SpawnMissileAngle(mobj_t *source, mobjtype_t type,
2143         angle_t angle, fixed_t momz)
2144 {
2145         fixed_t z;
2146         mobj_t *mo;
2147
2148         switch(type)
2149         {
2150                 case MT_MNTRFX1: // Minotaur swing attack missile
2151                         z = source->z+40*FRACUNIT;
2152                         break;
2153                 case MT_MNTRFX2: // Minotaur floor fire missile
2154                         z = ONFLOORZ+source->floorclip;
2155                         break;
2156                 case MT_ICEGUY_FX2: // Secondary Projectiles of the Ice Guy
2157                         z = source->z+3*FRACUNIT;
2158                         break;
2159                 case MT_MSTAFF_FX2:
2160                         z = source->z+40*FRACUNIT;
2161                         break;
2162                 default:
2163                         z = source->z+32*FRACUNIT;
2164                         break;
2165         }
2166         z -= source->floorclip;
2167         mo = P_SpawnMobj(source->x, source->y, z, type);
2168         if(mo->info->seesound)
2169         {
2170                 S_StartSound(mo, mo->info->seesound);
2171         }
2172         mo->target = source; // Originator
2173         mo->angle = angle;
2174         angle >>= ANGLETOFINESHIFT;
2175         mo->momx = FixedMul(mo->info->speed, finecosine[angle]);
2176         mo->momy = FixedMul(mo->info->speed, finesine[angle]);
2177         mo->momz = momz;
2178         return(P_CheckMissileSpawn(mo) ? mo : NULL);
2179 }
2180
2181 //---------------------------------------------------------------------------
2182 //
2183 // FUNC P_SpawnMissileAngleSpeed
2184 //
2185 // Returns NULL if the missile exploded immediately, otherwise returns
2186 // a mobj_t pointer to the missile.
2187 //
2188 //---------------------------------------------------------------------------
2189
2190 mobj_t *P_SpawnMissileAngleSpeed(mobj_t *source, mobjtype_t type,
2191         angle_t angle, fixed_t momz, fixed_t speed)
2192 {
2193         fixed_t z;
2194         mobj_t *mo;
2195
2196         z = source->z;
2197         z -= source->floorclip;
2198         mo = P_SpawnMobj(source->x, source->y, z, type);
2199         if(mo->info->seesound)
2200         {
2201                 //S_StartSound(mo, mo->info->seesound);
2202         }
2203         mo->target = source; // Originator
2204         mo->angle = angle;
2205         angle >>= ANGLETOFINESHIFT;
2206         mo->momx = FixedMul(speed, finecosine[angle]);
2207         mo->momy = FixedMul(speed, finesine[angle]);
2208         mo->momz = momz;
2209         return(P_CheckMissileSpawn(mo) ? mo : NULL);
2210 }
2211
2212
2213
2214 /*
2215 ================
2216 =
2217 = P_SpawnPlayerMissile
2218 =
2219 = Tries to aim at a nearby monster
2220 ================
2221 */
2222
2223 mobj_t *P_SpawnPlayerMissile(mobj_t *source, mobjtype_t type)
2224 {
2225         angle_t an;
2226         fixed_t x, y, z, slope;
2227
2228         // Try to find a target
2229         an = source->angle;
2230         slope = P_AimLineAttack(source, an, 16*64*FRACUNIT);
2231         if(!linetarget)
2232         {
2233                 an += 1<<26;
2234                 slope = P_AimLineAttack(source, an, 16*64*FRACUNIT);
2235                 if(!linetarget)
2236                 {
2237                         an -= 2<<26;
2238                         slope = P_AimLineAttack(source, an, 16*64*FRACUNIT);
2239                 }
2240                 if(!linetarget)
2241                 {
2242                         an = source->angle;
2243                         slope = ((source->player->lookdir)<<FRACBITS)/173;
2244                 }
2245         }
2246         x = source->x;
2247         y = source->y;
2248         if(type == MT_LIGHTNING_FLOOR)
2249         {       
2250                 z = ONFLOORZ;
2251                 slope = 0;
2252         }
2253         else if(type == MT_LIGHTNING_CEILING)
2254         {
2255                 z = ONCEILINGZ;
2256                 slope = 0;
2257         }
2258         else
2259         {
2260                 z = source->z + 4*8*FRACUNIT+((source->player->lookdir)<<FRACBITS)/173;
2261                 z -= source->floorclip;
2262         }
2263         MissileMobj = P_SpawnMobj(x, y, z, type);
2264         if(MissileMobj->info->seesound)
2265         {
2266                 //S_StartSound(MissileMobj, MissileMobj->info->seesound);
2267         }
2268         MissileMobj->target = source;
2269         MissileMobj->angle = an;
2270         MissileMobj->momx = FixedMul(MissileMobj->info->speed,
2271                 finecosine[an>>ANGLETOFINESHIFT]);
2272         MissileMobj->momy = FixedMul(MissileMobj->info->speed,
2273                 finesine[an>>ANGLETOFINESHIFT]);
2274         MissileMobj->momz = FixedMul(MissileMobj->info->speed, slope);
2275         if(MissileMobj->type == MT_MWAND_MISSILE 
2276                 || MissileMobj->type == MT_CFLAME_MISSILE)
2277         { // Ultra-fast ripper spawning missile
2278                 MissileMobj->x += (MissileMobj->momx>>3);
2279                 MissileMobj->y += (MissileMobj->momy>>3);
2280                 MissileMobj->z += (MissileMobj->momz>>3);
2281         }
2282         else
2283         { // Normal missile
2284                 MissileMobj->x += (MissileMobj->momx>>1);
2285                 MissileMobj->y += (MissileMobj->momy>>1);
2286                 MissileMobj->z += (MissileMobj->momz>>1);
2287         }
2288         if(!P_TryMove(MissileMobj, MissileMobj->x, MissileMobj->y))
2289         { // Exploded immediately
2290                 P_ExplodeMissile(MissileMobj);
2291                 return(NULL);
2292         }
2293         return(MissileMobj);
2294 }
2295
2296
2297 //----------------------------------------------------------------------------
2298 //
2299 // P_SpawnPlayerMinotaur - 
2300 //
2301 //      Special missile that has larger blocking than player
2302 //----------------------------------------------------------------------------
2303
2304 /*
2305 mobj_t *P_SpawnPlayerMinotaur(mobj_t *source, mobjtype_t type)
2306 {
2307         angle_t an;
2308         fixed_t x, y, z;
2309         fixed_t dist=0 *FRACUNIT;
2310
2311         an = source->angle;
2312         x = source->x + FixedMul(dist, finecosine[an>>ANGLETOFINESHIFT]);
2313         y = source->y + FixedMul(dist, finesine[an>>ANGLETOFINESHIFT]);
2314         z = source->z + 4*8*FRACUNIT+((source->player->lookdir)<<FRACBITS)/173;
2315         z -= source->floorclip;
2316         MissileMobj = P_SpawnMobj(x, y, z, type);
2317         if(MissileMobj->info->seesound)
2318         {
2319                 //S_StartSound(MissileMobj, MissileMobj->info->seesound);
2320         }
2321         MissileMobj->target = source;
2322         MissileMobj->angle = an;
2323         MissileMobj->momx = FixedMul(MissileMobj->info->speed,
2324                 finecosine[an>>ANGLETOFINESHIFT]);
2325         MissileMobj->momy = FixedMul(MissileMobj->info->speed,
2326                 finesine[an>>ANGLETOFINESHIFT]);
2327         MissileMobj->momz = 0;
2328
2329 //      MissileMobj->x += (MissileMobj->momx>>3);
2330 //      MissileMobj->y += (MissileMobj->momy>>3);
2331 //      MissileMobj->z += (MissileMobj->momz>>3);
2332
2333         if(!P_TryMove(MissileMobj, MissileMobj->x, MissileMobj->y))
2334         { // Wouln't fit
2335
2336                 return(NULL);
2337         }
2338         return(MissileMobj);
2339 }
2340 */
2341
2342 //---------------------------------------------------------------------------
2343 //
2344 // PROC P_SPMAngle
2345 //
2346 //---------------------------------------------------------------------------
2347
2348 mobj_t *P_SPMAngle(mobj_t *source, mobjtype_t type, angle_t angle)
2349 {
2350         mobj_t *th;
2351         angle_t an;
2352         fixed_t x, y, z, slope;
2353
2354 //
2355 // see which target is to be aimed at
2356 //
2357         an = angle;
2358         slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
2359         if (!linetarget)
2360         {
2361                 an += 1<<26;
2362                 slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
2363                 if (!linetarget)
2364                 {
2365                         an -= 2<<26;
2366                         slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
2367                 }
2368                 if (!linetarget)
2369                 {
2370                         an = angle;
2371                         slope = ((source->player->lookdir)<<FRACBITS)/173;
2372                 }
2373         }
2374         x = source->x;
2375         y = source->y;
2376         z = source->z + 4*8*FRACUNIT+((source->player->lookdir)<<FRACBITS)/173;
2377         z -= source->floorclip;
2378         th = P_SpawnMobj(x, y, z, type);
2379 //      if(th->info->seesound)
2380 //      {
2381 //              S_StartSound(th, th->info->seesound);
2382 //      }
2383         th->target = source;
2384         th->angle = an;
2385         th->momx = FixedMul(th->info->speed, finecosine[an>>ANGLETOFINESHIFT]);
2386         th->momy = FixedMul(th->info->speed, finesine[an>>ANGLETOFINESHIFT]);
2387         th->momz = FixedMul(th->info->speed, slope);
2388         return(P_CheckMissileSpawn(th) ? th : NULL);
2389 }
2390
2391 //===========================================================================
2392 //
2393 // P_SPMAngleXYZ
2394 //
2395 //===========================================================================
2396
2397 mobj_t *P_SPMAngleXYZ(mobj_t *source, fixed_t x, fixed_t y, 
2398         fixed_t z, mobjtype_t type, angle_t angle)
2399 {
2400         mobj_t *th;
2401         angle_t an;
2402         fixed_t slope;
2403
2404 //
2405 // see which target is to be aimed at
2406 //
2407         an = angle;
2408         slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
2409         if (!linetarget)
2410         {
2411                 an += 1<<26;
2412                 slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
2413                 if (!linetarget)
2414                 {
2415                         an -= 2<<26;
2416                         slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
2417                 }
2418                 if (!linetarget)
2419                 {
2420                         an = angle;
2421                         slope = ((source->player->lookdir)<<FRACBITS)/173;
2422                 }
2423         }
2424         z += 4*8*FRACUNIT+((source->player->lookdir)<<FRACBITS)/173;
2425         z -= source->floorclip;
2426         th = P_SpawnMobj(x, y, z, type);
2427 //      if(th->info->seesound)
2428 //      {
2429 //              S_StartSound(th, th->info->seesound);
2430 //      }
2431         th->target = source;
2432         th->angle = an;
2433         th->momx = FixedMul(th->info->speed, finecosine[an>>ANGLETOFINESHIFT]);
2434         th->momy = FixedMul(th->info->speed, finesine[an>>ANGLETOFINESHIFT]);
2435         th->momz = FixedMul(th->info->speed, slope);
2436         return(P_CheckMissileSpawn(th) ? th : NULL);
2437 }
2438
2439 mobj_t *P_SpawnKoraxMissile(fixed_t x, fixed_t y, fixed_t z,
2440         mobj_t *source, mobj_t *dest, mobjtype_t type)
2441 {
2442         mobj_t *th;
2443         angle_t an;
2444         int dist;
2445
2446         z -= source->floorclip;
2447         th = P_SpawnMobj(x, y, z, type);
2448         if(th->info->seesound)
2449         {
2450                 S_StartSound(th, th->info->seesound);
2451         }
2452         th->target = source; // Originator
2453         an = R_PointToAngle2(x, y, dest->x, dest->y);
2454         if(dest->flags&MF_SHADOW)
2455         { // Invisible target
2456                 an += (P_Random()-P_Random())<<21;
2457         }
2458         th->angle = an;
2459         an >>= ANGLETOFINESHIFT;
2460         th->momx = FixedMul(th->info->speed, finecosine[an]);
2461         th->momy = FixedMul(th->info->speed, finesine[an]);
2462         dist = P_AproxDistance(dest->x - x, dest->y - y);
2463         dist = dist/th->info->speed;
2464         if(dist < 1)
2465         {
2466                 dist = 1;
2467         }
2468         th->momz = (dest->z-z+(30*FRACUNIT))/dist;
2469         return(P_CheckMissileSpawn(th) ? th : NULL);
2470 }
2471