Added some extra particle effects just for kicks. Made various actors freeze-aware. Tweaked a couple things here and there.
542 lines
12 KiB
Text
542 lines
12 KiB
Text
Class FlakAmmo : Ammo
|
|
{
|
|
Default
|
|
{
|
|
Tag "Flak Shells";
|
|
Inventory.PickupMessage "You picked up 10 Flak Shells.";
|
|
Inventory.Amount 10;
|
|
Inventory.MaxAmount 50;
|
|
Ammo.BackpackAmount 50;
|
|
Ammo.BackpackMaxAmount 100;
|
|
Ammo.DropAmount 10;
|
|
}
|
|
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;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
FSLG A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class ChunkLight : DynamicLight
|
|
{
|
|
Default
|
|
{
|
|
DynamicLight.Type "Point";
|
|
Args 255,224,128,8;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( !target )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
if ( globalfreeze || level.frozen ) return;
|
|
args[LIGHT_RED] = 255*target.alpha;
|
|
args[LIGHT_GREEN] = 224*target.alpha;
|
|
args[LIGHT_BLUE] = 128*target.alpha;
|
|
}
|
|
}
|
|
|
|
Class ChunkTrail : Actor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
Radius 0.1;
|
|
Height 0;
|
|
+NOBLOCKMAP;
|
|
+NOGRAVITY;
|
|
+DONTSPLASH;
|
|
+FORCEXYBILLBOARD;
|
|
+INVISIBLE; // temporarily until clipping screwery is fixed
|
|
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;
|
|
A_SpawnParticle("FFFF00",SPF_FULLBRIGHT,1,8,startalphaf:alpha);
|
|
A_SpawnParticle("E0A000",SPF_FULLBRIGHT,1,16,startalphaf:alpha*0.6);
|
|
A_SpawnParticle("804000",SPF_FULLBRIGHT,1,32,startalphaf:alpha*0.3);
|
|
if ( InStateSequence(CurState,FindState("Death")) ) return;
|
|
if ( !target )
|
|
{
|
|
SetStateLabel("Death");
|
|
return;
|
|
}
|
|
SetOrigin(target.pos+(0,0,speed),true);
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
FGLO A 1 Bright;
|
|
Wait;
|
|
Death:
|
|
FGLO A 1 Bright A_FadeOut(0.1);
|
|
Wait;
|
|
}
|
|
|
|
}
|
|
|
|
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 4;
|
|
Height 4;
|
|
Speed 50;
|
|
DamageFunction Random[Flak](12,18);
|
|
DamageType 'Shredded';
|
|
BounceType "Doom";
|
|
BounceFactor 0.8;
|
|
PROJECTILE;
|
|
+USEBOUNCESTATE
|
|
-BOUNCEAUTOOFF
|
|
Scale 0.5;
|
|
}
|
|
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 = 0.5;
|
|
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;
|
|
lifetics++;
|
|
if ( lifetics > 3 )
|
|
{
|
|
lifetics = 0;
|
|
if ( frame < 11 ) frame++;
|
|
}
|
|
lifetime += lifespeed;
|
|
if ( (waterlevel <= 0) && (frame < 10) ) A_SpawnParticle("AAAAAA",0,35,2.0,velx:FRandom[Flak](-0.1,0.1),vely:FRandom[Flak](-0.1,0.1),velz:FRandom[Flak](-0.1,0.1),accelz:0.02,startalphaf:scale.x/0.5,sizestep:0.2);
|
|
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](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,4);
|
|
A_SpawnParticle("FFA000",SPF_FULLBRIGHT,Random[Flak](10,20),FRandom[Flak](1.2,3.6),0,0,0,0,pvel.x,pvel.y,pvel.z,0,0,0,3.0,-1,-0.25);
|
|
}
|
|
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.4,0.4),FRandom[Flak](-0.4,0.4),FRandom[Flak](-0.4,0.4))).unit()*vel.length();
|
|
A_PlaySound("flak/bounce",volume:0.3);
|
|
A_AlertMonsters();
|
|
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;
|
|
if ( waterlevel <= 0 ) A_SpawnParticle("AAAAAA",0,50,16.0,velx:FRandom[Flak](-0.5,0.5),vely:FRandom[Flak](-0.5,0.5),velz:FRandom[Flak](-0.5,0.5),accelz:0.05,startalphaf:scale.x,sizestep:1.0);
|
|
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] = 255*lifetime;
|
|
args[LIGHT_GREEN] = 224*lifetime;
|
|
args[LIGHT_BLUE] = 128*lifetime;
|
|
lifetime -= 0.05;
|
|
if ( lifetime <= 0 ) Destroy();
|
|
}
|
|
}
|
|
|
|
Class FlakSlug : Actor
|
|
{
|
|
ChunkTrail trail;
|
|
Default
|
|
{
|
|
Obituary "%o was ripped to shreds by %k's Flak Cannon.";
|
|
DamageType 'FlakDeath';
|
|
Radius 4;
|
|
Height 4;
|
|
Speed 40;
|
|
PROJECTILE;
|
|
-NOGRAVITY;
|
|
+SKYEXPLODE;
|
|
+FORCERADIUSDMG;
|
|
+HITTRACER;
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
trail = ChunkTrail(Spawn("ChunkTrail",pos));
|
|
trail.target = self;
|
|
trail.speed = 1;
|
|
vel.z += 5;
|
|
}
|
|
action void A_FlakExplode()
|
|
{
|
|
bForceXYBillboard = true;
|
|
A_SetRenderStyle(1.0,STYLE_Add);
|
|
A_SprayDecal("RocketBlast",150);
|
|
A_NoGravity();
|
|
A_SetScale(1.2);
|
|
A_Explode(Random[Flak](60,80),150);
|
|
A_QuakeEx(4,4,4,8,0,200,"",QF_RELATIVE|QF_SCALEDOWN,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<5; 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](40,80);
|
|
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);
|
|
A_SpawnParticle("FFA000",SPF_FULLBRIGHT,Random[Flak](20,40),FRandom[Flak](4.8,7.2),0,0,0,0,pvel.x,pvel.y,pvel.z,0,0,0,3.0,-1,-0.25);
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
FSLG A 1
|
|
{
|
|
for ( int i=0; i<6; i++ )
|
|
A_SpawnParticle("AAAAAA",0,50,12.0,velx:FRandom[Flak](-0.5,0.5),vely:FRandom[Flak](-0.5,0.5),velz:FRandom[Flak](-0.5,0.5),accelz:0.02,startalphaf:0.5,sizestep:1.0);
|
|
}
|
|
Wait;
|
|
Death:
|
|
EXP2 A 0 A_FlakExplode();
|
|
EXP2 ABCDEFGHIJKLMNOPQR 1 BRIGHT;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class FlakLight : DynamicLight
|
|
{
|
|
int cnt;
|
|
Default
|
|
{
|
|
DynamicLight.Type "Point";
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
args[LIGHT_INTENSITY] = 150;
|
|
args[LIGHT_RED] = 255;
|
|
args[LIGHT_GREEN] = 224;
|
|
args[LIGHT_BLUE] = 128;
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( !target )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
if ( target.player ) SetOrigin(target.pos+(0,0,target.player.viewheight),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_WEAPON);
|
|
}
|
|
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);
|
|
A_AlertMonsters();
|
|
A_QuakeEx(1,1,1,3,0,64,"",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+(0,0,player.viewheight)+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);
|
|
[x, y, z] = Matrix4.GetAxes(BulletSlope(),angle,roll);
|
|
Actor p;
|
|
for ( int i=0; i<8; 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++ )
|
|
{
|
|
Vector3 pvel = (x+(FRandom[Flak](-.8,.8),FRandom[Flak](-.8,.8),FRandom[Flak](-.8,.8))).unit()*FRandom[Flak](2,4);
|
|
A_SpawnParticle("FFA000",SPF_FULLBRIGHT,Random[Flak](10,20),FRandom[Flak](2.4,3.6),0,origin.x-pos.x,origin.y-pos.y,origin.z-pos.z,pvel.x,pvel.y,pvel.z,0,0,-0.1,3.0,-1,-0.25);
|
|
}
|
|
}
|
|
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);
|
|
A_AlertMonsters();
|
|
A_QuakeEx(2,2,2,6,0,64,"",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+(0,0,player.viewheight)+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++ )
|
|
{
|
|
Vector3 pvel = (x+(FRandom[Flak](-.8,.8),FRandom[Flak](-.8,.8),FRandom[Flak](-.8,.8))).unit()*FRandom[Flak](2,4);
|
|
A_SpawnParticle("FFA000",SPF_FULLBRIGHT,Random[Flak](10,20),FRandom[Flak](2.4,3.6),0,origin.x-pos.x,origin.y-pos.y,origin.z-pos.z,pvel.x,pvel.y,pvel.z,0,0,-0.1,3.0,-1,-0.25);
|
|
}
|
|
}
|
|
|
|
Default
|
|
{
|
|
Tag "Flak Cannon";
|
|
Inventory.PickupMessage "You got the Flak Cannon.";
|
|
Weapon.UpSound "flak/select";
|
|
Weapon.SlotNumber 8;
|
|
Weapon.AmmoType "FlakAmmo";
|
|
Weapon.AmmoUse 1;
|
|
Weapon.AmmoType2 "FlakAmmo";
|
|
Weapon.AmmoUse2 1;
|
|
Weapon.AmmoGive 10;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
FPCK A -1;
|
|
Stop;
|
|
FPCK B -1;
|
|
Stop;
|
|
Ready:
|
|
FLKS ABCDEFGHIJKLMNOPQRSTUVWXYZ 1;
|
|
FKS2 ABC 1;
|
|
FLKL A 1 A_Loading(true);
|
|
FLKL BCDEFGHIJKLMNO 1;
|
|
Goto Idle;
|
|
Loading:
|
|
FLKL A 1
|
|
{
|
|
A_CheckReload();
|
|
if ( invoker.Ammo1.Amount > 0 ) A_Loading();
|
|
}
|
|
FLKL BCDEFGHIJKLMNO 1;
|
|
Idle:
|
|
FLKI A 10;
|
|
FLKI A 1 A_WeaponReady();
|
|
Wait;
|
|
Fire:
|
|
FLKF A 1 A_FireChunks();
|
|
FLKF BCDEFGHIJ 1;
|
|
FLKF JJ 4;
|
|
Goto Loading;
|
|
AltFire:
|
|
FLKA A 1 A_FireSlug();
|
|
FLKA BCDEFGHIJK 2;
|
|
FLKA KKK 4;
|
|
Goto Loading;
|
|
Select:
|
|
FLKS A 1 A_Raise(int.max);
|
|
Wait;
|
|
Deselect:
|
|
FLKD ABCDEFGHIJ 2;
|
|
FLKD J 1 A_Lower(int.max);
|
|
Wait;
|
|
MuzzleFlash:
|
|
FMUZ A 3 Bright
|
|
{
|
|
let l = Spawn("FlakLight",pos);
|
|
l.target = self;
|
|
}
|
|
Stop;
|
|
}
|
|
}
|