stinger_oldsounds_m has been affected by this update. Also adjusted Eightball firing sounds so they're played from the projectiles, not the weapon, this makes them not as loud and is the correct behaviour.
660 lines
16 KiB
Text
660 lines
16 KiB
Text
Class URocketAmmo : Ammo
|
|
{
|
|
Default
|
|
{
|
|
Tag "$T_ROCKETCAN";
|
|
Inventory.Icon "I_Rocket";
|
|
Inventory.PickupMessage "";
|
|
Inventory.Amount 12;
|
|
Inventory.MaxAmount 48;
|
|
Ammo.BackpackAmount 6;
|
|
Ammo.BackpackMaxAmount 96;
|
|
Ammo.DropAmount 6;
|
|
+INVENTORY.IGNORESKILL;
|
|
}
|
|
override String PickupMessage()
|
|
{
|
|
if ( PickupMsg.Length() > 0 ) return Super.PickupMessage();
|
|
return String.Format("%s%d%s",StringTable.Localize("$I_ROCKETCANL"),Amount,StringTable.Localize("$I_ROCKETCANR"));
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
RPAK A 8 A_CheckProximity(1,"PlayerPawn",80,1,CPXF_ANCESTOR|CPXF_CHECKSIGHT);
|
|
Wait;
|
|
RPAK AABCDEFGHIJ 8;
|
|
RPAK J 8 A_CheckProximity(1,"PlayerPawn",80,0,CPXF_ANCESTOR|CPXF_CHECKSIGHT|CPXF_EXACT);
|
|
Goto Spawn+12;
|
|
RPAK JJIHGFEDCBA 8;
|
|
Goto Spawn;
|
|
}
|
|
}
|
|
Class URocketAmmo2 : URocketAmmo
|
|
{
|
|
Default
|
|
{
|
|
Tag "$T_ROCKETCAN2";
|
|
Inventory.Amount 2;
|
|
Ammo.DropAmount 2;
|
|
+INVENTORY.IGNORESKILL;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
RCKT A 8 A_CheckProximity(1,"PlayerPawn",80,1,CPXF_ANCESTOR|CPXF_CHECKSIGHT);
|
|
Wait;
|
|
RCKT AA 8;
|
|
RCKT B 8 A_CheckProximity(1,"PlayerPawn",80,0,CPXF_ANCESTOR|CPXF_CHECKSIGHT|CPXF_EXACT);
|
|
Goto Spawn+3;
|
|
RCKT BB 8;
|
|
Goto Spawn;
|
|
}
|
|
}
|
|
|
|
Class URocketTrail : Actor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Radius 0.1;
|
|
Height 0;
|
|
+NOBLOCKMAP;
|
|
+NOGRAVITY;
|
|
+DONTSPLASH;
|
|
+FORCEXYBILLBOARD;
|
|
+NOTELEPORT;
|
|
Scale 0.4;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
let l = Spawn("RocketLight",pos);
|
|
l.target = self;
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( !target || !target.bMISSILE )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
SetOrigin(target.pos,true);
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
MFLA A -1 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class URocket : Actor
|
|
{
|
|
Vector3 InitialDir, Acceleration;
|
|
int ticcnt;
|
|
bool ringex;
|
|
Default
|
|
{
|
|
Obituary "$O_EIGHTBALL";
|
|
DamageType 'RocketDeath';
|
|
Radius 2;
|
|
Height 2;
|
|
Speed 15;
|
|
PROJECTILE;
|
|
+SKYEXPLODE;
|
|
+EXPLODEONWATER;
|
|
+SEEKERMISSILE;
|
|
+FORCERADIUSDMG;
|
|
+NODAMAGETHRUST;
|
|
+INTERPOLATEANGLES;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
let l = Spawn("URocketTrail",pos);
|
|
l.target = self;
|
|
A_StartSound("eightball/fire",CHAN_WEAPON,attenuation:.6);
|
|
A_StartSound("eightball/fly",CHAN_VOICE,CHANF_LOOPING,1.,2.5);
|
|
if ( tracer ) vel *= 0.9;
|
|
Acceleration = vel.unit()*50;
|
|
}
|
|
action void A_RocketExplode( int dmg, int rad )
|
|
{
|
|
bFORCEXYBILLBOARD = true;
|
|
A_SetRenderStyle(1.0,STYLE_Add);
|
|
A_SprayDecal("RocketBlast",50);
|
|
A_NoGravity();
|
|
A_SetScale(FRandomPick[ExploS](-2.5,2.5),FRandomPick[ExploS](-2.5,2.5));
|
|
UTMainHandler.DoBlast(self,rad,80000);
|
|
A_Explode(dmg,rad);
|
|
A_QuakeEx(3,3,3,8,0,rad+50,"",QF_RELATIVE|QF_SCALEDOWN,falloff:rad,rollIntensity:0.2);
|
|
A_StartSound("eightball/explode",CHAN_VOICE);
|
|
A_AlertMonsters();
|
|
Spawn("RocketExplLight",pos);
|
|
int numpt = Random[Eightball](15,30);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[Eightball](-1,1),FRandom[Eightball](-1,1),FRandom[Eightball](-1,1)).unit()*FRandom[Eightball](1,3);
|
|
let s = Spawn("UTSmoke",pos);
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Random[Eightball](10,20);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[Eightball](-1,1),FRandom[Eightball](-1,1),FRandom[Eightball](-1,1)).unit()*FRandom[Eightball](2,6);
|
|
let s = Spawn("UTSpark",pos);
|
|
s.vel = pvel;
|
|
}
|
|
numpt = Random[Eightball](35,70);
|
|
for ( int i=0; i<numpt; i++ )
|
|
{
|
|
Vector3 pvel = (FRandom[Eightball](-1,1),FRandom[Eightball](-1,1),FRandom[Eightball](-1,1)).unit()*FRandom[Eightball](2,12);
|
|
let s = Spawn("UTChip",pos);
|
|
s.vel = pvel;
|
|
s.scale *= FRandom[Eightball](0.9,2.7);
|
|
}
|
|
if ( !invoker.ringex ) return;
|
|
Actor r = Spawn("ASMDSBeamRing",pos);
|
|
Vector3 HitNormal = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
|
|
if ( BlockingLine ) HitNormal = (-BlockingLine.delta.y,BlockingLine.delta.x,0).unit();
|
|
else if ( BlockingFloor )
|
|
{
|
|
// find closest 3d floor for its normal
|
|
F3DFloor ff = null;
|
|
for ( int i=0; i<BlockingFloor.Get3DFloorCount(); i++ )
|
|
{
|
|
if ( !(BlockingFloor.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
|
|
ff = BlockingFloor.Get3DFloor(i);
|
|
break;
|
|
}
|
|
if ( ff ) HitNormal = -ff.top.Normal;
|
|
else HitNormal = BlockingFloor.floorplane.Normal;
|
|
r.SetOrigin(r.Vec3Offset(0,0,2),false);
|
|
}
|
|
else if ( BlockingCeiling )
|
|
{
|
|
// find closest 3d floor for its normal
|
|
F3DFloor ff = null;
|
|
for ( int i=0; i<BlockingCeiling.Get3DFloorCount(); i++ )
|
|
{
|
|
if ( !(BlockingCeiling.Get3DFloor(i).bottom.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
|
|
ff = BlockingCeiling.Get3DFloor(i);
|
|
break;
|
|
}
|
|
if ( ff ) HitNormal = -ff.bottom.Normal;
|
|
else HitNormal = BlockingCeiling.ceilingplane.Normal;
|
|
}
|
|
r.angle = atan2(HitNormal.y,HitNormal.x);
|
|
r.pitch = asin(-HitNormal.z);
|
|
}
|
|
action void A_RocketSeek()
|
|
{
|
|
if ( invoker.InitialDir.length() < double.epsilon ) invoker.InitialDir = vel.unit();
|
|
if ( tracer && (tracer != target) )
|
|
{
|
|
Vector3 SeekingDir = level.Vec3Diff(pos,tracer.Vec3Offset(0,0,tracer.height/2)).unit();
|
|
if ( SeekingDir dot invoker.InitialDir > 0 )
|
|
{
|
|
double MagnitudeVel = Vel.length();
|
|
SeekingDir = (SeekingDir*0.5*MagnitudeVel+Vel).unit();
|
|
Vel = MagnitudeVel * SeekingDir;
|
|
invoker.Acceleration = 25 * SeekingDir;
|
|
}
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
RCKT ABC 1
|
|
{
|
|
roll += 30;
|
|
if ( invoker.ticcnt++ > 3 )
|
|
{
|
|
invoker.ticcnt = 0;
|
|
A_RocketSeek();
|
|
}
|
|
vel += invoker.Acceleration/TICRATE;
|
|
if ( vel.length() > 30. ) vel = Vel.unit()*30.;
|
|
Vector3 dir = vel.unit();
|
|
if ( waterlevel <= 0 ) vel = dir*min(vel.length()+1,24);
|
|
angle = atan2(dir.y,dir.x);
|
|
pitch = asin(-dir.z);
|
|
for ( int i=0; i<3; i++ )
|
|
{
|
|
let s = Spawn("UTSmoke",pos);
|
|
s.vel = (FRandom[Eightball](-0.2,0.2),FRandom[Eightball](-0.2,0.2),FRandom[Eightball](-0.2,0.2));
|
|
s.vel += vel*0.1;
|
|
}
|
|
}
|
|
Wait;
|
|
Death:
|
|
TNT1 A 0
|
|
{
|
|
A_RocketExplode(100,120);
|
|
return A_Jump(256,"Explo1","Explo2","Explo3","Explo4","Explo5");
|
|
}
|
|
Explo1:
|
|
EXP1 ABCDEFGH 3 Bright;
|
|
Stop;
|
|
Explo2:
|
|
EXP2 ABCDEFGH 3 Bright;
|
|
Stop;
|
|
Explo3:
|
|
EXP3 ABCDEFGH 3 Bright;
|
|
Stop;
|
|
Explo4:
|
|
EXP4 ABCDEFGH 3 Bright;
|
|
Stop;
|
|
Explo5:
|
|
EXP5 ABCDEFGH 3 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class UGrenade : URocket
|
|
{
|
|
double rollvel, pitchvel, anglevel;
|
|
|
|
Default
|
|
{
|
|
DamageType 'GrenadeDeath';
|
|
-NOGRAVITY;
|
|
+USEBOUNCESTATE;
|
|
-EXPLODEONWATER;
|
|
+CANBOUNCEWATER;
|
|
+NOEXPLODEFLOOR;
|
|
+DONTBOUNCEONSHOOTABLES;
|
|
BounceType "Hexen";
|
|
WallBounceFactor 0.75;
|
|
BounceFactor 0.75;
|
|
ReactionTime 85;
|
|
Speed 15;
|
|
Gravity 0.35;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Actor.PostBeginPlay();
|
|
rollvel = FRandom[Eightball](-8,8);
|
|
pitchvel = FRandom[Eightball](-8,8);
|
|
anglevel = FRandom[Eightball](-8,8);
|
|
ReactionTime += Random[Eightball](0,20);
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
RCKT A 1
|
|
{
|
|
if ( !bNOGRAVITY )
|
|
{
|
|
angle += anglevel;
|
|
pitch += pitchvel;
|
|
roll += rollvel;
|
|
}
|
|
let s = Spawn("UTSmoke",pos);
|
|
s.scale *= 2.0;
|
|
s.alpha *= 0.6;
|
|
s.vel = (FRandom[Eightball](-0.1,0.1),FRandom[Eightball](-0.1,0.1),FRandom[Eightball](-0.1,0.3));
|
|
s.vel += vel*0.05;
|
|
s.SetShade("000000");
|
|
A_Countdown();
|
|
}
|
|
Wait;
|
|
Bounce:
|
|
RCKT A 0
|
|
{
|
|
bHITOWNER = true;
|
|
A_StartSound("utrl/bounce");
|
|
rollvel = FRandom[Eightball](-16,16);
|
|
pitchvel = FRandom[Eightball](-16,16);
|
|
anglevel = FRandom[Eightball](-16,16);
|
|
if ( vel.z > 10 ) vel.z = 0.5*(10+vel.z);
|
|
else if ( BlockingFloor && (vel.xy.length() < 0.5) )
|
|
{
|
|
vel *= 0;
|
|
bNOGRAVITY = true;
|
|
bMOVEWITHSECTOR = true;
|
|
ClearBounce();
|
|
}
|
|
}
|
|
Goto Spawn;
|
|
Death:
|
|
TNT1 A 0 A_RocketExplode(120,140);
|
|
Goto Super::Death+1;
|
|
}
|
|
}
|
|
|
|
Class Eightball : UnrealWeapon
|
|
{
|
|
bool LockedOn;
|
|
Actor LockedTarget;
|
|
TextureID lockontex;
|
|
int locktics;
|
|
bool bSingleRocket;
|
|
|
|
override int, int, bool, bool GetClipAmount()
|
|
{
|
|
return special1?special1:-1, -1, false, false;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
lockontex = TexMan.CheckForTexture("Crosshr6",TexMan.Type_Any);
|
|
}
|
|
|
|
override void PreRender( double lbottom )
|
|
{
|
|
if ( LockedTarget ) Screen.DrawTexture(lockontex,false,Screen.GetWidth()*0.5,Screen.GetHeight()*0.5);
|
|
}
|
|
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( !Owner ) return;
|
|
if ( Owner.Health <= 0 )
|
|
{
|
|
LockedTarget = null;
|
|
LockedOn = false;
|
|
crosshair = 0;
|
|
return;
|
|
}
|
|
if ( LockedOn && (!LockedTarget || (LockedTarget.Health <= 0) || !LockedTarget.bIsMonster || LockedTarget.bKilled || LockedTarget.bCorpse || !LockedTarget.bShootable || (Owner.player.ReadyWeapon != self)) )
|
|
{
|
|
LockedTarget = null;
|
|
LockedOn = false;
|
|
if ( Owner.player.ReadyWeapon == self )
|
|
{
|
|
Owner.A_StartSound("eightball/seeklost",CHAN_WEAPONMISC,CHANF_OVERLAP,Dampener.Active(Owner)?.1:1.);
|
|
if ( !Dampener.Active(Owner) ) Owner.A_AlertMonsters();
|
|
}
|
|
}
|
|
if ( LockedTarget ) crosshair = 99;
|
|
else crosshair = 0;
|
|
}
|
|
|
|
// consumes 1 ammo
|
|
action void A_LoadRocket( bool checktarget = true )
|
|
{
|
|
Weapon weap = Weapon(invoker);
|
|
if ( !weap ) return;
|
|
if ( weap.Ammo1.Amount <= 0 ) return;
|
|
if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return;
|
|
if ( weap.bAltFire )
|
|
{
|
|
invoker.LockedTarget = null;
|
|
invoker.LockedOn = false;
|
|
}
|
|
if ( checktarget && !weap.bAltFire ) A_CheckTarget();
|
|
invoker.special1++;
|
|
}
|
|
|
|
// refire that is ignored if there's no ammo
|
|
action void A_LoadedRefire( statelabel flash = null )
|
|
{
|
|
Weapon weap = Weapon(invoker);
|
|
if ( !weap ) return;
|
|
if ( weap.Ammo1.Amount <= 0 ) return;
|
|
A_Refire(flash);
|
|
}
|
|
|
|
// fire all the rockets (or grenades)
|
|
action void A_FireRockets( int num )
|
|
{
|
|
Weapon weap = Weapon(invoker);
|
|
if ( !weap ) return;
|
|
A_Overlay(-9999,"Null");
|
|
invoker.special1 = 0;
|
|
if ( weap.bAltFire )
|
|
{
|
|
A_StartSound("eightball/altfire",CHAN_WEAPON,CHANF_OVERLAP,Dampener.Active(self)?.3:3.);
|
|
if ( !Dampener.Active(self) ) A_AlertMonsters();
|
|
}
|
|
else A_AlertMonsters();
|
|
invoker.FireEffect();
|
|
UTMainHandler.DoFlash(self,Color(64,255,0,0),1);
|
|
if ( self is 'UTPlayer' )
|
|
UTPlayer(self).PlayAttacking3();
|
|
A_QuakeEx(2+num,2+num,2+num,6+num,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.1+num*0.05);
|
|
for ( int i=0; i<num; i++ )
|
|
UTMainHandler.DoSwing(self,(FRandom[Eightball](-0.8,-0.8),FRandom[Eightball](-0.5,0.5)),1,-0.2,Random[Eightball](3,4),SWING_Spring,Random[Eightball](2,5),Random[Eightball](2,4));
|
|
Vector3 x, y, z, x2, y2, z2;
|
|
double a, s;
|
|
[x, y, z] = dt_CoordUtil.GetAxes(pitch,angle,roll);
|
|
Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x-2*z);
|
|
[x2, y2, z2] = dt_CoordUtil.GetAxes(BulletSlope(),angle,roll);
|
|
Actor p;
|
|
if ( weap.bAltFire )
|
|
{
|
|
// grenades
|
|
for ( int i=0; i<num; i++ )
|
|
{
|
|
a = FRandom[Eightball](0,360);
|
|
s = FRandom[Eightball](0,(num>1)?12:0);
|
|
Vector3 dir = (x2+cos(a)*y2*s*0.004+sin(a)*z2*s*0.004).unit();
|
|
p = Spawn("UGrenade",level.Vec3Offset(origin,cos(a)*y*s+sin(a)*z*s));
|
|
p.vel = x*(vel dot x)*0.4 + dir*p.speed*FRandom[Eightball](1.0,1.2);
|
|
p.vel.z += 3.5;
|
|
p.target = self;
|
|
}
|
|
}
|
|
else if ( num <= 1 )
|
|
{
|
|
// single rocket
|
|
p = Spawn("URocket",level.Vec3Offset(origin,cos(a)*y*s+sin(a)*z*s));
|
|
p.vel = x2*p.speed;
|
|
p.target = self;
|
|
p.tracer = invoker.LockedTarget;
|
|
}
|
|
else if ( player.cmd.buttons&BT_ALTATTACK )
|
|
{
|
|
// rockets ("tight wad" as UT calls it)
|
|
double step = 360/num;
|
|
a = 90;
|
|
s = (num>1)?6:0;
|
|
for ( int i=0; i<num; i++ )
|
|
{
|
|
p = Spawn("URocket",level.Vec3Offset(origin,cos(a)*y*s+sin(a)*z*s));
|
|
p.vel = x2*p.speed;
|
|
p.target = self;
|
|
p.tracer = invoker.LockedTarget;
|
|
a += step;
|
|
if ( !invoker.LockedTarget && (i==0) )
|
|
URocket(p).ringex = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// rockets (wide spread)
|
|
double range = 3.6*(num-1);
|
|
double step = range/(num-1);
|
|
s = -range*0.5;
|
|
for ( int i=0; i<num; i++ )
|
|
{
|
|
p = Spawn("URocket",level.Vec3Offset(origin,sin(s)*y));
|
|
p.vel = (x2+sin(s)*y2).unit()*p.speed;
|
|
p.target = self;
|
|
p.tracer = invoker.LockedTarget;
|
|
s += step;
|
|
}
|
|
}
|
|
// lose lock-on
|
|
if ( invoker.LockedOn ) A_StartSound("eightball/seeklost",CHAN_WEAPONMISC,CHANF_OVERLAP);
|
|
invoker.LockedTarget = null;
|
|
invoker.LockedOn = false;
|
|
for ( int i=0; i<12; i++ )
|
|
{
|
|
let s = Spawn("UTViewSmoke",origin);
|
|
UTViewSmoke(s).ofs = (10,0,-2);
|
|
UTViewSmoke(s).vvel = (FRandom[Eightball](0,1.2),FRandom[Eightball](-.4,.4),FRandom[Eightball](-.4,.4));
|
|
s.target = self;
|
|
s.scale *= 1.8;
|
|
s.alpha *= 0.8;
|
|
}
|
|
}
|
|
|
|
// lock-on check
|
|
action void A_CheckTarget()
|
|
{
|
|
let t = ThinkerIterator.Create("Actor");
|
|
Actor a;
|
|
double closest = double.max;
|
|
invoker.LockedTarget = null;
|
|
while ( a = Actor(t.Next()) )
|
|
{
|
|
if ( !a.bSHOOTABLE || (a.Health <= 0) || a.bKilled || !a.bIsMonster || a.bCorpse || (a == self) || isTeammate(a) || !CheckSight(a) ) continue;
|
|
Vector3 viewdir = (cos(angle)*cos(pitch),sin(angle)*cos(pitch),-sin(pitch));
|
|
Vector3 reldir = level.Vec3Diff(Vec2OffsetZ(0,0,player.viewz),a.Vec2OffsetZ(0,0,a.pos.z+a.height*0.5));
|
|
double reldist = reldir.length();
|
|
if ( reldist > 2000 ) continue;
|
|
if ( reldir.unit() dot viewdir < 0.99 ) continue;
|
|
if ( reldist < closest )
|
|
{
|
|
closest = reldist;
|
|
invoker.LockedTarget = a;
|
|
}
|
|
}
|
|
if ( invoker.LockedTarget )
|
|
{
|
|
A_StartSound("eightball/seeklock",CHAN_WEAPONMISC,CHANF_OVERLAP,Dampener.Active(self)?.1:1.);
|
|
if ( !Dampener.Active(self) ) A_AlertMonsters();
|
|
}
|
|
else if ( invoker.LockedOn )
|
|
{
|
|
A_StartSound("eightball/seeklost",CHAN_WEAPONMISC,CHANF_OVERLAP,Dampener.Active(self)?.1:1.);
|
|
if ( !Dampener.Active(self) ) A_AlertMonsters();
|
|
}
|
|
if ( invoker.LockedTarget ) invoker.LockedOn = true;
|
|
}
|
|
|
|
Default
|
|
{
|
|
Tag "$T_EIGHTBALL";
|
|
Inventory.PickupMessage "$I_EIGHTBALL";
|
|
Weapon.UpSound "eightball/select";
|
|
Weapon.SlotNumber 5;
|
|
Weapon.SelectionOrder 1000;
|
|
Weapon.SlotPriority 1;
|
|
Weapon.AmmoType "URocketAmmo";
|
|
Weapon.AmmoUse 1;
|
|
Weapon.AmmoType2 "URocketAmmo";
|
|
Weapon.AmmoUse2 1;
|
|
Weapon.AmmoGive 6;
|
|
UTWeapon.DropAmmo 3;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
EBLP A -1;
|
|
Stop;
|
|
EBLP B -1;
|
|
Stop;
|
|
Select:
|
|
EBLS A 1 A_Raise(int.max);
|
|
Wait;
|
|
Ready:
|
|
EBLS ABCDEFGHIJKLMNO 1 A_WeaponReady(WRF_NOFIRE);
|
|
EBLS O 8 A_Overlay(-9999,"Dummy");
|
|
Goto Idle+1;
|
|
Ready2:
|
|
EBLS O 0 A_CheckReload();
|
|
EBLL A 0 A_StartSound("eightball/load",CHAN_WEAPONMISC,CHANF_OVERLAP,Dampener.Active(self)?.1:1.);
|
|
EBLL ABCDEFGHIJK 1 A_WeaponReady(WRF_NOFIRE);
|
|
EBLL L 0 A_StartSound("eightball/rotate",CHAN_WEAPONMISC,CHANF_OVERLAP,Dampener.Active(self)?.01:.1);
|
|
EBLL LMNOPQRSTUVWXYZ[ 1 A_WeaponReady(WRF_NOFIRE);
|
|
EBLL Z 0; // force no tweening
|
|
EBLI A 0;
|
|
Goto Idle;
|
|
Idle:
|
|
#### # 0 A_Overlay(-9999,"Dummy");
|
|
EBLI AB 50;
|
|
Goto Idle+1;
|
|
Dummy:
|
|
TNT1 A 1
|
|
{
|
|
invoker.locktics = 0;
|
|
invoker.special1 = 0;
|
|
A_CheckReload();
|
|
A_WeaponReady(WRF_ALLOWRELOAD);
|
|
}
|
|
TNT1 A 1
|
|
{
|
|
A_CheckReload();
|
|
A_WeaponReady(WRF_ALLOWRELOAD);
|
|
invoker.locktics++;
|
|
if ( invoker.locktics > 42 )
|
|
{
|
|
invoker.locktics = 0;
|
|
A_CheckTarget();
|
|
}
|
|
}
|
|
Wait;
|
|
Reload:
|
|
#### # 5
|
|
{
|
|
A_Overlay(-9999,"Null");
|
|
A_StartSound("eightball/load",CHAN_WEAPONMISC,CHANF_OVERLAP,Dampener.Active(self)?.03:.3);
|
|
if ( invoker.bSingleRocket = !invoker.bSingleRocket )
|
|
A_Print(StringTable.Localize("$M_SINGLEROCKETON"));
|
|
else A_Print(StringTable.Localize("$M_SINGLEROCKETOFF"));
|
|
}
|
|
Goto Idle;
|
|
Dummy2:
|
|
TNT1 A 1
|
|
{
|
|
if ( !(player.cmd.buttons&(BT_ATTACK|BT_ALTATTACK)) )
|
|
player.SetPSprite(PSP_WEAPON,ResolveState("Release"));
|
|
}
|
|
Wait;
|
|
Fire:
|
|
AltFire:
|
|
// one is loaded already
|
|
#### # 1
|
|
{
|
|
A_Overlay(-9999,"Dummy2");
|
|
A_LoadRocket(false);
|
|
}
|
|
#### # 0 A_JumpIf(!invoker.bAltFire&&invoker.bSingleRocket,"Release");
|
|
#### # 0 A_LoadedRefire(1);
|
|
Goto Release;
|
|
Loading:
|
|
EBLI A 0;
|
|
EBLL A 0 A_StartSound("eightball/load",CHAN_WEAPONMISC,CHANF_OVERLAP,Dampener.Active(self)?.1:1.);
|
|
EBLL ABCDEFGHIJK 1;
|
|
EBLL L 0 A_LoadRocket();
|
|
EBLL L 0 A_StartSound("eightball/rotate",CHAN_WEAPONMISC,CHANF_OVERLAP,Dampener.Active(self)?.01:.1);
|
|
EBLL LMNOPQRSTUVWXYZ[ 1;
|
|
EBLL Z 0;
|
|
EBLI A 0;
|
|
EBLI A 1
|
|
{
|
|
if ( invoker.special1 >= 6 )
|
|
{
|
|
if ( sting_ehold )
|
|
{
|
|
invoker.special2 = 70;
|
|
return ResolveState("LoadHold");
|
|
}
|
|
else return ResolveState("Release");
|
|
}
|
|
return ResolveState(null);
|
|
}
|
|
EBLI A 0 A_LoadedRefire("Loading");
|
|
Goto Release;
|
|
LoadHold:
|
|
EBLI A 2;
|
|
LoadHoldL:
|
|
EBLI C 1 A_JumpIf(--invoker.special2<0,"Release");
|
|
EBLI C 0 A_LoadedRefire("LoadHoldL");
|
|
Goto Release;
|
|
Release:
|
|
EBLF A 0 A_FireRockets(invoker.special1);
|
|
EBLF ABCDEFGH 3;
|
|
EBLS S 0;
|
|
Goto Ready2;
|
|
Deselect:
|
|
EBLD A 1 A_Overlay(-9999,"Null");
|
|
EBLD BCDEFGHIJKL 1;
|
|
EBLD L 1 A_Lower(int.max);
|
|
Wait;
|
|
}
|
|
}
|