Class UFlakBox : Ammo
{
	Default
	{
		Tag "$T_FLAKAMMO";
		Inventory.Icon "I_FlakAm";
		Inventory.PickupMessage "";
		Inventory.Amount 10;
		Inventory.MaxAmount 50;
		Ammo.BackpackAmount 5;
		Ammo.BackpackMaxAmount 100;
		Ammo.DropAmount 5;
	}
	override String PickupMessage()
	{
		if ( PickupMsg.Length() > 0 ) return Super.PickupMessage();
		return String.Format("%s%d%s",StringTable.Localize("$I_FLAKAMMOL"),Amount,StringTable.Localize("$I_FLAKAMMOR"));
	}
	States
	{
	Spawn:
		FAMO A -1;
		Stop;
	}
}

Class UFlakAmmo : UFlakBox
{
	Default
	{
		Tag "$T_FLAKAMMO2";
		Inventory.Icon "I_FlakAm";
		Inventory.PickupMessage "$I_FLAKAMMO2";
		Inventory.Amount 1;
		Ammo.DropAmount 1;
		+INVENTORY.IGNORESKILL;
	}
	States
	{
	Spawn:
		FAMO B -1;
		Stop;
	}
}

// subclass to save time, much of the behavior is the same anyway
Class UFlakChunk : FlakChunk
{
	override void PostBeginPlay()
	{
		Actor.PostBeginPlay();
		// no trail, spin much slower
		lifetime = 0;
		rollvel = FRandom[Flak](5,10)*RandomPick[Flak](-1,1);
		pitchvel = FRandom[Flak](5,10)*RandomPick[Flak](-1,1);
		yawvel = FRandom[Flak](5,10)*RandomPick[Flak](-1,1);
		scale *= Frandom[Flak](0.8,1.2);
		SetState(ResolveState("Spawn")+Random[Flak](0,3));
	}
	override void Tick()
	{
		oldvel = vel;
		Actor.Tick();
		if ( isFrozen() ) return;
		// no slowing down in water, only set to falling
		if ( waterlevel > 0 )
		{
			bNOGRAVITY = false;
			bAMBUSH = true;
		}
		lifetime += lifespeed;
		// no frame changes, smoke based on speed + age
		if ( (waterlevel <= 0) && !bAMBUSH && !(GetAge()%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*clamp((120-GetAge())/120.+(vel.length()/20.),0.5,2.0))/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 ( InStateSequence(CurState,FindState("Death")) ) return;
		roll += rollvel;
		pitch += pitchvel;
		angle += pitchvel;
	}
	Default
	{
		DamageFunction 17;	// exactly 1 point higher than UT
		Scale 0.5;
	}
	States
	{
	Bounce:
		#### # 0
		{
			A_HandleBounce();
			// override spin velocity changes from parent class
			rollvel = FRandom[Flak](5,10)*RandomPick[Flak](-1,1);
			pitchvel = FRandom[Flak](5,10)*RandomPick[Flak](-1,1);
			yawvel = FRandom[Flak](5,10)*RandomPick[Flak](-1,1);
		}
		Goto Idle;
	}
}

// Also subclassed to save time, only the explosion needs to change
Class UFlakSlug : FlakSlug
{
	action void A_UFlakExplode()
	{
		bForceXYBillboard = true;
		A_SetRenderStyle(1.0,STYLE_Add);
		A_SprayDecal("RocketBlast",50);
		A_NoGravity();
		A_SetScale(2.2);
		UTMainHandler.DoBlast(self,120,75000);
		A_Explode(70,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] = dt_CoordUtil.GetAxes(pitch,angle,roll);
		Actor p;
		Vector3 spawnofs;
		if ( BlockingMobj ) spawnofs = level.Vec3Diff(pos,BlockingMobj.Vec3Offset(0,0,BlockingMobj.height/2)).unit()*8;
		else if ( BlockingFloor ) spawnofs = BlockingFloor.floorplane.Normal*8;
		else if ( BlockingCeiling ) spawnofs = BlockingCeiling.ceilingplane.Normal*8;
		else if ( BlockingLine )
		{
			spawnofs = (-BlockingLine.delta.y,BlockingLine.delta.x,0).unit()*8;
			if ( !BlockingLine.sidedef[1] || (CurSector == BlockingLine.frontsector) )
				spawnofs *= -1;
		}
		for ( int i=0; i<5; i++ )
		{
			p = Spawn("UFlakChunk",Vec3Offset(spawnofs.x,spawnofs.y,spawnofs.z));
			p.bHITOWNER = true;
			a = FRandom[Flak](0,360);
			s = FRandom[Flak](0,0.1);
			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](-3,3));
			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
	{
	Death:
		FEXP A 0 A_UFlakExplode();
		FEXP ABCDEFGHIJ 2 BRIGHT;
		Stop;
	}
}

Class UFlakMag : FlakMag
{
}

Class UFlakCannon : UnrealWeapon
{
	action void A_Loading( bool first = false )
	{
		if ( first ) A_PlaySound("flak/load",CHAN_WEAPON,Dampener.Active(self)?.1:1.);
		else A_PlaySound("flak/reload",CHAN_6,Dampener.Active(self)?.06:.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,Dampener.Active(self)?.2:1.);
		A_Overlay(PSP_FLASH,"Flash");
		A_OverlayFlags(PSP_FLASH,PSPF_RenderStyle,true);
		A_OverlayRenderstyle(PSP_FLASH,STYLE_Add);
		invoker.FireEffect();
		UTMainHandler.DoFlash(self,Color(48,255,96,0),1);
		UTMainHandler.DoSwing(self,(FRandom[Flak](-0.3,-0.8),FRandom[Flak](-0.5,0.5)),4,-1.5,2,SWING_Spring,2,2);
		if ( !Dampener.Active(self) ) 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] = dt_CoordUtil.GetAxes(pitch,angle,roll);
		Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+5*y-4*z);
		[x, y, z] = dt_CoordUtil.GetAxes(BulletSlope(),angle,roll);
		Vector3 offsets[8];	// vanilla adds these to each chunk
		offsets[0] = (0,0,0);
		offsets[1] = -z;
		offsets[2] = 2*y+z;
		offsets[3] = -y;
		offsets[4] = 2*y-z;
		offsets[5] = (0,0,0);
		offsets[6] = y-z;
		offsets[7] = 2*y+z;
		Actor p;
		for ( int i=0; i<8; i++ )
		{
			p = Spawn("UFlakChunk",level.Vec3Offset(origin,offsets[i]));
			a = FRandom[Flak](0,360);
			s = FRandom[Flak](0,0.1);
			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](-3,3));
			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,5,-4);
			UTViewSpark(s).vvel = (FRandom[Flak](3,12),FRandom[Flak](-4,4),FRandom[Flak](-4,4));
			s.target = self;
		}
		for ( int i=0; i<10; i++ )
		{
			let s = Spawn("UTViewSmoke",origin);
			UTViewSmoke(s).ofs = (10,5,-4);
			UTViewSmoke(s).vvel = (FRandom[Flak](0,1.2),FRandom[Flak](-.4,.4),FRandom[Flak](-.4,.4));
			s.target = self;
			s.scale *= 1.6;
			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,Dampener.Active(self)?.2:1.);
		A_Overlay(PSP_FLASH,"Flash");
		A_OverlayFlags(PSP_FLASH,PSPF_RenderStyle,true);
		A_OverlayRenderstyle(PSP_FLASH,STYLE_Add);
		invoker.FireEffect();
		UTMainHandler.DoFlash(self,Color(32,255,96,0),1);
		UTMainHandler.DoSwing(self,(FRandom[Flak](-0.4,-0.8),FRandom[Flak](0.4,0.8)),4,-1,3,SWING_Spring,3,5);
		if ( !Dampener.Active(self) ) 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] = dt_CoordUtil.GetAxes(pitch,angle,roll);
		Vector3 origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),10*x+5*y-4*z);
		Actor p = Spawn("UFlakSlug",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,5,-4);
			UTViewSpark(s).vvel = (FRandom[Flak](3,12),FRandom[Flak](-4,4),FRandom[Flak](-4,4));
			s.target = self;
		}
		for ( int i=0; i<8; i++ )
		{
			let s = Spawn("UTViewSmoke",origin);
			UTViewSmoke(s).ofs = (10,5,-4);
			UTViewSmoke(s).vvel = (FRandom[Flak](0,1.2),FRandom[Flak](-.8,.8),FRandom[Flak](-.8,.8));
			s.target = self;
			s.scale *= 1.6;
			s.alpha *= 0.5;
		}
	}
	Default
	{
		Tag "$T_FLAKCANNON";
		Inventory.PickupMessage "$I_FLAKCANNON";
		Weapon.UpSound "flak/select";
		Weapon.SlotNumber 6;
		Weapon.SelectionOrder 1100;
		Weapon.SlotPriority 1;
		Weapon.AmmoType "UFlakBox";
		Weapon.AmmoUse 1;
		Weapon.AmmoType2 "UFlakBox";
		Weapon.AmmoUse2 1;
		Weapon.AmmoGive 10;
		UTWeapon.DropAmmo 5;
	}
	States
	{
	Spawn:
		FPCK A -1;
		Stop;
		FPCK B -1;
		Stop;
	Select:
		FLKS A 1 A_Raise(int.max);
		Wait;
	Ready:
		FLKS ABCDFGHIKLMNPQRSUVWXZ 1 A_WeaponReady(WRF_NOFIRE);
		FLS2 ABC 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;
		Goto Idle;
	Idle:
		FLKI A 1 A_WeaponReady();
		Wait;
	Fire:
		FLKF A 1 A_FireChunks();
		FLKF BCDEFGHI 1;
		FLKF J 5;
		FLKE A 1 A_PlaySound("flak/click",CHAN_6,Dampener.Active(self)?.05:.5);
		FLKE BCDEFGHIJKLMN 1;
		FLKE S 4
		{
			Vector3 x, y, z, origin;
			[x,y,z] = dt_CoordUtil.GetAxes(pitch,angle,roll);
			origin = level.Vec3Offset(Vec2OffsetZ(0,0,player.viewz),x*4.+y*3.-z*8.);
			let c = Spawn("UFlakMag",origin);
			c.angle = angle;
			c.pitch = pitch;
			c.vel = vel*.5+x*FRandom[Junk](-.8,.1)+y*FRandom[Junk](-.2,.2)-z*FRandom[Junk](1,2);
		}
		Goto Loading;
	AltFire:
		FLKA A 1 A_FireSlug();
		FLKA BCDEFGHIJK 1;
		FLKA K 10;
		Goto Loading;
	Deselect:
		FLKD A 0 A_JumpIfNoAmmo("Deselect2");
		FLKD ABCDEF 1;
		FLKD F 1 A_Lower(int.max);
		Wait;
	Deselect2:
		FLD2 ABCDEF 1;
		FLD2 F 1 A_Lower(int.max);
		Wait;
	Flash:
		FMUZ A 3 Bright
		{
			let l = Spawn("FlakLight",pos);
			l.target = self;
		}
		Stop;
	/*Flash:
		FLFF ABCDEFGHIJ 1 Bright;
		Stop;
	AltFlash:
		FLFA ABCDEF 1 Bright;
		Stop;*/
	}
}
