stinger_m/zscript/automag.zsc
Marisa Kirisame 3e169dfde6 Razorjack implemented, along with a couple extra features.
Adjust SCUBA Gear autouse behaviour so it works properly with manual use.
Add 3D floor handling code on various things.
Increased size of Eightball explosions to match original game.
Fix invisibility playing no sound when activated.
2019-09-11 19:37:10 +02:00

576 lines
15 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 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) || (weap.Ammo1.Amount <= 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 ( player.ReadyWeapon.CheckAmmo(Weapon.PrimaryFire,true) )
player.setpsprite(2,flash?ResolveState(flash):ResolveState("LeftHold"));
}
else if ( (player.cmd.buttons&BT_ALTATTACK) && invoker.slavealtfire && !pending && (player.health > 0) )
{
invoker.slaverefire++;
if ( player.ReadyWeapon.CheckAmmo(Weapon.AltFire,true) )
player.setpsprite(2,flash?ResolveState(flash):ResolveState("LeftAltHold"));
}
else
{
invoker.slaverefire = 0;
player.ReadyWeapon.CheckAmmo(invoker.slavealtfire?Weapon.AltFire:Weapon.PrimaryFire,true);
}
}
else
{
if ( invoker.clipcount < 5 ) A_PlaySound("automag/click",CHAN_ITEM,!Dampener.Active(self)?1.:.35);
if ( (invoker.clipcount <= 0) || (weap.Ammo1.Amount <= 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) && (weap.Ammo1.Amount > 0) )
{
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) && (weap.Ammo1.Amount > 0) )
{
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 ( weap.Ammo1.Amount <= 0 ) return;
if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return;
if ( slave ) invoker.slaveclipcount--;
else 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;
}
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.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
{
if ( (invoker.clipcount <= 0) && (invoker.Ammo1.Amount > 0) ) A_Overlay(PSP_WEAPON,"Reload");
else if ( ((invoker.clipcount < min(20,invoker.Ammo1.Amount)) || (invoker.slaveclipcount < min(20,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;
A_Overlay(2,"LeftDeselect");
}
else if ( invoker.slavereload ) A_Overlay(2,"LeftReload");
else if ( invoker.slavedown ) A_Overlay(2,"LeftDeselect");
else if ( invoker.slavespin ) A_Overlay(2,"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
{
invoker.slavereload = ((player.cmd.buttons&BT_RELOAD)&&invoker.slaveactive&&(invoker.slaveclipcount < min(20,invoker.Ammo1.Amount)))||(invoker.slaveclipcount <= 0);
return A_JumpIf(invoker.clipcount>=min(20,invoker.Ammo1.Amount),"Idle");
}
AUTR A 0
{
invoker.clipcount = Min(20,invoker.Ammo1.Amount);
A_Overlay(-9999,null);
A_WeaponOffset(0,32); // fix sudden psprite lowering
A_PlaySound("automag/click",CHAN_WEAPON,!Dampener.Active(self)?1.:.1);
}
AUTR ABCDEFGHIJKLMNOPQRSTUVWXY 1;
AUTD ABCD 1;
AUTD E 30
{
A_PlaySound("automag/reload",CHAN_WEAPON,!Dampener.Active(self)?1.:.1);
if ( self is 'UTPlayer' )
UTPlayer(self).PlayReloading();
}
AUTS A 0 A_PlaySound("automag/select",CHAN_WEAPON,!Dampener.Active(self)?1.:.1);
Goto Ready;
LeftReload:
2UTR A 0
{
invoker.slaveclipcount = Min(20,invoker.Ammo1.Amount);
invoker.slavereload = false;
A_Overlay(-9998,null);
A_PlaySound("automag/click",CHAN_6,!Dampener.Active(self)?1.:.1);
}
2UTR ABCDEFGHIJKLMNOPQRSTUVWXY 1;
2UTD ABCD 1;
2UTD E 30
{
A_PlaySound("automag/reload",CHAN_6,!Dampener.Active(self)?1.:.1);
if ( self is 'UTPlayer' )
UTPlayer(self).PlayReloading();
}
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:
AUTI A 1 { invoker.slavedown = true; }
AUTD A 0 A_Overlay(-9999,null);
AUTD A 0 A_JumpIf(invoker.slaveactive,"Deselect");
AUTD ABCD 1;
AUTD E 1 A_Lower(int.max);
Wait;
LeftDeselect:
2UTD A 0
{
A_Overlay(-9998,null);
invoker.slaveactive = false;
}
2UTD ABCD 1;
2UTD E 0;
Stop;
MuzzleFlash:
AMUZ A 2 Bright
{
let l = Spawn("EnforcerLight",pos);
l.target = self;
}
Stop;
AltMuzzleFlash:
AMUZ B 2 Bright
{
let l = Spawn("EnforcerLight",pos);
l.target = self;
}
Stop;
LeftMuzzleFlash:
AMUZ C 2 Bright
{
let l = Spawn("EnforcerLight",pos);
l.target = self;
}
Stop;
LeftAltMuzzleFlash:
AMUZ D 2 Bright
{
let l = Spawn("EnforcerLight",pos);
l.target = self;
}
Stop;
}
}