flak_m/zscript/flakcannon.zsc

635 lines
14 KiB
Text

Class Tier5Ammo : RandomSpawner2 replaces RocketAmmo
{
Default
{
DropItem "FlakAmmo2", 255, 1;
DropItem "UTRocketAmmo2", 255, 1;
}
}
Class Tier5Ammo2 : RandomSpawner2 replaces RocketBox
{
Default
{
DropItem "FlakAmmo", 255, 1;
DropItem "UTRocketAmmo", 255, 1;
}
}
Class Tier5Weapon : RandomSpawner2 replaces RocketLauncher
{
Default
{
DropItem "FlakCannon", 255, 1;
DropItem "UTRocketLauncher", 255, 1;
}
}
Class FlakAmmo : Ammo
{
Default
{
Tag "Flak Shells";
Inventory.PickupMessage "You picked up %d Flak Shells.";
Inventory.Amount 10;
Inventory.MaxAmount 50;
Ammo.BackpackAmount 20;
Ammo.BackpackMaxAmount 100;
Ammo.DropAmount 5;
}
override String PickupMessage()
{
return String.Format(pickupmsg,Amount);
}
States
{
Spawn:
FAMO A -1;
Stop;
}
}
Class FlakAmmo2 : FlakAmmo
{
Default
{
Tag "Flak Shell";
Inventory.PickupMessage "You picked up a Flak Shell.";
Inventory.Amount 1;
Ammo.DropAmount 1;
+INVENTORY.IGNORESKILL;
}
States
{
Spawn:
FSLG A -1;
Stop;
}
}
Class ChunkLight : DynamicLight
{
Default
{
DynamicLight.Type "Point";
Args 255,224,128,8;
}
override void Tick()
{
Super.Tick();
if ( !target )
{
Destroy();
return;
}
if ( globalfreeze || level.frozen ) return;
args[LIGHT_RED] = int(255*(10-target.frame)*0.1);
args[LIGHT_GREEN] = int(224*(10-target.frame)*0.1);
args[LIGHT_BLUE] = int(128*(10-target.frame)*0.1);
}
}
Class ChunkTrail : Actor
{
Default
{
RenderStyle "Add";
Radius 0.1;
Height 0;
+NOBLOCKMAP;
+NOGRAVITY;
+DONTSPLASH;
+FORCEXYBILLBOARD;
Scale 0.2;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
let l = Spawn("ChunkLight",pos);
l.target = self;
}
override void Tick()
{
Super.Tick();
if ( globalfreeze || level.frozen ) return;
if ( InStateSequence(CurState,FindState("Death")) ) return;
if ( !target )
{
int dist = FindState("Spawn").DistanceTo(CurState);
SetState(FindState("Death")+dist);
return;
}
SetOrigin(target.pos+(0,0,speed),true);
}
States
{
Spawn:
FGLO ABCDEFGHIJK 3 Bright;
Stop;
Death:
FGLO ABCDEFGHIJK 1 Bright;
Stop;
}
}
Class FlakChunk : Actor
{
Actor lasthit;
ChunkTrail trail;
double rollvel, pitchvel, yawvel;
double lifetime, lifespeed;
int lifetics;
Default
{
Obituary "%o was ripped to shreds by %k's Flak Cannon.";
Radius 2;
Height 2;
Speed 50;
DamageFunction int(Random[Flak](15,20)*max(0.1,1.0-lifetime*4.1));
DamageType 'Shredded';
BounceType "Doom";
BounceFactor 0.8;
WallBounceFactor 0.8;
PROJECTILE;
+USEBOUNCESTATE;
-BOUNCEAUTOOFF;
+CANBOUNCEWATER;
+SKYEXPLODE;
Scale 0.3;
}
override bool CanCollideWith( Actor other, bool passive )
{
return (vel.length()>4.0);
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
lifetime = 0;
lifespeed = FRandom[Flak](0.004,0.008);
trail = ChunkTrail(Spawn("ChunkTrail",pos));
trail.target = self;
trail.speed = 1.2;
rollvel = FRandom[Flak](50,100)*RandomPick[Flak](-1,1);
pitchvel = FRandom[Flak](50,100)*RandomPick[Flak](-1,1);
yawvel = FRandom[Flak](50,100)*RandomPick[Flak](-1,1);
scale *= Frandom[Flak](0.8,1.2);
SetState(ResolveState("Spawn")+Random[Flak](0,3));
}
override void Tick()
{
Super.Tick();
if ( globalfreeze || level.frozen ) return;
if ( waterlevel > 0 )
{
vel.xy *= 0.98;
rollvel *= 0.98;
pitchvel *= 0.98;
yawvel *= 0.98;
if ( trail ) trail.Destroy();
}
lifetics++;
if ( lifetics > 3 )
{
lifetics = 0;
if ( frame < 11 ) frame++;
}
lifetime += lifespeed;
if ( (waterlevel <= 0) && (frame < 10) && !(lifetics%2) )
{
let s = Spawn("UTSmoke",pos);
s.vel = (FRandom[Flak](-0.1,0.1),FRandom[Flak](-0.1,0.1),FRandom[Flak](-0.1,0.1));
s.alpha = scale.x/0.5;
s.SetShade("AAAAAA");
}
else if ( waterlevel > 0 )
{
let s = Spawn("UTBubble",pos);
s.vel = (FRandom[Flak](-0.1,0.1),FRandom[Flak](-0.1,0.1),FRandom[Flak](-0.1,0.1));
s.scale *= scale.x*0.5;
}
if ( trail ) trail.alpha = max(0,11-frame)/11.;
if ( InStateSequence(CurState,FindState("Death")) ) return;
A_SetRoll(roll+rollvel,SPF_INTERPOLATE);
A_SetPitch(pitch+pitchvel,SPF_INTERPOLATE);
A_SetAngle(angle+pitchvel,SPF_INTERPOLATE);
}
action void A_HandleBounce()
{
A_SprayDecal("WallCrack",-8);
int numpt = Random[Flak](2,3);
if ( frame < 10 )
{
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[Flak](-1,1),FRandom[Flak](-1,1),FRandom[Flak](-1,1)).unit()*FRandom[Flak](2,4);
let s = Spawn("UTSpark",pos);
s.vel = pvel;
}
}
A_Gravity();
invoker.rollvel = FRandom[Flak](50,100)*RandomPick[Flak](-1,1)*(vel.length()/speed);
invoker.pitchvel = FRandom[Flak](50,100)*RandomPick[Flak](-1,1)*(vel.length()/speed);
invoker.yawvel = FRandom[Flak](50,100)*RandomPick[Flak](-1,1)*(vel.length()/speed);
vel = (vel.unit()+(FRandom[Flak](-0.2,0.2),FRandom[Flak](-0.2,0.2),FRandom[Flak](-0.2,0.2))).unit()*vel.length();
A_PlaySound("flak/bounce",volume:0.3);
A_AlertMonsters();
bBOUNCEAUTOOFFFLOORONLY = true;
if ( vel.length() < 4.0 ) ExplodeMissile();
}
override int DoSpecialDamage( Actor target, int damage, Name damagetype )
{
if ( !target.bNOBLOOD )
{
if ( target != lasthit ) target.SpawnBlood(pos,AngleTo(target),damage);
A_PlaySound("flak/meat",volume:0.3);
A_AlertMonsters();
}
lasthit = target;
return damage;
}
States
{
Spawn:
FCH1 A 0;
Goto Idle;
FCH2 A 0;
Goto Idle;
FCH3 A 0;
Goto Idle;
FCH4 A 0;
Goto Idle;
Idle:
#### # -1;
Stop;
Bounce:
#### # 0 A_HandleBounce();
Goto Idle;
Death:
#### # 0
{
bMOVEWITHSECTOR = true;
A_SetTics(Random[Flak](30,50));
}
#### # 1
{
A_SetScale(scale.x-0.002);
if ( scale.x <= 0.0 ) Destroy();
}
Wait;
Crash:
TNT1 A 0
{
Spawn("BulletPuff",pos);
A_PlaySound("flak/hit",volume:0.3);
A_AlertMonsters();
}
XDeath:
TNT1 A 1;
Stop;
Dummy:
FCH1 ABCDEFGHIJKL -1;
FCH2 ABCDEFGHIJKL -1;
FCH3 ABCDEFGHIJKL -1;
FCH4 ABCDEFGHIJKL -1;
Stop;
}
}
Class SlugSmoke : Actor
{
double lifetime, lifespeed;
Default
{
Radius 0.1;
Height 0;
+NOBLOCKMAP;
+NOGRAVITY;
+DONTSPLASH;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
lifetime = 0;
lifespeed = FRandom[Flak](0.004,0.008);
}
override void Tick()
{
Super.Tick();
if ( globalfreeze || level.frozen ) return;
lifetime += lifespeed;
let s = Spawn("UTSmoke",pos);
s.vel = (FRandom[Flak](-0.5,0.5),FRandom[Flak](-0.5,0.5),FRandom[Flak](-0.5,0.5));
s.vel.z += 2.;
s.alpha = scale.x;
s.SetShade("AAAAAA");
scale.x = max(0,1-lifetime);
if ( scale.x <= 0 ) Destroy();
}
States
{
Spawn:
TNT1 A -1;
Stop;
}
}
Class SlugLight : DynamicLight
{
double lifetime;
Default
{
DynamicLight.Type "Point";
Args 255,224,128,80;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
lifetime = 1.0;
}
override void Tick()
{
Super.Tick();
if ( globalfreeze || level.frozen ) return;
args[LIGHT_RED] = int(255*lifetime);
args[LIGHT_GREEN] = int(224*lifetime);
args[LIGHT_BLUE] = int(128*lifetime);
lifetime -= 0.05;
if ( lifetime <= 0 ) Destroy();
}
}
Class FlakSlug : Actor
{
Default
{
Obituary "%o was ripped to shreds by %k's Flak Cannon.";
DamageType 'FlakDeath';
Radius 2;
Height 2;
Speed 40;
PROJECTILE;
-NOGRAVITY;
+SKYEXPLODE;
+EXPLODEONWATER;
+HITTRACER;
+FORCERADIUSDMG;
+NODAMAGETHRUST;
}
override void PostBeginPlay()
{
Super.PostBeginPlay();
vel.z += 4;
}
override void Tick()
{
Super.Tick();
if ( waterlevel > 0 ) vel.xy *= 0.98;
}
action void A_FlakExplode()
{
bForceXYBillboard = true;
A_SetRenderStyle(1.0,STYLE_Add);
A_SprayDecal("RocketBlast",50);
A_NoGravity();
A_SetScale(1.2);
UTMainHandler.DoBlast(self,120,75000);
A_Explode(Random[Flak](70,80),120);
A_QuakeEx(4,4,4,8,0,170,"",QF_RELATIVE|QF_SCALEDOWN,falloff:120,rollIntensity:0.2);
A_PlaySound("flak/explode",CHAN_VOICE);
A_AlertMonsters();
if ( !Tracer ) Spawn("SlugSmoke",pos);
Spawn("SlugLight",pos);
Vector3 x, y, z;
double a, s;
[x, y, z] = Matrix4.GetAxes(pitch,angle,roll);
Actor p;
for ( int i=0; i<6; i++ )
{
p = Spawn("FlakChunk",pos);
a = FRandom[Flak](0,360);
s = FRandom[Flak](0,0.2);
Vector3 dir = (x+y*cos(a)*s+z*sin(a)*s).unit();
p.angle = atan2(dir.y,dir.x);
p.pitch = -asin(dir.z);
p.vel = (cos(p.angle)*cos(p.pitch),sin(p.angle)*cos(p.pitch),-sin(p.pitch))*p.speed*FRandom[Flak](0.5,1.5);
p.target = target;
}
int numpt = Random[Flak](8,12);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[Flak](-1,1),FRandom[Flak](-1,1),FRandom[Flak](-1,1)).unit()*FRandom[Flak](2,8);
let s = Spawn("UTSpark",pos);
s.vel = pvel;
}
numpt = Random[Flak](15,30);
for ( int i=0; i<numpt; i++ )
{
Vector3 pvel = (FRandom[Flak](-1,1),FRandom[Flak](-1,1),FRandom[Flak](-1,1)).unit()*FRandom[Flak](6,16);
let s = Spawn("UTChip",pos);
s.vel = pvel;
s.scale *= FRandom[Flak](0.9,1.8);
}
}
States
{
Spawn:
FSLG A 1
{
for ( int i=0; i<6; i++ )
{
let s = Spawn("UTSmoke",pos);
s.vel = (FRandom[Flak](-0.5,0.5),FRandom[Flak](-0.5,0.5),FRandom[Flak](-0.5,0.5));
s.alpha = 0.5;
s.SetShade("AAAAAA");
}
}
Wait;
Death:
EXP2 A 0 A_FlakExplode();
EXP2 ABCDEFGHIJKLMNOPQR 1 BRIGHT;
Stop;
}
}
Class FlakLight : DynamicLight
{
int cnt;
Default
{
DynamicLight.Type "Point";
args 255,224,128,150;
}
override void Tick()
{
Super.Tick();
if ( !target )
{
Destroy();
return;
}
if ( target.player ) SetOrigin(target.Vec3Offset(0,0,target.player.viewz-target.pos.z),true);
else SetOrigin(target.pos,true);
if ( cnt++ > 2 ) Destroy();
}
}
Class FlakCannon : UTWeapon
{
action void A_Loading( bool first = false )
{
if ( first ) A_PlaySound("flak/load",CHAN_WEAPON);
else A_PlaySound("flak/reload",CHAN_6);
}
action void A_FireChunks()
{
Weapon weap = Weapon(invoker);
if ( !weap ) return;
if ( weap.Ammo1.Amount <= 0 ) return;
if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return;
A_PlaySound("flak/fire",CHAN_WEAPON);
invoker.FireEffect();
UTMainHandler.DoFlash(self,Color(160,255,96,0),1);
A_AlertMonsters();
A_QuakeEx(1,1,1,3,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.05);
Vector3 x, y, z;
double a, s;
[x, y, z] = Matrix4.GetAxes(pitch,angle,roll);
Vector3 origin = (pos.x,pos.y,player.viewz)+10.0*x+4.0*y-3.0*z;
A_Overlay(-2,"MuzzleFlash");
A_OverlayFlags(-2,PSPF_RENDERSTYLE|PSPF_FORCESTYLE,true);
A_OverlayRenderstyle(-2,STYLE_Add);
[x, y, z] = Matrix4.GetAxes(BulletSlope(),angle,roll);
Actor p;
for ( int i=0; i<10; i++ )
{
p = Spawn("FlakChunk",origin);
a = FRandom[Flak](0,360);
s = FRandom[Flak](0,0.2);
Vector3 dir = (x+y*cos(a)*s+z*sin(a)*s).unit();
p.angle = atan2(dir.y,dir.x);
p.pitch = -asin(dir.z);
p.vel = (cos(p.angle)*cos(p.pitch),sin(p.angle)*cos(p.pitch),-sin(p.pitch))*p.speed;
p.target = self;
}
int numpt = Random[Flak](20,30);
for ( int i=0; i<numpt; i++ )
{
let s = Spawn("UTViewSpark",origin);
UTViewSpark(s).ofs = (10,2,-3);
UTViewSpark(s).vvel = (FRandom[Flak](3,12),FRandom[Flak](-4,4),FRandom[Flak](-4,4));
s.target = self;
}
for ( int i=0; i<12; i++ )
{
let s = Spawn("UTViewSmoke",origin);
UTViewSmoke(s).ofs = (10,2,-3);
UTViewSmoke(s).vvel = (FRandom[Flak](0,1.2),FRandom[Flak](-.4,.4),FRandom[Flak](-.4,.4));
s.target = self;
s.scale *= 2.4;
s.alpha *= 0.5;
}
}
action void A_FireSlug()
{
Weapon weap = Weapon(invoker);
if ( !weap ) return;
if ( weap.Ammo1.Amount <= 0 ) return;
if ( !weap.DepleteAmmo(weap.bAltFire,true,1) ) return;
A_PlaySound("flak/altfire",CHAN_WEAPON);
invoker.FireEffect();
UTMainHandler.DoFlash(self,Color(128,255,96,0),1);
A_AlertMonsters();
A_QuakeEx(2,2,2,6,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:0.1);
Vector3 x, y, z;
double a, s;
[x, y, z] = Matrix4.GetAxes(pitch,angle,roll);
Vector3 origin = (pos.x,pos.y,player.viewz)+10.0*x+2.0*y-3.0*z;
A_Overlay(-2,"MuzzleFlash");
A_OverlayFlags(-2,PSPF_RENDERSTYLE|PSPF_FORCESTYLE,true);
A_OverlayRenderstyle(-2,STYLE_Add);
Actor p = Spawn("FlakSlug",origin);
p.angle = angle;
p.pitch = BulletSlope();
p.vel = (cos(p.angle)*cos(p.pitch),sin(p.angle)*cos(p.pitch),-sin(p.pitch))*p.speed;
p.target = self;
int numpt = Random[Flak](10,15);
for ( int i=0; i<numpt; i++ )
{
let s = Spawn("UTViewSpark",origin);
UTViewSpark(s).ofs = (10,2,-3);
UTViewSpark(s).vvel = (FRandom[Flak](3,12),FRandom[Flak](-4,4),FRandom[Flak](-4,4));
s.target = self;
}
for ( int i=0; i<16; i++ )
{
let s = Spawn("UTViewSmoke",origin);
UTViewSmoke(s).ofs = (10,2,-3);
UTViewSmoke(s).vvel = (FRandom[Flak](0,1.2),FRandom[Flak](-.8,.8),FRandom[Flak](-.8,.8));
s.target = self;
s.scale *= 2.4;
s.alpha *= 0.5;
}
}
Default
{
Tag "Flak Cannon";
Inventory.PickupMessage "You got the Flak Cannon.";
Weapon.UpSound "flak/select";
Weapon.SlotNumber 8;
Weapon.SelectionOrder 2;
Weapon.AmmoType "FlakAmmo";
Weapon.AmmoUse 1;
Weapon.AmmoType2 "FlakAmmo";
Weapon.AmmoUse2 1;
Weapon.AmmoGive 10;
UTWeapon.DropAmmo 5;
}
States
{
Spawn:
FPCK A -1;
Stop;
FPCK B -1;
Stop;
Ready:
FLKS ABDEGHJKMNPQSTVWYZ 1 A_WeaponReady(WRF_NOFIRE);
FKS2 BC 1 A_WeaponReady(WRF_NOFIRE);
FLKL A 1 A_Loading(true);
FLKL BCEFGIJKMNO 1;
Goto Idle;
Loading:
FLKL A 1
{
A_CheckReload();
if ( invoker.Ammo1.Amount > 0 ) A_Loading();
}
FLKL BCEFGIJKMNO 1;
Idle:
FLKI A 1 A_WeaponReady();
Wait;
Fire:
FLKF A 1 A_FireChunks();
FLKF BCDEFGHI 1;
FLKF J 4;
Goto Loading;
AltFire:
FLKA A 1 A_FireSlug();
FLKA BCDEFGHIJK 2;
FLKA K 4;
Goto Loading;
Select:
FLKS A 1 A_Raise(int.max);
Wait;
Deselect:
FLKD ABCDEFGHIJ 1;
FLKD J 1 A_Lower(int.max);
Wait;
MuzzleFlash:
FMUZ A 3 Bright
{
let l = Spawn("FlakLight",pos);
l.target = self;
}
Stop;
}
}