Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- class PlayerPawn : Actor
- {
- const CROUCHSPEED = (1./12);
- // [RH] # of ticks to complete a turn180
- const TURN180_TICKS = ((TICRATE / 4) + 1);
- // 16 pixels of bob
- const MAXBOB = 16.;
- int crouchsprite;
- int MaxHealth;
- int BonusHealth;
- int MugShotMaxHealth;
- int RunHealth;
- private int PlayerFlags;
- clearscope Inventory InvFirst; // first inventory item displayed on inventory bar
- clearscope Inventory InvSel; // selected inventory item
- Name SoundClass; // Sound class
- Name Portrait;
- Name Slot[10];
- double HexenArmor[5];
- // [GRB] Player class properties
- double JumpZ;
- double GruntSpeed;
- double FallingScreamMinSpeed, FallingScreamMaxSpeed;
- double ViewHeight;
- double ForwardMove1, ForwardMove2;
- double SideMove1, SideMove2;
- TextureID ScoreIcon;
- int SpawnMask;
- Name MorphWeapon;
- double AttackZOffset; // attack height, relative to player center
- double UseRange; // [NS] Distance at which player can +use
- double AirCapacity; // Multiplier for air supply underwater.
- Class<Inventory> FlechetteType;
- color DamageFade; // [CW] Fades for when you are being damaged.
- double ViewBob; // [SP] ViewBob Multiplier
- double FullHeight;
- double curBob;
- meta Name HealingRadiusType;
- meta Name InvulMode;
- meta Name Face;
- meta int TeleportFreezeTime;
- meta int ColorRangeStart; // Skin color range
- meta int ColorRangeEnd;
- property prefix: Player;
- property HealRadiusType: HealingradiusType;
- property InvulnerabilityMode: InvulMode;
- property AttackZOffset: AttackZOffset;
- property JumpZ: JumpZ;
- property GruntSpeed: GruntSpeed;
- property FallingScreamSpeed: FallingScreamMinSpeed, FallingScreamMaxSpeed;
- property ViewHeight: ViewHeight;
- property UseRange: UseRange;
- property AirCapacity: AirCapacity;
- property MaxHealth: MaxHealth;
- property MugshotMaxHealth: MugshotMaxHealth;
- property RunHealth: RunHealth;
- property MorphWeapon: MorphWeapon;
- property FlechetteType: FlechetteType;
- property Portrait: Portrait;
- property TeleportFreezeTime: TeleportFreezeTime;
- property ViewBob: ViewBob;
- flagdef NoThrustWhenInvul: PlayerFlags, 0;
- flagdef CanSuperMorph: PlayerFlags, 1;
- flagdef CrouchableMorph: PlayerFlags, 2;
- Default
- {
- Health 100;
- Radius 16;
- Height 56;
- Mass 100;
- Painchance 255;
- Speed 1;
- +SOLID
- +SHOOTABLE
- +DROPOFF
- +PICKUP
- +NOTDMATCH
- +FRIENDLY
- +SLIDESONWALLS
- +CANPASS
- +CANPUSHWALLS
- +FLOORCLIP
- +WINDTHRUST
- +TELESTOMP
- +NOBLOCKMONST
- Player.AttackZOffset 8;
- Player.JumpZ 8;
- Player.GruntSpeed 12;
- Player.FallingScreamSpeed 35,40;
- Player.ViewHeight 41;
- Player.UseRange 64;
- Player.ForwardMove 1,1;
- Player.SideMove 1,1;
- Player.ColorRange 0,0;
- Player.SoundClass "player";
- Player.DamageScreenColor "ff 00 00";
- Player.MugShotMaxHealth 0;
- Player.FlechetteType "ArtiPoisonBag3";
- Player.AirCapacity 1;
- Player.ViewBob 1;
- Player.TeleportFreezeTime 18;
- Obituary "$OB_MPDEFAULT";
- }
- //===========================================================================
- //
- // PlayerPawn :: Tick
- //
- //===========================================================================
- override void Tick()
- {
- if (player != NULL && player.mo == self && CanCrouch() && player.playerstate != PST_DEAD)
- {
- Height = FullHeight * player.crouchfactor;
- }
- else
- {
- if (health > 0) Height = FullHeight;
- }
- Super.Tick();
- }
- //===========================================================================
- //
- //
- //
- //===========================================================================
- override void BeginPlay()
- {
- Super.BeginPlay ();
- ChangeStatNum (STAT_PLAYER);
- FullHeight = Height;
- if (!SetupCrouchSprite(crouchsprite)) crouchsprite = 0;
- }
- //===========================================================================
- //
- // PlayerPawn :: PostBeginPlay
- //
- //===========================================================================
- override void PostBeginPlay()
- {
- Super.PostBeginPlay();
- WeaponSlots.SetupWeaponSlots(self);
- // Voodoo dolls: restore original floorz/ceilingz logic
- if (player == NULL || player.mo != self)
- {
- FindFloorCeiling(FFCF_ONLYSPAWNPOS|FFCF_NOPORTALS);
- SetZ(floorz);
- FindFloorCeiling(FFCF_ONLYSPAWNPOS);
- }
- else
- {
- player.SendPitchLimits();
- }
- }
- //===========================================================================
- //
- // PlayerPawn :: MarkPrecacheSounds
- //
- //===========================================================================
- override void MarkPrecacheSounds()
- {
- Super.MarkPrecacheSounds();
- MarkPlayerSounds();
- }
- //----------------------------------------------------------------------------
- //
- //
- //
- //----------------------------------------------------------------------------
- virtual void PlayIdle ()
- {
- if (InStateSequence(CurState, SeeState))
- SetState (SpawnState);
- }
- virtual void PlayRunning ()
- {
- if (InStateSequence(CurState, SpawnState) && SeeState != NULL)
- SetState (SeeState);
- }
- virtual void PlayAttacking ()
- {
- if (MissileState != null) SetState (MissileState);
- }
- virtual void PlayAttacking2 ()
- {
- if (MeleeState != null) SetState (MeleeState);
- }
- virtual void MorphPlayerThink()
- {
- }
- //----------------------------------------------------------------------------
- //
- //
- //
- //----------------------------------------------------------------------------
- virtual void OnRespawn()
- {
- if (sv_respawnprotect && (deathmatch || alwaysapplydmflags))
- {
- let invul = Powerup(Spawn("PowerInvulnerable"));
- invul.EffectTics = 3 * TICRATE;
- invul.BlendColor = 0; // don't mess with the view
- invul.bUndroppable = true; // Don't drop self
- bRespawnInvul = true; // [RH] special effect
- }
- }
- //----------------------------------------------------------------------------
- //
- //
- //
- //----------------------------------------------------------------------------
- override String GetObituary(Actor victim, Actor inflictor, Name mod, bool playerattack)
- {
- if (victim.player != player && victim.IsTeammate(self))
- {
- victim = self;
- return String.Format("$OB_FRIENDLY%d", random[Obituary](1, 4));
- }
- else
- {
- if (mod == 'Telefrag') return "$OB_MPTELEFRAG";
- String message;
- if (inflictor != NULL && inflictor != self)
- {
- message = inflictor.GetObituary(victim, inflictor, mod, playerattack);
- }
- if (message.Length() == 0 && playerattack && player.ReadyWeapon != NULL)
- {
- message = player.ReadyWeapon.GetObituary(victim, inflictor, mod, playerattack);
- }
- if (message.Length() == 0)
- {
- if (mod == 'BFGSplash') return "$OB_MPBFG_SPLASH";
- if (mod == 'Railgun') return "$OB_RAILGUN";
- message = Obituary;
- }
- return message;
- }
- }
- //----------------------------------------------------------------------------
- //
- // This is for SBARINFO.
- //
- //----------------------------------------------------------------------------
- clearscope int, int GetEffectTicsForItem(class<Inventory> item) const
- {
- let pg = (class<PowerupGiver>)(item);
- if (pg != null)
- {
- let powerupType = (class<Powerup>)(GetDefaultByType(pg).PowerupType);
- let powerup = Powerup(FindInventory(powerupType));
- if(powerup != null)
- {
- let maxtics = GetDefaultByType(pg).EffectTics;
- if (maxtics == 0) maxtics = powerup.default.EffectTics;
- return powerup.EffectTics, maxtics;
- }
- }
- return -1, -1;
- }
- //===========================================================================
- //
- // PlayerPawn :: CheckWeaponSwitch
- //
- // Checks if weapons should be changed after picking up ammo
- //
- //===========================================================================
- void CheckWeaponSwitch(Class<Ammo> ammotype)
- {
- let player = self.player;
- if (!player.GetNeverSwitch() && player.PendingWeapon == WP_NOCHANGE &&
- (player.ReadyWeapon == NULL || player.ReadyWeapon.bWimpy_Weapon))
- {
- let best = BestWeapon (ammotype);
- if (best != NULL && (player.ReadyWeapon == NULL ||
- best.SelectionOrder < player.ReadyWeapon.SelectionOrder))
- {
- player.PendingWeapon = best;
- }
- }
- }
- //---------------------------------------------------------------------------
- //
- // PROC P_FireWeapon
- //
- //---------------------------------------------------------------------------
- virtual void FireWeapon (State stat)
- {
- let player = self.player;
- // [SO] 9/2/02: People were able to do an awful lot of damage
- // when they were observers...
- if (player.Bot == null && bot_observer)
- {
- return;
- }
- let weapn = player.ReadyWeapon;
- if (weapn == null || !weapn.CheckAmmo (Weapon.PrimaryFire, true))
- {
- return;
- }
- player.WeaponState &= ~WF_WEAPONBOBBING;
- PlayAttacking ();
- weapn.bAltFire = false;
- if (stat == null)
- {
- stat = weapn.GetAtkState(!!player.refire);
- }
- player.SetPsprite(PSP_WEAPON, stat);
- if (!weapn.bNoAlert)
- {
- SoundAlert (self, false);
- }
- }
- //---------------------------------------------------------------------------
- //
- // PROC P_FireWeaponAlt
- //
- //---------------------------------------------------------------------------
- virtual void FireWeaponAlt (State stat)
- {
- // [SO] 9/2/02: People were able to do an awful lot of damage
- // when they were observers...
- if (player.Bot == null && bot_observer)
- {
- return;
- }
- let weapn = player.ReadyWeapon;
- if (weapn == null || weapn.FindState('AltFire') == null || !weapn.CheckAmmo (Weapon.AltFire, true))
- {
- return;
- }
- player.WeaponState &= ~WF_WEAPONBOBBING;
- PlayAttacking ();
- weapn.bAltFire = true;
- if (stat == null)
- {
- stat = weapn.GetAltAtkState(!!player.refire);
- }
- player.SetPsprite(PSP_WEAPON, stat);
- if (!weapn.bNoAlert)
- {
- SoundAlert (self, false);
- }
- }
- //---------------------------------------------------------------------------
- //
- // PROC P_CheckWeaponFire
- //
- // The player can fire the weapon.
- // [RH] This was in A_WeaponReady before, but that only works well when the
- // weapon's ready frames have a one tic delay.
- //
- //---------------------------------------------------------------------------
- void CheckWeaponFire ()
- {
- let player = self.player;
- let weapon = player.ReadyWeapon;
- if (weapon == NULL)
- return;
- // Check for fire. Some weapons do not auto fire.
- if ((player.WeaponState & WF_WEAPONREADY) && (player.cmd.buttons & BT_ATTACK))
- {
- if (!player.attackdown || !weapon.bNoAutofire)
- {
- player.attackdown = true;
- FireWeapon (NULL);
- return;
- }
- }
- else if ((player.WeaponState & WF_WEAPONREADYALT) && (player.cmd.buttons & BT_ALTATTACK))
- {
- if (!player.attackdown || !weapon.bNoAutofire)
- {
- player.attackdown = true;
- FireWeaponAlt (NULL);
- return;
- }
- }
- else
- {
- player.attackdown = false;
- }
- }
- //---------------------------------------------------------------------------
- //
- // PROC P_CheckWeaponChange
- //
- // The player can change to another weapon at self time.
- // [GZ] This was cut from P_CheckWeaponFire.
- //
- //---------------------------------------------------------------------------
- virtual void CheckWeaponChange ()
- {
- let player = self.player;
- if ((player.WeaponState & WF_DISABLESWITCH) || // Weapon changing has been disabled.
- player.morphTics != 0) // Morphed classes cannot change weapons.
- { // ...so throw away any pending weapon requests.
- player.PendingWeapon = WP_NOCHANGE;
- }
- // Put the weapon away if the player has a pending weapon or has died, and
- // we're at a place in the state sequence where dropping the weapon is okay.
- if ((player.PendingWeapon != WP_NOCHANGE || player.health <= 0) &&
- player.WeaponState & WF_WEAPONSWITCHOK)
- {
- DropWeapon();
- }
- }
- //------------------------------------------------------------------------
- //
- // PROC P_MovePsprites
- //
- // Called every tic by player thinking routine
- //
- //------------------------------------------------------------------------
- virtual void TickPSprites()
- {
- let player = self.player;
- let pspr = player.psprites;
- while (pspr)
- {
- // Destroy the psprite if it's from a weapon that isn't currently selected by the player
- // or if it's from an inventory item that the player no longer owns.
- if ((pspr.Caller == null ||
- (pspr.Caller is "Inventory" && Inventory(pspr.Caller).Owner != pspr.Owner.mo) ||
- (pspr.Caller is "Weapon" && pspr.Caller != pspr.Owner.ReadyWeapon)))
- {
- pspr.Destroy();
- }
- else
- {
- pspr.Tick();
- }
- pspr = pspr.Next;
- }
- if ((health > 0) || (player.ReadyWeapon != null && !player.ReadyWeapon.bNoDeathInput))
- {
- if (player.ReadyWeapon == null)
- {
- if (player.PendingWeapon != WP_NOCHANGE)
- player.mo.BringUpWeapon();
- }
- else
- {
- CheckWeaponChange();
- if (player.WeaponState & (WF_WEAPONREADY | WF_WEAPONREADYALT))
- {
- CheckWeaponFire();
- }
- // Check custom buttons
- CheckWeaponButtons();
- }
- }
- }
- /*
- ==================
- =
- = P_CalcHeight
- =
- =
- Calculate the walking / running height adjustment
- =
- ==================
- */
- virtual void CalcHeight()
- {
- let player = self.player;
- double angle;
- double bob;
- bool still = false;
- // Regular movement bobbing
- // (needs to be calculated for gun swing even if not on ground)
- // killough 10/98: Make bobbing depend only on player-applied motion.
- //
- // Note: don't reduce bobbing here if on ice: if you reduce bobbing here,
- // it causes bobbing jerkiness when the player moves from ice to non-ice,
- // and vice-versa.
- if (player.cheats & CF_NOCLIP2)
- {
- player.bob = 0;
- }
- else if (bNoGravity && !player.onground)
- {
- player.bob = 0.5;
- }
- else
- {
- player.bob = player.Vel dot player.Vel;
- if (player.bob == 0)
- {
- still = true;
- }
- else
- {
- player.bob *= player.GetMoveBob();
- if (player.bob > MAXBOB)
- player.bob = MAXBOB;
- }
- }
- double defaultviewheight = ViewHeight + player.crouchviewdelta;
- if (player.cheats & CF_NOVELOCITY)
- {
- player.viewz = pos.Z + defaultviewheight;
- if (player.viewz > ceilingz-4)
- player.viewz = ceilingz-4;
- return;
- }
- if (still)
- {
- if (player.health > 0)
- {
- angle = Level.maptime / (120 * TICRATE / 35.) * 360.;
- bob = player.GetStillBob() * sin(angle);
- }
- else
- {
- bob = 0;
- }
- }
- else
- {
- angle = Level.maptime / (20 * TICRATE / 35.) * 360.;
- bob = player.bob * sin(angle) * (waterlevel > 1 ? 0.25f : 0.5f);
- }
- // move viewheight
- if (player.playerstate == PST_LIVE)
- {
- player.viewheight += player.deltaviewheight;
- if (player.viewheight > defaultviewheight)
- {
- player.viewheight = defaultviewheight;
- player.deltaviewheight = 0;
- }
- else if (player.viewheight < (defaultviewheight/2))
- {
- player.viewheight = defaultviewheight/2;
- if (player.deltaviewheight <= 0)
- player.deltaviewheight = 1 / 65536.;
- }
- if (player.deltaviewheight)
- {
- player.deltaviewheight += 0.25;
- if (!player.deltaviewheight)
- player.deltaviewheight = 1/65536.;
- }
- }
- if (player.morphTics)
- {
- bob = 0;
- }
- player.viewz = pos.Z + player.viewheight + (bob * clamp(ViewBob, 0. , 1.5)); // [SP] Allow DECORATE changes to view bobbing speed.
- if (Floorclip && player.playerstate != PST_DEAD
- && pos.Z <= floorz)
- {
- player.viewz -= Floorclip;
- }
- if (player.viewz > ceilingz - 4)
- {
- player.viewz = ceilingz - 4;
- }
- if (player.viewz < floorz + 4)
- {
- player.viewz = floorz + 4;
- }
- }
- //==========================================================================
- //
- // P_DeathThink
- //
- //==========================================================================
- virtual void DeathThink ()
- {
- let player = self.player;
- int dir;
- double delta;
- player.Uncrouch();
- TickPSprites();
- player.onground = (pos.Z <= floorz);
- if (self is "PlayerChunk")
- { // Flying bloody skull or flying ice chunk
- player.viewheight = 6;
- player.deltaviewheight = 0;
- if (player.onground)
- {
- if (Pitch > -19.)
- {
- double lookDelta = (-19. - Pitch) / 8;
- Pitch += lookDelta;
- }
- }
- }
- else if (!bIceCorpse)
- { // Fall to ground (if not frozen)
- player.deltaviewheight = 0;
- if (player.viewheight > 6)
- {
- player.viewheight -= 1;
- }
- if (player.viewheight < 6)
- {
- player.viewheight = 6;
- }
- if (Pitch < 0)
- {
- Pitch += 3;
- }
- else if (Pitch > 0)
- {
- Pitch -= 3;
- }
- if (abs(Pitch) < 3)
- {
- Pitch = 0.;
- }
- }
- player.mo.CalcHeight ();
- if (player.attacker && player.attacker != self)
- { // Watch killer
- double diff = deltaangle(angle, AngleTo(player.attacker));
- double delta = abs(diff);
- if (delta < 10)
- { // Looking at killer, so fade damage and poison counters
- if (player.damagecount)
- {
- player.damagecount--;
- }
- if (player.poisoncount)
- {
- player.poisoncount--;
- }
- }
- delta /= 8;
- Angle += clamp(diff, -5., 5.);
- }
- else
- {
- if (player.damagecount)
- {
- player.damagecount--;
- }
- if (player.poisoncount)
- {
- player.poisoncount--;
- }
- }
- if ((player.cmd.buttons & BT_USE ||
- ((deathmatch || alwaysapplydmflags) && sv_forcerespawn)) && !sv_norespawn)
- {
- if (Level.maptime >= player.respawn_time || ((player.cmd.buttons & BT_USE) && player.Bot == NULL))
- {
- player.cls = NULL; // Force a new class if the player is using a random class
- player.playerstate = (multiplayer || level.AllowRespawn || sv_singleplayerrespawn || G_SkillPropertyInt(SKILLP_PlayerRespawn)) ? PST_REBORN : PST_ENTER;
- if (special1 > 2)
- {
- special1 = 0;
- }
- }
- }
- }
- //===========================================================================
- //
- // PlayerPawn :: Die
- //
- //===========================================================================
- override void Die (Actor source, Actor inflictor, int dmgflags, Name MeansOfDeath)
- {
- Super.Die (source, inflictor, dmgflags, MeansOfDeath);
- if (player != NULL && player.mo == self) player.bonuscount = 0;
- if (player != NULL && player.mo != self)
- { // Make the real player die, too
- player.mo.Die (source, inflictor, dmgflags, MeansOfDeath);
- }
- else
- {
- if (player != NULL && sv_weapondrop)
- { // Voodoo dolls don't drop weapons
- let weap = player.ReadyWeapon;
- if (weap != NULL)
- {
- // kgDROP - start - modified copy from a_action.cpp
- let di = weap.GetDropItems();
- if (di != NULL)
- {
- while (di != NULL)
- {
- if (di.Name != 'None')
- {
- class<Actor> ti = di.Name;
- if (ti) A_DropItem (ti, di.Amount, di.Probability);
- }
- di = di.Next;
- }
- }
- else if (weap.SpawnState != NULL &&
- weap.SpawnState != GetDefaultByType('Actor').SpawnState)
- {
- let weapitem = Weapon(A_DropItem (weap.GetClass(), -1, 256));
- if (weapitem)
- {
- if (weap.AmmoGive1 && weap.Ammo1)
- {
- weapitem.AmmoGive1 = weap.Ammo1.Amount;
- }
- if (weap.AmmoGive2 && weap.Ammo2)
- {
- weapitem.AmmoGive2 = weap.Ammo2.Amount;
- }
- weapitem.bIgnoreSkill = true;
- }
- }
- else
- {
- let item = Inventory(A_DropItem (weap.AmmoType1, -1, 256));
- if (item != NULL)
- {
- item.Amount = weap.Ammo1.Amount;
- item.bIgnoreSkill = true;
- }
- item = Inventory(A_DropItem (weap.AmmoType2, -1, 256));
- if (item != NULL)
- {
- item.Amount = weap.Ammo2.Amount;
- item.bIgnoreSkill = true;
- }
- }
- }
- }
- if (!multiplayer && level.deathsequence != 'None')
- {
- level.StartIntermission(level.deathsequence, FSTATE_EndingGame);
- }
- }
- }
- //===========================================================================
- //
- // PlayerPawn :: FilterCoopRespawnInventory
- //
- // When respawning in coop, this function is called to walk through the dead
- // player's inventory and modify it according to the current game flags so
- // that it can be transferred to the new live player. This player currently
- // has the default inventory, and the oldplayer has the inventory at the time
- // of death.
- //
- //===========================================================================
- void FilterCoopRespawnInventory (PlayerPawn oldplayer)
- {
- // If we're losing everything, this is really simple.
- if (sv_cooploseinventory)
- {
- oldplayer.DestroyAllInventory();
- return;
- }
- // Walk through the old player's inventory and destroy or modify
- // according to dmflags.
- Inventory next;
- for (Inventory item = oldplayer.Inv; item != NULL; item = next)
- {
- next = item.Inv;
- // If this item is part of the default inventory, we never want
- // to destroy it, although we might want to copy the default
- // inventory amount.
- let defitem = FindInventory (item.GetClass());
- if (sv_cooplosekeys && defitem == NULL && item is 'Key')
- {
- item.Destroy();
- }
- else if (sv_cooploseweapons && defitem == NULL && item is 'Weapon')
- {
- item.Destroy();
- }
- else if (sv_cooplosearmor && item is 'Armor')
- {
- if (defitem == NULL)
- {
- item.Destroy();
- }
- else if (item is 'BasicArmor')
- {
- BasicArmor(item).SavePercent = BasicArmor(defitem).SavePercent;
- item.Amount = defitem.Amount;
- }
- else if (item is 'HexenArmor')
- {
- let to = HexenArmor(item);
- let from = HexenArmor(defitem);
- to.Slots[0] = from.Slots[0];
- to.Slots[1] = from.Slots[1];
- to.Slots[2] = from.Slots[2];
- to.Slots[3] = from.Slots[3];
- }
- }
- else if (sv_cooplosepowerups && defitem == NULL && item is 'Powerup')
- {
- item.Destroy();
- }
- else if ((sv_cooploseammo || sv_coophalveammo) && item is 'Ammo')
- {
- if (defitem == NULL)
- {
- if (sv_cooploseammo)
- {
- // Do NOT destroy the ammo, because a weapon might reference it.
- item.Amount = 0;
- }
- else if (item.Amount > 1)
- {
- item.Amount /= 2;
- }
- }
- else
- {
- // When set to lose ammo, you get to keep all your starting ammo.
- // When set to halve ammo, you won't be left with less than your starting amount.
- if (sv_cooploseammo)
- {
- item.Amount = defitem.Amount;
- }
- else if (item.Amount > 1)
- {
- item.Amount = MAX(item.Amount / 2, defitem.Amount);
- }
- }
- }
- }
- // Now destroy the default inventory this player is holding and move
- // over the old player's remaining inventory.
- DestroyAllInventory();
- ObtainInventory (oldplayer);
- player.ReadyWeapon = NULL;
- PickNewWeapon (NULL);
- }
- //----------------------------------------------------------------------------
- //
- // PROC P_CheckFOV
- //
- //----------------------------------------------------------------------------
- virtual void CheckFOV()
- {
- let player = self.player;
- // [RH] Zoom the player's FOV
- float desired = player.DesiredFOV;
- // Adjust FOV using on the currently held weapon.
- if (player.playerstate != PST_DEAD && // No adjustment while dead.
- player.ReadyWeapon != NULL && // No adjustment if no weapon.
- player.ReadyWeapon.FOVScale != 0) // No adjustment if the adjustment is zero.
- {
- // A negative scale is used to prevent G_AddViewAngle/G_AddViewPitch
- // from scaling with the FOV scale.
- desired *= abs(player.ReadyWeapon.FOVScale);
- }
- if (player.FOV != desired)
- {
- if (abs(player.FOV - desired) < 7.)
- {
- player.FOV = desired;
- }
- else
- {
- float zoom = MAX(7., abs(player.FOV - desired) * 0.025);
- if (player.FOV > desired)
- {
- player.FOV = player.FOV - zoom;
- }
- else
- {
- player.FOV = player.FOV + zoom;
- }
- }
- }
- }
- //----------------------------------------------------------------------------
- //
- // PROC P_CheckCheats
- //
- //----------------------------------------------------------------------------
- virtual void CheckCheats()
- {
- let player = self.player;
- // No-clip cheat
- if ((player.cheats & (CF_NOCLIP | CF_NOCLIP2)) == CF_NOCLIP2)
- { // No noclip2 without noclip
- player.cheats &= ~CF_NOCLIP2;
- }
- bNoClip = (player.cheats & (CF_NOCLIP | CF_NOCLIP2) || Default.bNoClip);
- if (player.cheats & CF_NOCLIP2)
- {
- bNoGravity = true;
- }
- else if (!bFly && !Default.bNoGravity)
- {
- bNoGravity = false;
- }
- }
- //----------------------------------------------------------------------------
- //
- // PROC P_CheckFrozen
- //
- //----------------------------------------------------------------------------
- virtual bool CheckFrozen()
- {
- let player = self.player;
- UserCmd cmd = player.cmd;
- bool totallyfrozen = player.IsTotallyFrozen();
- // [RH] Being totally frozen zeros out most input parameters.
- if (totallyfrozen)
- {
- if (gamestate == GS_TITLELEVEL)
- {
- cmd.buttons = 0;
- }
- else
- {
- cmd.buttons &= BT_USE;
- }
- cmd.pitch = 0;
- cmd.yaw = 0;
- cmd.roll = 0;
- cmd.forwardmove = 0;
- cmd.sidemove = 0;
- cmd.upmove = 0;
- player.turnticks = 0;
- }
- else if (player.cheats & CF_FROZEN)
- {
- cmd.forwardmove = 0;
- cmd.sidemove = 0;
- cmd.upmove = 0;
- }
- return totallyfrozen;
- }
- virtual bool CanCrouch() const
- {
- return player.morphTics == 0 || bCrouchableMorph;
- }
- //----------------------------------------------------------------------------
- //
- // PROC P_CrouchMove
- //
- //----------------------------------------------------------------------------
- virtual void CrouchMove(int direction)
- {
- let player = self.player;
- double defaultheight = FullHeight;
- double savedheight = Height;
- double crouchspeed = direction * CROUCHSPEED;
- double oldheight = player.viewheight;
- player.crouchdir = direction;
- player.crouchfactor += crouchspeed;
- // check whether the move is ok
- Height = defaultheight * player.crouchfactor;
- if (!TryMove(Pos.XY, false, NULL))
- {
- Height = savedheight;
- if (direction > 0)
- {
- // doesn't fit
- player.crouchfactor -= crouchspeed;
- return;
- }
- }
- Height = savedheight;
- player.crouchfactor = clamp(player.crouchfactor, 0.5, 1.);
- player.viewheight = ViewHeight * player.crouchfactor;
- player.crouchviewdelta = player.viewheight - ViewHeight;
- // Check for eyes going above/below fake floor due to crouching motion.
- CheckFakeFloorTriggers(pos.Z + oldheight, true);
- }
- //----------------------------------------------------------------------------
- //
- // PROC P_CheckCrouch
- //
- //----------------------------------------------------------------------------
- virtual void CheckCrouch(bool totallyfrozen)
- {
- let player = self.player;
- UserCmd cmd = player.cmd;
- if (cmd.buttons & BT_JUMP)
- {
- cmd.buttons &= ~BT_CROUCH;
- }
- if (CanCrouch() && player.health > 0 && level.IsCrouchingAllowed())
- {
- if (!totallyfrozen)
- {
- int crouchdir = player.crouching;
- if (crouchdir == 0)
- {
- crouchdir = (cmd.buttons & BT_CROUCH) ? -1 : 1;
- }
- else if (cmd.buttons & BT_CROUCH)
- {
- player.crouching = 0;
- }
- if (crouchdir == 1 && player.crouchfactor < 1 && pos.Z + height < ceilingz)
- {
- CrouchMove(1);
- }
- else if (crouchdir == -1 && player.crouchfactor > 0.5)
- {
- CrouchMove(-1);
- }
- }
- }
- else
- {
- player.Uncrouch();
- }
- player.crouchoffset = -(ViewHeight) * (1 - player.crouchfactor);
- }
- //----------------------------------------------------------------------------
- //
- // P_Thrust
- //
- // moves the given origin along a given angle
- //
- //----------------------------------------------------------------------------
- void ForwardThrust (double move, double angle)
- {
- if ((waterlevel || bNoGravity) && Pitch != 0 && !player.GetClassicFlight())
- {
- double zpush = move * sin(Pitch);
- if (waterlevel && waterlevel < 2 && zpush < 0) zpush = 0;
- Vel.Z -= zpush;
- move *= cos(Pitch);
- }
- Thrust(move, angle);
- }
- //----------------------------------------------------------------------------
- //
- // P_Bob
- // Same as P_Thrust, but only affects bobbing.
- //
- // killough 10/98: We apply thrust separately between the real physical player
- // and the part which affects bobbing. This way, bobbing only comes from player
- // motion, nothing external, avoiding many problems, e.g. bobbing should not
- // occur on conveyors, unless the player walks on one, and bobbing should be
- // reduced at a regular rate, even on ice (where the player coasts).
- //
- //----------------------------------------------------------------------------
- void Bob (double angle, double move, bool forward)
- {
- if (forward && (waterlevel || bNoGravity) && Pitch != 0)
- {
- move *= cos(Pitch);
- }
- player.Vel += AngleToVector(angle, move);
- }
- //===========================================================================
- //
- // PlayerPawn :: TweakSpeeds
- //
- //===========================================================================
- virtual double, double TweakSpeeds (double forward, double side)
- {
- // Strife's player can't run when its health is below 10
- if (health <= RunHealth)
- {
- forward = clamp(forward, -gameinfo.normforwardmove[0]*256, gameinfo.normforwardmove[0]*256);
- side = clamp(side, -gameinfo.normsidemove[0]*256, gameinfo.normsidemove[0]*256);
- }
- // [GRB]
- if (abs(forward) < 0x3200)
- {
- forward *= ForwardMove1;
- }
- else
- {
- forward *= ForwardMove2;
- }
- if (abs(side) < 0x2800)
- {
- side *= SideMove1;
- }
- else
- {
- side *= SideMove2;
- }
- if (!player.morphTics)
- {
- double factor = 1.;
- for(let it = Inv; it != null; it = it.Inv)
- {
- factor *= it.GetSpeedFactor ();
- }
- forward *= factor;
- side *= factor;
- }
- return forward, side;
- }
- //----------------------------------------------------------------------------
- //
- // PROC P_MovePlayer
- //
- //----------------------------------------------------------------------------
- virtual void MovePlayer ()
- {
- let player = self.player;
- UserCmd cmd = player.cmd;
- // [RH] 180-degree turn overrides all other yaws
- if (player.turnticks)
- {
- player.turnticks--;
- Angle += (180. / TURN180_TICKS);
- }
- else
- {
- Angle += cmd.yaw * (360./65536.);
- }
- player.onground = (pos.z <= floorz) || bOnMobj || bMBFBouncer || (player.cheats & CF_NOCLIP2);
- // killough 10/98:
- //
- // We must apply thrust to the player and bobbing separately, to avoid
- // anomalies. The thrust applied to bobbing is always the same strength on
- // ice, because the player still "works just as hard" to move, while the
- // thrust applied to the movement varies with 'movefactor'.
- if (cmd.forwardmove | cmd.sidemove)
- {
- double forwardmove, sidemove;
- double bobfactor;
- double friction, movefactor;
- double fm, sm;
- [friction, movefactor] = GetFriction();
- bobfactor = friction < ORIG_FRICTION ? movefactor : ORIG_FRICTION_FACTOR;
- if (!player.onground && !bNoGravity && !waterlevel)
- {
- // [RH] allow very limited movement if not on ground.
- movefactor *= level.aircontrol;
- bobfactor*= level.aircontrol;
- }
- fm = cmd.forwardmove;
- sm = cmd.sidemove;
- [fm, sm] = TweakSpeeds (fm, sm);
- fm *= Speed / 256;
- sm *= Speed / 256;
- // When crouching, speed and bobbing have to be reduced
- if (CanCrouch() && player.crouchfactor != 1)
- {
- fm *= player.crouchfactor;
- sm *= player.crouchfactor;
- bobfactor *= player.crouchfactor;
- }
- forwardmove = fm * movefactor * (35 / TICRATE);
- sidemove = sm * movefactor * (35 / TICRATE);
- if (forwardmove)
- {
- Bob(Angle, cmd.forwardmove * bobfactor / 256., true);
- ForwardThrust(forwardmove, Angle);
- }
- if (sidemove)
- {
- let a = Angle - 90;
- Bob(a, cmd.sidemove * bobfactor / 256., false);
- Thrust(sidemove, a);
- }
- if (!(player.cheats & CF_PREDICTING) && (forwardmove != 0 || sidemove != 0))
- {
- PlayRunning ();
- }
- if (player.cheats & CF_REVERTPLEASE)
- {
- player.cheats &= ~CF_REVERTPLEASE;
- player.camera = player.mo;
- }
- }
- }
- //----------------------------------------------------------------------------
- //
- // PROC P_CheckPitch
- //
- //----------------------------------------------------------------------------
- virtual void CheckPitch()
- {
- let player = self.player;
- // [RH] Look up/down stuff
- if (!level.IsFreelookAllowed())
- {
- Pitch = 0.;
- }
- else
- {
- // The player's view pitch is clamped between -32 and +56 degrees,
- // which translates to about half a screen height up and (more than)
- // one full screen height down from straight ahead when view panning
- // is used.
- int clook = player.cmd.pitch;
- if (clook != 0)
- {
- if (clook == -32768)
- { // center view
- player.centering = true;
- }
- else if (!player.centering)
- {
- // no more overflows with floating point. Yay! :)
- Pitch = clamp(Pitch - clook * (360. / 65536.), player.MinPitch, player.MaxPitch);
- }
- }
- }
- if (player.centering)
- {
- if (abs(Pitch) > 2.)
- {
- Pitch *= (2. / 3.);
- }
- else
- {
- Pitch = 0.;
- player.centering = false;
- if (PlayerNumber() == consoleplayer)
- {
- LocalViewPitch = 0;
- }
- }
- }
- }
- //----------------------------------------------------------------------------
- //
- // PROC P_CheckJump
- //
- //----------------------------------------------------------------------------
- virtual void CheckJump()
- {
- let player = self.player;
- // [RH] check for jump
- if (player.cmd.buttons & BT_JUMP)
- {
- if (player.crouchoffset != 0)
- {
- // Jumping while crouching will force an un-crouch but not jump
- player.crouching = 1;
- }
- else if (waterlevel >= 2)
- {
- Vel.Z = 4 * Speed;
- }
- else if (bNoGravity)
- {
- Vel.Z = 3.;
- }
- else if (level.IsJumpingAllowed() && player.onground && player.jumpTics == 0)
- {
- double jumpvelz = JumpZ * 35 / TICRATE;
- double jumpfac = 0;
- // [BC] If the player has the high jump power, double his jump velocity.
- // (actually, pick the best factors from all active items.)
- for (let p = Inv; p != null; p = p.Inv)
- {
- let pp = PowerHighJump(p);
- if (pp)
- {
- double f = pp.Strength;
- if (f > jumpfac) jumpfac = f;
- }
- }
- if (jumpfac > 0) jumpvelz *= jumpfac;
- Vel.Z += jumpvelz;
- bOnMobj = false;
- player.jumpTics = -1;
- if (!(player.cheats & CF_PREDICTING)) A_StartSound("*jump", CHAN_BODY);
- }
- }
- }
- //----------------------------------------------------------------------------
- //
- // PROC P_CheckMoveUpDown
- //
- //----------------------------------------------------------------------------
- virtual void CheckMoveUpDown()
- {
- let player = self.player;
- UserCmd cmd = player.cmd;
- if (cmd.upmove == -32768)
- { // Only land if in the air
- if (bNoGravity && waterlevel < 2)
- {
- bNoGravity = false;
- }
- }
- else if (cmd.upmove != 0)
- {
- // Clamp the speed to some reasonable maximum.
- cmd.upmove = clamp(cmd.upmove, -0x300, 0x300);
- if (waterlevel >= 2 || bFly || (player.cheats & CF_NOCLIP2))
- {
- Vel.Z = Speed * cmd.upmove / 128.;
- if (waterlevel < 2 && !bNoGravity)
- {
- bFly = true;
- bNoGravity = true;
- if ((Vel.Z <= -39) && !(player.cheats & CF_PREDICTING))
- { // Stop falling scream
- A_StopSound(CHAN_VOICE);
- }
- }
- }
- else if (cmd.upmove > 0 && !(player.cheats & CF_PREDICTING))
- {
- let fly = FindInventory("ArtiFly");
- if (fly != NULL)
- {
- UseInventory(fly);
- }
- }
- }
- }
- //----------------------------------------------------------------------------
- //
- // PROC P_HandleMovement
- //
- //----------------------------------------------------------------------------
- virtual void HandleMovement()
- {
- let player = self.player;
- // [RH] Check for fast turn around
- if (player.cmd.buttons & BT_TURN180 && !(player.oldbuttons & BT_TURN180))
- {
- player.turnticks = TURN180_TICKS;
- }
- // Handle movement
- if (reactiontime)
- { // Player is frozen
- reactiontime--;
- }
- else
- {
- MovePlayer();
- CheckJump();
- CheckMoveUpDown();
- }
- }
- //----------------------------------------------------------------------------
- //
- // PROC P_CheckUndoMorph
- //
- //----------------------------------------------------------------------------
- virtual void CheckUndoMorph()
- {
- let player = self.player;
- // Morph counter
- if (player.morphTics)
- {
- if (player.chickenPeck)
- { // Chicken attack counter
- player.chickenPeck -= 3;
- }
- if (!--player.morphTics)
- { // Attempt to undo the chicken/pig
- player.mo.UndoPlayerMorph(player, MRF_UNDOBYTIMEOUT);
- }
- }
- }
- //----------------------------------------------------------------------------
- //
- // PROC P_CheckPoison
- //
- //----------------------------------------------------------------------------
- virtual void CheckPoison()
- {
- let player = self.player;
- if (player.poisoncount && !(Level.maptime & 15))
- {
- player.poisoncount -= 5;
- if (player.poisoncount < 0)
- {
- player.poisoncount = 0;
- }
- player.PoisonDamage(player.poisoner, 1, true);
- }
- }
- //----------------------------------------------------------------------------
- //
- // PROC P_CheckDegeneration
- //
- //----------------------------------------------------------------------------
- virtual void CheckDegeneration()
- {
- // Apply degeneration.
- if (sv_degeneration)
- {
- let player = self.player;
- int maxhealth = GetMaxHealth(true);
- if ((Level.maptime % TICRATE) == 0 && player.health > maxhealth)
- {
- if (player.health - 5 < maxhealth)
- player.health = maxhealth;
- else
- player.health--;
- health = player.health;
- }
- }
- }
- //----------------------------------------------------------------------------
- //
- // PROC P_CheckAirSupply
- //
- //----------------------------------------------------------------------------
- virtual void CheckAirSupply()
- {
- // Handle air supply
- //if (level.airsupply > 0)
- {
- let player = self.player;
- if (waterlevel < 3 || (bInvulnerable) || (player.cheats & (CF_GODMODE | CF_NOCLIP2)) || (player.cheats & CF_GODMODE2))
- {
- ResetAirSupply();
- }
- else if (player.air_finished <= Level.maptime && !(Level.maptime & 31))
- {
- DamageMobj(NULL, NULL, 2 + ((Level.maptime - player.air_finished) / TICRATE), 'Drowning');
- }
- }
- }
- //----------------------------------------------------------------------------
- //
- // PROC P_PlayerThink
- //
- //----------------------------------------------------------------------------
- virtual void PlayerThink()
- {
- let player = self.player;
- UserCmd cmd = player.cmd;
- CheckFOV();
- if (player.inventorytics)
- {
- player.inventorytics--;
- }
- CheckCheats();
- if (bJustAttacked)
- { // Chainsaw/Gauntlets attack auto forward motion
- cmd.yaw = 0;
- cmd.forwardmove = 0xc800/2;
- cmd.sidemove = 0;
- bJustAttacked = false;
- }
- bool totallyfrozen = CheckFrozen();
- // Handle crouching
- CheckCrouch(totallyfrozen);
- CheckMusicChange();
- if (player.playerstate == PST_DEAD)
- {
- DeathThink ();
- return;
- }
- if (player.jumpTics != 0)
- {
- player.jumpTics--;
- if (player.onground && player.jumpTics < -18)
- {
- player.jumpTics = 0;
- }
- }
- if (player.morphTics && !(player.cheats & CF_PREDICTING))
- {
- MorphPlayerThink ();
- }
- CheckPitch();
- HandleMovement();
- CalcHeight ();
- if (!(player.cheats & CF_PREDICTING))
- {
- CheckEnvironment();
- // Note that after this point the PlayerPawn may have changed due to getting unmorphed or getting its skull popped so 'self' is no longer safe to use.
- // This also must not read mo into a local variable because several functions in this block can change the attached PlayerPawn.
- player.mo.CheckUse();
- player.mo.CheckUndoMorph();
- // Cycle psprites.
- player.mo.TickPSprites();
- // Other Counters
- if (player.damagecount) player.damagecount--;
- if (player.bonuscount) player.bonuscount--;
- if (player.hazardcount)
- {
- player.hazardcount--;
- if (!(Level.maptime % player.hazardinterval) && player.hazardcount > 16*TICRATE)
- player.mo.DamageMobj (NULL, NULL, 5, player.hazardtype);
- }
- player.mo.CheckPoison();
- player.mo.CheckDegeneration();
- player.mo.CheckAirSupply();
- }
- }
- //---------------------------------------------------------------------------
- //
- // PROC P_BringUpWeapon
- //
- // Starts bringing the pending weapon up from the bottom of the screen.
- // This is only called to start the rising, not throughout it.
- //
- //---------------------------------------------------------------------------
- void BringUpWeapon ()
- {
- let player = self.player;
- if (player.PendingWeapon == WP_NOCHANGE)
- {
- if (player.ReadyWeapon != null)
- {
- player.GetPSprite(PSP_WEAPON).y = WEAPONTOP;
- player.SetPsprite(PSP_WEAPON, player.ReadyWeapon.GetReadyState());
- }
- return;
- }
- let weapon = player.PendingWeapon;
- // If the player has a tome of power, use self weapon's powered up
- // version, if one is available.
- if (weapon != null &&
- weapon.SisterWeapon &&
- weapon.SisterWeapon.bPowered_Up &&
- player.mo.FindInventory ('PowerWeaponLevel2', true))
- {
- weapon = weapon.SisterWeapon;
- }
- player.PendingWeapon = WP_NOCHANGE;
- player.ReadyWeapon = weapon;
- player.mo.weaponspecial = 0;
- if (weapon != null)
- {
- weapon.PlayUpSound(self);
- player.refire = 0;
- player.GetPSprite(PSP_WEAPON).y = player.cheats & CF_INSTANTWEAPSWITCH? WEAPONTOP : WEAPONBOTTOM;
- // make sure that the previous weapon's flash state is terminated.
- // When coming here from a weapon drop it may still be active.
- player.SetPsprite(PSP_FLASH, null);
- player.SetPsprite(PSP_WEAPON, weapon.GetUpState());
- }
- }
- //===========================================================================
- //
- // PlayerPawn :: BestWeapon
- //
- // Returns the best weapon a player has, possibly restricted to a single
- // type of ammo.
- //
- //===========================================================================
- Weapon BestWeapon(Class<Ammo> ammotype)
- {
- Weapon bestMatch = NULL;
- int bestOrder = int.max;
- Inventory item;
- bool tomed = !!FindInventory ('PowerWeaponLevel2', true);
- // Find the best weapon the player has.
- for (item = Inv; item != NULL; item = item.Inv)
- {
- let weap = Weapon(item);
- if (weap == null)
- continue;
- // Don't select it if it's worse than what was already found.
- if (weap.SelectionOrder > bestOrder)
- continue;
- // Don't select it if its primary fire doesn't use the desired ammo.
- if (ammotype != NULL &&
- (weap.Ammo1 == NULL ||
- weap.Ammo1.GetClass() != ammotype))
- continue;
- // Don't select it if the Tome is active and self isn't the powered-up version.
- if (tomed && weap.SisterWeapon != NULL && weap.SisterWeapon.bPowered_Up)
- continue;
- // Don't select it if it's powered-up and the Tome is not active.
- if (!tomed && weap.bPowered_Up)
- continue;
- // Don't select it if there isn't enough ammo to use its primary fire.
- if (!(weap.bAMMO_OPTIONAL) &&
- !weap.CheckAmmo (Weapon.PrimaryFire, false))
- continue;
- // Don't select if if there isn't enough ammo as determined by the weapon's author.
- if (weap.MinSelAmmo1 > 0 && (weap.Ammo1 == NULL || weap.Ammo1.Amount < weap.MinSelAmmo1))
- continue;
- if (weap.MinSelAmmo2 > 0 && (weap.Ammo2 == NULL || weap.Ammo2.Amount < weap.MinSelAmmo2))
- continue;
- // This weapon is usable!
- bestOrder = weap.SelectionOrder;
- bestMatch = weap;
- }
- return bestMatch;
- }
- //---------------------------------------------------------------------------
- //
- // PROC P_DropWeapon
- //
- // The player died, so put the weapon away.
- //
- //---------------------------------------------------------------------------
- void DropWeapon ()
- {
- let player = self.player;
- if (player == null)
- {
- return;
- }
- // Since the weapon is dropping, stop blocking switching.
- player.WeaponState &= ~WF_DISABLESWITCH;
- Weapon weap = player.ReadyWeapon;
- if ((weap != null) && (player.health > 0 || !weap.bNoDeathDeselect))
- {
- player.SetPsprite(PSP_WEAPON, weap.GetDownState());
- }
- }
- //===========================================================================
- //
- // PlayerPawn :: PickNewWeapon
- //
- // Picks a new weapon for this player. Used mostly for running out of ammo,
- // but it also works when an ACS script explicitly takes the ready weapon
- // away or the player picks up some ammo they had previously run out of.
- //
- //===========================================================================
- Weapon PickNewWeapon(Class<Ammo> ammotype)
- {
- Weapon best = BestWeapon (ammotype);
- if (best != NULL)
- {
- player.PendingWeapon = best;
- if (player.ReadyWeapon != NULL)
- {
- DropWeapon();
- }
- else if (player.PendingWeapon != WP_NOCHANGE)
- {
- BringUpWeapon ();
- }
- }
- return best;
- }
- //===========================================================================
- //
- // PlayerPawn :: GiveDefaultInventory
- //
- //===========================================================================
- virtual void GiveDefaultInventory ()
- {
- let player = self.player;
- if (player == NULL) return;
- // HexenArmor must always be the first item in the inventory because
- // it provides player class based protection that should not affect
- // any other protection item.
- let myclass = GetClass();
- GiveInventoryType('HexenArmor');
- let harmor = HexenArmor(FindInventory('HexenArmor'));
- harmor.Slots[4] = self.HexenArmor[0];
- for (int i = 0; i < 4; ++i)
- {
- harmor.SlotsIncrement[i] = self.HexenArmor[i + 1];
- }
- // BasicArmor must come right after that. It should not affect any
- // other protection item as well but needs to process the damage
- // before the HexenArmor does.
- GiveInventoryType('BasicArmor');
- // Now add the items from the DECORATE definition
- let di = GetDropItems();
- while (di)
- {
- Class<Actor> ti = di.Name;
- if (ti)
- {
- let tinv = (class<Inventory>)(ti);
- if (!tinv)
- {
- Console.Printf(TEXTCOLOR_ORANGE .. "%s is not an inventory item and cannot be given to a player as start item.\n", di.Name);
- }
- else
- {
- let item = FindInventory(tinv);
- if (item != NULL)
- {
- item.Amount = clamp(
- item.Amount + (di.Amount ? di.Amount : item.default.Amount), 0, item.MaxAmount);
- }
- else
- {
- item = Inventory(Spawn(ti));
- item.bIgnoreSkill = true; // no skill multipliers here
- item.Amount = di.Amount;
- let weap = Weapon(item);
- if (weap)
- {
- // To allow better control any weapon is emptied of
- // ammo before being given to the player.
- weap.AmmoGive1 = weap.AmmoGive2 = 0;
- }
- bool res;
- Actor check;
- [res, check] = item.CallTryPickup(self);
- if (!res)
- {
- item.Destroy();
- item = NULL;
- }
- else if (check != self)
- {
- // Player was morphed. This is illegal at game start.
- // This problem is only detectable when it's too late to do something about it...
- ThrowAbortException("Cannot give morph item '%s' when starting a game!", di.Name);
- }
- }
- let weap = Weapon(item);
- if (weap != NULL && weap.CheckAmmo(Weapon.EitherFire, false))
- {
- player.ReadyWeapon = player.PendingWeapon = weap;
- }
- }
- }
- di = di.Next;
- }
- }
- //===========================================================================
- //
- // PlayerPawn :: GiveDeathmatchInventory
- //
- // Gives players items they should have in addition to their default
- // inventory when playing deathmatch. (i.e. all keys)
- //
- //===========================================================================
- virtual void GiveDeathmatchInventory()
- {
- for ( int i = 0; i < AllActorClasses.Size(); ++i)
- {
- let cls = (class<Key>)(AllActorClasses[i]);
- if (cls)
- {
- let keyobj = GetDefaultByType(cls);
- if (keyobj.special1 != 0)
- {
- GiveInventoryType(cls);
- }
- }
- }
- }
- //===========================================================================
- //
- //
- //
- //===========================================================================
- override int GetMaxHealth(bool withupgrades) const
- {
- int ret = MaxHealth > 0? MaxHealth : ((Level.compatflags & COMPATF_DEHHEALTH)? 100 : deh.MaxHealth);
- if (withupgrades) ret += stamina + BonusHealth;
- return ret;
- }
- //===========================================================================
- //
- //
- //
- //===========================================================================
- virtual int GetTeleportFreezeTime()
- {
- if (TeleportFreezeTime <= 0) return 0;
- let item = inv;
- while (item != null)
- {
- if (item.GetNoTeleportFreeze()) return 0;
- item = item.inv;
- }
- return TeleportFreezeTime;
- }
- //===========================================================================
- //
- // G_PlayerFinishLevel
- // Called when a player completes a level.
- //
- // flags is checked for RESETINVENTORY and RESETHEALTH only.
- //
- //===========================================================================
- void PlayerFinishLevel (int mode, int flags)
- {
- Inventory item, next;
- let p = player;
- if (p.morphTics != 0)
- { // Undo morph
- Unmorph(self, 0, true);
- }
- // 'self' will be no longer valid from here on in case of an unmorph
- let me = p.mo;
- // Strip all current powers, unless moving in a hub and the power is okay to keep.
- item = me.Inv;
- while (item != NULL)
- {
- next = item.Inv;
- if (item is 'Powerup')
- {
- if (deathmatch || ((mode != FINISH_SameHub || !item.bHUBPOWER) && !item.bPERSISTENTPOWER)) // Keep persistent powers in non-deathmatch games
- {
- item.Destroy ();
- }
- }
- item = next;
- }
- let ReadyWeapon = p.ReadyWeapon;
- if (ReadyWeapon != NULL && ReadyWeapon.bPOWERED_UP && p.PendingWeapon == ReadyWeapon.SisterWeapon)
- {
- // Unselect powered up weapons if the unpowered counterpart is pending
- p.ReadyWeapon = p.PendingWeapon;
- }
- // reset invisibility to default
- me.RestoreRenderStyle();
- p.extralight = 0; // cancel gun flashes
- p.fixedcolormap = PlayerInfo.NOFIXEDCOLORMAP; // cancel ir goggles
- p.fixedlightlevel = -1;
- p.damagecount = 0; // no palette changes
- p.bonuscount = 0;
- p.poisoncount = 0;
- p.inventorytics = 0;
- if (mode != FINISH_SameHub)
- {
- // Take away flight and keys (and anything else with IF_INTERHUBSTRIP set)
- item = me.Inv;
- while (item != NULL)
- {
- next = item.Inv;
- if (item.InterHubAmount < 1)
- {
- item.Destroy ();
- }
- item = next;
- }
- }
- if (mode == FINISH_NoHub && !level.KEEPFULLINVENTORY)
- { // Reduce all owned (visible) inventory to defined maximum interhub amount
- Array<Inventory> todelete;
- for (item = me.Inv; item != NULL; item = item.Inv)
- {
- // If the player is carrying more samples of an item than allowed, reduce amount accordingly
- if (item.bINVBAR && item.Amount > item.InterHubAmount)
- {
- item.Amount = item.InterHubAmount;
- if (level.REMOVEITEMS && !item.bUNDROPPABLE && !item.bUNCLEARABLE)
- {
- todelete.Push(item);
- }
- }
- }
- for (int i = 0; i < toDelete.Size(); i++)
- {
- let it = toDelete[i];
- if (!it.bDestroyed)
- {
- item.DepleteOrDestroy();
- }
- }
- }
- // Resets player health to default if not dead.
- if ((flags & CHANGELEVEL_RESETHEALTH) && p.playerstate != PST_DEAD)
- {
- p.health = me.health = me.SpawnHealth();
- }
- // Clears the entire inventory and gives back the defaults for starting a game
- if ((flags & CHANGELEVEL_RESETINVENTORY) && p.playerstate != PST_DEAD)
- {
- me.ClearInventory();
- me.GiveDefaultInventory();
- }
- }
- //===========================================================================
- //
- // FWeaponSlot :: PickWeapon
- //
- // Picks a weapon from this slot. If no weapon is selected in this slot,
- // or the first weapon in this slot is selected, returns the last weapon.
- // Otherwise, returns the previous weapon in this slot. This means
- // precedence is given to the last weapon in the slot, which by convention
- // is probably the strongest. Does not return weapons you have no ammo
- // for or which you do not possess.
- //
- //===========================================================================
- virtual Weapon PickWeapon(int slot, bool checkammo)
- {
- int i, j;
- let player = self.player;
- int Size = player.weapons.SlotSize(slot);
- // Does this slot even have any weapons?
- if (Size == 0)
- {
- return player.ReadyWeapon;
- }
- let ReadyWeapon = player.ReadyWeapon;
- if (ReadyWeapon != null)
- {
- for (i = 0; i < Size; i++)
- {
- let weapontype = player.weapons.GetWeapon(slot, i);
- if (weapontype == ReadyWeapon.GetClass() ||
- (ReadyWeapon.bPOWERED_UP && ReadyWeapon.SisterWeapon != null && ReadyWeapon.SisterWeapon.GetClass() == weapontype))
- {
- for (j = (i == 0 ? Size - 1 : i - 1);
- j != i;
- j = (j == 0 ? Size - 1 : j - 1))
- {
- let weapontype2 = player.weapons.GetWeapon(slot, j);
- let weap = Weapon(player.mo.FindInventory(weapontype2));
- if (weap != null)
- {
- if (!checkammo || weap.CheckAmmo(Weapon.EitherFire, false))
- {
- return weap;
- }
- }
- }
- }
- }
- }
- for (i = Size - 1; i >= 0; i--)
- {
- let weapontype = player.weapons.GetWeapon(slot, i);
- let weap = Weapon(player.mo.FindInventory(weapontype));
- if (weap != null)
- {
- if (!checkammo || weap.CheckAmmo(Weapon.EitherFire, false))
- {
- return weap;
- }
- }
- }
- return ReadyWeapon;
- }
- //===========================================================================
- //
- // FindMostRecentWeapon
- //
- // Locates the slot and index for the most recently selected weapon. If the
- // player is in the process of switching to a new weapon, that is the most
- // recently selected weapon. Otherwise, the current weapon is the most recent
- // weapon.
- //
- //===========================================================================
- bool, int, int FindMostRecentWeapon()
- {
- let player = self.player;
- let ReadyWeapon = player.ReadyWeapon;
- if (player.PendingWeapon != WP_NOCHANGE)
- {
- // Workaround for the current inability
- bool found;
- int slot;
- int index;
- [found, slot, index] = player.weapons.LocateWeapon(player.PendingWeapon.GetClass());
- return found, slot, index;
- }
- else if (ReadyWeapon != null)
- {
- bool found;
- int slot;
- int index;
- [found, slot, index] = player.weapons.LocateWeapon(ReadyWeapon.GetClass());
- if (!found)
- {
- // If the current weapon wasn't found and is powered up,
- // look for its non-powered up version.
- if (ReadyWeapon.bPOWERED_UP && ReadyWeapon.SisterWeaponType != null)
- {
- [found, slot, index] = player.weapons.LocateWeapon(ReadyWeapon.SisterWeaponType);
- return found, slot, index;
- }
- return false, 0, 0;
- }
- return true, slot, index;
- }
- else
- {
- return false, 0, 0;
- }
- }
- //===========================================================================
- //
- // FWeaponSlots :: PickNextWeapon
- //
- // Returns the "next" weapon for this player. If the current weapon is not
- // in a slot, then it just returns that weapon, since there's nothing to
- // consider it relative to.
- //
- //===========================================================================
- const NUM_WEAPON_SLOTS = 10;
- virtual Weapon PickNextWeapon()
- {
- let player = self.player;
- bool found;
- int startslot, startindex;
- int slotschecked = 0;
- [found, startslot, startindex] = FindMostRecentWeapon();
- let ReadyWeapon = player.ReadyWeapon;
- if (ReadyWeapon == null || found)
- {
- int slot;
- int index;
- if (ReadyWeapon == null)
- {
- startslot = NUM_WEAPON_SLOTS - 1;
- startindex = player.weapons.SlotSize(startslot) - 1;
- }
- slot = startslot;
- index = startindex;
- do
- {
- if (++index >= player.weapons.SlotSize(slot))
- {
- index = 0;
- slotschecked++;
- if (++slot >= NUM_WEAPON_SLOTS)
- {
- slot = 0;
- }
- }
- let type = player.weapons.GetWeapon(slot, index);
- let weap = Weapon(FindInventory(type));
- if (weap != null && weap.CheckAmmo(Weapon.EitherFire, false))
- {
- return weap;
- }
- } while ((slot != startslot || index != startindex) && slotschecked <= NUM_WEAPON_SLOTS);
- }
- return ReadyWeapon;
- }
- //===========================================================================
- //
- // FWeaponSlots :: PickPrevWeapon
- //
- // Returns the "previous" weapon for this player. If the current weapon is
- // not in a slot, then it just returns that weapon, since there's nothing to
- // consider it relative to.
- //
- //===========================================================================
- virtual Weapon PickPrevWeapon()
- {
- let player = self.player;
- int startslot, startindex;
- bool found;
- int slotschecked = 0;
- [found, startslot, startindex] = FindMostRecentWeapon();
- if (player.ReadyWeapon == null || found)
- {
- int slot;
- int index;
- if (player.ReadyWeapon == null)
- {
- startslot = 0;
- startindex = 0;
- }
- slot = startslot;
- index = startindex;
- do
- {
- if (--index < 0)
- {
- slotschecked++;
- if (--slot < 0)
- {
- slot = NUM_WEAPON_SLOTS - 1;
- }
- index = player.weapons.SlotSize(slot) - 1;
- }
- let type = player.weapons.GetWeapon(slot, index);
- let weap = Weapon(FindInventory(type));
- if (weap != null && weap.CheckAmmo(Weapon.EitherFire, false))
- {
- return weap;
- }
- } while ((slot != startslot || index != startindex) && slotschecked <= NUM_WEAPON_SLOTS);
- }
- return player.ReadyWeapon;
- }
- //============================================================================
- //
- // P_BobWeapon
- //
- // [RH] Moved this out of A_WeaponReady so that the weapon can bob every
- // tic and not just when A_WeaponReady is called. Not all weapons execute
- // A_WeaponReady every tic, and it looks bad if they don't bob smoothly.
- //
- // [XA] Added new bob styles and exposed bob properties. Thanks, Ryan Cordell!
- // [SP] Added new user option for bob speed
- //
- //============================================================================
- virtual Vector2 BobWeapon (double ticfrac)
- {
- Vector2 p1, p2, r;
- Vector2 result;
- float bobtarget;
- let player = self.player;
- if (!player) return (0, 0);
- let weapon = player.ReadyWeapon;
- if (weapon == null || weapon.bDontBob)
- {
- return (0, 0);
- }
- // [XA] Get the current weapon's bob properties.
- int bobstyle = weapon.BobStyle;
- double BobSpeed = (weapon.BobSpeed * 128);
- double Rangex = weapon.BobRangeX;
- double Rangey = weapon.BobRangeY;
- for (int i = 0; i < 2; i++)
- {
- // Bob the weapon based on movement speed. ([SP] And user's bob speed setting)
- double angle = (BobSpeed * player.GetWBobSpeed() * 35 / TICRATE*(Level.maptime - 1 + i)) * (360. / 8192.);
- // [RH] Smooth transitions between bobbing and not-bobbing frames.
- // This also fixes the bug where you can "stick" a weapon off-center by
- // shooting it when it's at the peak of its swing.
- bobtarget = double((player.WeaponState & WF_WEAPONBOBBING) ? player.bob : 0.);
- if (curbob != bobtarget)
- {
- if (abs(bobtarget - curbob) <= 1)
- {
- curbob = bobtarget;
- }
- else
- {
- double zoom = MAX(1., abs(curbob - bobtarget) / 40);
- if (curbob > bobtarget)
- {
- curbob -= zoom;
- }
- else
- {
- curbob += zoom;
- }
- }
- }
- if (curbob != 0)
- {
- //[SP] Added in decorate player.viewbob checks
- double bobx = (player.bob * Rangex * ViewBob);
- double boby = (player.bob * Rangey * ViewBob);
- switch (bobstyle)
- {
- case Bob_Normal:
- r.X = bobx * cos(angle);
- r.Y = boby * abs(sin(angle));
- break;
- case Bob_Inverse:
- r.X = bobx*cos(angle);
- r.Y = boby * (1. - abs(sin(angle)));
- break;
- case Bob_Alpha:
- r.X = bobx * sin(angle);
- r.Y = boby * abs(sin(angle));
- break;
- case Bob_InverseAlpha:
- r.X = bobx * sin(angle);
- r.Y = boby * (1. - abs(sin(angle)));
- break;
- case Bob_Smooth:
- r.X = bobx*cos(angle);
- r.Y = 0.5f * (boby * (1. - (cos(angle * 2))));
- break;
- case Bob_InverseSmooth:
- r.X = bobx*cos(angle);
- r.Y = 0.5f * (boby * (1. + (cos(angle * 2))));
- }
- }
- else
- {
- r = (0, 0);
- }
- if (i == 0) p1 = r; else p2 = r;
- }
- return p1 * (1. - ticfrac) + p2 * ticfrac;
- }
- //----------------------------------------------------------------------------
- //
- //
- //
- //----------------------------------------------------------------------------
- virtual clearscope color GetPainFlash() const
- {
- Color painFlash = GetPainFlashForType(DamageTypeReceived);
- if (painFlash == 0) painFlash = DamageFade;
- return painFlash;
- }
- //===========================================================================
- //
- // PlayerPawn :: ResetAirSupply
- //
- // Gives the player a full "tank" of air. If they had previously completely
- // run out of air, also plays the *gasp sound. Returns true if the player
- // was drowning.
- //
- //===========================================================================
- virtual bool ResetAirSupply (bool playgasp = true)
- {
- let player = self.player;
- bool wasdrowning = (player.air_finished < Level.maptime);
- if (playgasp && wasdrowning)
- {
- A_StartSound("*gasp", CHAN_VOICE);
- }
- if (Level.airsupply > 0 && AirCapacity > 0) player.air_finished = Level.maptime + int(Level.airsupply * AirCapacity);
- else player.air_finished = int.max;
- return wasdrowning;
- }
- //----------------------------------------------------------------------------
- //
- //
- //
- //----------------------------------------------------------------------------
- native clearscope static String GetPrintableDisplayName(Class<Actor> cls);
- native void CheckMusicChange();
- native void CheckEnvironment();
- native void CheckUse();
- native void CheckWeaponButtons();
- native void MarkPlayerSounds();
- private native int SetupCrouchSprite(int c);
- private native clearscope Color GetPainFlashForType(Name type);
- }
Add Comment
Please, Sign In to add comment