]> icculus.org git repositories - theoddone33/hhexen.git/blob - base/p_mobj.c
Drop in SDL
[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 /* jim allow other things to have BlasterMobjThinker()s (crossbow) */
966                                else if((mobj->type == MT_CFLAME_MISSILE) &&
967                                        !--mobj->special1)
968                                 {
969                                         mobj->special1 = 4;
970                                         z = mobj->z-12*FRACUNIT;
971                                         if(z < mobj->floorz)
972                                         {
973                                                 z = mobj->floorz;
974                                         }
975                                         mo = P_SpawnMobj(mobj->x, mobj->y, z, MT_CFLAMEFLOOR);
976                                         if(mo)
977                                         {
978                                                 mo->angle = mobj->angle;
979                                         }
980                                 }
981                         }
982                 }
983         }
984         // Advance the state
985         if(mobj->tics != -1)
986         {
987                 mobj->tics--;
988                 while(!mobj->tics)
989                 {
990                         if(!P_SetMobjState(mobj, mobj->state->nextstate))
991                         { // mobj was removed
992                                 return;
993                         }
994                 }
995         }
996 }
997
998 //===========================================================================
999 //
1000 // PlayerLandedOnThing
1001 //
1002 //===========================================================================
1003
1004 static void PlayerLandedOnThing(mobj_t *mo, mobj_t *onmobj)
1005 {
1006         mo->player->deltaviewheight = mo->momz>>3;
1007         if(mo->momz < -23*FRACUNIT)
1008         {
1009                 P_FallingDamage(mo->player);
1010                 P_NoiseAlert(mo, mo);
1011         }
1012         else if(mo->momz < -GRAVITY*12 
1013                 && !mo->player->morphTics)
1014         {
1015                 S_StartSound(mo, SFX_PLAYER_LAND);
1016                 switch(mo->player->class)
1017                 {
1018                         case PCLASS_FIGHTER:
1019                                 S_StartSound(mo, SFX_PLAYER_FIGHTER_GRUNT);
1020                                 break;
1021                         case PCLASS_CLERIC:
1022                                 S_StartSound(mo, SFX_PLAYER_CLERIC_GRUNT);
1023                                 break;
1024                         case PCLASS_MAGE:
1025                                 S_StartSound(mo, SFX_PLAYER_MAGE_GRUNT);
1026                                 break;
1027                         default:
1028                                 break;
1029                 }
1030         }
1031         else if(!mo->player->morphTics)
1032         {
1033                 S_StartSound(mo, SFX_PLAYER_LAND);
1034         }
1035         if(mouselook && !demorecording && !demoplayback) {
1036                 mo->player->centering = false;
1037         }
1038         else { mo->player->centering = true;
1039         }
1040 }
1041
1042 //----------------------------------------------------------------------------
1043 //
1044 // PROC P_MobjThinker
1045 //
1046 //----------------------------------------------------------------------------
1047
1048 void P_MobjThinker(mobj_t *mobj)
1049 {
1050         mobj_t *onmo;
1051 /*
1052         // Reset to not blasted when momentums are gone
1053         if((mobj->flags2&MF2_BLASTED) && (!(mobj->momx)) && (!(mobj->momy)))
1054                 ResetBlasted(mobj);
1055 */
1056         // Handle X and Y momentums
1057         BlockingMobj = NULL;
1058         if(mobj->momx || mobj->momy || (mobj->flags&MF_SKULLFLY))
1059         {
1060                 P_XYMovement(mobj);
1061                 if(mobj->thinker.function == (think_t)-1)
1062                 { // mobj was removed
1063                         return;
1064                 }
1065         }
1066         else if(mobj->flags2&MF2_BLASTED)
1067         { // Reset to not blasted when momentums are gone
1068                 ResetBlasted(mobj);
1069         }
1070         if(mobj->flags2&MF2_FLOATBOB)
1071         { // Floating item bobbing motion (special1 is height)
1072                 mobj->z = mobj->floorz +
1073                                         mobj->special1 +
1074                                         FloatBobOffsets[(mobj->health++)&63];
1075         }
1076         else if((mobj->z != mobj->floorz) || mobj->momz || BlockingMobj)
1077         {       // Handle Z momentum and gravity
1078                 if(mobj->flags2&MF2_PASSMOBJ)
1079                 {
1080                         if(!(onmo = P_CheckOnmobj(mobj)))
1081                         {
1082                                 P_ZMovement(mobj);
1083                                 if(mobj->player && mobj->flags&MF2_ONMOBJ)
1084                                 {
1085                                         mobj->flags2 &= ~MF2_ONMOBJ;
1086                                 }
1087                         }
1088                         else
1089                         {
1090                                 if(mobj->player)
1091                                 {
1092                                         if(mobj->momz < -GRAVITY*8 && !(mobj->flags2&MF2_FLY))
1093                                         {
1094                                                 PlayerLandedOnThing(mobj, onmo);
1095                                         }
1096                                         if(onmo->z+onmo->height-mobj->z <= 24*FRACUNIT)
1097                                         {
1098                                                 mobj->player->viewheight -= onmo->z+onmo->height
1099                                                         -mobj->z;
1100                                                 mobj->player->deltaviewheight = 
1101                                                         (VIEWHEIGHT-mobj->player->viewheight)>>3;
1102                                                 mobj->z = onmo->z+onmo->height;
1103                                                 mobj->flags2 |= MF2_ONMOBJ;
1104                                                 mobj->momz = 0;
1105                                         }                               
1106                                         else
1107                                         { // hit the bottom of the blocking mobj
1108                                                 mobj->momz = 0;
1109                                         }
1110                                 }
1111 /* Landing on another player, and mimicking his movements
1112                                 if(mobj->player && onmo->player)
1113                                 {
1114                                         mobj->momx = onmo->momx;
1115                                         mobj->momy = onmo->momy;
1116                                         if(onmo->z < onmo->floorz)
1117                                         {
1118                                                 mobj->z += onmo->floorz-onmo->z;
1119                                                 if(onmo->player)
1120                                                 {
1121                                                         onmo->player->viewheight -= onmo->floorz-onmo->z;
1122                                                         onmo->player->deltaviewheight = (VIEWHEIGHT-
1123                                                                 onmo->player->viewheight)>>3;
1124                                                 }
1125                                                 onmo->z = onmo->floorz;
1126                                         }
1127                                 }
1128 */
1129                         }
1130                 }
1131                 else
1132                 {
1133                         P_ZMovement(mobj);
1134                 }
1135                 if(mobj->thinker.function == (think_t)-1)
1136                 { // mobj was removed
1137                         return;
1138                 }
1139         }
1140
1141         // Cycle through states, calling action functions at transitions
1142         if(mobj->tics != -1)
1143         {
1144                 mobj->tics--;
1145                 // you can cycle through multiple states in a tic
1146                 while(!mobj->tics)
1147                 {
1148                         if(!P_SetMobjState(mobj, mobj->state->nextstate))
1149                         { // mobj was removed
1150                                 return;
1151                         }
1152                 }
1153         }
1154 }
1155
1156 //==========================================================================
1157 //
1158 // P_SpawnMobj
1159 //
1160 //==========================================================================
1161
1162 mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
1163 {
1164         mobj_t *mobj;
1165         state_t *st;
1166         mobjinfo_t *info;
1167         fixed_t space;
1168
1169         mobj = Z_Malloc(sizeof(*mobj), PU_LEVEL, NULL);
1170         memset(mobj, 0, sizeof(*mobj));
1171         info = &mobjinfo[type];
1172         mobj->type = type;
1173         mobj->info = info;
1174         mobj->x = x;
1175         mobj->y = y;
1176         mobj->radius = info->radius;
1177         mobj->height = info->height;
1178         mobj->flags = info->flags;
1179         mobj->flags2 = info->flags2;
1180         mobj->damage = info->damage;
1181         mobj->health = info->spawnhealth;
1182         if(gameskill != sk_nightmare)
1183         {
1184                 mobj->reactiontime = info->reactiontime;
1185         }
1186         mobj->lastlook = P_Random()%MAXPLAYERS;
1187
1188         // Set the state, but do not use P_SetMobjState, because action
1189         // routines can't be called yet.  If the spawnstate has an action
1190         // routine, it will not be called.
1191         st = &states[info->spawnstate];
1192         mobj->state = st;
1193         mobj->tics = st->tics;
1194         mobj->sprite = st->sprite;
1195         mobj->frame = st->frame;
1196
1197         // Set subsector and/or block links.
1198         P_SetThingPosition(mobj);
1199         mobj->floorz = mobj->subsector->sector->floorheight;
1200         mobj->ceilingz = mobj->subsector->sector->ceilingheight;
1201         if(z == ONFLOORZ)
1202         {
1203                 mobj->z = mobj->floorz;
1204         }
1205         else if(z == ONCEILINGZ)
1206         {
1207                 mobj->z = mobj->ceilingz-mobj->info->height;
1208         }       
1209         else if(z == FLOATRANDZ)
1210         {
1211                 space = ((mobj->ceilingz)-(mobj->info->height))-mobj->floorz;
1212                 if(space > 48*FRACUNIT)
1213                 {
1214                         space -= 40*FRACUNIT;
1215                         mobj->z = ((space*P_Random())>>8)+mobj->floorz+40*FRACUNIT;
1216                 }
1217                 else
1218                 {
1219                         mobj->z = mobj->floorz;
1220                 }
1221         }
1222         else if (mobj->flags2&MF2_FLOATBOB)
1223         {
1224                 mobj->z = mobj->floorz + z;             // artifact z passed in as height
1225         }
1226         else
1227         {
1228                 mobj->z = z;
1229         }
1230         if(mobj->flags2&MF2_FLOORCLIP && P_GetThingFloorType(mobj) >= FLOOR_LIQUID
1231                 && mobj->z == mobj->subsector->sector->floorheight)
1232         {
1233                 mobj->floorclip = 10*FRACUNIT;
1234         }
1235         else
1236         {
1237                 mobj->floorclip = 0;
1238         }
1239
1240         mobj->thinker.function = P_MobjThinker;
1241         P_AddThinker(&mobj->thinker);
1242         return(mobj);
1243 }
1244
1245 //==========================================================================
1246 //
1247 // P_RemoveMobj
1248 //
1249 //==========================================================================
1250
1251 void P_RemoveMobj(mobj_t *mobj)
1252 {
1253         // Remove from creature queue
1254         if(mobj->flags&MF_COUNTKILL &&
1255                 mobj->flags&MF_CORPSE)
1256         {
1257                 A_DeQueueCorpse(mobj);
1258         }
1259
1260         if(mobj->tid)
1261         { // Remove from TID list
1262                 P_RemoveMobjFromTIDList(mobj);
1263         }
1264
1265         // Unlink from sector and block lists
1266         P_UnsetThingPosition(mobj);
1267
1268         // Stop any playing sound
1269         S_StopSound(mobj);
1270
1271         // Free block
1272         P_RemoveThinker((thinker_t *)mobj);
1273 }
1274
1275 //==========================================================================
1276 //
1277 // P_SpawnPlayer
1278 //
1279 // Called when a player is spawned on the level.  Most of the player
1280 // structure stays unchanged between levels.
1281 //
1282 //==========================================================================
1283
1284 void P_SpawnPlayer(mapthing_t *mthing)
1285 {
1286         player_t *p;
1287         fixed_t x, y, z;
1288         mobj_t *mobj;
1289
1290         if(!playeringame[mthing->type-1])
1291         { // Not playing
1292                 return;
1293         }
1294         p = &players[mthing->type-1];
1295         if(p->playerstate == PST_REBORN)
1296         {
1297                 G_PlayerReborn(mthing->type-1);
1298         }
1299         x = mthing->x << FRACBITS;
1300         y = mthing->y << FRACBITS;
1301         z = ONFLOORZ;
1302         if(randomclass && deathmatch)
1303         {
1304                 p->class = P_Random()%3;
1305                 if(p->class == PlayerClass[mthing->type-1])
1306                 {
1307                         p->class = (p->class+1)%3;
1308                 }
1309                 PlayerClass[mthing->type-1] = p->class;
1310                 SB_SetClassData();
1311         }
1312         else
1313         {
1314                 p->class = PlayerClass[mthing->type-1];
1315         }
1316         switch(p->class)
1317         {
1318                 case PCLASS_FIGHTER:
1319                         mobj = P_SpawnMobj(x, y, z, MT_PLAYER_FIGHTER);
1320                         break;
1321                 case PCLASS_CLERIC:
1322                         mobj = P_SpawnMobj(x, y, z, MT_PLAYER_CLERIC);
1323                         break;
1324                 case PCLASS_MAGE:
1325                         mobj = P_SpawnMobj(x, y, z, MT_PLAYER_MAGE);
1326                         break;
1327                 case PCLASS_ASS:
1328                         mobj = P_SpawnMobj(x, y, z, MT_PLAYER_ASS);
1329                         break;
1330                 default:
1331                         I_Error("P_SpawnPlayer: Unknown class type");
1332                         /* jim never happens but keeps gcc happy */
1333                         mobj = NULL;
1334                         break;
1335         }
1336
1337         // Set translation table data
1338         if(p->class == PCLASS_FIGHTER && (mthing->type == 1 || mthing->type == 3))
1339         { 
1340                 // The first type should be blue, and the third should be the
1341                 // Fighter's original gold color
1342                 if(mthing->type == 1)
1343                 {
1344                         mobj->flags |= 2<<MF_TRANSSHIFT;
1345                 }
1346         }
1347         else if(mthing->type > 1)
1348         { // Set color translation bits for player sprites
1349                 mobj->flags |= (mthing->type-1)<<MF_TRANSSHIFT;
1350         }
1351
1352         mobj->angle = ANG45 * (mthing->angle/45);
1353         mobj->player = p;
1354         mobj->health = p->health;
1355         p->mo = mobj;
1356         p->playerstate = PST_LIVE;
1357         p->refire = 0;
1358         P_ClearMessage(p);
1359         p->damagecount = 0;
1360         p->bonuscount = 0;
1361         p->poisoncount = 0;
1362         p->morphTics = 0;
1363         p->extralight = 0;
1364         p->fixedcolormap = 0;
1365         p->viewheight = VIEWHEIGHT;
1366         P_SetupPsprites(p);
1367         if(deathmatch)
1368         { // Give all keys in death match mode
1369                 p->keys = 2047;
1370         }
1371 }
1372
1373 //==========================================================================
1374 //
1375 // P_SpawnMapThing
1376 //
1377 // The fields of the mapthing should already be in host byte order.
1378 //
1379 //==========================================================================
1380
1381 void P_SpawnMapThing(mapthing_t *mthing)
1382 {
1383         int i;
1384         unsigned int spawnMask;
1385         mobj_t *mobj;
1386         fixed_t x, y, z;
1387         // Put in Cleric twice, since we can't have an assassin flag.
1388         static unsigned int classFlags[] =
1389         {
1390                 MTF_FIGHTER,
1391                 MTF_CLERIC,
1392                 MTF_MAGE,
1393                 MTF_CLERIC
1394         };
1395
1396         // Count deathmatch start positions
1397         if(mthing->type == 11)
1398         {
1399                 if(deathmatch_p < &deathmatchstarts[MAXDEATHMATCHSTARTS])
1400                 {
1401                         memcpy(deathmatch_p, mthing, sizeof(*mthing));
1402                         deathmatch_p++;
1403                 }
1404                 return;
1405         }
1406         if(mthing->type == PO_ANCHOR_TYPE)
1407         { // Polyobj Anchor Pt.
1408                 return;
1409         }
1410         else if(mthing->type == PO_SPAWN_TYPE
1411                 || mthing->type == PO_SPAWNCRUSH_TYPE)
1412         { // Polyobj Anchor Pt.
1413                 po_NumPolyobjs++;
1414                 return;
1415         }
1416
1417         // Check for player starts 1 to 4
1418         if(mthing->type <= 4)
1419         {
1420                 playerstarts[mthing->arg1][mthing->type-1] = *mthing;
1421                 if(!deathmatch && !mthing->arg1)
1422                 {
1423                         P_SpawnPlayer(mthing);
1424                 }
1425                 return;
1426         }
1427         // Check for player starts 5 to 8
1428         if(mthing->type >= 9100 && mthing->type <= 9103)
1429         {
1430                 mthing->type = 5+mthing->type-9100; // Translate to 5 - 8
1431                 playerstarts[mthing->arg1][mthing->type-1] = *mthing;
1432                 if(!deathmatch && !mthing->arg1)
1433                 {
1434                         P_SpawnPlayer(mthing);
1435                 }
1436                 return;
1437         }
1438
1439         if(mthing->type >= 1400 && mthing->type < 1410)
1440         {
1441                 R_PointInSubsector(mthing->x<<FRACBITS, 
1442                         mthing->y<<FRACBITS)->sector->seqType = mthing->type-1400;
1443                 return;
1444         }
1445
1446         // Check current game type with spawn flags
1447         if(netgame == false)
1448         {
1449                 spawnMask = MTF_GSINGLE;
1450         }
1451         else if(deathmatch)
1452         {
1453                 spawnMask = MTF_GDEATHMATCH;
1454         }
1455         else
1456         {
1457                 spawnMask = MTF_GCOOP;
1458         }
1459         if(!(mthing->options&spawnMask))
1460         {
1461                 return;
1462         }
1463
1464         // Check current skill with spawn flags
1465         if(gameskill == sk_baby || gameskill == sk_easy)
1466         {
1467                 spawnMask = MTF_EASY;
1468         }
1469         else if(gameskill == sk_hard || gameskill == sk_nightmare)
1470         {
1471                 spawnMask = MTF_HARD;
1472         }
1473         else
1474         {
1475                 spawnMask = MTF_NORMAL;
1476         }
1477         if(!(mthing->options&spawnMask))
1478         {
1479                 return;
1480         }
1481
1482         // Check current character classes with spawn flags
1483         if(netgame == false)
1484         { // Single player
1485                 if((mthing->options&classFlags[PlayerClass[0]]) == 0)
1486                 { // Not for current class
1487                         return;
1488                 }
1489         }
1490         else if(deathmatch == false)
1491         { // Cooperative
1492                 spawnMask = 0;
1493                 for(i = 0; i < MAXPLAYERS; i++)
1494                 {
1495                         if(playeringame[i])
1496                         {
1497                                 spawnMask |= classFlags[PlayerClass[i]];
1498                         }
1499                 }
1500                 if((mthing->options&spawnMask) == 0)
1501                 {
1502                         return;
1503                 }
1504         }
1505
1506         // Find which type to spawn
1507         for(i = 0; i < NUMMOBJTYPES; i++)
1508         {
1509                 if(mthing->type == mobjinfo[i].doomednum)
1510                 {
1511                         break;
1512                 }
1513         }
1514         
1515         if(i == NUMMOBJTYPES)
1516         { // Can't find thing type
1517                 I_Error("P_SpawnMapThing: Unknown type %i at (%i, %i)",
1518                         mthing->type, mthing->x, mthing->y);
1519         }
1520
1521         // Don't spawn keys and players in deathmatch
1522         if(deathmatch && mobjinfo[i].flags&MF_NOTDMATCH)
1523         {
1524                 return;
1525         }
1526                 
1527         // Don't spawn monsters if -nomonsters
1528         if(nomonsters && (mobjinfo[i].flags&MF_COUNTKILL))
1529         {
1530                 return;
1531         }
1532
1533         x = mthing->x<<FRACBITS;
1534         y = mthing->y<<FRACBITS;
1535         if(mobjinfo[i].flags&MF_SPAWNCEILING)
1536         {
1537                 z = ONCEILINGZ;
1538         }
1539         else if(mobjinfo[i].flags2&MF2_SPAWNFLOAT)
1540         {
1541                 z = FLOATRANDZ;
1542         }
1543         else if(mobjinfo[i].flags2&MF2_FLOATBOB)
1544         {
1545                 z = mthing->height<<FRACBITS;
1546         }
1547         else
1548         {
1549                 z = ONFLOORZ;
1550         }
1551         switch(i)
1552         { // Special stuff
1553                 case MT_ZLYNCHED_NOHEART:
1554                         P_SpawnMobj(x, y, ONFLOORZ, MT_BLOODPOOL);
1555                         break;
1556                 default:
1557                         break;
1558         }
1559         mobj = P_SpawnMobj(x, y, z, i);
1560         if(z == ONFLOORZ)
1561         {
1562                 mobj->z += mthing->height<<FRACBITS;
1563         }
1564         else if(z == ONCEILINGZ)
1565         {
1566                 mobj->z -= mthing->height<<FRACBITS;
1567         }
1568         mobj->tid = mthing->tid;
1569         mobj->special = mthing->special;
1570         mobj->args[0] = mthing->arg1;
1571         mobj->args[1] = mthing->arg2;
1572         mobj->args[2] = mthing->arg3;
1573         mobj->args[3] = mthing->arg4;
1574         mobj->args[4] = mthing->arg5;
1575         if(mobj->flags2&MF2_FLOATBOB)
1576         { // Seed random starting index for bobbing motion
1577                 mobj->health = P_Random();
1578                 mobj->special1 = mthing->height<<FRACBITS;
1579         }
1580         if(mobj->tics > 0)
1581         {
1582                 mobj->tics = 1+(P_Random()%mobj->tics);
1583         }
1584 //      if(mobj->flags&MF_COUNTITEM)
1585 //      {
1586 //              totalitems++;
1587 //      }
1588         if (mobj->flags&MF_COUNTKILL)
1589         {
1590                 // Quantize angle to 45 degree increments
1591                 mobj->angle = ANG45*(mthing->angle/45);
1592         }
1593         else
1594         {
1595                 // Scale angle correctly (source is 0..359)
1596                 mobj->angle = ((mthing->angle<<8)/360)<<24;
1597         }
1598         if(mthing->options&MTF_AMBUSH)
1599         {
1600                 mobj->flags |= MF_AMBUSH;
1601         }
1602         if(mthing->options&MTF_DORMANT)
1603         {
1604                 mobj->flags2 |= MF2_DORMANT;
1605                 if(mobj->type == MT_ICEGUY)
1606                 {
1607                         P_SetMobjState(mobj, S_ICEGUY_DORMANT);
1608                 }
1609                 mobj->tics = -1;
1610         }
1611 }
1612
1613 //==========================================================================
1614 //
1615 // P_CreateTIDList
1616 //
1617 //==========================================================================
1618
1619 void P_CreateTIDList(void)
1620 {
1621         int i;
1622         mobj_t *mobj;
1623         thinker_t *t;
1624
1625         i = 0;
1626         for(t = thinkercap.next; t != &thinkercap; t = t->next)
1627         { // Search all current thinkers
1628                 if(t->function != P_MobjThinker)
1629                 { // Not a mobj thinker
1630                         continue;
1631                 }
1632                 mobj = (mobj_t *)t;
1633                 if(mobj->tid != 0)
1634                 { // Add to list
1635                         if(i == MAX_TID_COUNT)
1636                         {
1637                                 I_Error("P_CreateTIDList: MAX_TID_COUNT (%d) exceeded.",
1638                                         MAX_TID_COUNT);
1639                         }
1640                         TIDList[i] = mobj->tid;
1641                         TIDMobj[i++] = mobj;
1642                 }
1643         }
1644         // Add termination marker
1645         TIDList[i] = 0;
1646 }
1647
1648 //==========================================================================
1649 //
1650 // P_InsertMobjIntoTIDList
1651 //
1652 //==========================================================================
1653
1654 void P_InsertMobjIntoTIDList(mobj_t *mobj, int tid)
1655 {
1656         int i;
1657         int index;
1658
1659         index = -1;
1660         for(i = 0; TIDList[i] != 0; i++)
1661         {
1662                 if(TIDList[i] == -1)
1663                 { // Found empty slot
1664                         index = i;
1665                         break;
1666                 }
1667         }
1668         if(index == -1)
1669         { // Append required
1670                 if(i == MAX_TID_COUNT)
1671                 {
1672                         I_Error("P_InsertMobjIntoTIDList: MAX_TID_COUNT (%d)"
1673                                 "exceeded.", MAX_TID_COUNT);
1674                 }
1675                 index = i;
1676                 TIDList[index+1] = 0;
1677         }
1678         mobj->tid = tid;
1679         TIDList[index] = tid;
1680         TIDMobj[index] = mobj;
1681 }
1682
1683 //==========================================================================
1684 //
1685 // P_RemoveMobjFromTIDList
1686 //
1687 //==========================================================================
1688
1689 void P_RemoveMobjFromTIDList(mobj_t *mobj)
1690 {
1691         int i;
1692
1693         for(i = 0; TIDList[i] != 0; i++)
1694         {
1695                 if(TIDMobj[i] == mobj)
1696                 {
1697                         TIDList[i] = -1;
1698                         TIDMobj[i] = NULL;
1699                         mobj->tid = 0;
1700                         return;
1701                 }
1702         }
1703         mobj->tid = 0;
1704 }
1705
1706 //==========================================================================
1707 //
1708 // P_FindMobjFromTID
1709 //
1710 //==========================================================================
1711
1712 mobj_t *P_FindMobjFromTID(int tid, int *searchPosition)
1713 {
1714         int i;
1715
1716         for(i = *searchPosition+1; TIDList[i] != 0; i++)
1717         {
1718                 if(TIDList[i] == tid)
1719                 {
1720                         *searchPosition = i;
1721                         return TIDMobj[i];
1722                 }
1723         }
1724         *searchPosition = -1;
1725         return NULL;
1726 }
1727
1728 /*
1729 ===============================================================================
1730
1731                                                 GAME SPAWN FUNCTIONS
1732
1733 ===============================================================================
1734 */
1735
1736 //---------------------------------------------------------------------------
1737 //
1738 // PROC P_SpawnPuff
1739 //
1740 //---------------------------------------------------------------------------
1741
1742 extern fixed_t attackrange;
1743
1744 void P_SpawnPuff(fixed_t x, fixed_t y, fixed_t z)
1745 {
1746         mobj_t *puff;
1747
1748         z += ((P_Random()-P_Random())<<10);
1749         puff = P_SpawnMobj(x, y, z, PuffType);
1750         if(linetarget && puff->info->seesound)
1751         { // Hit thing sound
1752                 S_StartSound(puff, puff->info->seesound);
1753         }
1754         else if(puff->info->attacksound)
1755         {
1756                 S_StartSound(puff, puff->info->attacksound);
1757         }
1758         switch(PuffType)
1759         {
1760                 case MT_PUNCHPUFF:
1761                         puff->momz = FRACUNIT;
1762                         break;
1763                 case MT_HAMMERPUFF:
1764                         puff->momz = .8*FRACUNIT;
1765                         break;
1766                 default:
1767                         break;
1768         }
1769         PuffSpawned = puff;
1770 }
1771
1772 /*
1773 ================
1774 =
1775 = P_SpawnBlood
1776 =
1777 ================
1778 */
1779
1780 /*
1781 void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, int damage)
1782 {
1783         mobj_t  *th;
1784         
1785         z += ((P_Random()-P_Random())<<10);
1786         th = P_SpawnMobj (x,y,z, MT_BLOOD);
1787         th->momz = FRACUNIT*2;
1788         th->tics -= P_Random()&3;
1789
1790         if (damage <= 12 && damage >= 9)
1791                 P_SetMobjState (th,S_BLOOD2);
1792         else if (damage < 9)
1793                 P_SetMobjState (th,S_BLOOD3);
1794 }
1795 */
1796
1797 //---------------------------------------------------------------------------
1798 //
1799 // PROC P_BloodSplatter
1800 //
1801 //---------------------------------------------------------------------------
1802
1803 void P_BloodSplatter(fixed_t x, fixed_t y, fixed_t z, mobj_t *originator)
1804 {
1805         mobj_t *mo;
1806
1807         mo = P_SpawnMobj(x, y, z, MT_BLOODSPLATTER);
1808         mo->target = originator;
1809         mo->momx = (P_Random()-P_Random())<<10;
1810         mo->momy = (P_Random()-P_Random())<<10;
1811         mo->momz = 3*FRACUNIT;
1812 }
1813
1814 //===========================================================================
1815 //
1816 //  P_BloodSplatter2
1817 //
1818 //===========================================================================
1819
1820 void P_BloodSplatter2(fixed_t x, fixed_t y, fixed_t z, mobj_t *originator)
1821 {
1822         mobj_t *mo;
1823
1824         mo = P_SpawnMobj(x+((P_Random()-128)<<11), y+((P_Random()-128)<<11), z, 
1825                 MT_AXEBLOOD);
1826         mo->target = originator;
1827 }
1828
1829 //---------------------------------------------------------------------------
1830 //
1831 // PROC P_RipperBlood
1832 //
1833 //---------------------------------------------------------------------------
1834
1835 void P_RipperBlood(mobj_t *mo)
1836 {
1837         mobj_t *th;
1838         fixed_t x, y, z;
1839
1840         x = mo->x+((P_Random()-P_Random())<<12);
1841         y = mo->y+((P_Random()-P_Random())<<12);
1842         z = mo->z+((P_Random()-P_Random())<<12);
1843         th = P_SpawnMobj(x, y, z, MT_BLOOD);
1844 //      th->flags |= MF_NOGRAVITY;
1845         th->momx = mo->momx>>1;
1846         th->momy = mo->momy>>1;
1847         th->tics += P_Random()&3;
1848 }
1849
1850 //---------------------------------------------------------------------------
1851 //
1852 // FUNC P_GetThingFloorType
1853 //
1854 //---------------------------------------------------------------------------
1855
1856 int P_GetThingFloorType(mobj_t *thing)
1857 {
1858         if(thing->floorpic)
1859         {               
1860                 return(TerrainTypes[thing->floorpic]);
1861         }
1862         else
1863         {
1864                 return(TerrainTypes[thing->subsector->sector->floorpic]);
1865         }
1866 /*
1867         if(thing->subsector->sector->floorpic
1868                 == W_GetNumForName("FLTWAWA1")-firstflat)
1869         {
1870                 return(FLOOR_WATER);
1871         }
1872         else
1873         {
1874                 return(FLOOR_SOLID);
1875         }
1876 */
1877 }
1878
1879 //---------------------------------------------------------------------------
1880 //
1881 // FUNC P_HitFloor
1882 //
1883 //---------------------------------------------------------------------------
1884 #define SMALLSPLASHCLIP 12<<FRACBITS;
1885
1886 int P_HitFloor(mobj_t *thing)
1887 {
1888         mobj_t *mo;
1889         int smallsplash=false;
1890
1891         if(thing->floorz != thing->subsector->sector->floorheight)
1892         { // don't splash if landing on the edge above water/lava/etc....
1893                 return(FLOOR_SOLID);
1894         }
1895
1896         // Things that don't splash go here
1897         switch(thing->type)
1898         {
1899                 case MT_LEAF1:
1900                 case MT_LEAF2:
1901 //              case MT_BLOOD:                  // I set these to low mass -- pm
1902 //              case MT_BLOODSPLATTER:
1903                 case MT_SPLASH:
1904                 case MT_SLUDGECHUNK:
1905                         return(FLOOR_SOLID);
1906                 default:
1907                         break;
1908         }
1909
1910         // Small splash for small masses
1911         if (thing->info->mass < 10) smallsplash = true;
1912
1913         switch(P_GetThingFloorType(thing))
1914         {
1915                 case FLOOR_WATER:
1916                         if (smallsplash)
1917                         {
1918                                 mo=P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SPLASHBASE);
1919                                 if (mo) mo->floorclip += SMALLSPLASHCLIP;
1920                                 S_StartSound(mo, SFX_AMBIENT10);        // small drip
1921                         }
1922                         else
1923                         {
1924                                 mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SPLASH);
1925                                 mo->target = thing;
1926                                 mo->momx = (P_Random()-P_Random())<<8;
1927                                 mo->momy = (P_Random()-P_Random())<<8;
1928                                 mo->momz = 2*FRACUNIT+(P_Random()<<8);
1929                                 mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SPLASHBASE);
1930                                 if (thing->player) P_NoiseAlert(thing, thing);
1931                                 S_StartSound(mo, SFX_WATER_SPLASH);
1932                         }
1933                         return(FLOOR_WATER);
1934                 case FLOOR_LAVA:
1935                         if (smallsplash)
1936                         {
1937                                 mo=P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_LAVASPLASH);
1938                                 if (mo) mo->floorclip += SMALLSPLASHCLIP;
1939                         }
1940                         else
1941                         {
1942                                 mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_LAVASMOKE);
1943                                 mo->momz = FRACUNIT+(P_Random()<<7);
1944                                 mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_LAVASPLASH);
1945                                 if (thing->player) P_NoiseAlert(thing, thing);
1946                         }
1947                         S_StartSound(mo, SFX_LAVA_SIZZLE);
1948                         if(thing->player && leveltime&31)
1949                         {
1950                                 P_DamageMobj(thing, &LavaInflictor, NULL, 5);
1951                         }
1952                         return(FLOOR_LAVA);
1953                 case FLOOR_SLUDGE:
1954                         if (smallsplash)
1955                         {
1956                                 mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ,
1957                                         MT_SLUDGESPLASH);
1958                                 if (mo) mo->floorclip += SMALLSPLASHCLIP;
1959                         }
1960                         else
1961                         {
1962                                 mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, MT_SLUDGECHUNK);
1963                                 mo->target = thing;
1964                                 mo->momx = (P_Random()-P_Random())<<8;
1965                                 mo->momy = (P_Random()-P_Random())<<8;
1966                                 mo->momz = FRACUNIT+(P_Random()<<8);
1967                                 mo = P_SpawnMobj(thing->x, thing->y, ONFLOORZ, 
1968                                         MT_SLUDGESPLASH);
1969                                 if (thing->player) P_NoiseAlert(thing, thing);
1970                         }
1971                         S_StartSound(mo, SFX_SLUDGE_GLOOP);
1972                         return(FLOOR_SLUDGE);
1973         }
1974         return(FLOOR_SOLID);
1975 }
1976
1977
1978 //---------------------------------------------------------------------------
1979 //
1980 // FUNC P_CheckMissileSpawn
1981 //
1982 // Returns true if the missile is at a valid spawn point, otherwise
1983 // explodes it and returns false.
1984 //
1985 //---------------------------------------------------------------------------
1986
1987 boolean P_CheckMissileSpawn(mobj_t *missile)
1988 {
1989         //missile->tics -= P_Random()&3;
1990
1991         // move a little forward so an angle can be computed if it
1992         // immediately explodes
1993   /*
1994    * jim - handle fast missiles with BlasterMobjThinker()s
1995    * assume so if momentum > MAXMOVE
1996    * this is a horrible kludge, but to be honest so is the BlasterMobjThinker
1997    *  stuff in the first place
1998    */
1999   if ((missile->momx > MAXMOVE) || (missile->momy > MAXMOVE))
2000   {
2001     missile->x += (missile->momx>>3);
2002     missile->y += (missile->momy>>3);
2003     missile->z += (missile->momz>>3);
2004   }
2005   else
2006   {
2007         missile->x += (missile->momx>>1);
2008         missile->y += (missile->momy>>1);
2009         missile->z += (missile->momz>>1);
2010   }
2011         if(!P_TryMove(missile, missile->x, missile->y))
2012         {
2013                 P_ExplodeMissile(missile);
2014                 return(false);
2015         }
2016         return(true);
2017 }
2018
2019 //---------------------------------------------------------------------------
2020 //
2021 // FUNC P_SpawnMissile
2022 //
2023 // Returns NULL if the missile exploded immediately, otherwise returns
2024 // a mobj_t pointer to the missile.
2025 //
2026 //---------------------------------------------------------------------------
2027
2028 mobj_t *P_SpawnMissile(mobj_t *source, mobj_t *dest, mobjtype_t type)
2029 {
2030         fixed_t z;
2031         mobj_t *th;
2032         angle_t an;
2033         int dist;
2034
2035         switch(type)
2036         {
2037                 case MT_MNTRFX1: // Minotaur swing attack missile
2038                         z = source->z+40*FRACUNIT;
2039                         break;
2040                 case MT_MNTRFX2: // Minotaur floor fire missile
2041                         z = ONFLOORZ+source->floorclip;
2042                         break;
2043                 case MT_CENTAUR_FX:
2044                         z = source->z+45*FRACUNIT;
2045                         break;
2046                 case MT_ICEGUY_FX:
2047                         z = source->z+40*FRACUNIT;
2048                         break;
2049                 case MT_HOLY_MISSILE:
2050                         z = source->z+40*FRACUNIT;
2051                         break;
2052                 default:
2053                         z = source->z+32*FRACUNIT;
2054                         break;
2055         }
2056         z -= source->floorclip;
2057         th = P_SpawnMobj(source->x, source->y, z, type);
2058         if(th->info->seesound)
2059         {
2060                 S_StartSound(th, th->info->seesound);
2061         }
2062         th->target = source; // Originator
2063         an = R_PointToAngle2(source->x, source->y, dest->x, dest->y);
2064         if(dest->flags&MF_SHADOW)
2065         { // Invisible target
2066                 an += (P_Random()-P_Random())<<21;
2067         }
2068         th->angle = an;
2069         an >>= ANGLETOFINESHIFT;
2070         th->momx = FixedMul(th->info->speed, finecosine[an]);
2071         th->momy = FixedMul(th->info->speed, finesine[an]);
2072         dist = P_AproxDistance(dest->x - source->x, dest->y - source->y);
2073         dist = dist/th->info->speed;
2074         if(dist < 1)
2075         {
2076                 dist = 1;
2077         }
2078         th->momz = (dest->z-source->z)/dist;
2079         return(P_CheckMissileSpawn(th) ? th : NULL);
2080 }
2081
2082 //---------------------------------------------------------------------------
2083 //
2084 // FUNC P_SpawnMissileXYZ
2085 //
2086 // Returns NULL if the missile exploded immediately, otherwise returns
2087 // a mobj_t pointer to the missile.
2088 //
2089 //---------------------------------------------------------------------------
2090
2091 mobj_t *P_SpawnMissileXYZ(fixed_t x, fixed_t y, fixed_t z,
2092         mobj_t *source, mobj_t *dest, mobjtype_t type)
2093 {
2094         mobj_t *th;
2095         angle_t an;
2096         int dist;
2097
2098         z -= source->floorclip;
2099         th = P_SpawnMobj(x, y, z, type);
2100         if(th->info->seesound)
2101         {
2102                 S_StartSound(th, th->info->seesound);
2103         }
2104         th->target = source; // Originator
2105         an = R_PointToAngle2(source->x, source->y, dest->x, dest->y);
2106         if(dest->flags&MF_SHADOW)
2107         { // Invisible target
2108                 an += (P_Random()-P_Random())<<21;
2109         }
2110         th->angle = an;
2111         an >>= ANGLETOFINESHIFT;
2112         th->momx = FixedMul(th->info->speed, finecosine[an]);
2113         th->momy = FixedMul(th->info->speed, finesine[an]);
2114         dist = P_AproxDistance(dest->x - source->x, dest->y - source->y);
2115         dist = dist/th->info->speed;
2116         if(dist < 1)
2117         {
2118                 dist = 1;
2119         }
2120         th->momz = (dest->z-source->z)/dist;
2121         return(P_CheckMissileSpawn(th) ? th : NULL);
2122 }
2123
2124 //---------------------------------------------------------------------------
2125 //
2126 // FUNC P_SpawnMissileAngle
2127 //
2128 // Returns NULL if the missile exploded immediately, otherwise returns
2129 // a mobj_t pointer to the missile.
2130 //
2131 //---------------------------------------------------------------------------
2132
2133 mobj_t *P_SpawnMissileAngle(mobj_t *source, mobjtype_t type,
2134         angle_t angle, fixed_t momz)
2135 {
2136         fixed_t z;
2137         mobj_t *mo;
2138
2139         switch(type)
2140         {
2141                 case MT_MNTRFX1: // Minotaur swing attack missile
2142                         z = source->z+40*FRACUNIT;
2143                         break;
2144                 case MT_MNTRFX2: // Minotaur floor fire missile
2145                         z = ONFLOORZ+source->floorclip;
2146                         break;
2147                 case MT_ICEGUY_FX2: // Secondary Projectiles of the Ice Guy
2148                         z = source->z+3*FRACUNIT;
2149                         break;
2150                 case MT_MSTAFF_FX2:
2151                         z = source->z+40*FRACUNIT;
2152                         break;
2153                 default:
2154                         z = source->z+32*FRACUNIT;
2155                         break;
2156         }
2157         z -= source->floorclip;
2158         mo = P_SpawnMobj(source->x, source->y, z, type);
2159         if(mo->info->seesound)
2160         {
2161                 S_StartSound(mo, mo->info->seesound);
2162         }
2163         mo->target = source; // Originator
2164         mo->angle = angle;
2165         angle >>= ANGLETOFINESHIFT;
2166         mo->momx = FixedMul(mo->info->speed, finecosine[angle]);
2167         mo->momy = FixedMul(mo->info->speed, finesine[angle]);
2168         mo->momz = momz;
2169         return(P_CheckMissileSpawn(mo) ? mo : NULL);
2170 }
2171
2172 //---------------------------------------------------------------------------
2173 //
2174 // FUNC P_SpawnMissileAngleSpeed
2175 //
2176 // Returns NULL if the missile exploded immediately, otherwise returns
2177 // a mobj_t pointer to the missile.
2178 //
2179 //---------------------------------------------------------------------------
2180
2181 mobj_t *P_SpawnMissileAngleSpeed(mobj_t *source, mobjtype_t type,
2182         angle_t angle, fixed_t momz, fixed_t speed)
2183 {
2184         fixed_t z;
2185         mobj_t *mo;
2186
2187         z = source->z;
2188         z -= source->floorclip;
2189         mo = P_SpawnMobj(source->x, source->y, z, type);
2190         if(mo->info->seesound)
2191         {
2192                 //S_StartSound(mo, mo->info->seesound);
2193         }
2194         mo->target = source; // Originator
2195         mo->angle = angle;
2196         angle >>= ANGLETOFINESHIFT;
2197         mo->momx = FixedMul(speed, finecosine[angle]);
2198         mo->momy = FixedMul(speed, finesine[angle]);
2199         mo->momz = momz;
2200         return(P_CheckMissileSpawn(mo) ? mo : NULL);
2201 }
2202
2203
2204
2205 /*
2206 ================
2207 =
2208 = P_SpawnPlayerMissile
2209 =
2210 = Tries to aim at a nearby monster
2211 ================
2212 */
2213
2214 mobj_t *P_SpawnPlayerMissile(mobj_t *source, mobjtype_t type)
2215 {
2216         angle_t an;
2217         fixed_t x, y, z, slope;
2218
2219         // Try to find a target
2220         an = source->angle;
2221         slope = P_AimLineAttack(source, an, 16*64*FRACUNIT);
2222         if(!linetarget)
2223         {
2224                 an += 1<<26;
2225                 slope = P_AimLineAttack(source, an, 16*64*FRACUNIT);
2226                 if(!linetarget)
2227                 {
2228                         an -= 2<<26;
2229                         slope = P_AimLineAttack(source, an, 16*64*FRACUNIT);
2230                 }
2231                 if(!linetarget)
2232                 {
2233                         an = source->angle;
2234                         slope = ((source->player->lookdir)<<FRACBITS)/173;
2235                 }
2236         }
2237         x = source->x;
2238         y = source->y;
2239         if(type == MT_LIGHTNING_FLOOR)
2240         {       
2241                 z = ONFLOORZ;
2242                 slope = 0;
2243         }
2244         else if(type == MT_LIGHTNING_CEILING)
2245         {
2246                 z = ONCEILINGZ;
2247                 slope = 0;
2248         }
2249         else
2250         {
2251                 z = source->z + 4*8*FRACUNIT+((source->player->lookdir)<<FRACBITS)/173;
2252                 z -= source->floorclip;
2253         }
2254         MissileMobj = P_SpawnMobj(x, y, z, type);
2255         if(MissileMobj->info->seesound)
2256         {
2257                 //S_StartSound(MissileMobj, MissileMobj->info->seesound);
2258         }
2259         MissileMobj->target = source;
2260         MissileMobj->angle = an;
2261         MissileMobj->momx = FixedMul(MissileMobj->info->speed,
2262                 finecosine[an>>ANGLETOFINESHIFT]);
2263         MissileMobj->momy = FixedMul(MissileMobj->info->speed,
2264                 finesine[an>>ANGLETOFINESHIFT]);
2265         MissileMobj->momz = FixedMul(MissileMobj->info->speed, slope);
2266         if(MissileMobj->type == MT_MWAND_MISSILE 
2267                 || MissileMobj->type == MT_CFLAME_MISSILE)
2268         { // Ultra-fast ripper spawning missile
2269                 MissileMobj->x += (MissileMobj->momx>>3);
2270                 MissileMobj->y += (MissileMobj->momy>>3);
2271                 MissileMobj->z += (MissileMobj->momz>>3);
2272         }
2273         else
2274         { // Normal missile
2275                 MissileMobj->x += (MissileMobj->momx>>1);
2276                 MissileMobj->y += (MissileMobj->momy>>1);
2277                 MissileMobj->z += (MissileMobj->momz>>1);
2278         }
2279         if(!P_TryMove(MissileMobj, MissileMobj->x, MissileMobj->y))
2280         { // Exploded immediately
2281                 P_ExplodeMissile(MissileMobj);
2282                 return(NULL);
2283         }
2284         return(MissileMobj);
2285 }
2286
2287
2288 //----------------------------------------------------------------------------
2289 //
2290 // P_SpawnPlayerMinotaur - 
2291 //
2292 //      Special missile that has larger blocking than player
2293 //----------------------------------------------------------------------------
2294
2295 /*
2296 mobj_t *P_SpawnPlayerMinotaur(mobj_t *source, mobjtype_t type)
2297 {
2298         angle_t an;
2299         fixed_t x, y, z;
2300         fixed_t dist=0 *FRACUNIT;
2301
2302         an = source->angle;
2303         x = source->x + FixedMul(dist, finecosine[an>>ANGLETOFINESHIFT]);
2304         y = source->y + FixedMul(dist, finesine[an>>ANGLETOFINESHIFT]);
2305         z = source->z + 4*8*FRACUNIT+((source->player->lookdir)<<FRACBITS)/173;
2306         z -= source->floorclip;
2307         MissileMobj = P_SpawnMobj(x, y, z, type);
2308         if(MissileMobj->info->seesound)
2309         {
2310                 //S_StartSound(MissileMobj, MissileMobj->info->seesound);
2311         }
2312         MissileMobj->target = source;
2313         MissileMobj->angle = an;
2314         MissileMobj->momx = FixedMul(MissileMobj->info->speed,
2315                 finecosine[an>>ANGLETOFINESHIFT]);
2316         MissileMobj->momy = FixedMul(MissileMobj->info->speed,
2317                 finesine[an>>ANGLETOFINESHIFT]);
2318         MissileMobj->momz = 0;
2319
2320 //      MissileMobj->x += (MissileMobj->momx>>3);
2321 //      MissileMobj->y += (MissileMobj->momy>>3);
2322 //      MissileMobj->z += (MissileMobj->momz>>3);
2323
2324         if(!P_TryMove(MissileMobj, MissileMobj->x, MissileMobj->y))
2325         { // Wouln't fit
2326
2327                 return(NULL);
2328         }
2329         return(MissileMobj);
2330 }
2331 */
2332
2333 //---------------------------------------------------------------------------
2334 //
2335 // PROC P_SPMAngle
2336 //
2337 //---------------------------------------------------------------------------
2338
2339 mobj_t *P_SPMAngle(mobj_t *source, mobjtype_t type, angle_t angle)
2340 {
2341         mobj_t *th;
2342         angle_t an;
2343         fixed_t x, y, z, slope;
2344
2345 //
2346 // see which target is to be aimed at
2347 //
2348         an = angle;
2349         slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
2350         if (!linetarget)
2351         {
2352                 an += 1<<26;
2353                 slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
2354                 if (!linetarget)
2355                 {
2356                         an -= 2<<26;
2357                         slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
2358                 }
2359                 if (!linetarget)
2360                 {
2361                         an = angle;
2362                         slope = ((source->player->lookdir)<<FRACBITS)/173;
2363                 }
2364         }
2365         x = source->x;
2366         y = source->y;
2367         z = source->z + 4*8*FRACUNIT+((source->player->lookdir)<<FRACBITS)/173;
2368         z -= source->floorclip;
2369         th = P_SpawnMobj(x, y, z, type);
2370 //      if(th->info->seesound)
2371 //      {
2372 //              S_StartSound(th, th->info->seesound);
2373 //      }
2374         th->target = source;
2375         th->angle = an;
2376         th->momx = FixedMul(th->info->speed, finecosine[an>>ANGLETOFINESHIFT]);
2377         th->momy = FixedMul(th->info->speed, finesine[an>>ANGLETOFINESHIFT]);
2378         th->momz = FixedMul(th->info->speed, slope);
2379         return(P_CheckMissileSpawn(th) ? th : NULL);
2380 }
2381
2382 //===========================================================================
2383 //
2384 // P_SPMAngleXYZ
2385 //
2386 //===========================================================================
2387
2388 mobj_t *P_SPMAngleXYZ(mobj_t *source, fixed_t x, fixed_t y, 
2389         fixed_t z, mobjtype_t type, angle_t angle)
2390 {
2391         mobj_t *th;
2392         angle_t an;
2393         fixed_t slope;
2394
2395 //
2396 // see which target is to be aimed at
2397 //
2398         an = angle;
2399         slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
2400         if (!linetarget)
2401         {
2402                 an += 1<<26;
2403                 slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
2404                 if (!linetarget)
2405                 {
2406                         an -= 2<<26;
2407                         slope = P_AimLineAttack (source, an, 16*64*FRACUNIT);
2408                 }
2409                 if (!linetarget)
2410                 {
2411                         an = angle;
2412                         slope = ((source->player->lookdir)<<FRACBITS)/173;
2413                 }
2414         }
2415         z += 4*8*FRACUNIT+((source->player->lookdir)<<FRACBITS)/173;
2416         z -= source->floorclip;
2417         th = P_SpawnMobj(x, y, z, type);
2418 //      if(th->info->seesound)
2419 //      {
2420 //              S_StartSound(th, th->info->seesound);
2421 //      }
2422         th->target = source;
2423         th->angle = an;
2424         th->momx = FixedMul(th->info->speed, finecosine[an>>ANGLETOFINESHIFT]);
2425         th->momy = FixedMul(th->info->speed, finesine[an>>ANGLETOFINESHIFT]);
2426         th->momz = FixedMul(th->info->speed, slope);
2427         return(P_CheckMissileSpawn(th) ? th : NULL);
2428 }
2429
2430 mobj_t *P_SpawnKoraxMissile(fixed_t x, fixed_t y, fixed_t z,
2431         mobj_t *source, mobj_t *dest, mobjtype_t type)
2432 {
2433         mobj_t *th;
2434         angle_t an;
2435         int dist;
2436
2437         z -= source->floorclip;
2438         th = P_SpawnMobj(x, y, z, type);
2439         if(th->info->seesound)
2440         {
2441                 S_StartSound(th, th->info->seesound);
2442         }
2443         th->target = source; // Originator
2444         an = R_PointToAngle2(x, y, dest->x, dest->y);
2445         if(dest->flags&MF_SHADOW)
2446         { // Invisible target
2447                 an += (P_Random()-P_Random())<<21;
2448         }
2449         th->angle = an;
2450         an >>= ANGLETOFINESHIFT;
2451         th->momx = FixedMul(th->info->speed, finecosine[an]);
2452         th->momy = FixedMul(th->info->speed, finesine[an]);
2453         dist = P_AproxDistance(dest->x - x, dest->y - y);
2454         dist = dist/th->info->speed;
2455         if(dist < 1)
2456         {
2457                 dist = 1;
2458         }
2459         th->momz = (dest->z-z+(30*FRACUNIT))/dist;
2460         return(P_CheckMissileSpawn(th) ? th : NULL);
2461 }
2462