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] =
40 int PStateRun[NUMCLASSES] =
51 int PStateAttack[NUMCLASSES] =
62 int PStateAttackEnd[NUMCLASSES] =
73 int ArmorMax[NUMCLASSES] = { 20, 18, 16,
84 = moves the given origin along a given angle
89 void P_Thrust(player_t *player, angle_t angle, fixed_t move)
91 angle >>= ANGLETOFINESHIFT;
92 if(player->powers[pw_flight] && !(player->mo->z <= player->mo->floorz))
94 player->mo->momx += FixedMul(move, finecosine[angle]);
95 player->mo->momy += FixedMul(move, finesine[angle]);
97 else if(P_GetThingFloorType(player->mo) == FLOOR_ICE) // Friction_Low
99 player->mo->momx += FixedMul(move>>1, finecosine[angle]);
100 player->mo->momy += FixedMul(move>>1, finesine[angle]);
104 player->mo->momx += FixedMul(move, finecosine[angle]);
105 player->mo->momy += FixedMul(move, finesine[angle]);
116 Calculate the walking / running height adjustment
121 void P_CalcHeight (player_t *player)
127 // regular movement bobbing (needs to be calculated for gun swing even
129 // OPTIMIZE: tablify angle
131 player->bob = FixedMul (player->mo->momx, player->mo->momx)+
132 FixedMul (player->mo->momy,player->mo->momy);
134 if (player->bob>MAXBOB)
135 player->bob = MAXBOB;
136 if(player->mo->flags2&MF2_FLY && !onground)
138 player->bob = FRACUNIT/2;
141 if ((player->cheats & CF_NOMOMENTUM))
143 player->viewz = player->mo->z + VIEWHEIGHT;
144 if (player->viewz > player->mo->ceilingz-4*FRACUNIT)
145 player->viewz = player->mo->ceilingz-4*FRACUNIT;
146 player->viewz = player->mo->z + player->viewheight;
150 angle = (FINEANGLES/20*leveltime)&FINEMASK;
151 bob = FixedMul ( player->bob/2, finesine[angle]);
156 if (player->playerstate == PST_LIVE)
158 player->viewheight += player->deltaviewheight;
159 if (player->viewheight > VIEWHEIGHT)
161 player->viewheight = VIEWHEIGHT;
162 player->deltaviewheight = 0;
164 if (player->viewheight < VIEWHEIGHT/2)
166 player->viewheight = VIEWHEIGHT/2;
167 if (player->deltaviewheight <= 0)
168 player->deltaviewheight = 1;
171 if (player->deltaviewheight)
173 player->deltaviewheight += FRACUNIT/4;
174 if (!player->deltaviewheight)
175 player->deltaviewheight = 1;
179 if(player->morphTics)
181 player->viewz = player->mo->z+player->viewheight-(20*FRACUNIT);
185 player->viewz = player->mo->z+player->viewheight+bob;
187 if(player->mo->floorclip && player->playerstate != PST_DEAD
188 && player->mo->z <= player->mo->floorz)
190 player->viewz -= player->mo->floorclip;
192 if(player->viewz > player->mo->ceilingz-4*FRACUNIT)
194 player->viewz = player->mo->ceilingz-4*FRACUNIT;
196 if(player->viewz < player->mo->floorz+4*FRACUNIT)
198 player->viewz = player->mo->floorz+4*FRACUNIT;
210 void P_MovePlayer(player_t *player)
217 player->mo->angle += (cmd->angleturn<<16);
219 onground = (player->mo->z <= player->mo->floorz
220 || (player->mo->flags2&MF2_ONMOBJ));
224 if(onground || player->mo->flags2&MF2_FLY)
226 P_Thrust(player, player->mo->angle, cmd->forwardmove*2048);
230 P_Thrust(player, player->mo->angle, FRACUNIT>>8);
235 if(onground || player->mo->flags2&MF2_FLY)
237 P_Thrust(player, player->mo->angle-ANG90, cmd->sidemove*2048);
241 P_Thrust(player, player->mo->angle, FRACUNIT>>8);
244 if(cmd->forwardmove || cmd->sidemove)
246 if(player->mo->state == &states[PStateNormal[player->class]])
248 P_SetMobjState(player->mo, PStateRun[player->class]);
252 look = cmd->lookfly&15;
261 player->centering = true;
265 player->lookdir += 5*look;
266 if(player->lookdir > 90 || player->lookdir < -110)
268 player->lookdir -= 5*look;
272 if(player->centering)
274 if(player->lookdir > 0)
276 player->lookdir -= 8;
278 else if(player->lookdir < 0)
280 player->lookdir += 8;
282 if(abs(player->lookdir) < 8)
285 player->centering = false;
288 fly = cmd->lookfly>>4;
293 if(fly && player->powers[pw_flight])
297 player->flyheight = fly*2;
298 if(!(player->mo->flags2&MF2_FLY))
300 player->mo->flags2 |= MF2_FLY;
301 player->mo->flags |= MF_NOGRAVITY;
302 if(player->mo->momz <= -39*FRACUNIT)
303 { // stop falling scream
304 S_StopSound(player->mo);
310 player->mo->flags2 &= ~MF2_FLY;
311 player->mo->flags &= ~MF_NOGRAVITY;
316 P_PlayerUseArtifact(player, arti_fly);
318 if(player->mo->flags2&MF2_FLY)
320 player->mo->momz = player->flyheight*FRACUNIT;
321 if(player->flyheight)
323 player->flyheight /= 2;
328 //==========================================================================
332 //==========================================================================
334 void P_DeathThink(player_t *player)
342 P_MovePsprites(player);
344 onground = (player->mo->z <= player->mo->floorz);
345 if(player->mo->type == MT_BLOODYSKULL || player->mo->type == MT_ICECHUNK)
346 { // Flying bloody skull or flying ice chunk
347 player->viewheight = 6*FRACUNIT;
348 player->deltaviewheight = 0;
349 //player->damagecount = 20;
352 if(player->lookdir < 60)
354 lookDelta = (60-player->lookdir)/8;
355 if(lookDelta < 1 && (leveltime&1))
359 else if(lookDelta > 6)
363 player->lookdir += lookDelta;
367 else if(!(player->mo->flags2&MF2_ICEDAMAGE))
368 { // Fall to ground (if not frozen)
369 player->deltaviewheight = 0;
370 if(player->viewheight > 6*FRACUNIT)
372 player->viewheight -= FRACUNIT;
374 if(player->viewheight < 6*FRACUNIT)
376 player->viewheight = 6*FRACUNIT;
378 if(player->lookdir > 0)
380 player->lookdir -= 6;
382 else if(player->lookdir < 0)
384 player->lookdir += 6;
386 if(abs(player->lookdir) < 6)
391 P_CalcHeight(player);
393 if(player->attacker && player->attacker != player->mo)
395 dir = P_FaceMobj(player->mo, player->attacker, &delta);
396 if(delta < ANGLE_1*10)
397 { // Looking at killer, so fade damage and poison counters
398 if(player->damagecount)
400 player->damagecount--;
402 if(player->poisoncount)
404 player->poisoncount--;
408 if(delta > ANGLE_1*5)
414 player->mo->angle += delta;
417 { // Turn counter clockwise
418 player->mo->angle -= delta;
421 else if(player->damagecount || player->poisoncount)
423 if(player->damagecount)
425 player->damagecount--;
429 player->poisoncount--;
433 if(player->cmd.buttons&BT_USE)
435 if(player == &players[consoleplayer])
437 I_SetPalette((byte *)W_CacheLumpName("PLAYPAL", PU_CACHE));
443 player->playerstate = PST_REBORN;
444 player->mo->special1 = player->class;
445 if(player->mo->special1 > 2)
447 player->mo->special1 = 0;
449 // Let the mobj know the player has entered the reborn state. Some
450 // mobjs need to know when it's ok to remove themselves.
451 player->mo->special2 = 666;
455 //----------------------------------------------------------------------------
457 // PROC P_MorphPlayerThink
459 //----------------------------------------------------------------------------
461 void P_MorphPlayerThink(player_t *player)
465 if(player->morphTics&15)
470 if(!(pmo->momx+pmo->momy) && P_Random() < 64)
472 P_SetPspriteNF(player, ps_weapon, S_SNOUTATK2);
473 S_StartSound(pmo, SFX_PIG_ACTIVE1); // snort
480 S_StartSound(pmo, SFX_PIG_ACTIVE1);
484 S_StartSound(pmo, SFX_PIG_ACTIVE2);
489 //----------------------------------------------------------------------------
491 // FUNC P_GetPlayerNum
493 //----------------------------------------------------------------------------
495 int P_GetPlayerNum(player_t *player)
499 for(i = 0; i < MAXPLAYERS; i++)
501 if(player == &players[i])
509 //----------------------------------------------------------------------------
511 // FUNC P_UndoPlayerMorph
513 //----------------------------------------------------------------------------
515 boolean P_UndoPlayerMorph(player_t *player)
535 weapon = pmo->special1;
536 oldFlags = pmo->flags;
537 oldFlags2 = pmo->flags2;
538 oldBeast = pmo->type;
539 P_SetMobjState(pmo, S_FREETARGMOBJ);
540 playerNum = P_GetPlayerNum(player);
541 switch(PlayerClass[playerNum])
544 mo = P_SpawnMobj(x, y, z, MT_PLAYER_FIGHTER);
547 mo = P_SpawnMobj(x, y, z, MT_PLAYER_CLERIC);
550 mo = P_SpawnMobj(x, y, z, MT_PLAYER_MAGE);
554 mo = P_SpawnMobj(x, y, z, MT_PLAYER_ASS);
558 I_Error("P_UndoPlayerMorph: Unknown player class %d\n",
560 /* jim never happens but keeps gcc happy */
564 if(P_TestMobjLocation(mo) == false)
567 mo = P_SpawnMobj(x, y, z, oldBeast);
569 mo->health = player->health;
570 mo->special1 = weapon;
572 mo->flags = oldFlags;
573 mo->flags2 = oldFlags2;
575 player->morphTics = 2*35;
578 if(player->class == PCLASS_FIGHTER)
580 // The first type should be blue, and the third should be the
581 // Fighter's original gold color
584 mo->flags |= 2<<MF_TRANSSHIFT;
586 else if(playerNum != 2)
588 mo->flags |= playerNum<<MF_TRANSSHIFT;
592 { // Set color translation bits for player sprites
593 mo->flags |= playerNum<<MF_TRANSSHIFT;
597 mo->reactiontime = 18;
598 if(oldFlags2&MF2_FLY)
600 mo->flags2 |= MF2_FLY;
601 mo->flags |= MF_NOGRAVITY;
603 player->morphTics = 0;
604 player->health = mo->health = MAXHEALTH;
606 player->class = PlayerClass[playerNum];
607 angle >>= ANGLETOFINESHIFT;
608 fog = P_SpawnMobj(x+20*finecosine[angle],
609 y+20*finesine[angle], z+TELEFOGHEIGHT, MT_TFOG);
610 S_StartSound(fog, SFX_TELEPORT);
611 P_PostMorphWeapon(player, weapon);
616 //----------------------------------------------------------------------------
618 // PROC P_PlayerThink
620 //----------------------------------------------------------------------------
622 void P_PlayerThink(player_t *player)
625 weapontype_t newweapon;
630 if(player->cheats&CF_NOCLIP)
632 player->mo->flags |= MF_NOCLIP;
636 player->mo->flags &= ~MF_NOCLIP;
639 if(player->mo->flags&MF_JUSTATTACKED)
640 { // Gauntlets attack auto forward motion
642 cmd->forwardmove = 0xc800/512;
644 player->mo->flags &= ~MF_JUSTATTACKED;
646 // messageTics is above the rest of the counters so that messages will
647 // go away, even in death.
648 player->messageTics--; // Can go negative
649 if(!player->messageTics || player->messageTics == -1)
650 { // Refresh the screen when a message goes away
651 player->ultimateMessage = false; // clear out any chat messages.
652 player->yellowMessage = false;
653 if(player == &players[consoleplayer])
655 BorderTopRefresh = true;
658 player->worldTimer++;
659 if(player->playerstate == PST_DEAD)
661 P_DeathThink(player);
668 if(player->morphTics)
670 P_MorphPlayerThink(player);
673 if(player->mo->reactiontime)
674 { // Player is frozen
675 player->mo->reactiontime--;
679 P_MovePlayer(player);
681 if(player->powers[pw_speed] && !(leveltime&1)
682 && P_AproxDistance(pmo->momx, pmo->momy) > 12*FRACUNIT)
687 speedMo = P_SpawnMobj(pmo->x, pmo->y, pmo->z, MT_PLAYER_SPEED);
690 speedMo->angle = pmo->angle;
691 playerNum = P_GetPlayerNum(player);
692 if(player->class == PCLASS_FIGHTER)
694 // The first type should be blue, and the
695 // third should be the Fighter's original gold color
698 speedMo->flags |= 2<<MF_TRANSSHIFT;
700 else if(playerNum != 2)
702 speedMo->flags |= playerNum<<MF_TRANSSHIFT;
706 { // Set color translation bits for player sprites
707 speedMo->flags |= playerNum<<MF_TRANSSHIFT;
709 speedMo->target = pmo;
710 speedMo->special1 = player->class;
711 if(speedMo->special1 > 2)
713 speedMo->special1 = 0;
715 speedMo->sprite = pmo->sprite;
716 speedMo->floorclip = pmo->floorclip;
717 if(player == &players[consoleplayer])
719 speedMo->flags2 |= MF2_DONTDRAW;
724 P_CalcHeight(player);
725 if(player->mo->subsector->sector->special)
727 P_PlayerInSpecialSector(player);
729 if((floorType = P_GetThingFloorType(player->mo)) != FLOOR_SOLID)
731 P_PlayerOnSpecialFlat(player, floorType);
733 switch(player->class)
736 if(player->mo->momz <= -35*FRACUNIT
737 && player->mo->momz >= -40*FRACUNIT && !player->morphTics
738 && !S_GetSoundPlayingInfo(player->mo,
739 SFX_PLAYER_FIGHTER_FALLING_SCREAM))
741 S_StartSound(player->mo,
742 SFX_PLAYER_FIGHTER_FALLING_SCREAM);
746 if(player->mo->momz <= -35*FRACUNIT
747 && player->mo->momz >= -40*FRACUNIT && !player->morphTics
748 && !S_GetSoundPlayingInfo(player->mo,
749 SFX_PLAYER_CLERIC_FALLING_SCREAM))
751 S_StartSound(player->mo,
752 SFX_PLAYER_CLERIC_FALLING_SCREAM);
756 if(player->mo->momz <= -35*FRACUNIT
757 && player->mo->momz >= -40*FRACUNIT && !player->morphTics
758 && !S_GetSoundPlayingInfo(player->mo,
759 SFX_PLAYER_MAGE_FALLING_SCREAM))
761 S_StartSound(player->mo,
762 SFX_PLAYER_MAGE_FALLING_SCREAM);
766 if(player->mo->momz <= -35*FRACUNIT
767 && player->mo->momz >= -40*FRACUNIT && !player->morphTics
768 && !S_GetSoundPlayingInfo(player->mo,
769 SFX_PLAYER_MAGE_FALLING_SCREAM))
771 S_StartSound(player->mo,
772 SFX_PLAYER_MAGE_FALLING_SCREAM);
781 if((cmd->arti&AFLAG_JUMP) && onground && !player->jumpTics)
783 if(player->morphTics)
785 player->mo->momz = 6*FRACUNIT;
789 player->mo->momz = 9*FRACUNIT;
791 player->mo->flags2 &= ~MF2_ONMOBJ;
792 player->jumpTics = 18;
794 else if(cmd->arti&AFLAG_SUICIDE)
796 P_DamageMobj(player->mo, NULL, NULL, 10000);
798 if(cmd->arti == NUMARTIFACTS)
799 { // use one of each artifact (except puzzle artifacts)
802 for(i = 1; i < arti_firstpuzzitem; i++)
804 P_PlayerUseArtifact(player, i);
809 P_PlayerUseArtifact(player, cmd->arti&AFLAG_MASK);
812 // Check for weapon change
813 if(cmd->buttons&BT_SPECIAL)
814 { // A special event has no other buttons
817 if(cmd->buttons&BT_CHANGE && !player->morphTics)
819 // The actual changing of the weapon is done when the weapon
820 // psprite can do it (A_WeaponReady), so it doesn't happen in
821 // the middle of an attack.
822 newweapon = (cmd->buttons&BT_WEAPONMASK)>>BT_WEAPONSHIFT;
823 if(player->weaponowned[newweapon]
824 && newweapon != player->readyweapon)
826 player->pendingweapon = newweapon;
830 if(cmd->buttons&BT_USE)
835 player->usedown = true;
840 player->usedown = false;
843 if(player->morphTics)
845 if(!--player->morphTics)
846 { // Attempt to undo the pig
847 P_UndoPlayerMorph(player);
851 P_MovePsprites(player);
853 if(player->powers[pw_invulnerability])
855 if(player->class == PCLASS_CLERIC)
857 if(!(leveltime&7) && player->mo->flags&MF_SHADOW
858 && !(player->mo->flags2&MF2_DONTDRAW))
860 player->mo->flags &= ~MF_SHADOW;
861 if(!(player->mo->flags&MF_ALTSHADOW))
863 player->mo->flags2 |= MF2_DONTDRAW|MF2_NONSHOOTABLE;
868 if(player->mo->flags2&MF2_DONTDRAW)
870 if(!(player->mo->flags&MF_SHADOW))
872 player->mo->flags |= MF_SHADOW|MF_ALTSHADOW;
876 player->mo->flags2 &= ~(MF2_DONTDRAW|MF2_NONSHOOTABLE);
881 player->mo->flags |= MF_SHADOW;
882 player->mo->flags &= ~MF_ALTSHADOW;
886 if(!(--player->powers[pw_invulnerability]))
888 player->mo->flags2 &= ~(MF2_INVULNERABLE|MF2_REFLECTIVE);
889 if(player->class == PCLASS_CLERIC)
891 player->mo->flags2 &= ~(MF2_DONTDRAW|MF2_NONSHOOTABLE);
892 player->mo->flags &= ~(MF_SHADOW|MF_ALTSHADOW);
896 if(player->powers[pw_minotaur])
898 player->powers[pw_minotaur]--;
900 if(player->powers[pw_infrared])
902 player->powers[pw_infrared]--;
904 if(player->powers[pw_flight] && netgame)
906 if(!--player->powers[pw_flight])
908 // if(player->mo->z != player->mo->floorz) { }
909 player->mo->flags2 &= ~MF2_FLY;
910 player->mo->flags &= ~MF_NOGRAVITY;
911 BorderTopRefresh = true; //make sure the sprite's cleared out
914 if(player->powers[pw_speed])
916 player->powers[pw_speed]--;
918 if(player->damagecount)
920 player->damagecount--;
922 if(player->bonuscount)
924 player->bonuscount--;
926 if(player->poisoncount && !(leveltime&15))
928 player->poisoncount -= 5;
929 if(player->poisoncount < 0)
931 player->poisoncount = 0;
933 P_PoisonDamage(player, player->poisoner, 1, true);
936 // if(player->powers[pw_invulnerability])
938 // if(player->powers[pw_invulnerability] > BLINKTHRESHOLD
939 // || (player->powers[pw_invulnerability]&8))
941 // player->fixedcolormap = INVERSECOLORMAP;
945 // player->fixedcolormap = 0;
949 if(player->powers[pw_infrared])
951 if (player->powers[pw_infrared] <= BLINKTHRESHOLD)
953 if(player->powers[pw_infrared]&8)
955 player->fixedcolormap = 0;
959 player->fixedcolormap = 1;
962 else if(!(leveltime&16) && player == &players[consoleplayer])
966 if(player->fixedcolormap+newtorchdelta > 7
967 || player->fixedcolormap+newtorchdelta < 1
968 || newtorch == player->fixedcolormap)
974 player->fixedcolormap += newtorchdelta;
979 newtorch = (M_Random()&7)+1;
980 newtorchdelta = (newtorch == player->fixedcolormap) ?
981 0 : ((newtorch > player->fixedcolormap) ? 1 : -1);
987 player->fixedcolormap = 0;
991 //----------------------------------------------------------------------------
995 //----------------------------------------------------------------------------
997 void P_ArtiTele(player_t *player)
1007 selections = deathmatch_p-deathmatchstarts;
1008 i = P_Random()%selections;
1009 destX = deathmatchstarts[i].x<<FRACBITS;
1010 destY = deathmatchstarts[i].y<<FRACBITS;
1011 destAngle = ANG45*(deathmatchstarts[i].angle/45);
1015 destX = playerstarts[0][0].x<<FRACBITS;
1016 destY = playerstarts[0][0].y<<FRACBITS;
1017 destAngle = ANG45*(playerstarts[0][0].angle/45);
1019 P_Teleport(player->mo, destX, destY, destAngle, true);
1020 if(player->morphTics)
1021 { // Teleporting away will undo any morph effects (pig)
1022 P_UndoPlayerMorph(player);
1024 //S_StartSound(NULL, sfx_wpnup); // Full volume laugh
1028 //----------------------------------------------------------------------------
1030 // PROC P_ArtiTeleportOther
1032 //----------------------------------------------------------------------------
1034 void P_ArtiTeleportOther(player_t *player)
1038 mo=P_SpawnPlayerMissile(player->mo, MT_TELOTHER_FX1);
1041 mo->target = player->mo;
1046 void P_TeleportToPlayerStarts(mobj_t *victim)
1049 fixed_t destX,destY;
1052 for (i=0;i<MAXPLAYERS;i++)
1054 if (!playeringame[i]) continue;
1057 i = P_Random()%selections;
1058 destX = playerstarts[0][i].x<<FRACBITS;
1059 destY = playerstarts[0][i].y<<FRACBITS;
1060 destAngle = ANG45*(playerstarts[0][i].angle/45);
1061 P_Teleport(victim, destX, destY, destAngle, true);
1062 //S_StartSound(NULL, sfx_wpnup); // Full volume laugh
1065 void P_TeleportToDeathmatchStarts(mobj_t *victim)
1068 fixed_t destX,destY;
1071 selections = deathmatch_p-deathmatchstarts;
1074 i = P_Random()%selections;
1075 destX = deathmatchstarts[i].x<<FRACBITS;
1076 destY = deathmatchstarts[i].y<<FRACBITS;
1077 destAngle = ANG45*(deathmatchstarts[i].angle/45);
1078 P_Teleport(victim, destX, destY, destAngle, true);
1079 //S_StartSound(NULL, sfx_wpnup); // Full volume laugh
1083 P_TeleportToPlayerStarts(victim);
1089 //----------------------------------------------------------------------------
1091 // PROC P_TeleportOther
1093 //----------------------------------------------------------------------------
1094 void P_TeleportOther(mobj_t *victim)
1099 P_TeleportToDeathmatchStarts(victim);
1101 P_TeleportToPlayerStarts(victim);
1105 // If death action, run it upon teleport
1106 if (victim->flags&MF_COUNTKILL && victim->special)
1108 P_RemoveMobjFromTIDList(victim);
1109 P_ExecuteLineSpecial(victim->special, victim->args,
1111 victim->special = 0;
1114 // Send all monsters to deathmatch spots
1115 P_TeleportToDeathmatchStarts(victim);
1121 #define BLAST_RADIUS_DIST 255*FRACUNIT
1122 #define BLAST_SPEED 20*FRACUNIT
1123 #define BLAST_FULLSTRENGTH 255
1125 void ResetBlasted(mobj_t *mo)
1127 mo->flags2 &= ~MF2_BLASTED;
1128 if (!(mo->flags&MF_ICECORPSE))
1130 mo->flags2 &= ~MF2_SLIDE;
1134 void P_BlastMobj(mobj_t *source, mobj_t *victim, fixed_t strength)
1140 angle = R_PointToAngle2(source->x, source->y, victim->x, victim->y);
1141 angle >>= ANGLETOFINESHIFT;
1142 if (strength < BLAST_FULLSTRENGTH)
1144 victim->momx = FixedMul(strength, finecosine[angle]);
1145 victim->momy = FixedMul(strength, finesine[angle]);
1148 // Players handled automatically
1152 victim->flags2 |= MF2_SLIDE;
1153 victim->flags2 |= MF2_BLASTED;
1156 else // full strength blast from artifact
1158 if (victim->flags&MF_MISSILE)
1160 switch(victim->type)
1162 case MT_SORCBALL1: // don't blast sorcerer balls
1167 case MT_MSTAFF_FX2: // Reflect to originator
1168 victim->special1 = (int)victim->target;
1169 victim->target = source;
1175 if (victim->type == MT_HOLY_FX)
1177 if ((mobj_t *)(victim->special1) == source)
1179 victim->special1 = (int)victim->target;
1180 victim->target = source;
1183 victim->momx = FixedMul(BLAST_SPEED, finecosine[angle]);
1184 victim->momy = FixedMul(BLAST_SPEED, finesine[angle]);
1187 ang = R_PointToAngle2(victim->x, victim->y, source->x, source->y);
1188 ang >>= ANGLETOFINESHIFT;
1189 x = victim->x + FixedMul(victim->radius+FRACUNIT, finecosine[ang]);
1190 y = victim->y + FixedMul(victim->radius+FRACUNIT, finesine[ang]);
1191 z = victim->z - victim->floorclip + (victim->height>>1);
1192 mo=P_SpawnMobj(x, y, z, MT_BLASTEFFECT);
1195 mo->momx = victim->momx;
1196 mo->momy = victim->momy;
1199 if (victim->flags&MF_MISSILE)
1201 victim->momz = 8*FRACUNIT;
1202 mo->momz = victim->momz;
1206 victim->momz = (1000/victim->info->mass)<<FRACBITS;
1210 // Players handled automatically
1214 victim->flags2 |= MF2_SLIDE;
1215 victim->flags2 |= MF2_BLASTED;
1221 // Blast all mobj things away
1222 void P_BlastRadius(player_t *player)
1225 mobj_t *pmo=player->mo;
1229 S_StartSound(pmo, SFX_ARTIFACT_BLAST);
1230 P_NoiseAlert(player->mo, player->mo);
1232 for(think = thinkercap.next; think != &thinkercap; think = think->next)
1234 if(think->function != P_MobjThinker)
1235 { // Not a mobj thinker
1238 mo = (mobj_t *)think;
1239 if((mo == pmo) || (mo->flags2&MF2_BOSS))
1240 { // Not a valid monster
1243 if ((mo->type == MT_POISONCLOUD) || // poison cloud
1244 (mo->type == MT_HOLY_FX) || // holy fx
1245 (mo->flags&MF_ICECORPSE)) // frozen corpse
1247 // Let these special cases go
1249 else if ((mo->flags&MF_COUNTKILL) &&
1254 else if (!(mo->flags&MF_COUNTKILL) &&
1256 !(mo->flags&MF_MISSILE))
1257 { // Must be monster, player, or missile
1260 if (mo->flags2&MF2_DORMANT)
1262 continue; // no dormant creatures
1264 if ((mo->type == MT_WRAITHB) && (mo->flags2&MF2_DONTDRAW))
1266 continue; // no underground wraiths
1268 if ((mo->type == MT_SPLASHBASE) ||
1269 (mo->type == MT_SPLASH))
1273 if(mo->type == MT_SERPENT || mo->type == MT_SERPENTLEADER)
1277 dist = P_AproxDistance(pmo->x - mo->x, pmo->y - mo->y);
1278 if(dist > BLAST_RADIUS_DIST)
1282 P_BlastMobj(pmo, mo, BLAST_FULLSTRENGTH);
1287 #define HEAL_RADIUS_DIST 255*FRACUNIT
1289 // Do class specific effect for everyone in radius
1290 boolean P_HealRadius(player_t *player)
1293 mobj_t *pmo=player->mo;
1296 int effective=false;
1299 for(think = thinkercap.next; think != &thinkercap; think = think->next)
1301 if(think->function != P_MobjThinker)
1302 { // Not a mobj thinker
1305 mo = (mobj_t *)think;
1307 if (!mo->player) continue;
1308 if (mo->health <= 0) continue;
1309 dist = P_AproxDistance(pmo->x - mo->x, pmo->y - mo->y);
1310 if(dist > HEAL_RADIUS_DIST)
1315 switch(player->class)
1317 case PCLASS_FIGHTER: // Radius armor boost
1318 if ((P_GiveArmor(mo->player, ARMOR_ARMOR, 1)) ||
1319 (P_GiveArmor(mo->player, ARMOR_SHIELD, 1)) ||
1320 (P_GiveArmor(mo->player, ARMOR_HELMET, 1)) ||
1321 (P_GiveArmor(mo->player, ARMOR_AMULET, 1)))
1324 S_StartSound(mo, SFX_MYSTICINCANT);
1327 case PCLASS_CLERIC: // Radius heal
1328 amount = 50 + (P_Random()%50);
1329 if (P_GiveBody(mo->player, amount))
1332 S_StartSound(mo, SFX_MYSTICINCANT);
1335 case PCLASS_MAGE: // Radius mana boost
1336 amount = 50 + (P_Random()%50);
1337 if ((P_GiveMana(mo->player, MANA_1, amount)) ||
1338 (P_GiveMana(mo->player, MANA_2, amount)))
1341 S_StartSound(mo, SFX_MYSTICINCANT);
1345 case PCLASS_ASS: // Also Radius heal
1346 amount = 50 + (P_Random()%50);
1347 if (P_GiveBody(mo->player, amount))
1350 S_StartSound(mo, SFX_MYSTICINCANT);
1363 //----------------------------------------------------------------------------
1365 // PROC P_PlayerNextArtifact
1367 //----------------------------------------------------------------------------
1369 void P_PlayerNextArtifact(player_t *player)
1374 if(player == &players[consoleplayer])
1387 inv_ptr = player->inventorySlotNum-1;
1397 player->readyArtifact =
1398 player->inventory[inv_ptr].type;
1402 //----------------------------------------------------------------------------
1404 // PROC P_PlayerRemoveArtifact
1406 //----------------------------------------------------------------------------
1408 void P_PlayerRemoveArtifact(player_t *player, int slot)
1414 player->artifactCount--;
1415 if(!(--player->inventory[slot].count))
1416 { // Used last of a type - compact the artifact list
1417 player->readyArtifact = arti_none;
1418 player->inventory[slot].type = arti_none;
1419 for(i = slot+1; i < player->inventorySlotNum; i++)
1421 player->inventory[i-1] = player->inventory[i];
1423 player->inventorySlotNum--;
1424 if(player == &players[consoleplayer])
1425 { // Set position markers and get next readyArtifact
1435 if(inv_ptr >= player->inventorySlotNum)
1437 inv_ptr = player->inventorySlotNum-1;
1443 player->readyArtifact =
1444 player->inventory[inv_ptr].type;
1449 //----------------------------------------------------------------------------
1451 // PROC P_PlayerUseArtifact
1453 //----------------------------------------------------------------------------
1455 void P_PlayerUseArtifact(player_t *player, artitype_t arti)
1459 for(i = 0; i < player->inventorySlotNum; i++)
1461 if(player->inventory[i].type == arti)
1462 { // Found match - try to use
1463 if(P_UseArtifact(player, arti))
1464 { // Artifact was used - remove it from inventory
1465 P_PlayerRemoveArtifact(player, i);
1466 if(player == &players[consoleplayer])
1468 if(arti < arti_firstpuzzitem)
1470 S_StartSound(NULL, SFX_ARTIFACT_USE);
1474 S_StartSound(NULL, SFX_PUZZLE_SUCCESS);
1479 else if(arti < arti_firstpuzzitem)
1480 { // Unable to use artifact, advance pointer
1481 P_PlayerNextArtifact(player);
1488 //==========================================================================
1492 // Returns true if the artifact was used.
1494 //==========================================================================
1496 boolean P_UseArtifact(player_t *player, artitype_t arti)
1505 case arti_invulnerability:
1506 if(!P_GivePower(player, pw_invulnerability))
1512 if(!P_GiveBody(player, 25))
1517 case arti_superhealth:
1518 if(!P_GiveBody(player, 100))
1523 case arti_healingradius:
1524 if (!P_HealRadius(player))
1530 if(!P_GivePower(player, pw_infrared))
1537 P_SpawnPlayerMissile(mo, MT_EGGFX);
1538 P_SPMAngle(mo, MT_EGGFX, mo->angle-(ANG45/6));
1539 P_SPMAngle(mo, MT_EGGFX, mo->angle+(ANG45/6));
1540 P_SPMAngle(mo, MT_EGGFX, mo->angle-(ANG45/3));
1541 P_SPMAngle(mo, MT_EGGFX, mo->angle+(ANG45/3));
1544 if(!P_GivePower(player, pw_flight))
1548 if(player->mo->momz <= -35*FRACUNIT)
1549 { // stop falling scream
1550 S_StopSound(player->mo);
1554 mo = P_SpawnPlayerMissile(player->mo, MT_SUMMON_FX);
1557 mo->target = player->mo;
1558 mo->special1 = (int)(player->mo);
1559 mo->momz = 5*FRACUNIT;
1565 case arti_teleportother:
1566 P_ArtiTeleportOther(player);
1568 case arti_poisonbag:
1569 angle = player->mo->angle>>ANGLETOFINESHIFT;
1570 if(player->class == PCLASS_CLERIC)
1572 mo = P_SpawnMobj(player->mo->x+16*finecosine[angle],
1573 player->mo->y+24*finesine[angle], player->mo->z-
1574 player->mo->floorclip+8*FRACUNIT, MT_POISONBAG);
1577 mo->target = player->mo;
1580 else if(player->class == PCLASS_MAGE)
1582 mo = P_SpawnMobj(player->mo->x+16*finecosine[angle],
1583 player->mo->y+24*finesine[angle], player->mo->z-
1584 player->mo->floorclip+8*FRACUNIT, MT_FIREBOMB);
1587 mo->target = player->mo;
1590 else // PCLASS_FIGHTER, obviously (also pig, not so obviously)
1592 mo = P_SpawnMobj(player->mo->x, player->mo->y,
1593 player->mo->z-player->mo->floorclip+35*FRACUNIT,
1597 mo->angle = player->mo->angle+(((P_Random()&7)-4)<<24);
1598 mo->momz = 4*FRACUNIT+((player->lookdir)<<(FRACBITS-4));
1599 mo->z += player->lookdir<<(FRACBITS-4);
1600 P_ThrustMobj(mo, mo->angle, mo->info->speed);
1601 mo->momx += player->mo->momx>>1;
1602 mo->momy += player->mo->momy>>1;
1603 mo->target = player->mo;
1604 mo->tics -= P_Random()&3;
1605 P_CheckMissileSpawn(mo);
1610 if(!P_GivePower(player, pw_speed))
1615 case arti_boostmana:
1616 if(!P_GiveMana(player, MANA_1, MAX_MANA))
1618 if(!P_GiveMana(player, MANA_2, MAX_MANA))
1626 P_GiveMana(player, MANA_2, MAX_MANA);
1629 case arti_boostarmor:
1632 for(i = 0; i < NUMARMOR; i++)
1634 count += P_GiveArmor(player, i, 1); // 1 point per armor type
1641 case arti_blastradius:
1642 P_BlastRadius(player);
1645 case arti_puzzskull:
1646 case arti_puzzgembig:
1647 case arti_puzzgemred:
1648 case arti_puzzgemgreen1:
1649 case arti_puzzgemgreen2:
1650 case arti_puzzgemblue1:
1651 case arti_puzzgemblue2:
1652 case arti_puzzbook1:
1653 case arti_puzzbook2:
1654 case arti_puzzskull2:
1655 case arti_puzzfweapon:
1656 case arti_puzzcweapon:
1657 case arti_puzzmweapon:
1658 case arti_puzzgear1:
1659 case arti_puzzgear2:
1660 case arti_puzzgear3:
1661 case arti_puzzgear4:
1662 if(P_UsePuzzleItem(player, arti-arti_firstpuzzitem))
1668 P_SetYellowMessage(player, TXT_USEPUZZLEFAILED, false);
1678 //============================================================================
1682 //============================================================================
1684 void A_SpeedFade(mobj_t *actor)
1686 actor->flags |= MF_SHADOW;
1687 actor->flags &= ~MF_ALTSHADOW;
1688 actor->sprite = actor->target->sprite;