2 //**************************************************************************
4 //** p_user.c : Heretic 2 : Raven Software, Corp.
11 //**************************************************************************
17 void P_PlayerNextArtifact(player_t *player);
21 #define MAXBOB 0x100000 // 16 pixels of bob
26 int newtorch; // used in the torch flicker effect.
29 int PStateNormal[NUMCLASSES] =
38 int PStateRun[NUMCLASSES] =
47 int PStateAttack[NUMCLASSES] =
56 int PStateAttackEnd[NUMCLASSES] =
65 int ArmorMax[NUMCLASSES] = { 20, 18, 16, 17, 1 };
71 = moves the given origin along a given angle
76 void P_Thrust(player_t *player, angle_t angle, fixed_t move)
78 angle >>= ANGLETOFINESHIFT;
79 if(player->powers[pw_flight] && !(player->mo->z <= player->mo->floorz))
81 player->mo->momx += FixedMul(move, finecosine[angle]);
82 player->mo->momy += FixedMul(move, finesine[angle]);
84 else if(P_GetThingFloorType(player->mo) == FLOOR_ICE) // Friction_Low
86 player->mo->momx += FixedMul(move>>1, finecosine[angle]);
87 player->mo->momy += FixedMul(move>>1, finesine[angle]);
91 player->mo->momx += FixedMul(move, finecosine[angle]);
92 player->mo->momy += FixedMul(move, finesine[angle]);
103 Calculate the walking / running height adjustment
108 void P_CalcHeight (player_t *player)
114 // regular movement bobbing (needs to be calculated for gun swing even
116 // OPTIMIZE: tablify angle
118 player->bob = FixedMul (player->mo->momx, player->mo->momx)+
119 FixedMul (player->mo->momy,player->mo->momy);
121 if (player->bob>MAXBOB)
122 player->bob = MAXBOB;
123 if(player->mo->flags2&MF2_FLY && !onground)
125 player->bob = FRACUNIT/2;
128 if ((player->cheats & CF_NOMOMENTUM))
130 player->viewz = player->mo->z + VIEWHEIGHT;
131 if (player->viewz > player->mo->ceilingz-4*FRACUNIT)
132 player->viewz = player->mo->ceilingz-4*FRACUNIT;
133 player->viewz = player->mo->z + player->viewheight;
137 angle = (FINEANGLES/20*leveltime)&FINEMASK;
138 bob = FixedMul ( player->bob/2, finesine[angle]);
143 if (player->playerstate == PST_LIVE)
145 player->viewheight += player->deltaviewheight;
146 if (player->viewheight > VIEWHEIGHT)
148 player->viewheight = VIEWHEIGHT;
149 player->deltaviewheight = 0;
151 if (player->viewheight < VIEWHEIGHT/2)
153 player->viewheight = VIEWHEIGHT/2;
154 if (player->deltaviewheight <= 0)
155 player->deltaviewheight = 1;
158 if (player->deltaviewheight)
160 player->deltaviewheight += FRACUNIT/4;
161 if (!player->deltaviewheight)
162 player->deltaviewheight = 1;
166 if(player->morphTics)
168 player->viewz = player->mo->z+player->viewheight-(20*FRACUNIT);
172 player->viewz = player->mo->z+player->viewheight+bob;
174 if(player->mo->floorclip && player->playerstate != PST_DEAD
175 && player->mo->z <= player->mo->floorz)
177 player->viewz -= player->mo->floorclip;
179 if(player->viewz > player->mo->ceilingz-4*FRACUNIT)
181 player->viewz = player->mo->ceilingz-4*FRACUNIT;
183 if(player->viewz < player->mo->floorz+4*FRACUNIT)
185 player->viewz = player->mo->floorz+4*FRACUNIT;
197 void P_MovePlayer(player_t *player)
204 player->mo->angle += (cmd->angleturn<<16);
206 onground = (player->mo->z <= player->mo->floorz
207 || (player->mo->flags2&MF2_ONMOBJ));
211 if(onground || player->mo->flags2&MF2_FLY)
213 P_Thrust(player, player->mo->angle, cmd->forwardmove*2048);
217 P_Thrust(player, player->mo->angle, FRACUNIT>>8);
222 if(onground || player->mo->flags2&MF2_FLY)
224 P_Thrust(player, player->mo->angle-ANG90, cmd->sidemove*2048);
228 P_Thrust(player, player->mo->angle, FRACUNIT>>8);
231 if(cmd->forwardmove || cmd->sidemove)
233 if(player->mo->state == &states[PStateNormal[player->class]])
235 P_SetMobjState(player->mo, PStateRun[player->class]);
239 look = cmd->lookfly&15;
248 player->centering = true;
252 player->lookdir += 5*look;
253 if(player->lookdir > 90 || player->lookdir < -110)
255 player->lookdir -= 5*look;
259 if(player->centering)
261 if(player->lookdir > 0)
263 player->lookdir -= 8;
265 else if(player->lookdir < 0)
267 player->lookdir += 8;
269 if(abs(player->lookdir) < 8)
272 player->centering = false;
275 fly = cmd->lookfly>>4;
280 if(fly && player->powers[pw_flight])
284 player->flyheight = fly*2;
285 if(!(player->mo->flags2&MF2_FLY))
287 player->mo->flags2 |= MF2_FLY;
288 player->mo->flags |= MF_NOGRAVITY;
289 if(player->mo->momz <= -39*FRACUNIT)
290 { // stop falling scream
291 S_StopSound(player->mo);
297 player->mo->flags2 &= ~MF2_FLY;
298 player->mo->flags &= ~MF_NOGRAVITY;
303 P_PlayerUseArtifact(player, arti_fly);
305 if(player->mo->flags2&MF2_FLY)
307 player->mo->momz = player->flyheight*FRACUNIT;
308 if(player->flyheight)
310 player->flyheight /= 2;
315 //==========================================================================
319 //==========================================================================
321 void P_DeathThink(player_t *player)
329 P_MovePsprites(player);
331 onground = (player->mo->z <= player->mo->floorz);
332 if(player->mo->type == MT_BLOODYSKULL || player->mo->type == MT_ICECHUNK)
333 { // Flying bloody skull or flying ice chunk
334 player->viewheight = 6*FRACUNIT;
335 player->deltaviewheight = 0;
336 //player->damagecount = 20;
339 if(player->lookdir < 60)
341 lookDelta = (60-player->lookdir)/8;
342 if(lookDelta < 1 && (leveltime&1))
346 else if(lookDelta > 6)
350 player->lookdir += lookDelta;
354 else if(!(player->mo->flags2&MF2_ICEDAMAGE))
355 { // Fall to ground (if not frozen)
356 player->deltaviewheight = 0;
357 if(player->viewheight > 6*FRACUNIT)
359 player->viewheight -= FRACUNIT;
361 if(player->viewheight < 6*FRACUNIT)
363 player->viewheight = 6*FRACUNIT;
365 if(player->lookdir > 0)
367 player->lookdir -= 6;
369 else if(player->lookdir < 0)
371 player->lookdir += 6;
373 if(abs(player->lookdir) < 6)
378 P_CalcHeight(player);
380 if(player->attacker && player->attacker != player->mo)
382 dir = P_FaceMobj(player->mo, player->attacker, &delta);
383 if(delta < ANGLE_1*10)
384 { // Looking at killer, so fade damage and poison counters
385 if(player->damagecount)
387 player->damagecount--;
389 if(player->poisoncount)
391 player->poisoncount--;
395 if(delta > ANGLE_1*5)
401 player->mo->angle += delta;
404 { // Turn counter clockwise
405 player->mo->angle -= delta;
408 else if(player->damagecount || player->poisoncount)
410 if(player->damagecount)
412 player->damagecount--;
416 player->poisoncount--;
420 if(player->cmd.buttons&BT_USE)
422 if(player == &players[consoleplayer])
424 I_SetPalette((byte *)W_CacheLumpName("PLAYPAL", PU_CACHE));
430 player->playerstate = PST_REBORN;
431 player->mo->special1 = player->class;
432 if(player->mo->special1 > 2)
434 player->mo->special1 = 0;
436 // Let the mobj know the player has entered the reborn state. Some
437 // mobjs need to know when it's ok to remove themselves.
438 player->mo->special2 = 666;
442 //----------------------------------------------------------------------------
444 // PROC P_MorphPlayerThink
446 //----------------------------------------------------------------------------
448 void P_MorphPlayerThink(player_t *player)
452 if(player->morphTics&15)
457 if(!(pmo->momx+pmo->momy) && P_Random() < 64)
459 P_SetPspriteNF(player, ps_weapon, S_SNOUTATK2);
460 S_StartSound(pmo, SFX_PIG_ACTIVE1); // snort
467 S_StartSound(pmo, SFX_PIG_ACTIVE1);
471 S_StartSound(pmo, SFX_PIG_ACTIVE2);
476 //----------------------------------------------------------------------------
478 // FUNC P_GetPlayerNum
480 //----------------------------------------------------------------------------
482 int P_GetPlayerNum(player_t *player)
486 for(i = 0; i < MAXPLAYERS; i++)
488 if(player == &players[i])
496 //----------------------------------------------------------------------------
498 // FUNC P_UndoPlayerMorph
500 //----------------------------------------------------------------------------
502 boolean P_UndoPlayerMorph(player_t *player)
522 weapon = pmo->special1;
523 oldFlags = pmo->flags;
524 oldFlags2 = pmo->flags2;
525 oldBeast = pmo->type;
526 P_SetMobjState(pmo, S_FREETARGMOBJ);
527 playerNum = P_GetPlayerNum(player);
528 switch(PlayerClass[playerNum])
531 mo = P_SpawnMobj(x, y, z, MT_PLAYER_FIGHTER);
534 mo = P_SpawnMobj(x, y, z, MT_PLAYER_CLERIC);
537 mo = P_SpawnMobj(x, y, z, MT_PLAYER_MAGE);
540 mo = P_SpawnMobj(x, y, z, MT_PLAYER_ASS);
543 I_Error("P_UndoPlayerMorph: Unknown player class %d\n",
545 /* jim never happens but keeps gcc happy */
549 if(P_TestMobjLocation(mo) == false)
552 mo = P_SpawnMobj(x, y, z, oldBeast);
554 mo->health = player->health;
555 mo->special1 = weapon;
557 mo->flags = oldFlags;
558 mo->flags2 = oldFlags2;
560 player->morphTics = 2*35;
563 if(player->class == PCLASS_FIGHTER)
565 // The first type should be blue, and the third should be the
566 // Fighter's original gold color
569 mo->flags |= 2<<MF_TRANSSHIFT;
571 else if(playerNum != 2)
573 mo->flags |= playerNum<<MF_TRANSSHIFT;
577 { // Set color translation bits for player sprites
578 mo->flags |= playerNum<<MF_TRANSSHIFT;
582 mo->reactiontime = 18;
583 if(oldFlags2&MF2_FLY)
585 mo->flags2 |= MF2_FLY;
586 mo->flags |= MF_NOGRAVITY;
588 player->morphTics = 0;
589 player->health = mo->health = MAXHEALTH;
591 player->class = PlayerClass[playerNum];
592 angle >>= ANGLETOFINESHIFT;
593 fog = P_SpawnMobj(x+20*finecosine[angle],
594 y+20*finesine[angle], z+TELEFOGHEIGHT, MT_TFOG);
595 S_StartSound(fog, SFX_TELEPORT);
596 P_PostMorphWeapon(player, weapon);
601 //----------------------------------------------------------------------------
603 // PROC P_PlayerThink
605 //----------------------------------------------------------------------------
607 void P_PlayerThink(player_t *player)
610 weapontype_t newweapon;
615 if(player->cheats&CF_NOCLIP)
617 player->mo->flags |= MF_NOCLIP;
621 player->mo->flags &= ~MF_NOCLIP;
624 if(player->mo->flags&MF_JUSTATTACKED)
625 { // Gauntlets attack auto forward motion
627 cmd->forwardmove = 0xc800/512;
629 player->mo->flags &= ~MF_JUSTATTACKED;
631 // messageTics is above the rest of the counters so that messages will
632 // go away, even in death.
633 player->messageTics--; // Can go negative
634 if(!player->messageTics || player->messageTics == -1)
635 { // Refresh the screen when a message goes away
636 player->ultimateMessage = false; // clear out any chat messages.
637 player->yellowMessage = false;
638 if(player == &players[consoleplayer])
640 BorderTopRefresh = true;
643 player->worldTimer++;
644 if(player->playerstate == PST_DEAD)
646 P_DeathThink(player);
653 if(player->morphTics)
655 P_MorphPlayerThink(player);
658 if(player->mo->reactiontime)
659 { // Player is frozen
660 player->mo->reactiontime--;
664 P_MovePlayer(player);
666 if(player->powers[pw_speed] && !(leveltime&1)
667 && P_AproxDistance(pmo->momx, pmo->momy) > 12*FRACUNIT)
672 speedMo = P_SpawnMobj(pmo->x, pmo->y, pmo->z, MT_PLAYER_SPEED);
675 speedMo->angle = pmo->angle;
676 playerNum = P_GetPlayerNum(player);
677 if(player->class == PCLASS_FIGHTER)
679 // The first type should be blue, and the
680 // third should be the Fighter's original gold color
683 speedMo->flags |= 2<<MF_TRANSSHIFT;
685 else if(playerNum != 2)
687 speedMo->flags |= playerNum<<MF_TRANSSHIFT;
691 { // Set color translation bits for player sprites
692 speedMo->flags |= playerNum<<MF_TRANSSHIFT;
694 speedMo->target = pmo;
695 speedMo->special1 = player->class;
696 if(speedMo->special1 > 2)
698 speedMo->special1 = 0;
700 speedMo->sprite = pmo->sprite;
701 speedMo->floorclip = pmo->floorclip;
702 if(player == &players[consoleplayer])
704 speedMo->flags2 |= MF2_DONTDRAW;
709 P_CalcHeight(player);
710 if(player->mo->subsector->sector->special)
712 P_PlayerInSpecialSector(player);
714 if((floorType = P_GetThingFloorType(player->mo)) != FLOOR_SOLID)
716 P_PlayerOnSpecialFlat(player, floorType);
718 switch(player->class)
721 if(player->mo->momz <= -35*FRACUNIT
722 && player->mo->momz >= -40*FRACUNIT && !player->morphTics
723 && !S_GetSoundPlayingInfo(player->mo,
724 SFX_PLAYER_FIGHTER_FALLING_SCREAM))
726 S_StartSound(player->mo,
727 SFX_PLAYER_FIGHTER_FALLING_SCREAM);
731 if(player->mo->momz <= -35*FRACUNIT
732 && player->mo->momz >= -40*FRACUNIT && !player->morphTics
733 && !S_GetSoundPlayingInfo(player->mo,
734 SFX_PLAYER_CLERIC_FALLING_SCREAM))
736 S_StartSound(player->mo,
737 SFX_PLAYER_CLERIC_FALLING_SCREAM);
741 if(player->mo->momz <= -35*FRACUNIT
742 && player->mo->momz >= -40*FRACUNIT && !player->morphTics
743 && !S_GetSoundPlayingInfo(player->mo,
744 SFX_PLAYER_MAGE_FALLING_SCREAM))
746 S_StartSound(player->mo,
747 SFX_PLAYER_MAGE_FALLING_SCREAM);
750 if(player->mo->momz <= -35*FRACUNIT
751 && player->mo->momz >= -40*FRACUNIT && !player->morphTics
752 && !S_GetSoundPlayingInfo(player->mo,
753 SFX_PLAYER_MAGE_FALLING_SCREAM))
755 S_StartSound(player->mo,
756 SFX_PLAYER_MAGE_FALLING_SCREAM);
763 if((cmd->arti&AFLAG_JUMP) && onground && !player->jumpTics)
765 if(player->morphTics)
767 player->mo->momz = 6*FRACUNIT;
771 player->mo->momz = 9*FRACUNIT;
773 player->mo->flags2 &= ~MF2_ONMOBJ;
774 player->jumpTics = 18;
776 else if(cmd->arti&AFLAG_SUICIDE)
778 P_DamageMobj(player->mo, NULL, NULL, 10000);
780 if(cmd->arti == NUMARTIFACTS)
781 { // use one of each artifact (except puzzle artifacts)
784 for(i = 1; i < arti_firstpuzzitem; i++)
786 P_PlayerUseArtifact(player, i);
791 P_PlayerUseArtifact(player, cmd->arti&AFLAG_MASK);
794 // Check for weapon change
795 if(cmd->buttons&BT_SPECIAL)
796 { // A special event has no other buttons
799 if(cmd->buttons&BT_CHANGE && !player->morphTics)
801 // The actual changing of the weapon is done when the weapon
802 // psprite can do it (A_WeaponReady), so it doesn't happen in
803 // the middle of an attack.
804 newweapon = (cmd->buttons&BT_WEAPONMASK)>>BT_WEAPONSHIFT;
805 if(player->weaponowned[newweapon]
806 && newweapon != player->readyweapon)
808 player->pendingweapon = newweapon;
812 if(cmd->buttons&BT_USE)
817 player->usedown = true;
822 player->usedown = false;
825 if(player->morphTics)
827 if(!--player->morphTics)
828 { // Attempt to undo the pig
829 P_UndoPlayerMorph(player);
833 P_MovePsprites(player);
835 if(player->powers[pw_invulnerability])
837 if(player->class == PCLASS_CLERIC)
839 if(!(leveltime&7) && player->mo->flags&MF_SHADOW
840 && !(player->mo->flags2&MF2_DONTDRAW))
842 player->mo->flags &= ~MF_SHADOW;
843 if(!(player->mo->flags&MF_ALTSHADOW))
845 player->mo->flags2 |= MF2_DONTDRAW|MF2_NONSHOOTABLE;
850 if(player->mo->flags2&MF2_DONTDRAW)
852 if(!(player->mo->flags&MF_SHADOW))
854 player->mo->flags |= MF_SHADOW|MF_ALTSHADOW;
858 player->mo->flags2 &= ~(MF2_DONTDRAW|MF2_NONSHOOTABLE);
863 player->mo->flags |= MF_SHADOW;
864 player->mo->flags &= ~MF_ALTSHADOW;
868 if(!(--player->powers[pw_invulnerability]))
870 player->mo->flags2 &= ~(MF2_INVULNERABLE|MF2_REFLECTIVE);
871 if(player->class == PCLASS_CLERIC)
873 player->mo->flags2 &= ~(MF2_DONTDRAW|MF2_NONSHOOTABLE);
874 player->mo->flags &= ~(MF_SHADOW|MF_ALTSHADOW);
878 if(player->powers[pw_minotaur])
880 player->powers[pw_minotaur]--;
882 if(player->powers[pw_infrared])
884 player->powers[pw_infrared]--;
886 if(player->powers[pw_flight] && netgame)
888 if(!--player->powers[pw_flight])
890 // if(player->mo->z != player->mo->floorz) { }
891 player->mo->flags2 &= ~MF2_FLY;
892 player->mo->flags &= ~MF_NOGRAVITY;
893 BorderTopRefresh = true; //make sure the sprite's cleared out
896 if(player->powers[pw_speed])
898 player->powers[pw_speed]--;
900 if(player->damagecount)
902 player->damagecount--;
904 if(player->bonuscount)
906 player->bonuscount--;
908 if(player->poisoncount && !(leveltime&15))
910 player->poisoncount -= 5;
911 if(player->poisoncount < 0)
913 player->poisoncount = 0;
915 P_PoisonDamage(player, player->poisoner, 1, true);
918 // if(player->powers[pw_invulnerability])
920 // if(player->powers[pw_invulnerability] > BLINKTHRESHOLD
921 // || (player->powers[pw_invulnerability]&8))
923 // player->fixedcolormap = INVERSECOLORMAP;
927 // player->fixedcolormap = 0;
931 if(player->powers[pw_infrared])
933 if (player->powers[pw_infrared] <= BLINKTHRESHOLD)
935 if(player->powers[pw_infrared]&8)
937 player->fixedcolormap = 0;
941 player->fixedcolormap = 1;
944 else if(!(leveltime&16) && player == &players[consoleplayer])
948 if(player->fixedcolormap+newtorchdelta > 7
949 || player->fixedcolormap+newtorchdelta < 1
950 || newtorch == player->fixedcolormap)
956 player->fixedcolormap += newtorchdelta;
961 newtorch = (M_Random()&7)+1;
962 newtorchdelta = (newtorch == player->fixedcolormap) ?
963 0 : ((newtorch > player->fixedcolormap) ? 1 : -1);
969 player->fixedcolormap = 0;
973 //----------------------------------------------------------------------------
977 //----------------------------------------------------------------------------
979 void P_ArtiTele(player_t *player)
989 selections = deathmatch_p-deathmatchstarts;
990 i = P_Random()%selections;
991 destX = deathmatchstarts[i].x<<FRACBITS;
992 destY = deathmatchstarts[i].y<<FRACBITS;
993 destAngle = ANG45*(deathmatchstarts[i].angle/45);
997 destX = playerstarts[0][0].x<<FRACBITS;
998 destY = playerstarts[0][0].y<<FRACBITS;
999 destAngle = ANG45*(playerstarts[0][0].angle/45);
1001 P_Teleport(player->mo, destX, destY, destAngle, true);
1002 if(player->morphTics)
1003 { // Teleporting away will undo any morph effects (pig)
1004 P_UndoPlayerMorph(player);
1006 //S_StartSound(NULL, sfx_wpnup); // Full volume laugh
1010 //----------------------------------------------------------------------------
1012 // PROC P_ArtiTeleportOther
1014 //----------------------------------------------------------------------------
1016 void P_ArtiTeleportOther(player_t *player)
1020 mo=P_SpawnPlayerMissile(player->mo, MT_TELOTHER_FX1);
1023 mo->target = player->mo;
1028 void P_TeleportToPlayerStarts(mobj_t *victim)
1031 fixed_t destX,destY;
1034 for (i=0;i<MAXPLAYERS;i++)
1036 if (!playeringame[i]) continue;
1039 i = P_Random()%selections;
1040 destX = playerstarts[0][i].x<<FRACBITS;
1041 destY = playerstarts[0][i].y<<FRACBITS;
1042 destAngle = ANG45*(playerstarts[0][i].angle/45);
1043 P_Teleport(victim, destX, destY, destAngle, true);
1044 //S_StartSound(NULL, sfx_wpnup); // Full volume laugh
1047 void P_TeleportToDeathmatchStarts(mobj_t *victim)
1050 fixed_t destX,destY;
1053 selections = deathmatch_p-deathmatchstarts;
1056 i = P_Random()%selections;
1057 destX = deathmatchstarts[i].x<<FRACBITS;
1058 destY = deathmatchstarts[i].y<<FRACBITS;
1059 destAngle = ANG45*(deathmatchstarts[i].angle/45);
1060 P_Teleport(victim, destX, destY, destAngle, true);
1061 //S_StartSound(NULL, sfx_wpnup); // Full volume laugh
1065 P_TeleportToPlayerStarts(victim);
1071 //----------------------------------------------------------------------------
1073 // PROC P_TeleportOther
1075 //----------------------------------------------------------------------------
1076 void P_TeleportOther(mobj_t *victim)
1081 P_TeleportToDeathmatchStarts(victim);
1083 P_TeleportToPlayerStarts(victim);
1087 // If death action, run it upon teleport
1088 if (victim->flags&MF_COUNTKILL && victim->special)
1090 P_RemoveMobjFromTIDList(victim);
1091 P_ExecuteLineSpecial(victim->special, victim->args,
1093 victim->special = 0;
1096 // Send all monsters to deathmatch spots
1097 P_TeleportToDeathmatchStarts(victim);
1103 #define BLAST_RADIUS_DIST 255*FRACUNIT
1104 #define BLAST_SPEED 20*FRACUNIT
1105 #define BLAST_FULLSTRENGTH 255
1107 void ResetBlasted(mobj_t *mo)
1109 mo->flags2 &= ~MF2_BLASTED;
1110 if (!(mo->flags&MF_ICECORPSE))
1112 mo->flags2 &= ~MF2_SLIDE;
1116 void P_BlastMobj(mobj_t *source, mobj_t *victim, fixed_t strength)
1122 angle = R_PointToAngle2(source->x, source->y, victim->x, victim->y);
1123 angle >>= ANGLETOFINESHIFT;
1124 if (strength < BLAST_FULLSTRENGTH)
1126 victim->momx = FixedMul(strength, finecosine[angle]);
1127 victim->momy = FixedMul(strength, finesine[angle]);
1130 // Players handled automatically
1134 victim->flags2 |= MF2_SLIDE;
1135 victim->flags2 |= MF2_BLASTED;
1138 else // full strength blast from artifact
1140 if (victim->flags&MF_MISSILE)
1142 switch(victim->type)
1144 case MT_SORCBALL1: // don't blast sorcerer balls
1149 case MT_MSTAFF_FX2: // Reflect to originator
1150 victim->special1 = (int)victim->target;
1151 victim->target = source;
1157 if (victim->type == MT_HOLY_FX)
1159 if ((mobj_t *)(victim->special1) == source)
1161 victim->special1 = (int)victim->target;
1162 victim->target = source;
1165 victim->momx = FixedMul(BLAST_SPEED, finecosine[angle]);
1166 victim->momy = FixedMul(BLAST_SPEED, finesine[angle]);
1169 ang = R_PointToAngle2(victim->x, victim->y, source->x, source->y);
1170 ang >>= ANGLETOFINESHIFT;
1171 x = victim->x + FixedMul(victim->radius+FRACUNIT, finecosine[ang]);
1172 y = victim->y + FixedMul(victim->radius+FRACUNIT, finesine[ang]);
1173 z = victim->z - victim->floorclip + (victim->height>>1);
1174 mo=P_SpawnMobj(x, y, z, MT_BLASTEFFECT);
1177 mo->momx = victim->momx;
1178 mo->momy = victim->momy;
1181 if (victim->flags&MF_MISSILE)
1183 victim->momz = 8*FRACUNIT;
1184 mo->momz = victim->momz;
1188 victim->momz = (1000/victim->info->mass)<<FRACBITS;
1192 // Players handled automatically
1196 victim->flags2 |= MF2_SLIDE;
1197 victim->flags2 |= MF2_BLASTED;
1203 // Blast all mobj things away
1204 void P_BlastRadius(player_t *player)
1207 mobj_t *pmo=player->mo;
1211 S_StartSound(pmo, SFX_ARTIFACT_BLAST);
1212 P_NoiseAlert(player->mo, player->mo);
1214 for(think = thinkercap.next; think != &thinkercap; think = think->next)
1216 if(think->function != P_MobjThinker)
1217 { // Not a mobj thinker
1220 mo = (mobj_t *)think;
1221 if((mo == pmo) || (mo->flags2&MF2_BOSS))
1222 { // Not a valid monster
1225 if ((mo->type == MT_POISONCLOUD) || // poison cloud
1226 (mo->type == MT_HOLY_FX) || // holy fx
1227 (mo->flags&MF_ICECORPSE)) // frozen corpse
1229 // Let these special cases go
1231 else if ((mo->flags&MF_COUNTKILL) &&
1236 else if (!(mo->flags&MF_COUNTKILL) &&
1238 !(mo->flags&MF_MISSILE))
1239 { // Must be monster, player, or missile
1242 if (mo->flags2&MF2_DORMANT)
1244 continue; // no dormant creatures
1246 if ((mo->type == MT_WRAITHB) && (mo->flags2&MF2_DONTDRAW))
1248 continue; // no underground wraiths
1250 if ((mo->type == MT_SPLASHBASE) ||
1251 (mo->type == MT_SPLASH))
1255 if(mo->type == MT_SERPENT || mo->type == MT_SERPENTLEADER)
1259 dist = P_AproxDistance(pmo->x - mo->x, pmo->y - mo->y);
1260 if(dist > BLAST_RADIUS_DIST)
1264 P_BlastMobj(pmo, mo, BLAST_FULLSTRENGTH);
1269 #define HEAL_RADIUS_DIST 255*FRACUNIT
1271 // Do class specific effect for everyone in radius
1272 boolean P_HealRadius(player_t *player)
1275 mobj_t *pmo=player->mo;
1278 int effective=false;
1281 for(think = thinkercap.next; think != &thinkercap; think = think->next)
1283 if(think->function != P_MobjThinker)
1284 { // Not a mobj thinker
1287 mo = (mobj_t *)think;
1289 if (!mo->player) continue;
1290 if (mo->health <= 0) continue;
1291 dist = P_AproxDistance(pmo->x - mo->x, pmo->y - mo->y);
1292 if(dist > HEAL_RADIUS_DIST)
1297 switch(player->class)
1299 case PCLASS_FIGHTER: // Radius armor boost
1300 if ((P_GiveArmor(mo->player, ARMOR_ARMOR, 1)) ||
1301 (P_GiveArmor(mo->player, ARMOR_SHIELD, 1)) ||
1302 (P_GiveArmor(mo->player, ARMOR_HELMET, 1)) ||
1303 (P_GiveArmor(mo->player, ARMOR_AMULET, 1)))
1306 S_StartSound(mo, SFX_MYSTICINCANT);
1309 case PCLASS_CLERIC: // Radius heal
1310 amount = 50 + (P_Random()%50);
1311 if (P_GiveBody(mo->player, amount))
1314 S_StartSound(mo, SFX_MYSTICINCANT);
1317 case PCLASS_MAGE: // Radius mana boost
1318 amount = 50 + (P_Random()%50);
1319 if ((P_GiveMana(mo->player, MANA_1, amount)) ||
1320 (P_GiveMana(mo->player, MANA_2, amount)))
1323 S_StartSound(mo, SFX_MYSTICINCANT);
1326 case PCLASS_ASS: // Also Radius heal
1327 amount = 50 + (P_Random()%50);
1328 if (P_GiveBody(mo->player, amount))
1331 S_StartSound(mo, SFX_MYSTICINCANT);
1343 //----------------------------------------------------------------------------
1345 // PROC P_PlayerNextArtifact
1347 //----------------------------------------------------------------------------
1349 void P_PlayerNextArtifact(player_t *player)
1354 if(player == &players[consoleplayer])
1367 inv_ptr = player->inventorySlotNum-1;
1377 player->readyArtifact =
1378 player->inventory[inv_ptr].type;
1382 //----------------------------------------------------------------------------
1384 // PROC P_PlayerRemoveArtifact
1386 //----------------------------------------------------------------------------
1388 void P_PlayerRemoveArtifact(player_t *player, int slot)
1394 player->artifactCount--;
1395 if(!(--player->inventory[slot].count))
1396 { // Used last of a type - compact the artifact list
1397 player->readyArtifact = arti_none;
1398 player->inventory[slot].type = arti_none;
1399 for(i = slot+1; i < player->inventorySlotNum; i++)
1401 player->inventory[i-1] = player->inventory[i];
1403 player->inventorySlotNum--;
1404 if(player == &players[consoleplayer])
1405 { // Set position markers and get next readyArtifact
1415 if(inv_ptr >= player->inventorySlotNum)
1417 inv_ptr = player->inventorySlotNum-1;
1423 player->readyArtifact =
1424 player->inventory[inv_ptr].type;
1429 //----------------------------------------------------------------------------
1431 // PROC P_PlayerUseArtifact
1433 //----------------------------------------------------------------------------
1435 void P_PlayerUseArtifact(player_t *player, artitype_t arti)
1439 for(i = 0; i < player->inventorySlotNum; i++)
1441 if(player->inventory[i].type == arti)
1442 { // Found match - try to use
1443 if(P_UseArtifact(player, arti))
1444 { // Artifact was used - remove it from inventory
1445 P_PlayerRemoveArtifact(player, i);
1446 if(player == &players[consoleplayer])
1448 if(arti < arti_firstpuzzitem)
1450 S_StartSound(NULL, SFX_ARTIFACT_USE);
1454 S_StartSound(NULL, SFX_PUZZLE_SUCCESS);
1459 else if(arti < arti_firstpuzzitem)
1460 { // Unable to use artifact, advance pointer
1461 P_PlayerNextArtifact(player);
1468 //==========================================================================
1472 // Returns true if the artifact was used.
1474 //==========================================================================
1476 boolean P_UseArtifact(player_t *player, artitype_t arti)
1485 case arti_invulnerability:
1486 if(!P_GivePower(player, pw_invulnerability))
1492 if(!P_GiveBody(player, 25))
1497 case arti_superhealth:
1498 if(!P_GiveBody(player, 100))
1503 case arti_healingradius:
1504 if (!P_HealRadius(player))
1510 if(!P_GivePower(player, pw_infrared))
1517 P_SpawnPlayerMissile(mo, MT_EGGFX);
1518 P_SPMAngle(mo, MT_EGGFX, mo->angle-(ANG45/6));
1519 P_SPMAngle(mo, MT_EGGFX, mo->angle+(ANG45/6));
1520 P_SPMAngle(mo, MT_EGGFX, mo->angle-(ANG45/3));
1521 P_SPMAngle(mo, MT_EGGFX, mo->angle+(ANG45/3));
1524 if(!P_GivePower(player, pw_flight))
1528 if(player->mo->momz <= -35*FRACUNIT)
1529 { // stop falling scream
1530 S_StopSound(player->mo);
1534 mo = P_SpawnPlayerMissile(player->mo, MT_SUMMON_FX);
1537 mo->target = player->mo;
1538 mo->special1 = (int)(player->mo);
1539 mo->momz = 5*FRACUNIT;
1545 case arti_teleportother:
1546 P_ArtiTeleportOther(player);
1548 case arti_poisonbag:
1549 angle = player->mo->angle>>ANGLETOFINESHIFT;
1550 if(player->class == PCLASS_CLERIC)
1552 mo = P_SpawnMobj(player->mo->x+16*finecosine[angle],
1553 player->mo->y+24*finesine[angle], player->mo->z-
1554 player->mo->floorclip+8*FRACUNIT, MT_POISONBAG);
1557 mo->target = player->mo;
1560 else if(player->class == PCLASS_MAGE)
1562 mo = P_SpawnMobj(player->mo->x+16*finecosine[angle],
1563 player->mo->y+24*finesine[angle], player->mo->z-
1564 player->mo->floorclip+8*FRACUNIT, MT_FIREBOMB);
1567 mo->target = player->mo;
1570 else // PCLASS_FIGHTER, obviously (also pig, not so obviously)
1572 mo = P_SpawnMobj(player->mo->x, player->mo->y,
1573 player->mo->z-player->mo->floorclip+35*FRACUNIT,
1577 mo->angle = player->mo->angle+(((P_Random()&7)-4)<<24);
1578 mo->momz = 4*FRACUNIT+((player->lookdir)<<(FRACBITS-4));
1579 mo->z += player->lookdir<<(FRACBITS-4);
1580 P_ThrustMobj(mo, mo->angle, mo->info->speed);
1581 mo->momx += player->mo->momx>>1;
1582 mo->momy += player->mo->momy>>1;
1583 mo->target = player->mo;
1584 mo->tics -= P_Random()&3;
1585 P_CheckMissileSpawn(mo);
1590 if(!P_GivePower(player, pw_speed))
1595 case arti_boostmana:
1596 if(!P_GiveMana(player, MANA_1, MAX_MANA))
1598 if(!P_GiveMana(player, MANA_2, MAX_MANA))
1606 P_GiveMana(player, MANA_2, MAX_MANA);
1609 case arti_boostarmor:
1612 for(i = 0; i < NUMARMOR; i++)
1614 count += P_GiveArmor(player, i, 1); // 1 point per armor type
1621 case arti_blastradius:
1622 P_BlastRadius(player);
1625 case arti_puzzskull:
1626 case arti_puzzgembig:
1627 case arti_puzzgemred:
1628 case arti_puzzgemgreen1:
1629 case arti_puzzgemgreen2:
1630 case arti_puzzgemblue1:
1631 case arti_puzzgemblue2:
1632 case arti_puzzbook1:
1633 case arti_puzzbook2:
1634 case arti_puzzskull2:
1635 case arti_puzzfweapon:
1636 case arti_puzzcweapon:
1637 case arti_puzzmweapon:
1638 case arti_puzzgear1:
1639 case arti_puzzgear2:
1640 case arti_puzzgear3:
1641 case arti_puzzgear4:
1642 if(P_UsePuzzleItem(player, arti-arti_firstpuzzitem))
1648 P_SetYellowMessage(player, TXT_USEPUZZLEFAILED, false);
1658 //============================================================================
1662 //============================================================================
1664 void A_SpeedFade(mobj_t *actor)
1666 actor->flags |= MF_SHADOW;
1667 actor->flags &= ~MF_ALTSHADOW;
1668 actor->sprite = actor->target->sprite;