]> icculus.org git repositories - theoddone33/hheretic.git/blob - base/p_user.c
Beginning removal of GLU.
[theoddone33/hheretic.git] / base / p_user.c
1
2 // P_user.c
3
4 #include <stdlib.h>
5 #include "doomdef.h"
6 #include "p_local.h"
7 #include "soundst.h"
8
9 void P_PlayerNextArtifact(player_t *player);
10
11 // Macros
12
13 #define MAXBOB 0x100000 // 16 pixels of bob
14
15 // Data
16
17 boolean onground;
18 int newtorch; // used in the torch flicker effect.
19 int newtorchdelta;
20
21 boolean WeaponInShareware[] =
22 {
23         true,           // Staff
24         true,           // Gold wand
25         true,           // Crossbow
26         true,           // Blaster
27         false,          // Skull rod
28         false,          // Phoenix rod
29         false,          // Mace
30         true,           // Gauntlets
31         true            // Beak
32 };
33
34 /*
35 ==================
36 =
37 = P_Thrust
38 =
39 = moves the given origin along a given angle
40 =
41 ==================
42 */
43
44 void P_Thrust(player_t *player, angle_t angle, fixed_t move)
45 {
46         angle >>= ANGLETOFINESHIFT;
47         if(player->powers[pw_flight] && !(player->mo->z <= player->mo->floorz))
48         {
49                 player->mo->momx += FixedMul(move, finecosine[angle]);
50                 player->mo->momy += FixedMul(move, finesine[angle]);
51         }
52         else if(player->mo->subsector->sector->special == 15) // Friction_Low
53         {
54                 player->mo->momx += FixedMul(move>>2, finecosine[angle]);
55                 player->mo->momy += FixedMul(move>>2, finesine[angle]);
56         }
57         else
58         {
59                 player->mo->momx += FixedMul(move, finecosine[angle]);
60                 player->mo->momy += FixedMul(move, finesine[angle]);
61         }
62 }
63
64
65 /*
66 ==================
67 =
68 = P_CalcHeight
69 =
70 =Calculate the walking / running height adjustment
71 =
72 ==================
73 */
74
75 void P_CalcHeight (player_t *player)
76 {
77         int             angle;
78         fixed_t bob;
79
80 //
81 // regular movement bobbing (needs to be calculated for gun swing even
82 // if not on ground)
83 // OPTIMIZE: tablify angle
84
85         player->bob = FixedMul (player->mo->momx, player->mo->momx)+
86         FixedMul (player->mo->momy,player->mo->momy);
87         player->bob >>= 2;
88         if (player->bob>MAXBOB)
89                 player->bob = MAXBOB;
90         if(player->mo->flags2&MF2_FLY && !onground)
91         {
92                 player->bob = FRACUNIT/2;
93         }
94
95         if ((player->cheats & CF_NOMOMENTUM))
96         {
97                 player->viewz = player->mo->z + VIEWHEIGHT;
98                 if (player->viewz > player->mo->ceilingz-4*FRACUNIT)
99                         player->viewz = player->mo->ceilingz-4*FRACUNIT;
100                 player->viewz = player->mo->z + player->viewheight;
101                 return;
102         }
103
104         angle = (FINEANGLES/20*leveltime)&FINEMASK;
105         bob = FixedMul ( player->bob/2, finesine[angle]);
106
107 //
108 // move viewheight
109 //
110         if (player->playerstate == PST_LIVE)
111         {
112                 player->viewheight += player->deltaviewheight;
113                 if (player->viewheight > VIEWHEIGHT)
114                 {
115                         player->viewheight = VIEWHEIGHT;
116                         player->deltaviewheight = 0;
117                 }
118                 if (player->viewheight < VIEWHEIGHT/2)
119                 {
120                         player->viewheight = VIEWHEIGHT/2;
121                         if (player->deltaviewheight <= 0)
122                                 player->deltaviewheight = 1;
123                 }
124
125                 if (player->deltaviewheight)
126                 {
127                         player->deltaviewheight += FRACUNIT/4;
128                         if (!player->deltaviewheight)
129                                 player->deltaviewheight = 1;
130                 }
131         }
132
133         if(player->chickenTics)
134         {
135                 player->viewz = player->mo->z+player->viewheight-(20*FRACUNIT);
136         }
137         else
138         {
139                 player->viewz = player->mo->z+player->viewheight+bob;
140         }
141         if(player->mo->flags2&MF2_FEETARECLIPPED
142                 && player->playerstate != PST_DEAD
143                 && player->mo->z <= player->mo->floorz)
144         {
145                 player->viewz -= FOOTCLIPSIZE;
146         }
147         if(player->viewz > player->mo->ceilingz-4*FRACUNIT)
148         {
149                 player->viewz = player->mo->ceilingz-4*FRACUNIT;
150         }
151         if(player->viewz < player->mo->floorz+4*FRACUNIT)
152         {
153                 player->viewz = player->mo->floorz+4*FRACUNIT;
154         }
155 }
156
157 /*
158 =================
159 =
160 = P_MovePlayer
161 =
162 =================
163 */
164
165 void P_MovePlayer(player_t *player)
166 {
167         int look;
168         int fly;
169         ticcmd_t *cmd;
170
171         cmd = &player->cmd;
172         player->mo->angle += (cmd->angleturn<<16);
173
174         onground = (player->mo->z <= player->mo->floorz
175                 || (player->mo->flags2&MF2_ONMOBJ));
176
177         if(player->chickenTics)
178         { // Chicken speed
179                 if(cmd->forwardmove && (onground||player->mo->flags2&MF2_FLY))
180                         P_Thrust(player, player->mo->angle, cmd->forwardmove*2500);
181                 if(cmd->sidemove && (onground||player->mo->flags2&MF2_FLY))
182                         P_Thrust(player, player->mo->angle-ANG90, cmd->sidemove*2500);
183         }
184         else
185         { // Normal speed
186                 if(cmd->forwardmove && (onground||player->mo->flags2&MF2_FLY))
187                         P_Thrust(player, player->mo->angle, cmd->forwardmove*2048);
188                 if(cmd->sidemove && (onground||player->mo->flags2&MF2_FLY))
189                         P_Thrust(player, player->mo->angle-ANG90, cmd->sidemove*2048);
190         }
191
192         if(cmd->forwardmove || cmd->sidemove)
193         {
194                 if(player->chickenTics)
195                 {
196                         if(player->mo->state == &states[S_CHICPLAY])
197                         {
198                                 P_SetMobjState(player->mo, S_CHICPLAY_RUN1);
199                         }
200                 }
201                 else
202                 {
203                         if(player->mo->state == &states[S_PLAY])
204                         {
205                                 P_SetMobjState(player->mo, S_PLAY_RUN1);
206                         }
207                 }
208         }
209
210         look = cmd->lookfly&15;
211         if(look > 7)
212         {
213                 look -= 16;
214         }
215         if(look)
216         {
217                 if(look == TOCENTER)
218                 {
219                         player->centering = true;
220                 }
221                 else
222                 {
223                         player->lookdir += 5*look;
224                         if(player->lookdir > 90 || player->lookdir < -110)
225                         {
226                                 player->lookdir -= 5*look;
227                         }
228                 }
229         }
230         if(player->centering)
231         {
232                 if(player->lookdir > 0)
233                 {
234                         player->lookdir -= 8;
235                 }
236                 else if(player->lookdir < 0)
237                 {
238                         player->lookdir += 8;
239                 }
240                 if(abs(player->lookdir) < 8)
241                 {
242                         player->lookdir = 0;
243                         player->centering = false;
244                 }
245         }
246         fly = cmd->lookfly>>4;
247         if(fly > 7)
248         {
249                 fly -= 16;
250         }
251         if(fly && player->powers[pw_flight])
252         {
253                 if(fly != TOCENTER)
254                 {
255                         player->flyheight = fly*2;
256                         if(!(player->mo->flags2&MF2_FLY))
257                         {
258                                 player->mo->flags2 |= MF2_FLY;
259                                 player->mo->flags |= MF_NOGRAVITY;
260                         }
261                 }
262                 else
263                 {
264                         player->mo->flags2 &= ~MF2_FLY;
265                         player->mo->flags &= ~MF_NOGRAVITY;
266                 }
267         }
268         else if(fly > 0)
269         {
270                 P_PlayerUseArtifact(player, arti_fly);
271         }
272         if(player->mo->flags2&MF2_FLY)
273         {
274                 player->mo->momz = player->flyheight*FRACUNIT;
275                 if(player->flyheight)
276                 {
277                         player->flyheight /= 2;
278                 }
279         }
280 }
281
282 /*
283 =================
284 =
285 = P_DeathThink
286 =
287 =================
288 */
289
290 #define         ANG5    (ANG90/18)
291
292 void P_DeathThink(player_t *player)
293 {
294         angle_t angle, delta;
295         extern int inv_ptr;
296         extern int curpos;
297         int lookDelta;
298
299         P_MovePsprites(player);
300
301         onground = (player->mo->z <= player->mo->floorz);
302         if(player->mo->type == MT_BLOODYSKULL)
303         { // Flying bloody skull
304                 player->viewheight = 6*FRACUNIT;
305                 player->deltaviewheight = 0;
306                 //player->damagecount = 20;
307                 if(onground)
308                 {
309                         if(player->lookdir < 60)
310                         {
311                                 lookDelta = (60-player->lookdir)/8;
312                                 if(lookDelta < 1 && (leveltime&1))
313                                 {
314                                         lookDelta = 1;
315                                 }
316                                 else if(lookDelta > 6)
317                                 {
318                                         lookDelta = 6;
319                                 }
320                                 player->lookdir += lookDelta;
321                         }
322                 }
323         }
324         else
325         { // Fall to ground
326                 player->deltaviewheight = 0;
327                 if(player->viewheight > 6*FRACUNIT)
328                         player->viewheight -= FRACUNIT;
329                 if(player->viewheight < 6*FRACUNIT)
330                         player->viewheight = 6*FRACUNIT;
331                 if(player->lookdir > 0)
332                 {
333                         player->lookdir -= 6;
334                 }
335                 else if(player->lookdir < 0)
336                 {
337                         player->lookdir += 6;
338                 }
339                 if(abs(player->lookdir) < 6)
340                 {
341                         player->lookdir = 0;
342                 }
343         }
344         P_CalcHeight(player);
345
346         if(player->attacker && player->attacker != player->mo)
347         {
348                 angle = R_PointToAngle2(player->mo->x, player->mo->y,
349                         player->attacker->x, player->attacker->y);
350                 delta = angle-player->mo->angle;
351                 if(delta < ANG5 || delta > (unsigned)-ANG5)
352                 { // Looking at killer, so fade damage flash down
353                         player->mo->angle = angle;
354                         if(player->damagecount)
355                         {
356                                 player->damagecount--;
357                         }
358                 }
359                 else if(delta < ANG180)
360                         player->mo->angle += ANG5;
361                 else
362                         player->mo->angle -= ANG5;
363         }
364         else if(player->damagecount)
365         {
366                 player->damagecount--;
367         }
368
369         if(player->cmd.buttons&BT_USE)
370         {
371                 if(player == &players[consoleplayer])
372                 {
373                         I_SetPalette((byte *)W_CacheLumpName("PLAYPAL", PU_CACHE));
374                         inv_ptr = 0;
375                         curpos = 0;
376                         newtorch = 0;
377                         newtorchdelta = 0;
378                 }
379                 player->playerstate = PST_REBORN;
380                 // Let the mobj know the player has entered the reborn state.  Some
381                 // mobjs need to know when it's ok to remove themselves.
382                 player->mo->special2 = 666;
383         }
384 }
385
386 //----------------------------------------------------------------------------
387 //
388 // PROC P_ChickenPlayerThink
389 //
390 //----------------------------------------------------------------------------
391
392 void P_ChickenPlayerThink(player_t *player)
393 {
394         mobj_t *pmo;
395
396         if(player->health > 0)
397         { // Handle beak movement
398                 P_UpdateBeak(player, &player->psprites[ps_weapon]);
399         }
400         if(player->chickenTics&15)
401         {
402                 return;
403         }
404         pmo = player->mo;
405         if(!(pmo->momx+pmo->momy) && P_Random() < 160)
406         { // Twitch view angle
407                 pmo->angle += (P_Random()-P_Random())<<19;
408         }
409         if((pmo->z <= pmo->floorz) && (P_Random() < 32))
410         { // Jump and noise
411                 pmo->momz += FRACUNIT;
412                 P_SetMobjState(pmo, S_CHICPLAY_PAIN);
413                 return;
414         }
415         if(P_Random() < 48)
416         { // Just noise
417                 S_StartSound(pmo, sfx_chicact);
418         }
419 }
420
421 //----------------------------------------------------------------------------
422 //
423 // FUNC P_GetPlayerNum
424 //
425 //----------------------------------------------------------------------------
426
427 int P_GetPlayerNum(player_t *player)
428 {
429         int i;
430
431         for(i = 0; i < MAXPLAYERS; i++)
432         {
433                 if(player == &players[i])
434                 {
435                         return(i);
436                 }
437         }
438         return(0);
439 }
440
441 //----------------------------------------------------------------------------
442 //
443 // FUNC P_UndoPlayerChicken
444 //
445 //----------------------------------------------------------------------------
446
447 boolean P_UndoPlayerChicken(player_t *player)
448 {
449         mobj_t *fog;
450         mobj_t *mo;
451         mobj_t *pmo;
452         fixed_t x;
453         fixed_t y;
454         fixed_t z;
455         angle_t angle;
456         int playerNum;
457         weapontype_t weapon;
458         int oldFlags;
459         int oldFlags2;
460
461         pmo = player->mo;
462         x = pmo->x;
463         y = pmo->y;
464         z = pmo->z;
465         angle = pmo->angle;
466         weapon = pmo->special1;
467         oldFlags = pmo->flags;
468         oldFlags2 = pmo->flags2;
469         P_SetMobjState(pmo, S_FREETARGMOBJ);
470         mo = P_SpawnMobj(x, y, z, MT_PLAYER);
471         if(P_TestMobjLocation(mo) == false)
472         { // Didn't fit
473                 P_RemoveMobj(mo);
474                 mo = P_SpawnMobj(x, y, z, MT_CHICPLAYER);
475                 mo->angle = angle;
476                 mo->health = player->health;
477                 mo->special1 = weapon;
478                 mo->player = player;
479                 mo->flags = oldFlags;
480                 mo->flags2 = oldFlags2;
481                 player->mo = mo;
482                 player->chickenTics = 2*35;
483                 return(false);
484         }
485         playerNum = P_GetPlayerNum(player);
486         if(playerNum != 0)
487         { // Set color translation
488                 mo->flags |= playerNum<<MF_TRANSSHIFT;
489         }
490         mo->angle = angle;
491         mo->player = player;
492         mo->reactiontime = 18;
493         if(oldFlags2&MF2_FLY)
494         {
495                 mo->flags2 |= MF2_FLY;
496                 mo->flags |= MF_NOGRAVITY;
497         }
498         player->chickenTics = 0;
499         player->powers[pw_weaponlevel2] = 0;
500         player->health = mo->health = MAXHEALTH;
501         player->mo = mo;
502         angle >>= ANGLETOFINESHIFT;
503         fog = P_SpawnMobj(x+20*finecosine[angle],
504                 y+20*finesine[angle], z+TELEFOGHEIGHT, MT_TFOG);
505         S_StartSound(fog, sfx_telept);
506         P_PostChickenWeapon(player, weapon);
507         return(true);
508 }
509
510 //----------------------------------------------------------------------------
511 //
512 // PROC P_PlayerThink
513 //
514 //----------------------------------------------------------------------------
515
516 void P_PlayerThink(player_t *player)
517 {
518         ticcmd_t *cmd;
519         weapontype_t newweapon;
520
521         extern boolean ultimatemsg;
522
523         // No-clip cheat
524         if(player->cheats&CF_NOCLIP)
525         {
526                 player->mo->flags |= MF_NOCLIP;
527         }
528         else
529         {
530                 player->mo->flags &= ~MF_NOCLIP;
531         }
532         cmd = &player->cmd;
533         if(player->mo->flags&MF_JUSTATTACKED)
534         { // Gauntlets attack auto forward motion
535                 cmd->angleturn = 0;
536                 cmd->forwardmove = 0xc800/512;
537                 cmd->sidemove = 0;
538                 player->mo->flags &= ~MF_JUSTATTACKED;
539         }
540 // messageTics is above the rest of the counters so that messages will
541 //              go away, even in death.
542         player->messageTics--; // Can go negative
543         if(!player->messageTics)
544         { // Refresh the screen when a message goes away
545                 ultimatemsg = false; // clear out any chat messages.
546                 BorderTopRefresh = true;
547         }
548         if(player->playerstate == PST_DEAD)
549         {
550                 P_DeathThink(player);
551                 return;
552         }
553         if(player->chickenTics)
554         {
555                 P_ChickenPlayerThink(player);
556         }
557         // Handle movement
558         if(player->mo->reactiontime)
559         { // Player is frozen
560                 player->mo->reactiontime--;
561         }
562         else
563         {
564                 P_MovePlayer(player);
565         }
566         P_CalcHeight(player);
567         if(player->mo->subsector->sector->special)
568         {
569                 P_PlayerInSpecialSector(player);
570         }
571         if(cmd->arti)
572         { // Use an artifact
573                 if(cmd->arti == 0xff)
574                 {
575                         P_PlayerNextArtifact(player);
576                 }
577                 else
578                 {
579                         P_PlayerUseArtifact(player, cmd->arti);
580                 }
581         }
582         // Check for weapon change
583         if(cmd->buttons&BT_SPECIAL)
584         { // A special event has no other buttons
585                 cmd->buttons = 0;
586         }
587         if(cmd->buttons&BT_CHANGE)
588         {
589                 // The actual changing of the weapon is done when the weapon
590                 // psprite can do it (A_WeaponReady), so it doesn't happen in
591                 // the middle of an attack.
592                 newweapon = (cmd->buttons&BT_WEAPONMASK)>>BT_WEAPONSHIFT;
593                 if(newweapon == wp_staff && player->weaponowned[wp_gauntlets]
594                         && !(player->readyweapon == wp_gauntlets))
595                 {
596                         newweapon = wp_gauntlets;
597                 }
598                 if(player->weaponowned[newweapon]
599                         && newweapon != player->readyweapon)
600                 {
601                         if(WeaponInShareware[newweapon] || !shareware)
602                         {
603                                 player->pendingweapon = newweapon;
604                         }
605                 }
606         }
607         // Check for use
608         if(cmd->buttons&BT_USE)
609         {
610                 if(!player->usedown)
611                 {
612                         P_UseLines(player);
613                         player->usedown = true;
614                 }
615         }
616         else
617         {
618                 player->usedown = false;
619         }
620         // Chicken counter
621         if(player->chickenTics)
622         {
623                 if(player->chickenPeck)
624                 { // Chicken attack counter
625                         player->chickenPeck -= 3;
626                 }
627                 if(!--player->chickenTics)
628                 { // Attempt to undo the chicken
629                         P_UndoPlayerChicken(player);
630                 }
631         }
632         // Cycle psprites
633         P_MovePsprites(player);
634         // Other Counters
635         if(player->powers[pw_invulnerability])
636         {
637                 player->powers[pw_invulnerability]--;
638         }
639         if(player->powers[pw_invisibility])
640         {
641                 if(!--player->powers[pw_invisibility])
642                 {
643                         player->mo->flags &= ~MF_SHADOW;
644                 }
645         }
646         if(player->powers[pw_infrared])
647         {
648                 player->powers[pw_infrared]--;
649         }
650         if(player->powers[pw_flight])
651         {
652                 if(!--player->powers[pw_flight])
653                 {
654 #ifdef __WATCOMC__
655                         if(player->mo->z != player->mo->floorz && !useexterndriver)
656                         {
657                                 player->centering = true;
658                         }
659 #else
660                         if(player->mo->z != player->mo->floorz)
661                         {
662                                 player->centering = true;
663                         }
664 #endif
665
666                         player->mo->flags2 &= ~MF2_FLY;
667                         player->mo->flags &= ~MF_NOGRAVITY;
668                         BorderTopRefresh = true; //make sure the sprite's cleared out
669                 }
670         }
671         if(player->powers[pw_weaponlevel2])
672         {
673                 if(!--player->powers[pw_weaponlevel2])
674                 {
675                         if((player->readyweapon == wp_phoenixrod)
676                                 && (player->psprites[ps_weapon].state
677                                 != &states[S_PHOENIXREADY])
678                                 && (player->psprites[ps_weapon].state
679                                 != &states[S_PHOENIXUP]))
680                         {
681                                 P_SetPsprite(player, ps_weapon, S_PHOENIXREADY);
682                                 player->ammo[am_phoenixrod] -= USE_PHRD_AMMO_2;
683                                 player->refire = 0;
684                         }
685                         else if((player->readyweapon == wp_gauntlets)
686                                 || (player->readyweapon == wp_staff))
687                         {
688                                 player->pendingweapon = player->readyweapon;
689                         }
690                         BorderTopRefresh = true;
691                 }
692         }
693         if(player->damagecount)
694         {
695                 player->damagecount--;
696         }
697         if(player->bonuscount)
698         {
699                 player->bonuscount--;
700         }
701         // Colormaps
702         if(player->powers[pw_invulnerability])
703         {
704                 if(player->powers[pw_invulnerability] > BLINKTHRESHOLD
705                         || (player->powers[pw_invulnerability]&8))
706                 {
707                         player->fixedcolormap = INVERSECOLORMAP;
708                 }
709                 else
710                 {
711                         player->fixedcolormap = 0;
712                 }
713         }
714         else if(player->powers[pw_infrared])
715         {
716                 if (player->powers[pw_infrared] <= BLINKTHRESHOLD)
717                 {
718                         if(player->powers[pw_infrared]&8)
719                         {
720                                 player->fixedcolormap = 0;
721                         }
722                         else
723                         {
724                                 player->fixedcolormap = 1;
725                         }
726                 }
727                 else if(!(leveltime&16) && player == &players[consoleplayer])
728                 {
729                         if(newtorch)
730                         {
731                                 if(player->fixedcolormap+newtorchdelta > 7
732                                         || player->fixedcolormap+newtorchdelta < 1
733                                         || newtorch == player->fixedcolormap)
734                                 {
735                                         newtorch = 0;
736                                 }
737                                 else
738                                 {
739                                         player->fixedcolormap += newtorchdelta;
740                                 }
741                         }
742                         else
743                         {
744                                 newtorch = (M_Random()&7)+1;
745                                 newtorchdelta = (newtorch == player->fixedcolormap) ?
746                                                 0 : ((newtorch > player->fixedcolormap) ? 1 : -1);
747                         }
748                 }
749         }
750         else
751         {
752                 player->fixedcolormap = 0;
753         }
754 }
755
756 //----------------------------------------------------------------------------
757 //
758 // PROC P_ArtiTele
759 //
760 //----------------------------------------------------------------------------
761
762 void P_ArtiTele(player_t *player)
763 {
764         int i;
765         int selections;
766         fixed_t destX;
767         fixed_t destY;
768         angle_t destAngle;
769
770         if(deathmatch)
771         {
772                 selections = deathmatch_p-deathmatchstarts;
773                 i = P_Random()%selections;
774                 destX = deathmatchstarts[i].x<<FRACBITS;
775                 destY = deathmatchstarts[i].y<<FRACBITS;
776                 destAngle = ANG45*(deathmatchstarts[i].angle/45);
777         }
778         else
779         {
780                 destX = playerstarts[0].x<<FRACBITS;
781                 destY = playerstarts[0].y<<FRACBITS;
782                 destAngle = ANG45*(playerstarts[0].angle/45);
783         }
784         P_Teleport(player->mo, destX, destY, destAngle);
785         S_StartSound(NULL, sfx_wpnup); // Full volume laugh
786 }
787
788 //----------------------------------------------------------------------------
789 //
790 // PROC P_PlayerNextArtifact
791 //
792 //----------------------------------------------------------------------------
793
794 void P_PlayerNextArtifact(player_t *player)
795 {
796         extern int inv_ptr;
797         extern int curpos;
798
799         if(player == &players[consoleplayer])
800         {
801                 inv_ptr--;
802                 if(inv_ptr < 6)
803                 {
804                         curpos--;
805                         if(curpos < 0)
806                         {
807                                 curpos = 0;
808                         }
809                 }
810                 if(inv_ptr < 0)
811                 {
812                         inv_ptr = player->inventorySlotNum-1;
813                         if(inv_ptr < 6)
814                         {
815                                 curpos = inv_ptr;
816                         }
817                         else
818                         {
819                                 curpos = 6;
820                         }
821                 }
822                 player->readyArtifact =
823                         player->inventory[inv_ptr].type;
824         }
825 }
826
827 //----------------------------------------------------------------------------
828 //
829 // PROC P_PlayerRemoveArtifact
830 //
831 //----------------------------------------------------------------------------
832
833 void P_PlayerRemoveArtifact(player_t *player, int slot)
834 {
835         int i;
836         extern int inv_ptr;
837         extern int curpos;
838
839         player->artifactCount--;
840         if(!(--player->inventory[slot].count))
841         { // Used last of a type - compact the artifact list
842                 player->readyArtifact = arti_none;
843                 player->inventory[slot].type = arti_none;
844                 for(i = slot+1; i < player->inventorySlotNum; i++)
845                 {
846                         player->inventory[i-1] = player->inventory[i];
847                 }
848                 player->inventorySlotNum--;
849                 if(player == &players[consoleplayer])
850                 { // Set position markers and get next readyArtifact
851                         inv_ptr--;
852                         if(inv_ptr < 6)
853                         {
854                                 curpos--;
855                                 if(curpos < 0)
856                                 {
857                                         curpos = 0;
858                                 }
859                         }
860                         if(inv_ptr >= player->inventorySlotNum)
861                         {
862                                 inv_ptr = player->inventorySlotNum-1;
863                         }
864                         if(inv_ptr < 0)
865                         {
866                                 inv_ptr = 0;
867                         }
868                         player->readyArtifact =
869                                 player->inventory[inv_ptr].type;
870                 }
871         }
872 }
873
874 //----------------------------------------------------------------------------
875 //
876 // PROC P_PlayerUseArtifact
877 //
878 //----------------------------------------------------------------------------
879
880 void P_PlayerUseArtifact(player_t *player, artitype_t arti)
881 {
882         int i;
883
884         for(i = 0; i < player->inventorySlotNum; i++)
885         {
886                 if(player->inventory[i].type == arti)
887                 { // Found match - try to use
888                         if(P_UseArtifact(player, arti))
889                         { // Artifact was used - remove it from inventory
890                                 P_PlayerRemoveArtifact(player, i);
891                                 if(player == &players[consoleplayer])
892                                 {
893                                         S_StartSound(NULL, sfx_artiuse);
894                                         ArtifactFlash = 4;
895                                 }
896                         }
897                         else
898                         { // Unable to use artifact, advance pointer
899                                 P_PlayerNextArtifact(player);
900                         }
901                         break;
902                 }
903         }
904 }
905
906 //----------------------------------------------------------------------------
907 //
908 // FUNC P_UseArtifact
909 //
910 // Returns true if artifact was used.
911 //
912 //----------------------------------------------------------------------------
913
914 boolean P_UseArtifact(player_t *player, artitype_t arti)
915 {
916         mobj_t *mo;
917         angle_t angle;
918
919         switch(arti)
920         {
921                 case arti_invulnerability:
922                         if(!P_GivePower(player, pw_invulnerability))
923                         {
924                                 return(false);
925                         }
926                         break;
927                 case arti_invisibility:
928                         if(!P_GivePower(player, pw_invisibility))
929                         {
930                                 return(false);
931                         }
932                         break;
933                 case arti_health:
934                         if(!P_GiveBody(player, 25))
935                         {
936                                 return(false);
937                         }
938                         break;
939                 case arti_superhealth:
940                         if(!P_GiveBody(player, 100))
941                         {
942                                 return(false);
943                         }
944                         break;
945                 case arti_tomeofpower:
946                         if(player->chickenTics)
947                         { // Attempt to undo chicken
948                                 if(P_UndoPlayerChicken(player) == false)
949                                 { // Failed
950                                         P_DamageMobj(player->mo, NULL, NULL, 10000);
951                                 }
952                                 else
953                                 { // Succeeded
954                                         player->chickenTics = 0;
955                                         S_StartSound(player->mo, sfx_wpnup);
956                                 }
957                         }
958                         else
959                         {
960                                 if(!P_GivePower(player, pw_weaponlevel2))
961                                 {
962                                         return(false);
963                                 }
964                                 if(player->readyweapon == wp_staff)
965                                 {
966                                         P_SetPsprite(player, ps_weapon, S_STAFFREADY2_1);
967                                 }
968                                 else if(player->readyweapon == wp_gauntlets)
969                                 {
970                                         P_SetPsprite(player, ps_weapon, S_GAUNTLETREADY2_1);
971                                 }
972                         }
973                         break;
974                 case arti_torch:
975                         if(!P_GivePower(player, pw_infrared))
976                         {
977                                 return(false);
978                         }
979                         break;
980                 case arti_firebomb:
981                         angle = player->mo->angle>>ANGLETOFINESHIFT;
982                         mo = P_SpawnMobj(player->mo->x+24*finecosine[angle],
983                                 player->mo->y+24*finesine[angle], player->mo->z - 15*FRACUNIT*
984                                 ((player->mo->flags2&MF2_FEETARECLIPPED) != 0), MT_FIREBOMB);
985                         mo->target = player->mo;
986                         break;
987                 case arti_egg:
988                         mo = player->mo;
989                         P_SpawnPlayerMissile(mo, MT_EGGFX);
990                         P_SPMAngle(mo, MT_EGGFX, mo->angle-(ANG45/6));
991                         P_SPMAngle(mo, MT_EGGFX, mo->angle+(ANG45/6));
992                         P_SPMAngle(mo, MT_EGGFX, mo->angle-(ANG45/3));
993                         P_SPMAngle(mo, MT_EGGFX, mo->angle+(ANG45/3));
994                         break;
995                 case arti_fly:
996                         if(!P_GivePower(player, pw_flight))
997                         {
998                                 return(false);
999                         }
1000                         break;
1001                 case arti_teleport:
1002                         P_ArtiTele(player);
1003                         break;
1004                 default:
1005                         return(false);
1006         }
1007         return(true);
1008 }