stinger_m/zscript/automag.zsc
Marisa Kirisame 225ffcc1e9 Overhaul to how reloading works, not much else has happened.
Addition to HUD for showing clip counts (kinda cheap-looking, but still better than what Oldskool did).
Charge for some weapons and loaded rockets for eightball also use the clipcount display, like in Doom Tournament.
Small fixups for dual wielding logic.
2019-09-17 02:47:13 +02:00

624 lines
17 KiB
Text

Class UClip : UMiniAmmo
{
Default
{
Tag "$T_CLIP";
Inventory.PickupMessage "$I_CLIP";
Inventory.Amount 20;
Ammo.DropAmount 5;
}
States
{
Spawn:
UCLP A -1;
Stop;
}
}
Class UCasing : UTCasing
{
}
Class Automag : UnrealWeapon
{
int ClipCount, SlaveClipCount;
bool SlaveActive, SlaveDown, SlaveReload, SlaveAltFire, SlaveSpin;
int SlaveRefire;
double AltAccuracy;
property ClipCount : ClipCount;
property SlaveClipCount : SlaveClipCount;
override int, int, bool, bool GetClipAmount()
{
if ( Amount > 1 ) return ClipCount, SlaveClipCount, (ClipCount<5), (SlaveClipCount<5);
return ClipCount, -1, (ClipCount<5), false;
}
override bool HandlePickup( Inventory item )
{
if ( sting_automags && (item.GetClass() == GetClass()) )
{
SetTag(StringTable.Localize("$T_AUTOMAG2"));
return Super.HandlePickup(item);
}
return Super.HandlePickup(item);
}
override String PickupMessage()
{
if ( Owner ) return Super.PickupMessage();
return StringTable.Localize("$I_AUTOMAG2");
}
override Inventory CreateTossable( int amt )
{
Inventory inv = Super.CreateTossable(amt);
if ( inv )
{
SetTag(StringTable.Localize("$T_AUTOMAG"));
inv.SetTag(StringTable.Localize("$T_AUTOMAG"));
if ( Owner && (Owner.player.ReadyWeapon == self) )
{
// delete the slave overlay
PSprite psp;
for ( psp = Owner.player.psprites; psp; psp = psp.next )
{
if ( (psp.Caller == self) && ((psp.id == 2) || (psp.id == -9998)) ) psp.Destroy();
slaveactive = false;
slavedown = false;
}
}
}
return inv;
}
action void A_AutomagRefire( statelabel flash = null, bool slave = false )
{
Weapon weap = Weapon(invoker);
if ( !weap || !player ) return;
if ( invoker.altaccuracy < 0.2 ) invoker.altaccuracy += 0.05;
if ( slave )
{
if ( invoker.slaveclipcount < 5 ) A_PlaySound("automag/click",CHAN_ITEM,!Dampener.Active(self)?1.:.35);
if ( invoker.slaveclipcount <= 0 )
{
invoker.slaverefire = 0;
return;
}
bool pending = (player.PendingWeapon != WP_NOCHANGE) && (player.WeaponState & WF_REFIRESWITCHOK);
if ( (player.cmd.buttons&BT_ATTACK) && !invoker.slavealtfire && !pending && (player.health > 0) )
{
invoker.slaverefire++;
if ( invoker.slaveclipcount > 0 )
player.setpsprite(2,flash?ResolveState(flash):ResolveState("LeftHold"));
}
else if ( (player.cmd.buttons&BT_ALTATTACK) && invoker.slavealtfire && !pending && (player.health > 0) )
{
invoker.slaverefire++;
if ( invoker.slaveclipcount > 0 )
player.setpsprite(2,flash?ResolveState(flash):ResolveState("LeftAltHold"));
}
else invoker.slaverefire = 0;
}
else
{
if ( invoker.clipcount < 5 ) A_PlaySound("automag/click",CHAN_ITEM,!Dampener.Active(self)?1.:.35);
if ( invoker.clipcount <= 0 )
{
A_ClearRefire();
return;
}
A_Refire(flash);
}
}
action void A_LeftWeaponReady()
{
Weapon weap = Weapon(invoker);
if ( !weap || !player ) return;
if ( player.cmd.buttons&BT_ATTACK && !player.ReadyWeapon.bAltFire )
{
if ( invoker.slaveclipcount <= 0 )
{
let psp = player.FindPSprite(PSP_WEAPON);
if ( (weap.Ammo1.Amount > 0) && !psp.CurState.InStateSequence(ResolveState("Reload")) )
player.setpsprite(2,ResolveState("LeftReload"));
return;
}
invoker.slaverefire = 0;
invoker.slavealtfire = false;
player.setpsprite(2,ResolveState("LeftFire"));
}
else if ( player.cmd.buttons&BT_ALTATTACK && player.ReadyWeapon.bAltFire )
{
if ( invoker.slaveclipcount <= 0 )
{
let psp = player.FindPSprite(PSP_WEAPON);
if ( (weap.Ammo1.Amount > 0) && !psp.CurState.InStateSequence(ResolveState("Reload")) )
player.setpsprite(2,ResolveState("LeftReload"));
return;
}
invoker.slaverefire = 0;
invoker.slavealtfire = true;
player.setpsprite(2,ResolveState("LeftAltFire"));
}
}
action void A_AutomagFire( bool alt = false, bool slave = false )
{
Weapon weap = Weapon(invoker);
if ( !weap ) return;
if ( slave )
{
if ( invoker.slaveclipcount <= 0 ) return;
invoker.slaveclipcount--;
}
else
{
if ( invoker.clipcount <= 0 ) return;
invoker.clipcount--;
}
invoker.FireEffect();
UTMainHandler.DoFlash(self,Color(32,255,128,0),1);
A_PlaySound("automag/fire",slave?CHAN_6:CHAN_WEAPON,!Dampener.Active(self)?1.:.2);
if ( !Dampener.Active(self) ) A_AlertMonsters();
A_QuakeEx(2,2,2,4,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.08);
if ( slave )
{
if ( alt ) A_Overlay(-3,"LeftAltMuzzleFlash");
else A_Overlay(-3,"LeftMuzzleFlash");
A_OverlayFlags(-3,PSPF_RENDERSTYLE|PSPF_FORCESTYLE,true);
A_OverlayRenderstyle(-3,STYLE_Add);
UTMainHandler.DoSwing(self,(FRandom[Automag](0.5,0.2),FRandom[Automag](-0.3,0.2)),2,0,1,SWING_Spring,0,2);
}
else
{
if ( alt ) A_Overlay(-2,"AltMuzzleFlash");
else A_Overlay(-2,"MuzzleFlash");
A_OverlayFlags(-2,PSPF_RENDERSTYLE|PSPF_FORCESTYLE,true);
A_OverlayRenderstyle(-2,STYLE_Add);
UTMainHandler.DoSwing(self,(FRandom[Automag](-0.2,-0.5),FRandom[Automag](-0.3,0.2)),2,0,1,SWING_Spring,0,2);
}
Vector3 x, y, z, x2, y2, z2;
[x, y, z] = dt_CoordUtil.GetAxes(pitch,angle,roll);
Vector3 origin = Vec2OffsetZ(0,0,player.viewz)+10.0*x;
int ydir = slave?-1:1;
if ( alt ) origin = origin-z*3.0+ydir*y*1.0;
else origin = origin-z*1.0+ydir*y*4.0;
double a = FRandom[Automag](0,360), s = FRandom[Automag](0,alt?invoker.altaccuracy:0.01);
[x2, y2, z2] = dt_CoordUtil.GetAxes(BulletSlope(),angle,roll);
Vector3 dir = (x2+y2*cos(a)*s+z2*sin(a)*s).unit();
FLineTraceData d;
LineTrace(atan2(dir.y,dir.x),10000,asin(-dir.z),TRF_ABSPOSITION,origin.z,origin.x,origin.y,d);
if ( d.HitType == TRACE_HitActor )
{
int dmg = 17;
dmg = d.HitActor.DamageMobj(invoker,self,dmg,'shot',DMG_USEANGLE|DMG_THRUSTLESS,atan2(d.HitDir.y,d.HitDir.x));
double mm = 3000;
if ( FRandom[Automag](0,1) < 0.2 ) mm *= 5;
UTMainHandler.DoKnockback(d.HitActor,d.HitDir,mm);
if ( d.HitActor.bNOBLOOD )
{
let p = Spawn("BulletImpact",d.HitLocation);
p.angle = atan2(d.HitDir.y,d.HitDir.x)+180;
p.pitch = asin(d.HitDir.z);
}
else
{
d.HitActor.TraceBleed(dmg,self);
d.HitActor.SpawnBlood(d.HitLocation,atan2(d.HitDir.y,d.HitDir.x)+180,dmg);
}
}
else if ( d.HitType != TRACE_HitNone )
{
Vector3 hitnormal = -d.HitDir;
if ( d.HitType == TRACE_HitFloor )
{
if ( d.Hit3DFloor ) hitnormal = -d.Hit3DFloor.top.Normal;
else hitnormal = d.HitSector.floorplane.Normal;
}
else if ( d.HitType == TRACE_HitCeiling )
{
if ( d.Hit3DFloor ) hitnormal = -d.Hit3DFloor.bottom.Normal;
else hitnormal = d.HitSector.ceilingplane.Normal;
}
else if ( d.HitType == TRACE_HitWall )
{
hitnormal = (-d.HitLine.delta.y,d.HitLine.delta.x,0).unit();
if ( !d.LineSide ) hitnormal *= -1;
}
let p = Spawn("BulletImpact",d.HitLocation+hitnormal*0.01);
p.angle = atan2(hitnormal.y,hitnormal.x);
p.pitch = asin(-hitnormal.z);
if ( d.HitLine ) d.HitLine.RemoteActivate(self,d.LineSide,SPAC_Impact,d.HitLocation);
}
for ( int i=0; i<3; i++ )
{
let s = Spawn("UTViewSmoke",origin);
if ( alt ) UTViewSmoke(s).ofs = (10,ydir,-3);
else UTViewSmoke(s).ofs = (10,4*ydir,-1);
s.target = self;
s.alpha *= 0.5;
}
origin += x*8.0+ydir*y*6.0-z*2.0;
let c = Spawn("UCasing",origin);
c.vel = x*FRandom[Junk](-1.5,1.5)+y*ydir*FRandom[Junk](2,4)+z*FRandom[Junk](2,3);
}
override String GetObituary( Actor victim, Actor inflictor, Name mod, bool playerattack )
{
if ( Amount > 1 ) return StringTable.Localize("$O_AUTOMAG2");
return StringTable.Localize("$O_AUTOMAG");
}
override void Travelled()
{
Super.Travelled();
slaveactive = false;
}
override void OwnerDied()
{
Super.OwnerDied();
slaverefire = 0;
}
override void Tick()
{
Super.Tick();
if ( sting_automags && (MaxAmount <= 1) ) MaxAmount = 2;
else if ( !sting_automags && (MaxAmount > 1) ) MaxAmount = 1;
if ( !Owner || sting_automags || (Amount <= 1) ) return;
// no dual wielding
if ( Owner.player.ReadyWeapon == self )
{
// delete the slave overlay
PSprite psp;
for ( psp = Owner.player.psprites; psp; psp = psp.next )
{
if ( (psp.Caller == self) && ((psp.id == 2) || (psp.id == -9998)) ) psp.Destroy();
slaveactive = false;
slavedown = false;
}
}
Amount = 1;
}
override bool CheckAmmo( int fireMode, bool autoSwitch, bool requireAmmo, int ammocount )
{
if ( (ClipCount > 0) || ((Amount>1) && (SlaveClipCount > 0)) ) return true;
return Super.CheckAmmo(firemode,autoswitch,requireammo,ammocount);
}
Default
{
Tag "$T_AUTOMAG";
Inventory.Icon "I_ClipAm";
Inventory.PickupMessage "$I_AUTOMAG";
Inventory.MaxAmount 1;
Inventory.InterHubAmount 2;
Weapon.UpSound "automag/select";
Weapon.SlotNumber 2;
Weapon.SelectionOrder 2;
Weapon.SlotPriority 1;
Weapon.AmmoType "UMiniAmmo";
Weapon.AmmoUse 1;
Weapon.AmmoType2 "UMiniAmmo";
Weapon.AmmoUse2 1;
Weapon.AmmoGive 30;
Weapon.Kickback 180;
UTWeapon.DropAmmo 10;
Automag.ClipCount 20;
Automag.SlaveClipCount 20;
}
States
{
Spawn:
AUTP A -1;
Stop;
AUTP B -1;
Stop;
Select:
AUTS A 1 A_Raise(int.max);
Ready:
AUTS A 0
{
invoker.slavedown = false;
if ( !invoker.slaveactive && (CountInv("Automag") > 1) )
A_Overlay(2,"LeftReady");
}
AUTS ABCDEFGHIJKLMNOPQRSTUVWXYZ 1 A_WeaponReady(WRF_NOFIRE);
AUS2 ABCD 1 A_WeaponReady(WRF_NOFIRE);
Idle:
AUTI A 0 A_Overlay(-9999,"Dummy");
AUTI AB 30;
AUTI A 0 A_Jump(50,"Twiddle");
Goto Idle+1;
LeftReady:
2UTS A 0
{
A_PlaySound("automag/select",CHAN_6,!Dampener.Active(self)?1.:.1);
invoker.slaveactive = true;
}
2UTS ABCDEFGHIJKLMNOPQRSTUVWXYZ 1 A_JumpIf(invoker.slavedown,"LeftDeselect");
2US2 ABCD 1 A_JumpIf(invoker.slavedown,"LeftDeselect");
LeftIdle:
2UTI A 0 A_Overlay(-9998,"LeftDummy");
2UTI AB 30;
2UTI A 0 A_Jump(50,"LeftTwiddle");
Goto LeftIdle+1;
Twiddle:
AUTT ABCDEFGHIJKLMNOPQRSTUVWXY 2;
Goto Idle+1;
LeftTwiddle:
2UTT ABCDEFGHIJKLMNOPQRSTUVWXY 2;
Goto LeftIdle+1;
Dummy:
TNT1 A 1
{
A_CheckReload();
if ( (invoker.clipcount <= 0) && (invoker.Ammo1.Amount > 0) ) player.SetPSprite(PSP_WEAPON,ResolveState("Reload"));
else if ( ((invoker.clipcount < min(invoker.default.clipcount,invoker.Ammo1.Amount)) || (invoker.slaveclipcount < min(invoker.default.slaveclipcount,invoker.Ammo1.Amount))) ) A_WeaponReady(WRF_ALLOWRELOAD|WRF_ALLOWZOOM);
else A_WeaponReady(WRF_ALLOWZOOM);
if ( !invoker.slaveactive && (CountInv("Automag") > 1) ) A_Overlay(2,"LeftReady");
}
Wait;
LeftDummy:
TNT1 A 1
{
if ( health <= 0 )
{
invoker.slaveactive = false;
player.SetPSprite(2,ResolveState("LeftDeselect"));
}
else if ( invoker.slavereload ) player.SetPSprite(2,ResolveState("LeftReload"));
else if ( invoker.slavedown ) player.SetPSprite(2,ResolveState("LeftDeselect"));
else if ( invoker.slavespin ) player.SetPSprite(2,ResolveState("LeftZoom"));
else A_LeftWeaponReady();
}
Wait;
Fire:
AUTF A 1 A_Overlay(-9999,null);
AUTF BCD 1;
Hold:
AUTF E 2 A_AutomagFire();
AUTF FG 2;
AUTF N 0 A_AutomagRefire(1);
Goto Release;
AUTF NN 2;
AUTF H 2 A_AutomagFire();
AUTF IJ 2;
AUTF N 0 A_AutomagRefire(1);
Goto Release;
AUTF NN 2;
AUTF K 2 A_AutomagFire();
AUTF LM 2;
AUTF N 0 A_AutomagRefire(1);
Goto Release;
AUTF NN 2;
Goto Hold;
Release:
AUTF NN 2;
AUTF OPQRST 1;
AUTI A 0;
Goto Idle;
LeftFire:
2UTI A 5 A_Overlay(-9998,null);
2UTI A 0 A_AutomagRefire(1,true);
Goto LeftIdle;
LeftHold:
2UTF ABCD 1;
2UTF E 2 A_AutomagFire(false,true);
2UTF FG 2;
2UTF N 0 A_AutomagRefire(1,true);
Goto LeftRelease;
2UTF NN 2;
2UTF H 2 A_AutomagFire(false,true);
2UTF IJ 2;
2UTF N 0 A_AutomagRefire(1,true);
Goto LeftRelease;
2UTF NN 2;
2UTF K 2 A_AutomagFire(false,true);
2UTF LM 2;
2UTF N 0 A_AutomagRefire(1,true);
Goto LeftRelease;
2UTF NN 2;
Goto LeftHold+4;
LeftRelease:
2UTF NN 2;
2UTF OPQRST 1;
2UTI A 0;
Goto LeftIdle;
AltFire:
AUTA A 0
{
invoker.altaccuracy = 0.08;
A_Overlay(-9999,null);
}
AUTA ABCDEFGHIJ 1;
AltHold:
AUTA K 2 A_AutomagFire(true);
AUTA LM 2;
AUTA T 0 A_AutomagRefire(1);
Goto AltRelease;
AUTA T 1;
AUTA N 2 A_AutomagFire(true);
AUTA OP 2;
AUTA T 0 A_AutomagRefire(1);
Goto AltRelease;
AUTA T 1;
AUTA Q 2 A_AutomagFire(true);
AUTA RS 2;
AUTA T 0 A_AutomagRefire(1);
Goto AltRelease;
AUTA T 1;
Goto AltHold;
AltRelease:
AUTA TUVWXYZ 1;
AUA2 ABCD 1;
Goto Idle;
LeftAltFire:
2UTI A 5 A_Overlay(-9998,null);
2UTI A 0 A_AutomagRefire(1,true);
LeftAltHold:
2UTA ABCDEFGHIJ 1;
2UTA K 2 A_AutomagFire(true,true);
2UTA LM 2;
2UTA T 0 A_AutomagRefire(1,true);
Goto LeftAltRelease;
2UTA T 1;
2UTA N 2 A_AutomagFire(true,true);
2UTA OP 2;
2UTA T 0 A_AutomagRefire(1,true);
Goto LeftAltRelease;
2UTA T 1;
2UTA Q 2 A_AutomagFire(true,true);
2UTA RS 2;
2UTA T 0 A_AutomagRefire(1,true);
Goto LeftAltRelease;
2UTA T 1;
Goto LeftAltHold+10;
LeftAltRelease:
2UTA TUVWXYZ 1;
2UA2 ABCD 1;
Goto LeftIdle;
Reload:
AUTR A 0
{
if ( invoker.clipcount>=min(invoker.default.clipcount,invoker.Ammo1.Amount) )
{
invoker.slavereload = (invoker.slaveactive&&(invoker.slaveclipcount < min(invoker.default.slaveclipcount,invoker.Ammo1.Amount)))||(invoker.slaveclipcount <= 0);
return ResolveState("Idle");
}
return ResolveState(null);
}
AUTR A 0
{
invoker.special1 = min(invoker.default.clipcount,invoker.Ammo1.Amount)-invoker.clipcount;
invoker.clipcount = -1;
A_Overlay(-9999,null);
A_PlaySound("automag/click",CHAN_WEAPON,!Dampener.Active(self)?1.:.1);
}
AUTR ABCDEFGHIJKLMNOPQRSTUVWXY 1;
AUTD ABCD 1;
AUTD E 30
{
invoker.clipcount = Min(invoker.default.clipcount,invoker.Ammo1.Amount);
invoker.Ammo1.Amount -= invoker.special1;
A_PlaySound("automag/reload",CHAN_WEAPON,!Dampener.Active(self)?1.:.1);
if ( self is 'UTPlayer' )
UTPlayer(self).PlayReloading();
invoker.slavereload = (invoker.slaveactive&&(invoker.slaveclipcount < min(invoker.default.slaveclipcount,invoker.Ammo1.Amount)))||(invoker.slaveclipcount <= 0);
}
AUTS A 0 A_PlaySound("automag/select",CHAN_WEAPON,!Dampener.Active(self)?1.:.1);
Goto Ready;
LeftReload:
2UTR A 0
{
if ( invoker.slaveclipcount>=min(invoker.default.slaveclipcount,invoker.Ammo1.Amount) )
{
invoker.slavereload = 0;
return ResolveState("LeftIdle");
}
invoker.special2 = min(invoker.default.slaveclipcount,invoker.Ammo1.Amount)-invoker.slaveclipcount;
invoker.slaveclipcount = -1;
A_Overlay(-9998,null);
A_PlaySound("automag/click",CHAN_6,!Dampener.Active(self)?1.:.1);
return ResolveState(null);
}
2UTR ABCDEFGHIJKLMNOPQRSTUVWXY 1;
2UTD ABCD 1;
2UTD E 30
{
invoker.slaveclipcount = Min(invoker.default.slaveclipcount,invoker.Ammo1.Amount);
invoker.Ammo1.Amount -= invoker.special2;
A_PlaySound("automag/reload",CHAN_6,!Dampener.Active(self)?1.:.1);
if ( self is 'UTPlayer' )
UTPlayer(self).PlayReloading();
invoker.slavereload = false;
}
2UTS A 0 A_PlaySound("automag/select",CHAN_6,!Dampener.Active(self)?1.:.1);
Goto LeftReady;
Zoom:
AUT2 A 1
{
A_Overlay(-9999,null);
invoker.slavespin = true;
}
AUT2 BCDEFGHIJKLMNOPQRSTUVWXYZ 1;
AUT3 AB 1;
ZoomLoop:
AUT3 CDEFGH 1;
AUT3 I 0 A_JumpIf(player.cmd.buttons&BT_ZOOM,"ZoomLoop1");
AUT3 IJKLMNOPQRS 1;
Goto Idle;
ZoomLoop1:
AUT3 I 1;
AUT3 C 0;
Goto ZoomLoop;
LeftZoom:
2UT2 A 1
{
A_Overlay(-9998,null);
invoker.slavespin = false;
}
2UT2 BCDEFGHIJKLMNOPQRSTUVWXYZ 1;
2UT3 AB 1;
LeftZoomLoop:
2UT3 CDEFGH 1;
2UT3 I 0 A_JumpIf(player.cmd.buttons&BT_ZOOM,"LeftZoomLoop1");
2UT3 IJKLMNOPQRS 1;
Goto LeftIdle;
LeftZoomLoop1:
2UT3 I 1;
2UT3 C 0;
Goto LeftZoomLoop;
Deselect:
AUTD A 0
{
A_Overlay(-9999,null);
invoker.slavedown = true;
}
AUTD ABCD 1;
AUTD E 1
{
if ( !player.FindPSprite(2) )
A_Lower(int.max);
}
Wait;
LeftDeselect:
2UTD A 0
{
A_Overlay(-9998,null);
invoker.slaveactive = false;
}
2UTD ABCD 1;
2UTD E 0;
Stop;
MuzzleFlash:
AMZ1 # 2 Bright
{
let psp = player.FindPSprite(OverlayID());
psp.frame = Random[Automag](0,4);
let l = Spawn("EnforcerLight",pos);
l.target = self;
}
Stop;
AltMuzzleFlash:
AMZ2 # 2 Bright
{
let psp = player.FindPSprite(OverlayID());
psp.frame = Random[Automag](0,4);
let l = Spawn("EnforcerLight",pos);
l.target = self;
}
Stop;
LeftMuzzleFlash:
AMZ3 # 2 Bright
{
let psp = player.FindPSprite(OverlayID());
psp.frame = Random[Automag](0,4);
let l = Spawn("EnforcerLight",pos);
l.target = self;
}
Stop;
LeftAltMuzzleFlash:
AMZ4 # 2 Bright
{
let psp = player.FindPSprite(OverlayID());
psp.frame = Random[Automag](0,4);
let l = Spawn("EnforcerLight",pos);
l.target = self;
}
Stop;
}
}