swwmgz_m/zscript/weapons/swwm_baseweapon.zsc

425 lines
13 KiB
Text

// Base class for all SWWM Weapons
Class SWWMWeapon : Weapon abstract
{
Mixin SWWMOverlapPickupSound;
Mixin SWWMRespawn;
bool wasused;
bool bUsePickup;
private int SWeaponFlags;
Class<Ammo> dropammotype;
Property DropAmmoType : dropammotype;
FlagDef NoFirstGive : SWeaponFlags, 0; // don't give ammo on first pickup (for weapons with a clip count)
FlagDef HideInMenu : SWeaponFlags, 1; // don't show in inventory menu (usually for sister weapons)
FlagDef NoSwapWeapon : SWeaponFlags, 2; // weapon is not affected by slot swapping
bool IsSwapWeapon( Inventory i ) const
{
if ( bNoSwapWeapon || (i.GetClass() == GetClass()) ) return false;
let w = SWWMWeapon(i);
if ( w && !w.bNoSwapWeapon && (SlotNumber != -1) && (w.SlotNumber == SlotNumber) )
return true;
return false;
}
SWWMWeapon HasSwapWeapon( Actor other ) const
{
if ( bNoSwapWeapon ) return null;
for ( Inventory i=other.inv; i; i=i.inv )
{
if ( IsSwapWeapon(i) )
return SWWMWeapon(i);
}
return null;
}
override void Touch( Actor toucher )
{
// cannot pick up swapweapon unless explicitly pressing use
SWWMWeapon sw;
if ( swwm_swapweapons && (sw = HasSwapWeapon(toucher)) )
{
if ( toucher.CheckLocalView() )
{
// use sisterweapon tag for dual wield (slot 2 weapons)
if ( sw.SisterWeapon && (sw.Amount > 1) )
Console.MidPrint(SmallFont,String.Format(StringTable.Localize("$SWWM_SWAPWEAPON"),sw.SisterWeapon.GetTag(),GetTag()));
else Console.MidPrint(SmallFont,String.Format(StringTable.Localize("$SWWM_SWAPWEAPON"),sw.GetTag(),GetTag()));
}
return;
}
if ( toucher.player && swwm_usetopickup && !bUsePickup )
return;
Super.Touch(toucher);
}
// allow pickup by use + swap weapon support
override bool Used( Actor user )
{
// no use through melee
if ( (user.player.ReadyWeapon is 'SWWMWeapon') && SWWMWeapon(user.player.ReadyWeapon).wallponch && !swwm_meleepickup )
return false;
Vector3 itempos = Vec3Offset(0,0,Height/2),
userpos = user.Vec2OffsetZ(0,0,user.player.viewz);
// test vertical range
Vector3 diff = level.Vec3Diff(user.Vec3Offset(0,0,user.Height/2),Vec3Offset(0,0,Height/2));
double rang = user.player?PlayerPawn(user.player.mo).UseRange:(user.Height/2);
if ( abs(diff.z) > rang ) return false;
// if the toucher owns our SwapWeapon, drop it before picking us up
bool swapto = false;
SWWMWeapon sw;
if ( swwm_swapweapons && (sw = HasSwapWeapon(user)) )
{
if ( (sw == user.player.ReadyWeapon) || (sw.SisterWeapon && (sw.SisterWeapon == user.player.ReadyWeapon)) )
swapto = true;
int ngun = sw.Amount;
double ang = -15*(ngun-1);
for ( int i=0; i<ngun; i++ )
{
let d = user.DropInventory(sw);
if ( !d || (ngun <= 1) ) continue;
// adjust angle for multi-drops
d.angle = user.angle+ang;
d.vel.xy = RotateVector((5,0),d.angle);
d.vel.z = 1;
d.vel += user.vel;
ang += 30;
}
// don't autoswitch just yet (hacky)
if ( swapto )
{
user.player.ReadyWeapon = null;
user.player.PendingWeapon = WP_NOCHANGE;
}
}
bUsePickup = true;
Touch(user);
bUsePickup = false;
// we got picked up
if ( bDestroyed || Owner || !bSPECIAL )
{
// autoswitch to us if we got swapped
if ( swapto ) user.A_SelectWeapon(GetClass());
Vector3 tracedir = level.Vec3Diff(userpos,itempos);
double dist = tracedir.length();
tracedir /= dist;
let cf = new("CrossLineFinder");
cf.Trace(userpos,level.PointInSector(userpos.xy),tracedir,dist,0);
// trigger all player cross lines found between user and item
for ( int i=0; i<cf.clines.Size(); i++ )
cf.clines[i].Activate(user,cf.csides[i],SPAC_Cross);
return true;
}
return false;
}
override int, int CheckAddToSlots()
{
if ( (GetReplacement(GetClass()) == GetClass()) && !bPowered_Up )
{
if ( swwm_singlefirst && SisterWeaponType )
{
let sw = GetDefaultByType(SisterWeaponType);
return sw.SlotNumber, int(sw.SlotPriority*65536);
}
return SlotNumber, int(SlotPriority*65536);
}
return -1, 0;
}
action void A_BumpFOV( double factor )
{
if ( !(self is 'Demolitionist') ) return;
Demolitionist(self).lastbump *= factor;
}
// subtracts given ammo from price, drops excess
virtual bool PickupForAmmoSWWM( SWWMWeapon ownedWeapon )
{
// save time, always return false if we don't use ammo
if ( !ownedWeapon.Ammo1 && !ownedWeapon.Ammo2 ) return false;
bool gotstuff = false;
int oldamount1 = 0, oldamount2 = 0;
if ( ownedWeapon.Ammo1 ) oldamount1 = ownedWeapon.Ammo1.Amount;
if ( ownedWeapon.Ammo2 ) 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 && Owner.player )
{
if ( ownedWeapon.Ammo1 && (oldamount1 == 0) )
PlayerPawn(Owner).CheckWeaponSwitch(ownedWeapon.Ammo1.GetClass());
else if ( ownedWeapon.Ammo2 && (oldamount2 == 0) )
PlayerPawn(Owner).CheckWeaponSwitch(ownedWeapon.Ammo2.GetClass());
}
if ( ownedWeapon.Ammo1 )
{
// subtract price of ammo we don't give
int ammonotgiven = default.AmmoGive1-AmmoGive1;
if ( ammonotgiven > 0 ) Stamina -= int(ownedWeapon.Ammo1.Stamina*(1.+.75*(ammonotgiven-1)));
// subtract price of given ammo
int ammogiven = ownedWeapon.Ammo1.Amount-oldamount1;
if ( ammogiven > 0 ) Stamina -= int(ownedWeapon.Ammo1.Stamina*(1.+.75*(ammogiven-1)));
// drop excess
int dropme = AmmoGive1-ammogiven;
if ( dropme > 0 )
{
// hacky, but it works
ownedWeapon.Ammo1.CreateTossable(dropme);
ownedWeapon.Ammo1.Amount += dropme;
}
}
if ( ownedWeapon.Ammo2 )
{
// subtract price of ammo we don't give
int ammonotgiven = default.AmmoGive2-AmmoGive2;
if ( ammonotgiven > 0 ) Stamina -= int(ownedWeapon.Ammo2.Stamina*(1.+.75*(ammonotgiven-1)));
// subtract price of given ammo
int ammogiven = ownedWeapon.Ammo2.Amount-oldamount2;
if ( ammogiven > 0 ) Stamina -= int(ownedWeapon.Ammo2.Stamina*(1.+.75*(ammogiven-1)));
// drop excess
int dropme = AmmoGive2-ammogiven;
if ( dropme > 0 )
{
// hacky, but it works
ownedWeapon.Ammo2.CreateTossable(dropme);
ownedWeapon.Ammo2.Amount += dropme;
}
}
return gotstuff;
}
override bool HandlePickup( Inventory item )
{
// can't hold both weapons at once
if ( swwm_swapweapons && IsSwapWeapon(item) )
return true;
if ( (GetClass() == item.GetClass()) && !item.ShouldStay() )
{
if ( SWWMWeapon(item).PickupForAmmoSWWM(self) )
item.bPickupGood = true;
if ( !deathmatch && (Amount+item.Amount > MaxAmount) && (item.Stamina > 0) )
{
// sell excess
int sellprice = item.Stamina/2;
SWWMScoreObj.Spawn(sellprice,Owner.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+Owner.Height/2));
SWWMCredits.Give(Owner.player,sellprice);
if ( Owner.player )
Console.Printf(StringTable.Localize(SWWMUtility.SellFemaleItem(item)?"$SWWM_SELLEXTRA_FEM":"$SWWM_SELLEXTRA"),Owner.player.GetUserName(),GetTag(),sellprice);
item.bPickupGood = true;
}
// reset the price in case it has to respawn
item.Stamina = item.default.Stamina;
return true;
}
return Super.HandlePickup(item);
}
override bool ShouldStay()
{
// SWWM weapons never stay unless explicitly stated
if ( !bDROPPED && (deathmatch || alwaysapplydmflags) && sv_weaponstay ) return true;
return false;
}
override void AttachToOwner( Actor other )
{
Inventory.AttachToOwner(other);
Ammo1 = AddAmmo(Owner,AmmoType1,bNoFirstGive?0:AmmoGive1);
Ammo2 = AddAmmo(Owner,AmmoType2,bNoFirstGive?0:AmmoGive2);
SisterWeapon = AddWeapon(SisterWeaponType);
if ( Owner.player )
{
if ( !Owner.player.GetNeverSwitch() && !bNo_Auto_Switch )
Owner.player.PendingWeapon = self;
if ( Owner.player.mo == players[consoleplayer].camera )
StatusBar.ReceivedWeapon(self);
}
GivenAsMorphWeapon = false;
}
override void DetachFromOwner()
{
Owner.A_StopSound(CHAN_WEAPON);
Owner.A_StopSound(CHAN_WEAPONEXTRA);
Owner.A_StopSound(CHAN_WEAPONEXTRA2);
Owner.A_StopSound(CHAN_WEAPONEXTRA3);
Super.DetachFromOwner();
}
override void OwnerDied()
{
if ( Owner.player && (Owner.player.ReadyWeapon == self) )
{
Owner.A_StopSound(CHAN_WEAPON);
Owner.A_StopSound(CHAN_WEAPONEXTRA);
Owner.A_StopSound(CHAN_WEAPONEXTRA2);
Owner.A_StopSound(CHAN_WEAPONEXTRA3);
}
A_ClearRefire();
Super.OwnerDied();
}
override String GetObituary( Actor victim, Actor inflictor, Name mod, bool playerattack )
{
if ( mod == 'Melee' ) return StringTable.Localize("$O_MELEE");
return Super.GetObituary(victim,inflictor,mod,playerattack);
}
// draw ammo on hud above weapon box
virtual ui void DrawWeapon( double TicFrac, double bx, double by, Vector2 hs, Vector2 ss )
{
}
// animations
action void A_PlayerFire()
{
let demo = Demolitionist(player.mo);
if ( demo && (demo.Health > 0) ) demo.PlayFire();
}
action void A_PlayerMelee( bool bFast = false )
{
let demo = Demolitionist(player.mo);
if ( demo && (demo.Health > 0) )
{
if ( bFast ) demo.PlayFastMelee();
else demo.PlayMelee();
}
}
action void A_PlayerReload()
{
let demo = Demolitionist(player.mo);
if ( demo && (demo.Health > 0) ) demo.PlayReload();
}
action void A_PlayerCheckGun()
{
let demo = Demolitionist(player.mo);
if ( demo && (demo.Health > 0) ) demo.PlayCheckGun();
}
// instant raise/lower
action void A_FullRaise()
{
if ( !player ) return;
if ( player.PendingWeapon != WP_NOCHANGE )
{
player.mo.DropWeapon();
return;
}
if ( !player.ReadyWeapon ) return;
let psp = player.GetPSprite(PSP_WEAPON);
if ( !psp ) return;
ResetPSprite(psp);
psp.y = WEAPONTOP;
// do not jump to ready state here, the weapon should do that
// directly once it finishes playing its select animation
}
action void A_FullLower()
{
if ( !player ) return;
if ( !player.ReadyWeapon )
{
player.mo.BringUpWeapon();
return;
}
let psp = player.GetPSprite(PSP_WEAPON);
if ( !psp ) return;
psp.y = WEAPONBOTTOM;
ResetPSprite(psp);
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.mo.BringUpWeapon();
}
override void PlayUpSound( Actor origin )
{
if ( UpSound ) origin.A_StartSound(UpSound,CHAN_WEAPON,CHANF_OVERLAP);
}
action void A_SWWMFlash( StateLabel flashlabel = null )
{
if ( !player || !player.ReadyWeapon )
return;
Weapon weap = player.ReadyWeapon;
State flashstate = null;
if ( !flashlabel )
{
if ( weap.bAltFire )
flashstate = weap.FindState('AltFlash');
if ( !flashstate )
flashstate = weap.FindState('Flash');
}
else flashstate = weap.FindState(flashlabel);
player.SetPSprite(PSP_FLASH,flashstate);
A_OverlayFlags(PSP_FLASH,PSPF_RENDERSTYLE|PSPF_FORCESTYLE,true);
A_OverlayRenderStyle(PSP_FLASH,STYLE_Add);
}
// tells the SWWM HUD that this weapon has ammo available
virtual clearscope bool ReportHUDAmmo()
{
return (!Ammo1||(Ammo1.Amount>0)||(Ammo2&&(Ammo2.Amount>0)));
}
// tells the Embiggener that this weapon uses the specified ammo type
// even if it is not its primary one
virtual clearscope bool UsesAmmo( Class<Ammo> kind )
{
return (AmmoType1&&(kind is AmmoType1))||(AmmoType2&&(kind is AmmoType2));
}
override void ModifyDropAmount( int dropamount )
{
Super.ModifyDropAmount(dropamount);
if ( (AmmoGive1 <= 0) && (default.AmmoGive1 > 0) )
AmmoGive1 = 1;
if ( (AmmoGive2 <= 0) && (default.AmmoGive2 > 0) )
AmmoGive2 = 1;
}
override bool SpecialDropAction( Actor dropper )
{
if ( swwm_enemydrops > 0 ) return false;
else if ( swwm_enemydrops == 0 )
{
// first, check if no others exist in the map, just in
// case this weapon drop MAY be needed
if ( !SWWMUtility.ItemExists(GetClass(),self) )
return false; // drop us
// drop our corresponding ammo
if ( !DropAmmoType ) return true;
let a = Inventory(Spawn(DropAmmoType,pos,ALLOW_REPLACE));
if ( !a ) return true;
a.bDROPPED = true;
a.bNOGRAVITY = false;
if ( !(level.compatflags&COMPATF_NOTOSSDROPS) )
a.TossItem();
if ( a is 'Ammo' )
a.ModifyDropAmount(Ammo(a).DropAmount);
a.bTOSSED = true;
if ( a.SpecialDropAction(dropper) )
a.Destroy();
return true;
}
// no weapon drops from enemies
return true;
}
override Inventory CreateTossable( int amt )
{
// disallow dropping if weapon isn't ready for switching
if ( (Owner.player.ReadyWeapon == self) && (!(Owner.player.WeaponState&WF_WEAPONSWITCHOK) || (Owner.player.WeaponState&WF_DISABLESWITCH)) )
return null;
return Super.CreateTossable(amt);
}
Default
{
Weapon.BobStyle "Alpha";
Weapon.BobSpeed 3.0;
Weapon.BobRangeX 0.5;
Weapon.BobRangeY 0.2;
Weapon.YAdjust 0;
Weapon.SlotPriority 1.;
Inventory.RestrictedTo "Demolitionist";
Inventory.PickupFlash "SWWMRedPickupFlash";
+INVENTORY.IGNORESKILL;
+WEAPON.NOALERT;
+WEAPON.NODEATHINPUT;
+FLOATBOB;
FloatBobStrength 0.25;
}
}