qzdoom-gpl/wadsrc/static/zscript/inventory/weapons.txt
Christoph Oelckers b3ba5bfe2c - allow 'const' on class functions. This is preferable to 'clearscope' so that the UI code can call getter functions without having to declare things as 'clearscope'.
Clearscope is a dangerous context and should be limited to the minimum extent possible and preferably be blocked in user code.
This may still need some work on const functions but better have it in now.
2017-03-04 12:07:45 +01:00

718 lines
No EOL
18 KiB
Text

class Weapon : StateProvider native
{
enum EFireMode
{
PrimaryFire,
AltFire,
EitherFire
};
const ZOOM_INSTANT = 1;
const ZOOM_NOSCALETURNING = 2;
native uint WeaponFlags;
native class<Ammo> AmmoType1, AmmoType2; // Types of ammo used by self weapon
native int AmmoGive1, AmmoGive2; // Amount of each ammo to get when picking up weapon
native int MinAmmo1, MinAmmo2; // Minimum ammo needed to switch to self weapon
native int AmmoUse1, AmmoUse2; // How much ammo to use with each shot
native int Kickback;
native float YAdjust; // For viewing the weapon fullscreen (visual only so no need to be a double)
native sound UpSound, ReadySound; // Sounds when coming up and idle
native class<Weapon> SisterWeaponType; // Another weapon to pick up with self one
native class<Actor> ProjectileType; // Projectile used by primary attack
native class<Actor> AltProjectileType; // Projectile used by alternate attack
native int SelectionOrder; // Lower-numbered weapons get picked first
native int MinSelAmmo1, MinSelAmmo2; // Ignore in BestWeapon() if inadequate ammo
native double MoveCombatDist; // Used by bots, but do they *really* need it?
native int ReloadCounter; // For A_CheckForReload
native int BobStyle; // [XA] Bobbing style. Defines type of bobbing (e.g. Normal, Alpha) (visual only so no need to be a double)
native float BobSpeed; // [XA] Bobbing speed. Defines how quickly a weapon bobs.
native float BobRangeX, BobRangeY; // [XA] Bobbing range. Defines how far a weapon bobs in either direction.
native Ammo Ammo1, Ammo2; // In-inventory instance variables
native Weapon SisterWeapon;
native float FOVScale;
native int Crosshair; // 0 to use player's crosshair
native bool GivenAsMorphWeapon;
native bool bAltFire; // Set when this weapon's alternate fire is used.
native readonly bool bDehAmmo;
Default
{
Inventory.PickupSound "misc/w_pkup";
Weapon.DefaultKickback;
Weapon.BobSpeed 1.0;
Weapon.BobRangeX 1.0;
Weapon.BobRangeY 1.0;
Weapon.SlotNumber -1;
Weapon.SlotPriority 32767;
+WEAPONSPAWN
DefaultStateUsage SUF_ACTOR|SUF_OVERLAY|SUF_WEAPON;
}
States
{
LightDone:
SHTG E 0 A_Light0;
Stop;
}
native bool CheckAmmo(int fireMode, bool autoSwitch, bool requireAmmo = false, int ammocount = -1);
native bool DepleteAmmo(bool altFire, bool checkEnough = true, int ammouse = -1);
virtual State GetReadyState ()
{
return FindState('Ready');
}
virtual State GetUpState ()
{
return FindState('Select');
}
virtual State GetDownState ()
{
return FindState('Deselect');
}
virtual State GetAtkState (bool hold)
{
State s = null;
if (hold) s = FindState('Hold');
if (s == null) s = FindState('Fire');
return s;
}
virtual State GetAltAtkState (bool hold)
{
State s = null;
if (hold) s = FindState('AltHold');
if (s == null) s = FindState('AltFire');
return s;
}
override String GetObituary(Actor victim, Actor inflictor, Name mod, bool playerattack) const
{
// Weapons may never return HitObituary by default. Override this if it is needed.
return Obituary;
}
action void A_GunFlash(statelabel flashlabel = null, int flags = 0)
{
let player = player;
if (null == player || player.ReadyWeapon == null)
{
return;
}
if (!(flags & GFF_NOEXTCHANGE))
{
player.mo.PlayAttacking2 ();
}
if (flashlabel == null)
{
if (player.ReadyWeapon.bAltFire)
{
flashlabel = 'AltFlash';
}
if (flashlabel == null)
{
flashlabel = 'Flash';
}
}
player.SetPsprite(PSP_FLASH, player.ReadyWeapon.FindState(flashlabel));
}
//---------------------------------------------------------------------------
//
// PROC A_Lower
//
//---------------------------------------------------------------------------
action void A_Lower(int lowerspeed = 6)
{
let player = player;
if (null == player)
{
return;
}
if (null == player.ReadyWeapon)
{
player.BringUpWeapon();
return;
}
let psp = player.GetPSprite(PSP_WEAPON);
if (player.morphTics || player.cheats & CF_INSTANTWEAPSWITCH)
{
psp.y = WEAPONBOTTOM;
}
else
{
psp.y += lowerspeed;
}
if (psp.y < WEAPONBOTTOM)
{ // Not lowered all the way yet
return;
}
if (player.playerstate == PST_DEAD)
{ // Player is dead, so don't bring up a pending weapon
// Player is dead, so keep the weapon off screen
player.SetPsprite(PSP_FLASH, null);
psp.SetState(player.ReadyWeapon.FindState('DeadLowered'));
return;
}
// [RH] Clear the flash state. Only needed for Strife.
player.SetPsprite(PSP_FLASH, null);
player.BringUpWeapon ();
return;
}
//---------------------------------------------------------------------------
//
// PROC A_Raise
//
//---------------------------------------------------------------------------
action void A_Raise(int raisespeed = 6)
{
let player = player;
if (null == player)
{
return;
}
if (player.PendingWeapon != WP_NOCHANGE)
{
player.DropWeapon();
return;
}
if (player.ReadyWeapon == null)
{
return;
}
let psp = player.GetPSprite(PSP_WEAPON);
psp.y -= raisespeed;
if (psp.y > WEAPONTOP)
{ // Not raised all the way yet
return;
}
psp.y = WEAPONTOP;
psp.SetState(player.ReadyWeapon.GetReadyState());
return;
}
//---------------------------------------------------------------------------
//
// PROC A_CheckReload
//
// Present in Doom, but unused. Also present in Strife, and actually used.
//
//---------------------------------------------------------------------------
action void A_CheckReload()
{
let player = self.player;
if (player != NULL)
{
player.ReadyWeapon.CheckAmmo (player.ReadyWeapon.bAltFire ? Weapon.AltFire : Weapon.PrimaryFire, true);
}
}
//===========================================================================
//
// A_ZoomFactor
//
//===========================================================================
action void A_ZoomFactor(double zoom = 1, int flags = 0)
{
let player = self.player;
if (player != NULL && player.ReadyWeapon != NULL)
{
zoom = 1 / clamp(zoom, 0.1, 50.0);
if (flags & 1)
{ // Make the zoom instant.
self.player.FOV = self.player.DesiredFOV * zoom;
}
if (flags & 2)
{ // Disable pitch/yaw scaling.
zoom = -zoom;
}
self.player.ReadyWeapon.FOVScale = zoom;
}
}
//===========================================================================
//
// A_SetCrosshair
//
//===========================================================================
action void A_SetCrosshair(int xhair)
{
let player = self.player;
if (player != NULL && player.ReadyWeapon != NULL)
{
player.ReadyWeapon.Crosshair = xhair;
}
}
//===========================================================================
//
// Weapon :: TryPickup
//
// If you can't see the weapon when it's active, then you can't pick it up.
//
//===========================================================================
override bool TryPickupRestricted (in out Actor toucher)
{
// Wrong class, but try to pick up for ammo
if (ShouldStay())
{ // Can't pick up weapons for other classes in coop netplay
return false;
}
bool gaveSome = (NULL != AddAmmo (toucher, AmmoType1, AmmoGive1));
gaveSome |= (NULL != AddAmmo (toucher, AmmoType2, AmmoGive2));
if (gaveSome)
{
GoAwayAndDie ();
}
return gaveSome;
}
//===========================================================================
//
// Weapon :: TryPickup
//
//===========================================================================
override bool TryPickup (in out Actor toucher)
{
State ReadyState = FindState('Ready');
if (ReadyState != NULL && ReadyState.ValidateSpriteFrame())
{
return Super.TryPickup (toucher);
}
return false;
}
//===========================================================================
//
// Weapon :: Use
//
// Make the player switch to self weapon.
//
//===========================================================================
override bool Use (bool pickup)
{
Weapon useweap = self;
// Powered up weapons cannot be used directly.
if (bPowered_Up) return false;
// If the player is powered-up, use the alternate version of the
// weapon, if one exists.
if (SisterWeapon != NULL &&
SisterWeapon.bPowered_Up &&
Owner.FindInventory ("PowerWeaponLevel2", true))
{
useweap = SisterWeapon;
}
if (Owner.player != NULL && Owner.player.ReadyWeapon != useweap)
{
Owner.player.PendingWeapon = useweap;
}
// Return false so that the weapon is not removed from the inventory.
return false;
}
//===========================================================================
//
// Weapon :: Destroy
//
//===========================================================================
override void OnDestroy()
{
let sister = SisterWeapon;
if (sister != NULL)
{
// avoid recursion
sister.SisterWeapon = NULL;
if (sister != self)
{ // In case we are our own sister, don't crash.
sister.Destroy();
}
}
Super.OnDestroy();
}
//===========================================================================
//
// Weapon :: HandlePickup
//
// Try to leach ammo from the weapon if you have it already.
//
//===========================================================================
override bool HandlePickup (Inventory item)
{
if (item.GetClass() == GetClass())
{
if (Weapon(item).PickupForAmmo (self))
{
item.bPickupGood = true;
}
if (MaxAmount > 1) //[SP] If amount<maxamount do another pickup test of the weapon itself!
{
return Super.HandlePickup (item);
}
return true;
}
return false;
}
//===========================================================================
//
// Weapon :: PickupForAmmo
//
// The player already has self weapon, so try to pick it up for ammo.
//
//===========================================================================
protected bool PickupForAmmo (Weapon ownedWeapon)
{
bool gotstuff = false;
// Don't take ammo if the weapon sticks around.
if (!ShouldStay ())
{
int oldamount1 = 0;
int oldamount2 = 0;
if (ownedWeapon.Ammo1 != NULL) oldamount1 = ownedWeapon.Ammo1.Amount;
if (ownedWeapon.Ammo2 != NULL) oldamount2 = ownedWeapon.Ammo2.Amount;
if (AmmoGive1 > 0) gotstuff = AddExistingAmmo (ownedWeapon.Ammo1, AmmoGive1);
if (AmmoGive2 > 0) gotstuff |= AddExistingAmmo (ownedWeapon.Ammo2, AmmoGive2);
let Owner = ownedWeapon.Owner;
if (gotstuff && Owner != NULL && Owner.player != NULL)
{
if (ownedWeapon.Ammo1 != NULL && oldamount1 == 0)
{
PlayerPawn(Owner).CheckWeaponSwitch(ownedWeapon.Ammo1.GetClass());
}
else if (ownedWeapon.Ammo2 != NULL && oldamount2 == 0)
{
PlayerPawn(Owner).CheckWeaponSwitch(ownedWeapon.Ammo2.GetClass());
}
}
}
return gotstuff;
}
//===========================================================================
//
// Weapon :: CreateCopy
//
//===========================================================================
override Inventory CreateCopy (Actor other)
{
let copy = Weapon(Super.CreateCopy (other));
if (copy != self && copy != null)
{
copy.AmmoGive1 = AmmoGive1;
copy.AmmoGive2 = AmmoGive2;
}
return copy;
}
//===========================================================================
//
// Weapon :: CreateTossable
//
// A weapon that's tossed out should contain no ammo, so you can't cheat
// by dropping it and then picking it back up.
//
//===========================================================================
override Inventory CreateTossable (int amt)
{
// Only drop the weapon that is meant to be placed in a level. That is,
// only drop the weapon that normally gives you ammo.
if (SisterWeapon != NULL &&
Default.AmmoGive1 == 0 && Default.AmmoGive2 == 0 &&
(SisterWeapon.Default.AmmoGive1 > 0 || SisterWeapon.Default.AmmoGive2 > 0))
{
return SisterWeapon.CreateTossable (amt);
}
let copy = Weapon(Super.CreateTossable (-1));
if (copy != NULL)
{
// If self weapon has a sister, remove it from the inventory too.
if (SisterWeapon != NULL)
{
SisterWeapon.SisterWeapon = NULL;
SisterWeapon.Destroy ();
}
// To avoid exploits, the tossed weapon must not have any ammo.
copy.AmmoGive1 = 0;
copy.AmmoGive2 = 0;
}
return copy;
}
//===========================================================================
//
// Weapon :: AttachToOwner
//
//===========================================================================
override void AttachToOwner (Actor other)
{
Super.AttachToOwner (other);
Ammo1 = AddAmmo (Owner, AmmoType1, AmmoGive1);
Ammo2 = AddAmmo (Owner, AmmoType2, AmmoGive2);
SisterWeapon = AddWeapon (SisterWeaponType);
if (Owner.player != NULL)
{
if (!Owner.player.GetNeverSwitch() && !bNo_Auto_Switch)
{
Owner.player.PendingWeapon = self;
}
if (Owner.player.mo == players[consoleplayer].camera)
{
StatusBar.ReceivedWeapon (self);
}
}
GivenAsMorphWeapon = false; // will be set explicitly by morphing code
}
//===========================================================================
//
// Weapon :: AddAmmo
//
// Give some ammo to the owner, even if it's just 0.
//
//===========================================================================
protected Ammo AddAmmo (Actor other, Class<Ammo> ammotype, int amount)
{
Ammo ammoitem;
if (ammotype == NULL)
{
return NULL;
}
// [BC] This behavior is from the original Doom. Give 5/2 times as much ammoitem when
// we pick up a weapon in deathmatch.
if (( deathmatch ) && ( gameinfo.gametype & GAME_DoomChex ))
amount = amount * 5 / 2;
// extra ammoitem in baby mode and nightmare mode
if (!bIgnoreSkill)
{
amount = int(amount * G_SkillPropertyFloat(SKILLP_AmmoFactor));
}
ammoitem = Ammo(other.FindInventory (ammotype));
if (ammoitem == NULL)
{
ammoitem = Ammo(Spawn (ammotype));
ammoitem.Amount = MIN (amount, ammoitem.MaxAmount);
ammoitem.AttachToOwner (other);
}
else if (ammoitem.Amount < ammoitem.MaxAmount)
{
ammoitem.Amount += amount;
if (ammoitem.Amount > ammoitem.MaxAmount)
{
ammoitem.Amount = ammoitem.MaxAmount;
}
}
return ammoitem;
}
//===========================================================================
//
// Weapon :: AddExistingAmmo
//
// Give the owner some more ammo he already has.
//
//===========================================================================
protected bool AddExistingAmmo (Inventory ammo, int amount)
{
if (ammo != NULL && (ammo.Amount < ammo.MaxAmount || sv_unlimited_pickup))
{
// extra ammo in baby mode and nightmare mode
if (!bIgnoreSkill)
{
amount = int(amount * G_SkillPropertyFloat(SKILLP_AmmoFactor));
}
ammo.Amount += amount;
if (ammo.Amount > ammo.MaxAmount && !sv_unlimited_pickup)
{
ammo.Amount = ammo.MaxAmount;
}
return true;
}
return false;
}
//===========================================================================
//
// Weapon :: AddWeapon
//
// Give the owner a weapon if they don't have it already.
//
//===========================================================================
protected Weapon AddWeapon (Class<Weapon> weapontype)
{
Weapon weap;
if (weapontype == NULL)
{
return NULL;
}
weap = Weapon(Owner.FindInventory (weapontype));
if (weap == NULL)
{
weap = Weapon(Spawn (weapontype));
weap.AttachToOwner (Owner);
}
return weap;
}
//===========================================================================
//
// Weapon :: ShouldStay
//
//===========================================================================
override bool ShouldStay ()
{
if (((multiplayer &&
(!deathmatch && !alwaysapplydmflags)) || sv_weaponstay) &&
!bDropped)
{
return true;
}
return false;
}
//===========================================================================
//
// Weapon :: EndPowerUp
//
// The Tome of Power just expired.
//
//===========================================================================
virtual void EndPowerup ()
{
let player = Owner.player;
if (SisterWeapon != NULL && bPowered_Up)
{
if (GetReadyState() != SisterWeapon.GetReadyState())
{
if (player.PendingWeapon == NULL || player.PendingWeapon == WP_NOCHANGE)
player.PendingWeapon = SisterWeapon;
}
else
{
let psp = player.FindPSprite(PSP_WEAPON);
if (psp != null && psp.Caller == player.ReadyWeapon)
{
// If the weapon changes but the state does not, we have to manually change the PSprite's caller here.
psp.Caller = SisterWeapon;
player.ReadyWeapon = SisterWeapon;
}
else
{
// Something went wrong. Initiate a regular weapon change.
player.PendingWeapon = SisterWeapon;
}
}
}
}
}
class WeaponGiver : Weapon
{
double AmmoFactor;
Default
{
Weapon.AmmoGive1 -1;
Weapon.AmmoGive2 -1;
}
override bool TryPickup(in out Actor toucher)
{
DropItem di = GetDropItems();
Weapon weap;
if (di != NULL)
{
Class<Weapon> ti = di.Name;
if (ti != NULL)
{
if (master == NULL)
{
// save the spawned weapon in 'master' to avoid constant respawning if it cannot be picked up.
master = weap = Weapon(Spawn(di.Name));
if (weap != NULL)
{
weap.bAlwaysPickup = false; // use the flag of self item only.
weap.bDropped = bDropped;
// If our ammo gives are non-negative, transfer them to the real weapon.
if (AmmoGive1 >= 0) weap.AmmoGive1 = AmmoGive1;
if (AmmoGive2 >= 0) weap.AmmoGive2 = AmmoGive2;
// If AmmoFactor is non-negative, modify the given ammo amounts.
if (AmmoFactor > 0)
{
weap.AmmoGive1 = int(weap.AmmoGive1 * AmmoFactor);
weap.AmmoGive2 = int(weap.AmmoGive2 * AmmoFactor);
}
weap.BecomeItem();
}
else return false;
}
weap = Weapon(master);
bool res = false;
if (weap != null)
{
res = weap.CallTryPickup(toucher);
if (res)
{
GoAwayAndDie();
master = NULL;
}
}
return res;
}
}
return false;
}
}
struct WeaponSlots native
{
native bool, int, int LocateWeapon(class<Weapon> weap);
}