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