1 //
2 // Copyright(C) 1993-1996 Id Software, Inc.
3 // Copyright(C) 2005-2014 Simon Howard
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 // GNU General Public License for more details.
14 //
15 // DESCRIPTION:
16 //	Player related stuff.
17 //	Bobbing POV/weapon, movement.
18 //	Pending weapon.
19 //
20 
21 #include <stdlib.h>
22 
23 #include "doomdef.h"
24 #include "d_event.h"
25 #include "p_local.h"
26 #include "sounds.h"     // villsa [STRIFE]
27 #include "p_dialog.h"   // villsa [STRIFE]
28 #include "d_main.h"     // villsa [STRIFE]
29 #include "doomstat.h"
30 #include "deh_str.h"    // haleyjd [STRIFE]
31 #include "z_zone.h"
32 #include "w_wad.h"
33 #include "p_pspr.h"
34 #include "m_misc.h"
35 #include "m_random.h"
36 #include "s_sound.h"
37 #include "p_inter.h"
38 
39 
40 
41 // Index of the special effects (INVUL inverse) map.
42 #define LOOKPITCHAMOUNT         6                       // villsa [STRIFE]
43 #define CENTERVIEWAMOUNT        (LOOKPITCHAMOUNT + 2)   // villsa [STRIFE]
44 #define LOOKUPMAX               90                      // villsa [STRIFE]
45 #define LOOKDOWNMAX             -110                    // villsa [STRIFE]
46 
47 
48 void P_DropInventoryItem(player_t* player, int sprite); // villsa [STRIFE]
49 boolean P_ItemBehavior(player_t* player, int item);     // villsa [STRIFE]
50 static char useinventorymsg[44];    // villsa [STRIFE]
51 
52 //
53 // Movement.
54 //
55 
56 // 16 pixels of bob
57 #define MAXBOB	0x100000
58 
59 boolean		onground;
60 
61 
62 //
63 // P_Thrust
64 // Moves the given origin along a given angle.
65 //
66 // [STRIFE] Verified unmodified
67 //
68 void
P_Thrust(player_t * player,angle_t angle,fixed_t move)69 P_Thrust
70 ( player_t*	player,
71   angle_t	angle,
72   fixed_t	move )
73 {
74     angle >>= ANGLETOFINESHIFT;
75 
76     player->mo->momx += FixedMul(move,finecosine[angle]);
77     player->mo->momy += FixedMul(move,finesine[angle]);
78 }
79 
80 
81 
82 
83 //
84 // P_CalcHeight
85 // Calculate the walking / running height adjustment
86 //
87 // [STRIFE] Some odd adjustments, and terrain view height adjustment
88 //
P_CalcHeight(player_t * player)89 void P_CalcHeight (player_t* player)
90 {
91     int     angle;
92     fixed_t bob;
93 
94     // Regular movement bobbing
95     // (needs to be calculated for gun swing
96     // even if not on ground)
97     // OPTIMIZE: tablify angle
98     // Note: a LUT allows for effects
99     //  like a ramp with low health.
100     player->bob =
101         FixedMul (player->mo->momx, player->mo->momx)
102         + FixedMul (player->mo->momy,player->mo->momy);
103 
104     player->bob >>= 2;
105 
106     if (player->bob>MAXBOB)
107         player->bob = MAXBOB;
108 
109     // haleyjd 20110205 [STRIFE]: No CF_NOMOMENTUM check, and Rogue also removed
110     // the dead code inside.
111     if (!onground)
112     {
113         /*
114         player->viewz = player->mo->z + VIEWHEIGHT;
115 
116         if (player->viewz > player->mo->ceilingz-4*FRACUNIT)
117             player->viewz = player->mo->ceilingz-4*FRACUNIT;
118         */
119 
120         player->viewz = player->mo->z + player->viewheight;
121         return;
122     }
123 
124     angle = (FINEANGLES/20*leveltime)&FINEMASK;
125     bob = FixedMul ( player->bob/2, finesine[angle]);
126 
127     // move viewheight
128     if (player->playerstate == PST_LIVE)
129     {
130         player->viewheight += player->deltaviewheight;
131 
132         if (player->viewheight > VIEWHEIGHT)
133         {
134             player->viewheight = VIEWHEIGHT;
135             player->deltaviewheight = 0;
136         }
137 
138         if (player->viewheight < VIEWHEIGHT/2)
139         {
140             player->viewheight = VIEWHEIGHT/2;
141             if (player->deltaviewheight <= 0)
142                 player->deltaviewheight = 1;
143         }
144 
145         if (player->deltaviewheight)
146         {
147             player->deltaviewheight += FRACUNIT/4;
148             if (!player->deltaviewheight)
149                 player->deltaviewheight = 1;
150         }
151     }
152     player->viewz = player->mo->z + player->viewheight + bob;
153 
154     // villsa [STRIFE] account for terrain lowering the view
155     if(player->mo->flags & MF_FEETCLIPPED)
156         player->viewz -= 13*FRACUNIT;
157 
158     if (player->viewz > player->mo->ceilingz-4*FRACUNIT)
159         player->viewz = player->mo->ceilingz-4*FRACUNIT;
160 
161     // haleyjd [STRIFE]: added a floorz clip here
162     if (player->viewz < player->mo->floorz)
163         player->viewz = player->mo->floorz;
164 }
165 
166 
167 
168 //
169 // P_MovePlayer
170 //
171 // [STRIFE] Adjustments to allow air control, jumping, and up/down look.
172 //
P_MovePlayer(player_t * player)173 void P_MovePlayer (player_t* player)
174 {
175     ticcmd_t*      cmd;
176 
177     cmd = &player->cmd;
178 
179     player->mo->angle += (cmd->angleturn<<16);
180 
181     // Do not let the player control movement
182     //  if not onground.
183     onground = (player->mo->z <= player->mo->floorz);
184 
185     // villsa [STRIFE] allows player to climb over things by jumping
186     // haleyjd 20110205: air control thrust should be 256, not cmd->forwardmove
187     if(!onground)
188     {
189         if(cmd->forwardmove)
190             P_Thrust (player, player->mo->angle, 256);
191     }
192     else
193     {
194         // villsa [STRIFE] jump button
195         if (cmd->buttons2 & BT2_JUMP)
196         {
197             if(!player->deltaviewheight)
198                 player->mo->momz += 8*FRACUNIT;
199         }
200 
201         // haleyjd 20110205 [STRIFE] Either Rogue or Watcom removed the
202         // redundant "onground" checks from these if's.
203         if (cmd->forwardmove)
204             P_Thrust (player, player->mo->angle, cmd->forwardmove*2048);
205 
206         if (cmd->sidemove)
207             P_Thrust (player, player->mo->angle-ANG90, cmd->sidemove*2048);
208     }
209 
210     // villsa [STRIFE] player walking state set
211     if ( (cmd->forwardmove || cmd->sidemove)
212         && player->mo->state == &states[S_PLAY_00] )
213     {
214         P_SetMobjState (player->mo, S_PLAY_01);
215     }
216 
217     // villsa [STRIFE] centerview button
218     if (cmd->buttons2 & BT2_CENTERVIEW)
219         player->centerview = 1;
220 
221     // villsa [STRIFE] adjust player's pitch when centerviewing
222     if (player->centerview)
223     {
224         if (player->pitch <= 0)
225         {
226             if (player->pitch < 0)
227                 player->pitch = player->pitch + CENTERVIEWAMOUNT;
228         }
229         else
230         {
231             player->pitch = player->pitch - CENTERVIEWAMOUNT;
232         }
233         if (abs(player->pitch) < CENTERVIEWAMOUNT)
234         {
235             player->pitch = 0;
236             player->centerview = 0;
237         }
238     }
239 
240     // villsa [STRIFE] look up action
241     if (cmd->buttons2 & BT2_LOOKUP)
242     {
243         player->pitch += LOOKPITCHAMOUNT;
244         if (player->pitch > LOOKUPMAX ||
245             player->pitch < LOOKDOWNMAX)
246             player->pitch -= LOOKPITCHAMOUNT;
247     }
248     else
249     {
250         // villsa [STRIFE] look down action
251         if (cmd->buttons2 & BT2_LOOKDOWN)
252         {
253             player->pitch -= LOOKPITCHAMOUNT;
254             if (player->pitch > LOOKUPMAX ||
255                 player->pitch < LOOKDOWNMAX)
256                 player->pitch += LOOKPITCHAMOUNT;
257         }
258     }
259 
260 }
261 
262 
263 
264 //
265 // P_DeathThink
266 // Fall on your face when dying.
267 // Decrease POV height to floor height.
268 //
269 // [STRIFE] Modifications for up/down look.
270 //
271 #define ANG5    (ANG90/18)
272 
P_DeathThink(player_t * player)273 void P_DeathThink(player_t* player)
274 {
275     angle_t angle;
276     angle_t delta;
277 
278     P_MovePsprites(player);
279 
280     // fall to the ground
281     if (player->viewheight > 6*FRACUNIT)
282         player->viewheight -= FRACUNIT;
283 
284     if (player->viewheight < 6*FRACUNIT)
285         player->viewheight = 6*FRACUNIT;
286 
287     player->deltaviewheight = 0;
288     onground = (player->mo->z <= player->mo->floorz);
289     P_CalcHeight(player);
290 
291     if(player->attacker && player->attacker != player->mo)
292     {
293         angle = R_PointToAngle2 (player->mo->x,
294                                  player->mo->y,
295                                  player->attacker->x,
296                                  player->attacker->y);
297 
298         delta = angle - player->mo->angle;
299 
300         if (delta < ANG5 || delta > (unsigned)-ANG5)
301         {
302             // Looking at killer,
303             //  so fade damage flash down.
304             player->mo->angle = angle;
305 
306             if (player->damagecount)
307                 player->damagecount--;
308         }
309         else if (delta < ANG180)
310             player->mo->angle += ANG5;
311         else
312             player->mo->angle -= ANG5;
313     }
314     else if (player->damagecount)
315         player->damagecount--;
316 
317     // villsa [STRIFE]
318     if(player->pitch <= 90)
319         player->pitch = player->pitch + 3;
320 
321     if(player->cmd.buttons & BT_USE)
322         player->playerstate = PST_REBORN;
323 }
324 
325 
326 
327 //
328 // P_PlayerThink
329 //
330 // [STRIFE] Massive changes/additions:
331 // * NOCLIP hack removed
332 // * P_DeathThink moved up
333 // * Inventory use/dropping
334 // * Strife weapons logic
335 // * Dialog
336 // * Strife powerups and nukage behavior
337 // * Fire Death/Sigil Shock
338 //
P_PlayerThink(player_t * player)339 void P_PlayerThink (player_t* player)
340 {
341     ticcmd_t*       cmd;
342     weapontype_t    newweapon;
343 
344     // villsa [STRIFE] unused code (see ST_Responder)
345     /*
346     // fixme: do this in the cheat code
347     if (player->cheats & CF_NOCLIP)
348         player->mo->flags |= MF_NOCLIP;
349     else
350         player->mo->flags &= ~MF_NOCLIP;
351     */
352 
353     // haleyjd 20110205 [STRIFE]: P_DeathThink moved up
354     if (player->playerstate == PST_DEAD)
355     {
356         P_DeathThink (player);
357         return;
358     }
359 
360     // chain saw run forward
361     cmd = &player->cmd;
362     if (player->mo->flags & MF_JUSTATTACKED)
363     {
364         cmd->angleturn = 0;
365         cmd->forwardmove = 0xc800/512;
366         cmd->sidemove = 0;
367         player->mo->flags &= ~MF_JUSTATTACKED;
368     }
369 
370     // Move around.
371     // Reactiontime is used to prevent movement
372     //  for a bit after a teleport.
373     if (player->mo->reactiontime)
374         player->mo->reactiontime--;
375     else
376         P_MovePlayer (player);
377 
378     P_CalcHeight (player);
379 
380     if (player->mo->subsector->sector->special)
381         P_PlayerInSpecialSector (player);
382 
383     // villsa [STRIFE] handle inventory input
384     if(cmd->buttons2 & (BT2_HEALTH|BT2_INVUSE|BT2_INVDROP))
385     {
386         if(!player->inventorydown)
387         {
388             if(cmd->buttons2 & BT2_HEALTH)
389                 P_UseInventoryItem(player, SPR_FULL);
390             else if(cmd->buttons2 & BT2_INVUSE)
391                 P_UseInventoryItem(player, cmd->inventory);
392             else if(cmd->buttons2 & BT2_INVDROP)
393             {
394                 P_DropInventoryItem(player, cmd->inventory);
395 
396                 // haleyjd 20110205: removed incorrect "else" here
397                 // villsa [STRIFE]
398                 if(workparm)
399                 {
400                     int cheat = player->cheats ^ 1;
401                     player->cheats ^= CF_NOCLIP;
402 
403                     if(cheat & CF_NOCLIP)
404                     {
405                         player->message = DEH_String("No Clipping Mode ON");
406                         player->mo->flags |= MF_NOCLIP;
407                     }
408                     else
409                     {
410                         player->mo->flags &= ~MF_NOCLIP;
411                         player->message = DEH_String("No Clipping Mode OFF");
412                     }
413                 }
414             }
415         }
416 
417         player->inventorydown = true;
418     }
419     else
420         player->inventorydown = false;
421 
422     // Check for weapon change.
423 
424     // A special event has no other buttons.
425     if(cmd->buttons & BT_SPECIAL)
426         cmd->buttons = 0;
427 
428     if(cmd->buttons & BT_CHANGE)
429     {
430         // The actual changing of the weapon is done
431         //  when the weapon psprite can do it
432         //  (read: not in the middle of an attack).
433         newweapon = (cmd->buttons & BT_WEAPONMASK) >> BT_WEAPONSHIFT;
434 
435         // villsa [STRIFE] select poison bow
436         if(newweapon == wp_elecbow)
437         {
438             if(player->weaponowned[wp_poisonbow] && player->readyweapon == wp_elecbow)
439             {
440                 if(player->ammo[weaponinfo[wp_poisonbow].ammo])
441                     newweapon = wp_poisonbow;
442             }
443         }
444 
445         // villsa [STRIFE] select wp grenade launcher
446         if(newweapon == wp_hegrenade)
447         {
448             if(player->weaponowned[wp_wpgrenade] && player->readyweapon == wp_hegrenade)
449             {
450                 if(player->ammo[weaponinfo[wp_wpgrenade].ammo])
451                     newweapon = wp_wpgrenade;
452             }
453         }
454 
455         // villsa [STRIFE] select torpedo
456         if(newweapon == wp_mauler)
457         {
458             if(player->weaponowned[wp_torpedo] && player->readyweapon == wp_mauler)
459             {
460                 // haleyjd 20140924: bug fix - using wrong enum value am_cell
461                 // caused this to check the missile launcher for rocket ammo
462                 if(player->ammo[weaponinfo[wp_torpedo].ammo] >= 30)
463                     newweapon = wp_torpedo;
464             }
465         }
466 
467         if(player->weaponowned[newweapon] && newweapon != player->readyweapon)
468         {
469             // villsa [STRIFE] check weapon if in demo mode or not
470             if(weaponinfo[newweapon].availabledemo || !isdemoversion)
471             {
472                 if(player->ammo[weaponinfo[newweapon].ammo])
473                     player->pendingweapon = newweapon;
474                 else
475                 {
476                     // decide between electric bow or poison arrow
477                     if(newweapon == wp_elecbow &&
478                         player->ammo[am_poisonbolts] &&
479                         player->readyweapon != wp_poisonbow)
480                     {
481                         player->pendingweapon = wp_poisonbow;
482                     }
483                     // decide between hp grenade launcher or wp grenade launcher
484                     else if(newweapon == wp_hegrenade &&
485                         player->ammo[am_wpgrenades] &&
486                         player->readyweapon != wp_wpgrenade)
487                     {
488                         player->pendingweapon = wp_wpgrenade;
489                     }
490 
491                     // villsa [STRIFE] - no check for mauler/torpedo??
492                 }
493             }
494         }
495     }
496 
497     // check for use
498     if(cmd->buttons & BT_USE)
499     {
500         if(!player->usedown)
501         {
502             P_DialogStart(player);  // villsa [STRIFE]
503             P_UseLines (player);
504             player->usedown = true;
505         }
506     }
507     else
508         player->usedown = false;
509 
510     // cycle psprites
511     P_MovePsprites (player);
512 
513     // Counters, time dependend power ups.
514 
515     // Strength counts up to diminish fade.
516     if (player->powers[pw_strength])
517         player->powers[pw_strength]++;
518 
519     // villsa [STRIFE] targeter powerup
520     if(player->powers[pw_targeter])
521     {
522         player->powers[pw_targeter]--;
523         if(player->powers[pw_targeter] == 1)
524         {
525             P_SetPsprite(player, ps_targcenter, S_NULL);
526             P_SetPsprite(player, ps_targleft,   S_NULL);
527             P_SetPsprite(player, ps_targright,  S_NULL);
528         }
529         else if(player->powers[pw_targeter] - 1 < 5*TICRATE)
530         {
531             if(player->powers[pw_targeter] & 32)
532             {
533                 P_SetPsprite(player, ps_targright, S_NULL);
534                 P_SetPsprite(player, ps_targleft,  S_TRGT_01);   // 11
535             }
536             else if(player->powers[pw_targeter] & 16) // haleyjd 20110205: missing else
537             {
538                 P_SetPsprite(player, ps_targright, S_TRGT_02);  // 12
539                 P_SetPsprite(player, ps_targleft,  S_NULL);
540             }
541         }
542     }
543 
544     if(player->powers[pw_invisibility])
545     {
546         // villsa [STRIFE] remove mvis flag as well
547         if(!--player->powers[pw_invisibility])
548             player->mo->flags &= ~(MF_SHADOW|MF_MVIS);
549     }
550 
551     if(player->powers[pw_ironfeet])
552     {
553         player->powers[pw_ironfeet]--;
554 
555         // villsa [STRIFE] gasmask sound
556         if(!(leveltime & 0x3f))
557             S_StartSound(player->mo, sfx_mask);
558     }
559 
560     if(player->powers[pw_allmap] > 1)
561         player->powers[pw_allmap]--;
562 
563     // haleyjd 08/30/10: [STRIFE]
564     // Nukage count keeps track of exposure to hazardous conditions over time.
565     // After accumulating 16 total seconds or more of exposure, you will take
566     // 5 damage roughly once per second until the count drops back under 560
567     // tics.
568     if(player->nukagecount)
569     {
570         player->nukagecount--;
571         if(!(leveltime & 0x1f) && player->nukagecount > 16*TICRATE)
572             P_DamageMobj(player->mo, NULL, NULL, 5);
573     }
574 
575     if(player->damagecount)
576         player->damagecount--;
577 
578     if(player->bonuscount)
579         player->bonuscount--;
580 
581     // villsa [STRIFE] checks for extralight
582     if(player->extralight >= 0)
583     {
584         if(player->cheats & CF_ONFIRE)
585             player->fixedcolormap = 1;
586         else
587             player->fixedcolormap = 0;
588     }
589     else // Sigil shock:
590         player->fixedcolormap = INVERSECOLORMAP;
591 }
592 
593 
594 //
595 // P_RemoveInventoryItem
596 // villsa [STRIFE] new function
597 //
P_RemoveInventoryItem(player_t * player,int slot,int amount)598 const char* P_RemoveInventoryItem(player_t *player, int slot, int amount)
599 {
600     mobjtype_t type;
601 
602     player->inventory[slot].amount -= amount;
603     player->st_update = true;
604 
605     type = player->inventory[slot].type;
606 
607     if(!player->inventory[slot].amount)
608     {
609         // shift everything above it down
610         // see P_TakeDialogItem for notes on possible bugs
611         int j;
612 
613         for(j = slot + 1; j <= player->numinventory; j++)
614         {
615             inventory_t *item1 = &(player->inventory[j - 1]);
616             inventory_t *item2 = &(player->inventory[j]);
617 
618             *item1 = *item2;
619         }
620 
621         player->inventory[player->numinventory].type = NUMMOBJTYPES;
622         player->inventory[player->numinventory].sprite = -1;
623         player->numinventory--;
624 
625         // update cursor position
626         if(player->inventorycursor >= player->numinventory)
627         {
628             if(player->inventorycursor)
629                 player->inventorycursor--;
630         }
631     }
632 
633     return mobjinfo[type].name;
634 }
635 
636 //
637 // P_DropInventoryItem
638 // villsa [STRIFE] new function
639 //
P_DropInventoryItem(player_t * player,int sprite)640 void P_DropInventoryItem(player_t* player, int sprite)
641 {
642     int invslot;
643     inventory_t *item;
644     mobjtype_t type;
645     int amount;
646 
647     invslot = 0;
648     amount = 1;
649 
650     while(invslot < player->numinventory && sprite != player->inventory[invslot].sprite)
651         invslot++;
652 
653     item = &(player->inventory[invslot]);
654     type = item->type;
655 
656     if(item->amount)
657     {
658         angle_t angle;
659         fixed_t dist;
660         mobj_t* mo;
661         mobj_t* mobjitem;
662         fixed_t x;
663         fixed_t y;
664         fixed_t z;
665         int r;
666 
667         if(item->type == MT_MONY_1)
668         {
669             if(item->amount >= 50)
670             {
671                 type = MT_MONY_50;
672                 amount = 50;
673             }
674             else if(item->amount >= 25)
675             {
676                 type = MT_MONY_25;
677                 amount = 25;
678             }
679             else if(item->amount >= 10)
680             {
681                 type = MT_MONY_10;
682                 amount = 10;
683             }
684         }
685 
686         if(type >= NUMMOBJTYPES)
687             return;
688 
689         angle = player->mo->angle;
690         r = P_Random();
691         angle = (angle + ((r - P_Random()) << 18)) >> ANGLETOFINESHIFT;
692 
693         if(angle < 7618 && angle >= 6718)
694             angle = 7618;
695 
696         else if(angle < 5570 && angle >= 4670)
697             angle = 5570;
698 
699         else if(angle < 3522 && angle >= 2622)
700             angle = 3522;
701 
702         else if(angle < 1474 && angle >= 574)
703             angle = 1474;
704 
705         mo = player->mo;
706         dist = mobjinfo[type].radius + mo->info->radius + (4*FRACUNIT);
707 
708         x = mo->x + FixedMul(finecosine[angle], dist);
709         y = mo->y + FixedMul(finesine[angle], dist);
710         z = mo->z + (10*FRACUNIT);
711         mobjitem = P_SpawnMobj(x, y, z, type);
712         mobjitem->flags |= (MF_SPECIAL|MF_DROPPED);
713 
714         if(P_CheckPosition(mobjitem, x, y))
715         {
716             mobjitem->angle = (angle << ANGLETOFINESHIFT);
717             mobjitem->momx = FixedMul(finecosine[angle], (5*FRACUNIT)) + mo->momx;
718             mobjitem->momy = FixedMul(finesine[angle], (5*FRACUNIT)) + mo->momy;
719             mobjitem->momz = FRACUNIT;
720 
721             P_RemoveInventoryItem(player, invslot, amount);
722         }
723         else
724             P_RemoveMobj(mobjitem);
725     }
726 }
727 
728 //
729 // P_TossDegninOre
730 // villsa [STRIFE] new function
731 //
P_TossDegninOre(player_t * player)732 boolean P_TossDegninOre(player_t* player)
733 {
734     angle_t angle;
735     mobj_t* mo;
736     mobj_t* ore;
737     fixed_t x;
738     fixed_t y;
739     fixed_t z;
740     fixed_t dist;
741 
742     angle = player->mo->angle >> ANGLETOFINESHIFT;
743 
744     if(angle < 7618 && angle >= 6718)
745         angle = 7618;
746 
747     else if(angle < 5570 && angle >= 4670)
748         angle = 5570;
749 
750     else if(angle < 3522 && angle >= 2622)
751         angle = 3522;
752 
753     else if(angle < 1474 && angle >= 574)
754         angle = 1474;
755 
756     mo = player->mo;
757     dist = mobjinfo[MT_DEGNINORE].radius + mo->info->radius + (4*FRACUNIT);
758 
759     x = mo->x + FixedMul(finecosine[angle], dist);
760     y = mo->y + FixedMul(finesine[angle], dist);
761     z = mo->z + (10*FRACUNIT);
762     ore = P_SpawnMobj(x, y, z, MT_DEGNINORE);
763 
764     if(P_CheckPosition(ore, x, y))
765     {
766         ore->target = mo;
767         ore->angle = (angle << ANGLETOFINESHIFT);
768         ore->momx = FixedMul(finecosine[angle], (5*FRACUNIT));
769         ore->momy = FixedMul(finesine[angle], (5*FRACUNIT));
770         ore->momz = FRACUNIT;
771         return true;
772     }
773     else
774         P_RemoveMobj(ore);
775 
776     return false;
777 }
778 
779 //
780 // P_SpawnTeleportBeacon
781 //
782 // villsa [STRIFE] new function
783 // haleyjd 20140918: bug fixed to propagate allegiance properly.
784 //
P_SpawnTeleportBeacon(player_t * player)785 boolean P_SpawnTeleportBeacon(player_t* player)
786 {
787     angle_t angle;
788     int r;
789     mobj_t* mo;
790     mobj_t* beacon;
791     fixed_t x;
792     fixed_t y;
793     fixed_t z;
794     fixed_t dist;
795 
796     angle = player->mo->angle;
797     r = P_Random();
798     angle = (angle + ((r - P_Random()) << 18)) >> ANGLETOFINESHIFT;
799 
800     if(angle < 7618 && angle >= 6718)
801         angle = 7618;
802 
803     else if(angle < 5570 && angle >= 4670)
804         angle = 5570;
805 
806     else if(angle < 3522 && angle >= 2622)
807         angle = 3522;
808 
809     else if(angle < 1474 && angle >= 574)
810         angle = 1474;
811 
812     mo = player->mo;
813     dist = mobjinfo[MT_BEACON].radius + mo->info->radius + (4*FRACUNIT);
814 
815     x = mo->x + FixedMul(finecosine[angle], dist);
816     y = mo->y + FixedMul(finesine[angle], dist);
817     z = mo->z + (10*FRACUNIT);
818     beacon = P_SpawnMobj(x, y, z, MT_BEACON);
819 
820     if(P_CheckPosition(beacon, x, y))
821     {
822         beacon->target = mo;
823         beacon->miscdata = (byte)(player->allegiance);
824         beacon->angle = (angle << ANGLETOFINESHIFT);
825         beacon->momx = FixedMul(finecosine[angle], (5*FRACUNIT));
826         beacon->momy = FixedMul(finesine[angle], (5*FRACUNIT));
827         beacon->momz = FRACUNIT;
828         P_SetMobjState(beacon, beacon->info->seestate);
829         return true;
830     }
831     else
832         P_RemoveMobj(beacon);
833 
834     return false;
835 }
836 
837 //
838 // P_UseInventoryItem
839 // villsa [STRIFE] new function
840 //
P_UseInventoryItem(player_t * player,int item)841 boolean P_UseInventoryItem(player_t* player, int item)
842 {
843     int i;
844     const char *name;
845 
846     if(player->cheats & CF_ONFIRE)
847         return false;
848 
849     for(i = 0; i < player->numinventory; i++)
850     {
851         if(item != player->inventory[i].sprite)
852             continue;
853 
854         if(!P_ItemBehavior(player, item))
855             return false;
856 
857         name = P_RemoveInventoryItem(player, i, 1);
858         if(name == NULL)
859             name = "Item";
860 
861         M_snprintf(useinventorymsg, sizeof(useinventorymsg),
862                    "You used the %s.", name);
863         player->message = useinventorymsg;
864 
865         if(player == &players[consoleplayer])
866             S_StartSound(NULL, sfx_itemup);
867 
868         return true;
869     }
870 
871     return false;
872 }
873 
874 //
875 // P_ItemBehavior
876 // villsa [STRIFE] new function
877 //
P_ItemBehavior(player_t * player,int item)878 boolean P_ItemBehavior(player_t* player, int item)
879 {
880     switch(item)
881     {
882     case SPR_ARM1:  // 136
883         return P_GiveArmor(player, 2);
884 
885     case SPR_ARM2:  // 137
886         return P_GiveArmor(player, 1);
887 
888     case SPR_SHD1:  // 186
889         return P_GivePower(player, pw_invisibility);
890 
891     case SPR_MASK:  // 187
892         return P_GivePower(player, pw_ironfeet);
893 
894     case SPR_PMUP:  // 191
895         if(!player->powers[pw_allmap])
896         {
897             player->message = "The scanner won't work without a map!";
898             return false;
899         }
900         player->powers[pw_allmap] = PMUPTICS;
901         return true; // haleyjd 20110228: repaired
902 
903     case SPR_STMP:  // 180
904         return P_GiveBody(player, 10);
905 
906     case SPR_MDKT:  // 181
907         return P_GiveBody(player, 25);
908 
909     case SPR_FULL:  // 130
910         return P_GiveBody(player, 200);
911 
912     case SPR_BEAC:  // 135
913         return P_SpawnTeleportBeacon(player);
914 
915     case SPR_TARG:  // 108
916         return P_GivePower(player, pw_targeter);
917     }
918 
919     return false;
920 }
921