flak_m/zscript/eightball.zsc
Marisa Kirisame 71b194c6c3 Renamed some sprites for compatibility with Smooth Doom.
Added water step/land sounds.
Made footsteps toggleable (in case the player is using another mod that adds them).
Added handling of liquid terrain on all actors that need it.
Fixed dual enforcers breaking after level transition.
Fixed some refire issues caused by the use of the Resurrect cheat.
Made guided redeemer missiles explode on player death.
Replaced pure particles on pulse gun effects with actor particles.
2018-06-01 17:49:49 +02:00

684 lines
14 KiB
Text

Class UTRocketAmmo : Ammo
{
Default
{
Tag "Rocket Pack";
Inventory.PickupMessage "You picked up a Rocket Pack.";
Inventory.Amount 12;
Inventory.MaxAmount 48;
Ammo.BackpackAmount 12;
Ammo.BackpackMaxAmount 48;
Ammo.DropAmount 3;
}
States
{
Spawn:
RPAK A -1;
Stop;
}
}
// There was no single rocket ammo in UT, so this one is also just improvised like the Redeemer ammo pickup
Class UTRocketAmmo2 : UTRocketAmmo
{
Default
{
Tag "Single Rocket";
Inventory.PickupMessage "You picked up a Single Rocket.";
Inventory.Amount 1;
Ammo.DropAmount 1;
}
States
{
Spawn:
RCKT A -1;
Stop;
}
}
Class RocketLight : DynamicLight
{
Default
{
DynamicLight.Type "Point";
Args 255,224,128,32;
}
override void Tick()
{
Super.Tick();
if ( !target )
{
Destroy();
return;
}
SetOrigin(target.pos,true);
}
}
Class UTRocketTrail : Actor
{
Default
{
RenderStyle "Add";
Radius 0.1;
Height 0;
+NOBLOCKMAP;
+NOGRAVITY;
+DONTSPLASH;
+FORCEXYBILLBOARD;
Scale 0.7;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
let l = Spawn("RocketLight",pos);
l.target = self;
}
override void Tick()
{
Super.Tick();
if ( !target || target.InStateSequence(target.CurState,target.FindState("Death")) )
{
Destroy();
return;
}
SetOrigin(target.pos,true);
}
States
{
Spawn:
RFLA A -1 Bright;
Stop;
}
}
Class RocketExplLight : SlugLight
{
Default
{
Args 255,224,128,120;
}
}
Class UTRocket : Actor
{
Default
{
Obituary "%o was smacked down by %k's Rocket Launcher.";
DamageFunction Random[Eightball](70,80);
DamageType 'RocketDeath';
Radius 2;
Height 2;
Speed 30;
PROJECTILE;
+SKYEXPLODE;
+EXPLODEONWATER;
+SEEKERMISSILE;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
let l = Spawn("UTRocketTrail",pos);
l.target = self;
A_PlaySound("utrl/fly",CHAN_VOICE,1.0,true,2.5);
}
action void A_RocketExplode()
{
bFORCEXYBILLBOARD = true;
A_SetRenderStyle(1.0,STYLE_Add);
A_SprayDecal("RocketBlast",150);
A_NoGravity();
A_SetScale(0.75);
A_Explode(Random[Eightball](60,70),100);
A_QuakeEx(3,3,3,8,0,250,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.2);
A_PlaySound("utrl/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,4);
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,8);
let s = Spawn("UTSpark",pos);
s.vel = pvel;
}
numpt = Random[Eightball](25,50);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[Eightball](-1,1),FRandom[Eightball](-1,1),FRandom[Eightball](-1,1)).unit()*FRandom[Eightball](4,12);
let s = Spawn("UTChip",pos);
s.vel = pvel;
}
}
States
{
Spawn:
RCKT B 1
{
A_SetRoll(roll+30,SPF_INTERPOLATE);
Vector3 dir = vel.unit();
A_SetAngle(atan2(dir.y,dir.x),SPF_INTERPOLATE);
A_SetPitch(asin(-dir.z),SPF_INTERPOLATE);
if ( tracer ) A_SeekerMissile(0,2,SMF_PRECISE);
Spawn("UTSmoke",pos);
}
Wait;
Death:
TNT1 A 0 A_RocketExplode();
SSMX ABCDEFGHIJ 2 Bright;
Stop;
}
}
Class UTGrenade : UTRocket
{
double rollvel, pitchvel, anglevel;
Default
{
DamageFunction Random[Eightball](80,90);
DamageType 'GrenadeDeath';
-NOGRAVITY;
+USEBOUNCESTATE;
-BOUNCEAUTOOFF;
+BOUNCEAUTOOFFFLOORONLY;
-EXPLODEONWATER;
+CANBOUNCEWATER;
BounceType "Doom";
BounceFactor 0.75;
ReactionTime 85;
Speed 20;
}
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
{
A_SetAngle(angle+anglevel,SPF_INTERPOLATE);
A_SetPitch(pitch+pitchvel,SPF_INTERPOLATE);
A_SetRoll(roll+rollvel,SPF_INTERPOLATE);
A_Countdown();
}
Wait;
Bounce:
RCKT A 0
{
A_PlaySound("utrl/bounce");
rollvel = FRandom[Eightball](-16,16);
pitchvel = FRandom[Eightball](-16,16);
anglevel = FRandom[Eightball](-16,16);
}
Goto Spawn;
}
}
Class UTRocketLauncher : UTWeapon
{
bool LockedOn;
Actor LockedTarget;
TextureID lockontex;
int locktics;
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 ( LockedOn && (!LockedTarget || (LockedTarget.Health <= 0) || !LockedTarget.bIsMonster || LockedTarget.bKilled || LockedTarget.bCorpse || !LockedTarget.bShootable) )
{
LockedTarget = null;
LockedOn = false;
Owner.A_PlaySound("utrl/seeklost",CHAN_6);
}
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();
}
// 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;
if ( weap.bAltFire ) A_PlaySound("utrl/altfire",CHAN_WEAPON);
else A_PlaySound("utrl/fire",CHAN_WEAPON);
invoker.FireEffect();
UTMainHandler.DoFlash(self,Color(64,255,0,0),1);
A_AlertMonsters();
A_QuakeEx(2+num,2+num,2+num,6+num,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.1+num*0.05);
Vector3 x, y, z, x2, y2, z2;
double a, s;
[x, y, z] = Matrix4.GetAxes(pitch,angle,roll);
Vector3 origin = (pos.x,pos.y,player.viewz)+10.0*x+6.0*y-6.0*z;
[x2, y2, z2] = Matrix4.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,0.06*(num-1));
Vector3 dir = (x2+cos(a)*y2*s+sin(a)*z2*s).unit();
p = Spawn("UTGrenade",origin);
p.vel = dir*p.speed*FRandom[Eightball](1.0,1.2);
p.vel.z += 5;
p.target = self;
}
}
else if ( num <= 1 )
{
// single rocket
p = Spawn("UTRocket",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.2:0.0;
for ( int i=0; i<num; i++ )
{
p = Spawn("UTRocket",origin+cos(a)*y*s+sin(a)*z*s);
p.vel = (x2+cos(a)*y2*s*0.02+sin(a)*z2*s*0.02).unit()*p.speed;
p.target = self;
p.tracer = invoker.LockedTarget;
a += step;
}
}
else
{
// rockets (wide spread)
double range = 2.5*(num-1);
double step = range/(num-1);
s = -range*0.5;
for ( int i=0; i<num; i++ )
{
p = Spawn("UTRocket",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_PlaySound("utrl/seeklost",CHAN_6);
invoker.LockedTarget = null;
invoker.LockedOn = false;
}
// 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_PlaySound("utrl/seeklock",CHAN_6);
else if ( invoker.LockedOn ) A_PlaySound("utrl/seeklost",CHAN_6);
if ( invoker.LockedTarget ) invoker.LockedOn = true;
}
Default
{
Tag "Rocket Launcher";
Inventory.PickupMessage "You got the Rocket Launcher.";
Weapon.UpSound "utrl/select";
Weapon.SlotNumber 9;
Weapon.SelectionOrder 1;
Weapon.AmmoType "UTRocketAmmo";
Weapon.AmmoUse 1;
Weapon.AmmoType2 "UTRocketAmmo";
Weapon.AmmoUse2 1;
Weapon.AmmoGive 6;
}
States
{
Spawn:
EBLP A -1;
Stop;
EBLP B -1;
Stop;
Select:
EBLS A 1 A_Raise(int.max);
Wait;
Ready:
EBLS ABCDEFGHIJKLMNOPQRST 1 A_WeaponReady(WRF_NOFIRE);
Idle:
EBLI A 1
{
invoker.locktics = 0;
A_CheckReload();
A_WeaponReady();
}
EBLI A 1
{
A_CheckReload();
A_WeaponReady();
invoker.locktics++;
if ( invoker.locktics > 42 )
{
invoker.locktics = 0;
A_CheckTarget();
}
}
Wait;
Fire:
AltFire:
// one is loaded already
EBLI A 3 A_LoadRocket(false);
EBLI A 0 A_LoadedRefire(1);
Goto FireOne;
// load two
EBLI A 2;
EBL1 A 0;
EBR1 A 2 A_PlaySound("utrl/rotate",CHAN_WEAPON,0.1);
EBR1 B 0 A_Refire(1);
Goto FireOne;
EBR1 B 2;
EBR1 C 0 A_Refire(1);
Goto FireOne;
EBR1 C 2;
EBR1 D 0 A_Refire(1);
Goto FireOne;
EBR1 D 2;
EBR1 E 0 A_Refire(1);
Goto FireOne;
EBR1 E 2;
EBR1 F 0 A_Refire(1);
Goto FireOne;
EBR1 F 2;
EBR1 G 0 A_Refire(1);
Goto FireOne;
EBR1 G 2;
EBL2 A 0 A_Refire(1);
Goto FireOne;
EBL2 A 3 A_PlaySound("utrl/load",CHAN_WEAPON);
EBL2 B 0 A_Refire(1);
Goto FireOne;
EBL2 B 3;
EBL2 C 0 A_Refire(1);
Goto FireOne;
EBL2 C 3;
EBL2 D 0 A_Refire(1);
Goto FireOne;
EBL2 D 3;
EBL2 E 0 A_Refire(1);
Goto FireOne;
EBL2 E 3;
EBL2 F 0 A_Refire(1);
Goto FireOne;
EBL2 F 3;
EBL2 G 0 A_Refire(1);
Goto FireOne;
EBL2 G 3 A_LoadRocket();
EBR2 A 0 A_LoadedRefire(1);
Goto FireTwo;
// load three
EBR2 A 2 A_PlaySound("utrl/rotate",CHAN_WEAPON,0.1);
EBR2 B 0 A_Refire(1);
Goto FireTwo;
EBR2 B 2;
EBR2 C 0 A_Refire(1);
Goto FireTwo;
EBR2 C 2;
EBR2 D 0 A_Refire(1);
Goto FireTwo;
EBR2 D 2;
EBR2 E 0 A_Refire(1);
Goto FireTwo;
EBR2 E 2;
EBR2 F 0 A_Refire(1);
Goto FireTwo;
EBR2 F 2;
EBR2 G 0 A_Refire(1);
Goto FireTwo;
EBR2 G 2;
EBL3 A 0 A_Refire(1);
Goto FireTwo;
EBL3 A 3 A_PlaySound("utrl/load",CHAN_WEAPON);
EBL3 B 0 A_Refire(1);
Goto FireTwo;
EBL3 B 3;
EBL3 C 0 A_Refire(1);
Goto FireTwo;
EBL3 C 3;
EBL3 D 0 A_Refire(1);
Goto FireTwo;
EBL3 D 3;
EBL3 E 0 A_Refire(1);
Goto FireTwo;
EBL3 E 3;
EBL3 F 0 A_Refire(1);
Goto FireTwo;
EBL3 F 3;
EBL3 G 0 A_Refire(1);
Goto FireTwo;
EBL3 G 3 A_LoadRocket();
EBR3 A 0 A_LoadedRefire(1);
Goto FireThree;
// load four
EBR3 A 2 A_PlaySound("utrl/rotate",CHAN_WEAPON,0.1);
EBR3 B 0 A_Refire(1);
Goto FireThree;
EBR3 B 2;
EBR3 C 0 A_Refire(1);
Goto FireThree;
EBR3 C 2;
EBR3 D 0 A_Refire(1);
Goto FireThree;
EBR3 D 2;
EBR3 E 0 A_Refire(1);
Goto FireThree;
EBR3 E 2;
EBR3 F 0 A_Refire(1);
Goto FireThree;
EBR3 F 2;
EBR3 G 0 A_Refire(1);
Goto FireThree;
EBR3 G 2;
EBL4 A 0 A_Refire(1);
Goto FireThree;
EBL4 A 3 A_PlaySound("utrl/load",CHAN_WEAPON);
EBL4 B 0 A_Refire(1);
Goto FireThree;
EBL4 B 3;
EBL4 C 0 A_Refire(1);
Goto FireThree;
EBL4 C 3;
EBL4 D 0 A_Refire(1);
Goto FireThree;
EBL4 D 3;
EBL4 E 0 A_Refire(1);
Goto FireThree;
EBL4 E 3;
EBL4 F 0 A_Refire(1);
Goto FireThree;
EBL4 F 3;
EBL4 G 0 A_Refire(1);
Goto FireThree;
EBL4 G 3 A_LoadRocket();
EBR4 A 0 A_LoadedRefire(1);
Goto FireFour;
// load five
EBR4 A 2 A_PlaySound("utrl/rotate",CHAN_WEAPON,0.1);
EBR4 B 0 A_Refire(1);
Goto FireFour;
EBR4 B 2;
EBR4 C 0 A_Refire(1);
Goto FireFour;
EBR4 C 2;
EBR4 D 0 A_Refire(1);
Goto FireFour;
EBR4 D 2;
EBR4 E 0 A_Refire(1);
Goto FireFour;
EBR4 E 2;
EBR4 F 0 A_Refire(1);
Goto FireFour;
EBR4 F 2;
EBR4 G 0 A_Refire(1);
Goto FireFour;
EBR4 G 2;
EBL5 A 0 A_Refire(1);
Goto FireFour;
EBL5 A 3 A_PlaySound("utrl/load",CHAN_WEAPON);
EBL5 B 0 A_Refire(1);
Goto FireFour;
EBL5 B 3;
EBL5 C 0 A_Refire(1);
Goto FireFour;
EBL5 C 3;
EBL5 D 0 A_Refire(1);
Goto FireFour;
EBL5 D 3;
EBL5 E 0 A_Refire(1);
Goto FireFour;
EBL5 E 3;
EBL5 F 0 A_Refire(1);
Goto FireFour;
EBL5 F 3;
EBL5 G 0 A_Refire(1);
Goto FireFour;
EBL5 G 3 A_LoadRocket();
EBR5 A 0 A_LoadedRefire(1);
Goto FireFive;
// load six
EBR5 A 2 A_PlaySound("utrl/rotate",CHAN_WEAPON,0.1);
EBR5 B 0 A_Refire(1);
Goto FireFive;
EBR5 B 2;
EBR5 C 0 A_Refire(1);
Goto FireFive;
EBR5 C 2;
EBR5 D 0 A_Refire(1);
Goto FireFive;
EBR5 D 2;
EBR5 E 0 A_Refire(1);
Goto FireFive;
EBR5 E 2;
EBR5 F 0 A_Refire(1);
Goto FireFive;
EBR5 F 2;
EBR5 G 0 A_Refire(1);
Goto FireFive;
EBR5 G 2;
EBL6 A 0 A_Refire(1);
Goto FireFive;
EBL6 A 3 A_PlaySound("utrl/load",CHAN_WEAPON);
EBL6 B 0 A_Refire(1);
Goto FireFive;
EBL6 B 3;
EBL6 C 0 A_Refire(1);
Goto FireFive;
EBL6 C 3;
EBL6 D 0 A_Refire(1);
Goto FireFive;
EBL6 D 3;
EBL6 E 0 A_Refire(1);
Goto FireFive;
EBL6 E 3;
EBL6 F 0 A_Refire(1);
Goto FireFive;
EBL6 F 3 A_LoadRocket();
Goto FireSix;
FireOne:
EBF1 A 0 A_FireRockets(1);
EBF1 ABCDEFGH 2;
EBLI A 10;
Goto Idle;
FireTwo:
EBF2 A 0 A_FireRockets(2);
EBF2 ABCDEFGHIJK 2;
EBLI A 10;
Goto Idle;
FireThree:
EBF3 A 0 A_FireRockets(3);
EBF3 ABCDEFGHIJ 2;
EBLI A 10;
Goto Idle;
FireFour:
EBF4 A 0 A_FireRockets(4);
EBF4 ABCDEFGHIJK 2;
EBLI A 10;
Goto Idle;
FireFive:
EBF5 A 0 A_FireRockets(5);
EBF5 ABCDEFGHIJKLM 2;
EBLI A 10;
Goto Idle;
FireSix:
EBF6 A 0 A_FireRockets(6);
EBF6 ABCDEFGHIJKLMNOP 2;
EBLI A 10;
Goto Idle;
Deselect:
EBLD ABCDEFGHIJK 1;
EBLD K 1 A_Lower(int.max);
Wait;
}
}