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