]> icculus.org git repositories - theoddone33/hhexen.git/blob - base/p_user.c
Add .gitignore for ignoring generated files.
[theoddone33/hhexen.git] / base / p_user.c
1
2 //**************************************************************************
3 //**
4 //** p_user.c : Heretic 2 : Raven Software, Corp.
5 //**
6 //** $RCSfile$
7 //** $Revision$
8 //** $Date$
9 //** $Author$
10 //**
11 //**************************************************************************
12
13 #include "h2def.h"
14 #include "p_local.h"
15 #include "soundst.h"
16
17 void P_PlayerNextArtifact(player_t *player);
18
19 // Macros
20
21 #define MAXBOB 0x100000 // 16 pixels of bob
22
23 // Data
24
25 boolean onground;
26 int newtorch; // used in the torch flicker effect.
27 int newtorchdelta;
28
29 int PStateNormal[NUMCLASSES] = 
30 {
31         S_FPLAY,
32         S_CPLAY,
33         S_MPLAY,
34 #ifdef ASSASSIN
35         S_APLAY,
36 #endif
37         S_PIGPLAY
38 };
39
40 int PStateRun[NUMCLASSES] = 
41 {
42         S_FPLAY_RUN1,
43         S_CPLAY_RUN1,
44         S_MPLAY_RUN1,
45 #ifdef ASSASSIN
46         S_APLAY_RUN1,
47 #endif
48         S_PIGPLAY_RUN1
49 };
50
51 int PStateAttack[NUMCLASSES] = 
52 {
53         S_FPLAY_ATK1,
54         S_CPLAY_ATK1,
55         S_MPLAY_ATK1,
56 #ifdef ASSASSIN
57         S_APLAY_ATK1,
58 #endif
59         S_PIGPLAY_ATK1
60 };
61
62 int PStateAttackEnd[NUMCLASSES] = 
63 {
64         S_FPLAY_ATK2,
65         S_CPLAY_ATK3,
66         S_MPLAY_ATK2,
67 #ifdef ASSASSIN
68         S_APLAY_ATK3,
69 #endif
70         S_PIGPLAY_ATK1  
71 };
72
73 int ArmorMax[NUMCLASSES] = { 20, 18, 16,
74 #ifdef ASSASSIN
75                                         17,
76 #endif
77                                         1 };
78
79 /*
80 ==================
81 =
82 = P_Thrust
83 =
84 = moves the given origin along a given angle
85 =
86 ==================
87 */
88
89 void P_Thrust(player_t *player, angle_t angle, fixed_t move)
90 {
91         angle >>= ANGLETOFINESHIFT;
92         if(player->powers[pw_flight] && !(player->mo->z <= player->mo->floorz))
93         {
94                 player->mo->momx += FixedMul(move, finecosine[angle]);
95                 player->mo->momy += FixedMul(move, finesine[angle]);
96         }
97         else if(P_GetThingFloorType(player->mo) == FLOOR_ICE) // Friction_Low
98         {
99                 player->mo->momx += FixedMul(move>>1, finecosine[angle]);
100                 player->mo->momy += FixedMul(move>>1, finesine[angle]);
101         }
102         else
103         {
104                 player->mo->momx += FixedMul(move, finecosine[angle]);
105                 player->mo->momy += FixedMul(move, finesine[angle]);
106         }
107 }
108
109
110 /*
111 ==================
112 =
113 = P_CalcHeight
114 =
115 =
116 Calculate the walking / running height adjustment
117 =
118 ==================
119 */
120
121 void P_CalcHeight (player_t *player)
122 {
123         int             angle;
124         fixed_t bob;
125
126 //
127 // regular movement bobbing (needs to be calculated for gun swing even
128 // if not on ground)
129 // OPTIMIZE: tablify angle
130
131         player->bob = FixedMul (player->mo->momx, player->mo->momx)+
132         FixedMul (player->mo->momy,player->mo->momy);
133         player->bob >>= 2;
134         if (player->bob>MAXBOB)
135                 player->bob = MAXBOB;
136         if(player->mo->flags2&MF2_FLY && !onground)
137         {
138                 player->bob = FRACUNIT/2;
139         }       
140         
141         if ((player->cheats & CF_NOMOMENTUM))
142         {
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;
147                 return;
148         }
149
150         angle = (FINEANGLES/20*leveltime)&FINEMASK;
151         bob = FixedMul ( player->bob/2, finesine[angle]);
152
153 //
154 // move viewheight
155 //
156         if (player->playerstate == PST_LIVE)
157         {
158                 player->viewheight += player->deltaviewheight;
159                 if (player->viewheight > VIEWHEIGHT)
160                 {
161                         player->viewheight = VIEWHEIGHT;
162                         player->deltaviewheight = 0;
163                 }
164                 if (player->viewheight < VIEWHEIGHT/2)
165                 {
166                         player->viewheight = VIEWHEIGHT/2;
167                         if (player->deltaviewheight <= 0)
168                                 player->deltaviewheight = 1;
169                 }
170
171                 if (player->deltaviewheight)
172                 {
173                         player->deltaviewheight += FRACUNIT/4;
174                         if (!player->deltaviewheight)
175                                 player->deltaviewheight = 1;
176                 }
177         }
178
179         if(player->morphTics)
180         {
181                 player->viewz = player->mo->z+player->viewheight-(20*FRACUNIT);
182         }
183         else
184         {
185                 player->viewz = player->mo->z+player->viewheight+bob;
186         }
187         if(player->mo->floorclip && player->playerstate != PST_DEAD
188                 && player->mo->z <= player->mo->floorz)
189         {
190                 player->viewz -= player->mo->floorclip;
191         }
192         if(player->viewz > player->mo->ceilingz-4*FRACUNIT)
193         {
194                 player->viewz = player->mo->ceilingz-4*FRACUNIT;
195         }
196         if(player->viewz < player->mo->floorz+4*FRACUNIT)
197         {
198                 player->viewz = player->mo->floorz+4*FRACUNIT;
199         }
200 }
201
202 /*
203 =================
204 =
205 = P_MovePlayer
206 =
207 =================
208 */
209
210 void P_MovePlayer(player_t *player)
211 {
212         int look;
213         int fly;
214         ticcmd_t *cmd;
215
216         cmd = &player->cmd;
217         player->mo->angle += (cmd->angleturn<<16);
218
219         onground = (player->mo->z <= player->mo->floorz
220                 || (player->mo->flags2&MF2_ONMOBJ));
221
222         if(cmd->forwardmove)
223         {
224                 if(onground || player->mo->flags2&MF2_FLY)
225                 {
226                         P_Thrust(player, player->mo->angle, cmd->forwardmove*2048);
227                 }
228                 else
229                 {
230                         P_Thrust(player, player->mo->angle, FRACUNIT>>8);
231                 }
232         }       
233         if(cmd->sidemove)
234         {
235                 if(onground || player->mo->flags2&MF2_FLY)
236                         {
237                         P_Thrust(player, player->mo->angle-ANG90, cmd->sidemove*2048);
238                 }
239                 else
240                 {
241                         P_Thrust(player, player->mo->angle, FRACUNIT>>8);
242                 }
243         }
244         if(cmd->forwardmove || cmd->sidemove)
245         {
246                 if(player->mo->state == &states[PStateNormal[player->class]])
247                 {
248                         P_SetMobjState(player->mo, PStateRun[player->class]);
249                 }
250         }
251
252         look = cmd->lookfly&15;
253         if(look > 7)
254         {
255                 look -= 16;
256         }
257         if(look)
258         {
259                 if(look == TOCENTER)
260                 {
261                         player->centering = true;
262                 }
263                 else
264                 {
265                         player->lookdir += 5*look;
266                         if(player->lookdir > 90 || player->lookdir < -110)
267                         {
268                                 player->lookdir -= 5*look;
269                         }
270                 }
271         }
272         if(player->centering)
273         {
274                 if(player->lookdir > 0)
275                 {
276                         player->lookdir -= 8;
277                 }
278                 else if(player->lookdir < 0)
279                 {
280                         player->lookdir += 8;
281                 }
282                 if(abs(player->lookdir) < 8)
283                 {
284                         player->lookdir = 0;
285                         player->centering = false;
286                 }
287         }
288         fly = cmd->lookfly>>4;
289         if(fly > 7)
290         {
291                 fly -= 16;
292         }
293         if(fly && player->powers[pw_flight])
294         {
295                 if(fly != TOCENTER)
296                 {
297                         player->flyheight = fly*2;
298                         if(!(player->mo->flags2&MF2_FLY))
299                         {
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);
305                                 }
306                         }
307                 }
308                 else
309                 {
310                         player->mo->flags2 &= ~MF2_FLY;
311                         player->mo->flags &= ~MF_NOGRAVITY;
312                 }
313         }
314         else if(fly > 0)
315         {
316                 P_PlayerUseArtifact(player, arti_fly);
317         }
318         if(player->mo->flags2&MF2_FLY)
319         {
320                 player->mo->momz = player->flyheight*FRACUNIT;
321                 if(player->flyheight)
322                 {
323                         player->flyheight /= 2;
324                 }
325         }
326 }
327
328 //==========================================================================
329 //
330 // P_DeathThink
331 //
332 //==========================================================================
333
334 void P_DeathThink(player_t *player)
335 {
336         int dir;
337         angle_t delta;
338         int lookDelta;
339         extern int inv_ptr;
340         extern int curpos;
341
342         P_MovePsprites(player);
343
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;
350                 if(onground)
351                 {
352                         if(player->lookdir < 60)
353                         {
354                                 lookDelta = (60-player->lookdir)/8;
355                                 if(lookDelta < 1 && (leveltime&1))
356                                 {
357                                         lookDelta = 1;
358                                 }
359                                 else if(lookDelta > 6)
360                                 {
361                                         lookDelta = 6;
362                                 }
363                                 player->lookdir += lookDelta;
364                         }
365                 }
366         }
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)
371                 {
372                         player->viewheight -= FRACUNIT;
373                 }
374                 if(player->viewheight < 6*FRACUNIT)
375                 {
376                         player->viewheight = 6*FRACUNIT;
377                 }
378                 if(player->lookdir > 0)
379                 {
380                         player->lookdir -= 6;
381                 }
382                 else if(player->lookdir < 0)
383                 {
384                         player->lookdir += 6;
385                 }
386                 if(abs(player->lookdir) < 6)
387                 {
388                         player->lookdir = 0;
389                 }
390         }
391         P_CalcHeight(player);
392
393         if(player->attacker && player->attacker != player->mo)
394         { // Watch killer
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)
399                         {
400                                 player->damagecount--;
401                         }
402                         if(player->poisoncount)
403                         {
404                                 player->poisoncount--;
405                         }
406                 }
407                 delta = delta/8;
408                 if(delta > ANGLE_1*5)
409                 {
410                         delta = ANGLE_1*5;
411                 }
412                 if(dir)
413                 { // Turn clockwise
414                         player->mo->angle += delta;
415                 }
416                 else
417                 { // Turn counter clockwise
418                         player->mo->angle -= delta;
419                 }
420         }
421         else if(player->damagecount || player->poisoncount)
422         {
423                 if(player->damagecount)
424                 {
425                         player->damagecount--;
426                 }
427                 else
428                 {
429                         player->poisoncount--;
430                 }
431         }
432
433         if(player->cmd.buttons&BT_USE)
434         {
435                 if(player == &players[consoleplayer])
436                 {
437                         I_SetPalette((byte *)W_CacheLumpName("PLAYPAL", PU_CACHE));
438                         inv_ptr = 0;
439                         curpos = 0;
440                         newtorch = 0;
441                         newtorchdelta = 0;
442                 }
443                 player->playerstate = PST_REBORN;
444                 player->mo->special1 = player->class;
445                 if(player->mo->special1 > 2)
446                 {
447                         player->mo->special1 = 0;
448                 }
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;
452         }
453 }
454
455 //----------------------------------------------------------------------------
456 //
457 // PROC P_MorphPlayerThink
458 //
459 //----------------------------------------------------------------------------
460
461 void P_MorphPlayerThink(player_t *player)
462 {
463         mobj_t *pmo;
464
465         if(player->morphTics&15)
466         {
467                 return;
468         }
469         pmo = player->mo;
470         if(!(pmo->momx+pmo->momy) && P_Random() < 64)
471         { // Snout sniff
472                 P_SetPspriteNF(player, ps_weapon, S_SNOUTATK2);
473                 S_StartSound(pmo, SFX_PIG_ACTIVE1); // snort
474                 return;
475         }
476         if(P_Random() < 48)
477         {
478                 if(P_Random() < 128)
479                 {
480                         S_StartSound(pmo, SFX_PIG_ACTIVE1);
481                 }
482                 else
483                 {
484                         S_StartSound(pmo, SFX_PIG_ACTIVE2);
485                 }
486         }               
487 }
488
489 //----------------------------------------------------------------------------
490 //
491 // FUNC P_GetPlayerNum
492 //
493 //----------------------------------------------------------------------------
494
495 int P_GetPlayerNum(player_t *player)
496 {
497         int i;
498
499         for(i = 0; i < MAXPLAYERS; i++)
500         {
501                 if(player == &players[i])
502                 {
503                         return(i);
504                 }
505         }
506         return(0);
507 }
508
509 //----------------------------------------------------------------------------
510 //
511 // FUNC P_UndoPlayerMorph
512 //
513 //----------------------------------------------------------------------------
514
515 boolean P_UndoPlayerMorph(player_t *player)
516 {
517         mobj_t *fog;
518         mobj_t *mo;
519         mobj_t *pmo;
520         fixed_t x;
521         fixed_t y;
522         fixed_t z;
523         angle_t angle;
524         int playerNum;
525         weapontype_t weapon;
526         int oldFlags;
527         int oldFlags2;
528         int oldBeast;
529
530         pmo = player->mo;
531         x = pmo->x;
532         y = pmo->y;
533         z = pmo->z;
534         angle = pmo->angle;
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])
542         {
543                 case PCLASS_FIGHTER:
544                         mo = P_SpawnMobj(x, y, z, MT_PLAYER_FIGHTER);
545                         break;
546                 case PCLASS_CLERIC:
547                         mo = P_SpawnMobj(x, y, z, MT_PLAYER_CLERIC);
548                         break;
549                 case PCLASS_MAGE:
550                         mo = P_SpawnMobj(x, y, z, MT_PLAYER_MAGE);
551                         break;
552 #ifdef ASSASSIN
553                 case PCLASS_ASS:
554                         mo = P_SpawnMobj(x, y, z, MT_PLAYER_ASS);
555                         break;
556 #endif
557                 default:
558                         I_Error("P_UndoPlayerMorph:  Unknown player class %d\n", 
559                                 player->class);
560                         /* jim never happens but keeps gcc happy */
561                         mo = NULL;
562                         break;
563         }
564         if(P_TestMobjLocation(mo) == false)
565         { // Didn't fit
566                 P_RemoveMobj(mo);
567                 mo = P_SpawnMobj(x, y, z, oldBeast);
568                 mo->angle = angle;
569                 mo->health = player->health;
570                 mo->special1 = weapon;
571                 mo->player = player;
572                 mo->flags = oldFlags;
573                 mo->flags2 = oldFlags2;
574                 player->mo = mo;
575                 player->morphTics = 2*35;
576                 return(false);
577         }
578         if(player->class == PCLASS_FIGHTER)
579         { 
580                 // The first type should be blue, and the third should be the
581                 // Fighter's original gold color
582                 if(playerNum == 0)
583                 {
584                         mo->flags |= 2<<MF_TRANSSHIFT;
585                 }
586                 else if(playerNum != 2)
587                 {
588                         mo->flags |= playerNum<<MF_TRANSSHIFT;
589                 }
590         }
591         else if(playerNum)
592         { // Set color translation bits for player sprites
593                 mo->flags |= playerNum<<MF_TRANSSHIFT;
594         }
595         mo->angle = angle;
596         mo->player = player;
597         mo->reactiontime = 18;
598         if(oldFlags2&MF2_FLY)
599         {
600                 mo->flags2 |= MF2_FLY;
601                 mo->flags |= MF_NOGRAVITY;
602         }
603         player->morphTics = 0;
604         player->health = mo->health = MAXHEALTH;
605         player->mo = mo;
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);
612         return(true);
613 }
614
615
616 //----------------------------------------------------------------------------
617 //
618 // PROC P_PlayerThink
619 //
620 //----------------------------------------------------------------------------
621
622 void P_PlayerThink(player_t *player)
623 {
624         ticcmd_t *cmd;
625         weapontype_t newweapon;
626         int floorType;          
627         mobj_t *pmo;            
628         
629         // No-clip cheat
630         if(player->cheats&CF_NOCLIP)
631         {
632                 player->mo->flags |= MF_NOCLIP;
633         }
634         else
635         {
636                 player->mo->flags &= ~MF_NOCLIP;
637         }
638         cmd = &player->cmd;
639         if(player->mo->flags&MF_JUSTATTACKED)
640         { // Gauntlets attack auto forward motion
641                 cmd->angleturn = 0;
642                 cmd->forwardmove = 0xc800/512;
643                 cmd->sidemove = 0;
644                 player->mo->flags &= ~MF_JUSTATTACKED;
645         }
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])
654                 {
655                         BorderTopRefresh = true;
656                 }
657         }
658         player->worldTimer++;
659         if(player->playerstate == PST_DEAD)
660         {
661                 P_DeathThink(player);
662                 return;
663         }
664         if(player->jumpTics)
665         {
666                 player->jumpTics--;
667         }
668         if(player->morphTics)
669         {
670                 P_MorphPlayerThink(player);
671         }
672         // Handle movement
673         if(player->mo->reactiontime)
674         { // Player is frozen
675                 player->mo->reactiontime--;
676         }
677         else
678         {
679                 P_MovePlayer(player);
680                 pmo = player->mo;
681                 if(player->powers[pw_speed] && !(leveltime&1)
682                         && P_AproxDistance(pmo->momx, pmo->momy) > 12*FRACUNIT)
683                 {
684                         mobj_t *speedMo;
685                         int playerNum;
686
687                         speedMo = P_SpawnMobj(pmo->x, pmo->y, pmo->z, MT_PLAYER_SPEED);
688                         if(speedMo)
689                         {
690                                 speedMo->angle = pmo->angle;
691                                 playerNum = P_GetPlayerNum(player);
692                                 if(player->class == PCLASS_FIGHTER)
693                                 { 
694                                         // The first type should be blue, and the 
695                                         // third should be the Fighter's original gold color
696                                         if(playerNum == 0)
697                                         {
698                                                 speedMo->flags |= 2<<MF_TRANSSHIFT;
699                                         }
700                                         else if(playerNum != 2)
701                                         {
702                                                 speedMo->flags |= playerNum<<MF_TRANSSHIFT;
703                                         }
704                                 }
705                                 else if(playerNum)
706                                 { // Set color translation bits for player sprites
707                                         speedMo->flags |= playerNum<<MF_TRANSSHIFT;
708                                 }
709                                 speedMo->target = pmo;
710                                 speedMo->special1 = player->class;
711                                 if(speedMo->special1 > 2)
712                                 {
713                                         speedMo->special1 = 0;
714                                 }
715                                 speedMo->sprite = pmo->sprite;
716                                 speedMo->floorclip = pmo->floorclip;
717                                 if(player == &players[consoleplayer])
718                                 {
719                                         speedMo->flags2 |= MF2_DONTDRAW;
720                                 }
721                         }
722                 }
723         }
724         P_CalcHeight(player);
725         if(player->mo->subsector->sector->special)
726         {
727                 P_PlayerInSpecialSector(player);
728         }
729         if((floorType = P_GetThingFloorType(player->mo)) != FLOOR_SOLID)
730         {
731                 P_PlayerOnSpecialFlat(player, floorType);
732         }
733         switch(player->class)
734         {
735                 case PCLASS_FIGHTER:
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))
740                                 {
741                                         S_StartSound(player->mo, 
742                                                 SFX_PLAYER_FIGHTER_FALLING_SCREAM);
743                                 }
744                         break;
745                 case PCLASS_CLERIC:
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))
750                                 {
751                                         S_StartSound(player->mo, 
752                                                 SFX_PLAYER_CLERIC_FALLING_SCREAM);
753                                 }
754                         break;
755                 case PCLASS_MAGE:
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))
760                                 {
761                                         S_StartSound(player->mo, 
762                                                 SFX_PLAYER_MAGE_FALLING_SCREAM);
763                                 }
764 #ifdef ASSASSIN
765                 case PCLASS_ASS:
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))
770                                 {
771                                         S_StartSound(player->mo, 
772                                                 SFX_PLAYER_MAGE_FALLING_SCREAM);
773                                 }
774                         break;
775 #endif
776                 default:
777                         break;
778         }
779         if(cmd->arti)
780         { // Use an artifact
781                 if((cmd->arti&AFLAG_JUMP) && onground && !player->jumpTics)
782                 {
783                         if(player->morphTics)
784                         {
785                                 player->mo->momz = 6*FRACUNIT;
786                         }
787                         else 
788                         {
789                                 player->mo->momz = 9*FRACUNIT;
790                         }
791                         player->mo->flags2 &= ~MF2_ONMOBJ;
792                         player->jumpTics = 18; 
793                 }
794                 else if(cmd->arti&AFLAG_SUICIDE)
795                 {
796                         P_DamageMobj(player->mo, NULL, NULL, 10000);
797                 }
798                 if(cmd->arti == NUMARTIFACTS)
799                 { // use one of each artifact (except puzzle artifacts)
800                         int i;
801
802                         for(i = 1; i < arti_firstpuzzitem; i++)
803                         {
804                                 P_PlayerUseArtifact(player, i);
805                         }
806                 }
807                 else
808                 {
809                         P_PlayerUseArtifact(player, cmd->arti&AFLAG_MASK);
810                 }
811         }
812         // Check for weapon change
813         if(cmd->buttons&BT_SPECIAL)
814         { // A special event has no other buttons
815                 cmd->buttons = 0;
816         }
817         if(cmd->buttons&BT_CHANGE && !player->morphTics)
818         {
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)
825                 {
826                         player->pendingweapon = newweapon;
827                 }
828         }
829         // Check for use
830         if(cmd->buttons&BT_USE)
831         {
832                 if(!player->usedown)
833                 {
834                         P_UseLines(player);
835                         player->usedown = true;
836                 }
837         }
838         else
839         {
840                 player->usedown = false;
841         }
842         // Morph counter
843         if(player->morphTics)
844         {
845                 if(!--player->morphTics)
846                 { // Attempt to undo the pig
847                         P_UndoPlayerMorph(player);
848                 }
849         }
850         // Cycle psprites
851         P_MovePsprites(player);
852         // Other Counters
853         if(player->powers[pw_invulnerability])
854         {
855                 if(player->class == PCLASS_CLERIC)
856                 {
857                         if(!(leveltime&7) && player->mo->flags&MF_SHADOW
858                                 && !(player->mo->flags2&MF2_DONTDRAW))
859                         {
860                                 player->mo->flags &= ~MF_SHADOW;
861                                 if(!(player->mo->flags&MF_ALTSHADOW))
862                                 {
863                                         player->mo->flags2 |= MF2_DONTDRAW|MF2_NONSHOOTABLE;
864                                 }
865                         }
866                         if(!(leveltime&31))
867                         {
868                                 if(player->mo->flags2&MF2_DONTDRAW)
869                                 {
870                                         if(!(player->mo->flags&MF_SHADOW))
871                                         {
872                                                 player->mo->flags |= MF_SHADOW|MF_ALTSHADOW;
873                                         }
874                                         else
875                                         {
876                                                 player->mo->flags2 &= ~(MF2_DONTDRAW|MF2_NONSHOOTABLE);
877                                         }
878                                 }
879                                 else
880                                 {
881                                         player->mo->flags |= MF_SHADOW;
882                                         player->mo->flags &= ~MF_ALTSHADOW;
883                                 }
884                         }               
885                 }
886                 if(!(--player->powers[pw_invulnerability]))
887                 {
888                         player->mo->flags2 &= ~(MF2_INVULNERABLE|MF2_REFLECTIVE);
889                         if(player->class == PCLASS_CLERIC)
890                         {
891                                 player->mo->flags2 &= ~(MF2_DONTDRAW|MF2_NONSHOOTABLE);
892                                 player->mo->flags &= ~(MF_SHADOW|MF_ALTSHADOW);
893                         }
894                 }
895         }
896         if(player->powers[pw_minotaur])
897         {
898                 player->powers[pw_minotaur]--;
899         }
900         if(player->powers[pw_infrared])
901         {
902                 player->powers[pw_infrared]--;
903         }
904         if(player->powers[pw_flight] && netgame)
905         {
906                 if(!--player->powers[pw_flight])
907                 {
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
912                 }
913         }
914         if(player->powers[pw_speed])
915         {
916                 player->powers[pw_speed]--;
917         }
918         if(player->damagecount)
919         {
920                 player->damagecount--;
921         }
922         if(player->bonuscount)
923         {
924                 player->bonuscount--;
925         }
926         if(player->poisoncount && !(leveltime&15))
927         {
928                 player->poisoncount -= 5;
929                 if(player->poisoncount < 0)
930                 {
931                         player->poisoncount = 0;
932                 }
933                 P_PoisonDamage(player, player->poisoner, 1, true); 
934         }
935         // Colormaps
936 //      if(player->powers[pw_invulnerability])
937 //      {
938 //              if(player->powers[pw_invulnerability] > BLINKTHRESHOLD
939 //                      || (player->powers[pw_invulnerability]&8))
940 //              {
941 //                      player->fixedcolormap = INVERSECOLORMAP;
942 //              }
943 //              else
944 //              {
945 //                      player->fixedcolormap = 0;
946 //              }
947 //      }
948 //      else 
949         if(player->powers[pw_infrared])
950         {
951                 if (player->powers[pw_infrared] <= BLINKTHRESHOLD)
952                 {
953                         if(player->powers[pw_infrared]&8)
954                         {
955                                 player->fixedcolormap = 0;
956                         }
957                         else
958                         {
959                                 player->fixedcolormap = 1;
960                         }
961                 }
962                 else if(!(leveltime&16) && player == &players[consoleplayer])
963                 {
964                         if(newtorch)
965                         {
966                                 if(player->fixedcolormap+newtorchdelta > 7 
967                                         || player->fixedcolormap+newtorchdelta < 1
968                                         || newtorch == player->fixedcolormap)
969                                 {
970                                         newtorch = 0;
971                                 }
972                                 else
973                                 {
974                                         player->fixedcolormap += newtorchdelta;
975                                 }
976                         }
977                         else
978                         {
979                                 newtorch = (M_Random()&7)+1;
980                                 newtorchdelta = (newtorch == player->fixedcolormap) ?
981                                                 0 : ((newtorch > player->fixedcolormap) ? 1 : -1);
982                         }
983                 }
984         }
985         else
986         {
987                 player->fixedcolormap = 0;
988         }
989 }
990
991 //----------------------------------------------------------------------------
992 //
993 // PROC P_ArtiTele
994 //
995 //----------------------------------------------------------------------------
996
997 void P_ArtiTele(player_t *player)
998 {
999         int i;
1000         int selections;
1001         fixed_t destX;
1002         fixed_t destY;
1003         angle_t destAngle;
1004
1005         if(deathmatch)
1006         {
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);
1012         }
1013         else
1014         {
1015                 destX = playerstarts[0][0].x<<FRACBITS;
1016                 destY = playerstarts[0][0].y<<FRACBITS;
1017                 destAngle = ANG45*(playerstarts[0][0].angle/45);
1018         }
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);
1023         }
1024         //S_StartSound(NULL, sfx_wpnup); // Full volume laugh
1025 }
1026
1027
1028 //----------------------------------------------------------------------------
1029 //
1030 // PROC P_ArtiTeleportOther
1031 //
1032 //----------------------------------------------------------------------------
1033
1034 void P_ArtiTeleportOther(player_t *player)
1035 {
1036         mobj_t *mo;
1037
1038         mo=P_SpawnPlayerMissile(player->mo, MT_TELOTHER_FX1);
1039         if (mo)
1040         {
1041                 mo->target = player->mo;
1042         }
1043 }
1044
1045
1046 void P_TeleportToPlayerStarts(mobj_t *victim)
1047 {
1048         int i,selections=0;
1049         fixed_t destX,destY;
1050         angle_t destAngle;
1051
1052         for (i=0;i<MAXPLAYERS;i++)
1053         {
1054             if (!playeringame[i]) continue;
1055                 selections++;
1056         }
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
1063 }
1064
1065 void P_TeleportToDeathmatchStarts(mobj_t *victim)
1066 {
1067         int i,selections;
1068         fixed_t destX,destY;
1069         angle_t destAngle;
1070
1071         selections = deathmatch_p-deathmatchstarts;
1072         if (selections)
1073         {
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
1080         }
1081         else
1082         {
1083                 P_TeleportToPlayerStarts(victim);
1084         }
1085 }
1086
1087
1088
1089 //----------------------------------------------------------------------------
1090 //
1091 // PROC P_TeleportOther
1092 //
1093 //----------------------------------------------------------------------------
1094 void P_TeleportOther(mobj_t *victim)
1095 {
1096         if (victim->player)
1097         {
1098                 if (deathmatch)
1099                         P_TeleportToDeathmatchStarts(victim);
1100                 else
1101                         P_TeleportToPlayerStarts(victim);
1102         }
1103         else
1104         {
1105                 // If death action, run it upon teleport
1106                 if (victim->flags&MF_COUNTKILL && victim->special)
1107                 {
1108                         P_RemoveMobjFromTIDList(victim);
1109                         P_ExecuteLineSpecial(victim->special, victim->args,
1110                                         NULL, 0, victim);
1111                         victim->special = 0;
1112                 }
1113
1114                 // Send all monsters to deathmatch spots
1115                 P_TeleportToDeathmatchStarts(victim);
1116         }
1117 }
1118
1119
1120
1121 #define BLAST_RADIUS_DIST       255*FRACUNIT
1122 #define BLAST_SPEED                     20*FRACUNIT
1123 #define BLAST_FULLSTRENGTH      255
1124
1125 void ResetBlasted(mobj_t *mo)
1126 {
1127         mo->flags2 &= ~MF2_BLASTED;
1128         if (!(mo->flags&MF_ICECORPSE))
1129         {
1130                 mo->flags2 &= ~MF2_SLIDE;
1131         }
1132 }
1133
1134 void P_BlastMobj(mobj_t *source, mobj_t *victim, fixed_t strength)
1135 {
1136         angle_t angle,ang;
1137         mobj_t *mo;
1138         fixed_t x,y,z;
1139
1140         angle = R_PointToAngle2(source->x, source->y, victim->x, victim->y);
1141         angle >>= ANGLETOFINESHIFT;
1142         if (strength < BLAST_FULLSTRENGTH)
1143         {
1144                 victim->momx = FixedMul(strength, finecosine[angle]);
1145                 victim->momy = FixedMul(strength, finesine[angle]);
1146                 if (victim->player)
1147                 {
1148                         // Players handled automatically
1149                 }
1150                 else
1151                 {
1152                         victim->flags2 |= MF2_SLIDE;
1153                         victim->flags2 |= MF2_BLASTED;
1154                 }
1155         }
1156         else            // full strength blast from artifact
1157         {
1158                 if (victim->flags&MF_MISSILE)
1159                 {
1160                         switch(victim->type)
1161                         {
1162                                 case MT_SORCBALL1:      // don't blast sorcerer balls
1163                                 case MT_SORCBALL2:
1164                                 case MT_SORCBALL3:
1165                                         return;
1166                                         break;
1167                                 case MT_MSTAFF_FX2:     // Reflect to originator
1168                                         victim->special1 = (int)victim->target; 
1169                                         victim->target = source;
1170                                         break;
1171                                 default:
1172                                         break;
1173                         }
1174                 }
1175                 if (victim->type == MT_HOLY_FX)
1176                 {
1177                         if ((mobj_t *)(victim->special1) == source)
1178                         {
1179                                 victim->special1 = (int)victim->target; 
1180                                 victim->target = source;
1181                         }
1182                 }
1183                 victim->momx = FixedMul(BLAST_SPEED, finecosine[angle]);
1184                 victim->momy = FixedMul(BLAST_SPEED, finesine[angle]);
1185
1186                 // Spawn blast puff
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);
1193                 if (mo)
1194                 {
1195                         mo->momx = victim->momx;
1196                         mo->momy = victim->momy;
1197                 }
1198
1199                 if (victim->flags&MF_MISSILE)
1200                 {
1201                         victim->momz = 8*FRACUNIT;
1202                         mo->momz = victim->momz;
1203                 }
1204                 else
1205                 {
1206                         victim->momz = (1000/victim->info->mass)<<FRACBITS;
1207                 }
1208                 if (victim->player)
1209                 {
1210                         // Players handled automatically
1211                 }
1212                 else
1213                 {
1214                         victim->flags2 |= MF2_SLIDE;
1215                         victim->flags2 |= MF2_BLASTED;
1216                 }
1217         }
1218 }
1219
1220
1221 // Blast all mobj things away
1222 void P_BlastRadius(player_t *player)
1223 {
1224         mobj_t *mo;
1225         mobj_t *pmo=player->mo;
1226         thinker_t *think;
1227         fixed_t dist;
1228
1229         S_StartSound(pmo, SFX_ARTIFACT_BLAST);
1230         P_NoiseAlert(player->mo, player->mo);
1231
1232         for(think = thinkercap.next; think != &thinkercap; think = think->next)
1233         {
1234                 if(think->function != P_MobjThinker)
1235                 { // Not a mobj thinker
1236                         continue;
1237                 }
1238                 mo = (mobj_t *)think;
1239                 if((mo == pmo) || (mo->flags2&MF2_BOSS))
1240                 { // Not a valid monster
1241                         continue;
1242                 }
1243                 if ((mo->type == MT_POISONCLOUD) ||             // poison cloud
1244                         (mo->type == MT_HOLY_FX) ||                     // holy fx
1245                         (mo->flags&MF_ICECORPSE))                       // frozen corpse
1246                 {
1247                         // Let these special cases go
1248                 }
1249                 else if ((mo->flags&MF_COUNTKILL) &&
1250                         (mo->health <= 0))
1251                 {
1252                         continue;
1253                 }
1254                 else if (!(mo->flags&MF_COUNTKILL) &&
1255                         !(mo->player) &&
1256                         !(mo->flags&MF_MISSILE))
1257                 {       // Must be monster, player, or missile
1258                         continue;
1259                 }
1260                 if (mo->flags2&MF2_DORMANT)
1261                 {
1262                         continue;               // no dormant creatures
1263                 }
1264                 if ((mo->type == MT_WRAITHB) && (mo->flags2&MF2_DONTDRAW))
1265                 {
1266                         continue;               // no underground wraiths
1267                 }
1268                 if ((mo->type == MT_SPLASHBASE) ||
1269                         (mo->type == MT_SPLASH))
1270                 {
1271                         continue;
1272                 }
1273                 if(mo->type == MT_SERPENT || mo->type == MT_SERPENTLEADER)
1274                 {
1275                         continue;
1276                 }
1277                 dist = P_AproxDistance(pmo->x - mo->x, pmo->y - mo->y);
1278                 if(dist > BLAST_RADIUS_DIST)
1279                 { // Out of range
1280                         continue;
1281                 }
1282                 P_BlastMobj(pmo, mo, BLAST_FULLSTRENGTH);
1283         }
1284 }
1285
1286
1287 #define HEAL_RADIUS_DIST        255*FRACUNIT
1288
1289 // Do class specific effect for everyone in radius
1290 boolean P_HealRadius(player_t *player)
1291 {
1292         mobj_t *mo;
1293         mobj_t *pmo=player->mo;
1294         thinker_t *think;
1295         fixed_t dist;
1296         int effective=false;
1297         int amount;
1298
1299         for(think = thinkercap.next; think != &thinkercap; think = think->next)
1300         {
1301                 if(think->function != P_MobjThinker)
1302                 { // Not a mobj thinker
1303                         continue;
1304                 }
1305                 mo = (mobj_t *)think;
1306
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)
1311                 { // Out of range
1312                         continue;
1313                 }
1314
1315                 switch(player->class)
1316                 {
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)))
1322                                 {
1323                                         effective=true;
1324                                         S_StartSound(mo, SFX_MYSTICINCANT);
1325                                 }
1326                                 break;
1327                         case PCLASS_CLERIC:                     // Radius heal
1328                                 amount = 50 + (P_Random()%50);
1329                                 if (P_GiveBody(mo->player, amount))
1330                                 {
1331                                         effective=true;
1332                                         S_StartSound(mo, SFX_MYSTICINCANT);
1333                                 }
1334                                 break;
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)))
1339                                 {
1340                                         effective=true;
1341                                         S_StartSound(mo, SFX_MYSTICINCANT);
1342                                 }
1343                                 break;
1344 #ifdef ASSASSIN
1345                         case PCLASS_ASS:                // Also Radius heal
1346                                 amount = 50 + (P_Random()%50);
1347                                 if (P_GiveBody(mo->player, amount))
1348                                 {
1349                                         effective=true;
1350                                         S_StartSound(mo, SFX_MYSTICINCANT);
1351                                 }
1352                                 break;
1353 #endif
1354                         case PCLASS_PIG:
1355                         default:
1356                                 break;
1357                 }
1358         }
1359         return(effective);
1360 }
1361
1362
1363 //----------------------------------------------------------------------------
1364 //
1365 // PROC P_PlayerNextArtifact
1366 //
1367 //----------------------------------------------------------------------------
1368
1369 void P_PlayerNextArtifact(player_t *player)
1370 {
1371         extern int inv_ptr;
1372         extern int curpos;
1373
1374         if(player == &players[consoleplayer])
1375         {
1376                 inv_ptr--;
1377                 if(inv_ptr < 6)
1378                 {
1379                         curpos--;
1380                         if(curpos < 0)
1381                         {
1382                                 curpos = 0;
1383                         }
1384                 }
1385                 if(inv_ptr < 0)
1386                 {
1387                         inv_ptr = player->inventorySlotNum-1;
1388                         if(inv_ptr < 6)
1389                         {
1390                                 curpos = inv_ptr;
1391                         }
1392                         else
1393                         {
1394                                 curpos = 6;
1395                         }
1396                 }
1397                 player->readyArtifact =
1398                         player->inventory[inv_ptr].type;
1399         }
1400 }
1401
1402 //----------------------------------------------------------------------------
1403 //
1404 // PROC P_PlayerRemoveArtifact
1405 //
1406 //----------------------------------------------------------------------------
1407
1408 void P_PlayerRemoveArtifact(player_t *player, int slot)
1409 {
1410         int i;
1411         extern int inv_ptr;
1412         extern int curpos;
1413
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++)
1420                 {
1421                         player->inventory[i-1] = player->inventory[i];
1422                 }
1423                 player->inventorySlotNum--;
1424                 if(player == &players[consoleplayer])
1425                 { // Set position markers and get next readyArtifact
1426                         inv_ptr--;
1427                         if(inv_ptr < 6)
1428                         {
1429                                 curpos--;
1430                                 if(curpos < 0)
1431                                 {
1432                                         curpos = 0;
1433                                 }
1434                         }
1435                         if(inv_ptr >= player->inventorySlotNum)
1436                         {
1437                                 inv_ptr = player->inventorySlotNum-1;
1438                         }
1439                         if(inv_ptr < 0)
1440                         {
1441                                 inv_ptr = 0;
1442                         }
1443                         player->readyArtifact =
1444                                 player->inventory[inv_ptr].type;
1445                 }
1446         }
1447 }
1448
1449 //----------------------------------------------------------------------------
1450 //
1451 // PROC P_PlayerUseArtifact
1452 //
1453 //----------------------------------------------------------------------------
1454
1455 void P_PlayerUseArtifact(player_t *player, artitype_t arti)
1456 {
1457         int i;
1458
1459         for(i = 0; i < player->inventorySlotNum; i++)
1460         {
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])
1467                                 {
1468                                         if(arti < arti_firstpuzzitem)
1469                                         {
1470                                                 S_StartSound(NULL, SFX_ARTIFACT_USE);
1471                                         }
1472                                         else
1473                                         {
1474                                                 S_StartSound(NULL, SFX_PUZZLE_SUCCESS);
1475                                         }
1476                                         ArtifactFlash = 4;
1477                                 }
1478                         }
1479                         else if(arti < arti_firstpuzzitem)
1480                         { // Unable to use artifact, advance pointer
1481                                 P_PlayerNextArtifact(player);
1482                         }
1483                         break;
1484                 }
1485         }
1486 }
1487
1488 //==========================================================================
1489 //
1490 // P_UseArtifact
1491 //
1492 // Returns true if the artifact was used.
1493 //
1494 //==========================================================================
1495
1496 boolean P_UseArtifact(player_t *player, artitype_t arti)
1497 {
1498         mobj_t *mo;
1499         angle_t angle;
1500         int i;
1501         int count;
1502
1503         switch(arti)
1504         {
1505                 case arti_invulnerability:
1506                         if(!P_GivePower(player, pw_invulnerability))
1507                         {
1508                                 return(false);
1509                         }
1510                         break;
1511                 case arti_health:
1512                         if(!P_GiveBody(player, 25))
1513                         {
1514                                 return(false);
1515                         }
1516                         break;
1517                 case arti_superhealth:
1518                         if(!P_GiveBody(player, 100))
1519                         {
1520                                 return(false);
1521                         }
1522                         break;
1523                 case arti_healingradius:
1524                         if (!P_HealRadius(player))
1525                         {
1526                                 return(false);
1527                         }
1528                         break;
1529                 case arti_torch:
1530                         if(!P_GivePower(player, pw_infrared))
1531                         {
1532                                 return(false);
1533                         }
1534                         break;
1535                 case arti_egg:
1536                         mo = player->mo;
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));
1542                         break;
1543                 case arti_fly:
1544                         if(!P_GivePower(player, pw_flight))
1545                         {
1546                                 return(false);
1547                         }
1548                         if(player->mo->momz <= -35*FRACUNIT)
1549                         { // stop falling scream
1550                                 S_StopSound(player->mo);
1551                         }
1552                         break;
1553                 case arti_summon:
1554                         mo = P_SpawnPlayerMissile(player->mo, MT_SUMMON_FX);
1555                         if (mo)
1556                         {
1557                                 mo->target = player->mo;
1558                                 mo->special1 = (int)(player->mo);
1559                                 mo->momz = 5*FRACUNIT;
1560                         }
1561                         break;
1562                 case arti_teleport:
1563                         P_ArtiTele(player);
1564                         break;
1565                 case arti_teleportother:
1566                         P_ArtiTeleportOther(player);
1567                         break;
1568                 case arti_poisonbag:
1569                         angle = player->mo->angle>>ANGLETOFINESHIFT;
1570                         if(player->class == PCLASS_CLERIC)
1571                         {
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);
1575                                 if(mo)
1576                                 {
1577                                         mo->target = player->mo;
1578                                 }
1579                         }
1580                         else if(player->class == PCLASS_MAGE)
1581                         {
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);
1585                                 if(mo)
1586                                 {
1587                                         mo->target = player->mo;
1588                                 }
1589                         }                       
1590                         else // PCLASS_FIGHTER, obviously (also pig, not so obviously)
1591                         {
1592                                 mo = P_SpawnMobj(player->mo->x, player->mo->y, 
1593                                         player->mo->z-player->mo->floorclip+35*FRACUNIT,
1594                                         MT_THROWINGBOMB);
1595                                 if(mo)
1596                                 {
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);                                                                                        
1606                                 } 
1607                         }
1608                         break;
1609                 case arti_speed:
1610                         if(!P_GivePower(player, pw_speed))
1611                         {
1612                                 return(false);
1613                         }
1614                         break;
1615                 case arti_boostmana:
1616                         if(!P_GiveMana(player, MANA_1, MAX_MANA))
1617                         {
1618                                 if(!P_GiveMana(player, MANA_2, MAX_MANA))
1619                                 {
1620                                         return false;
1621                                 }
1622                                 
1623                         }
1624                         else 
1625                         {
1626                                 P_GiveMana(player, MANA_2, MAX_MANA);
1627                         }
1628                         break;
1629                 case arti_boostarmor:
1630                         count = 0;
1631
1632                         for(i = 0; i < NUMARMOR; i++)
1633                         {
1634                                 count += P_GiveArmor(player, i, 1); // 1 point per armor type
1635                         }
1636                         if(!count)
1637                         {
1638                                 return false;
1639                         }
1640                         break;
1641                 case arti_blastradius:
1642                         P_BlastRadius(player);
1643                         break;
1644
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))
1663                         {
1664                                 return true;
1665                         }
1666                         else
1667                         {
1668                                 P_SetYellowMessage(player, TXT_USEPUZZLEFAILED, false);
1669                                 return false;
1670                         }
1671                         break;
1672                 default:
1673                         return false;
1674         }
1675         return true;
1676 }
1677
1678 //============================================================================
1679 //
1680 // A_SpeedFade
1681 //
1682 //============================================================================
1683
1684 void A_SpeedFade(mobj_t *actor)
1685 {
1686         actor->flags |= MF_SHADOW;
1687         actor->flags &= ~MF_ALTSHADOW;
1688         actor->sprite = actor->target->sprite;
1689 }
1690