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