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 10 Flak Shells.";
		Inventory.Amount 10;
		Inventory.MaxAmount 50;
		Ammo.BackpackAmount 20;
		Ammo.BackpackMaxAmount 50;
		Ammo.DropAmount 5;
	}
	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 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;
	bool hasbounced;
	Default
	{
		Obituary "%o was ripped to shreds by %k's Flak Cannon.";
		Radius 2;
		Height 0;
		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;
		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) )
		{
			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()
	{
		invoker.hasbounced = true;
		A_SprayDecal("WallCrack",-8);
		int numpt = Random[Flak](3,6);
		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.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;
		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] = 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';
		DamageFunction Random[Flak](60,80);
		Radius 2;
		Height 0;
		Speed 40;
		PROJECTILE;
		-NOGRAVITY;
		+SKYEXPLODE;
		+HITTRACER;
	}
	override void PostBeginPlay()
	{
		Super.PostBeginPlay();
		trail = ChunkTrail(Spawn("ChunkTrail",pos));
		trail.target = self;
		trail.speed = 1;
		vel.z += 5;
	}
	override void Tick()
	{
		Super.Tick();
		if ( waterlevel > 0 )
		{
			vel.xy *= 0.98;
			if ( trail ) trail.Destroy();
		}
	}
	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](40,60),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](10,20);
		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](20,40);
		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("UTChip",pos);
			s.vel = pvel;
		}
	}
	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+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](8,32);
			let s = Spawn("UTSpark",origin);
			s.vel = pvel;
			s.alpha *= 0.2;
		}
	}
	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++ )
		{
			Vector3 pvel = (x+(FRandom[Flak](-.8,.8),FRandom[Flak](-.8,.8),FRandom[Flak](-.8,.8))).unit()*FRandom[Flak](8,32);
			let s = Spawn("UTSpark",origin);
			s.vel = pvel;
			s.alpha *= 0.2;
		}
	}

	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;
	}
	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 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 2;
		FLKD J 1 A_Lower(int.max);
		Wait;
	MuzzleFlash:
		FMUZ A 3 Bright
		{
			let l = Spawn("FlakLight",pos);
			l.target = self;
		}
		Stop;
	}
}
