Class GHAGThunderbolt : GHAGPokemonMove
{
	Default
	{
		Weapon.Slotnumber 3;
		
		Tag "Thunderbolt";
		Inventory.PickupMessage "Tada! Gardevoir learned \ckThunderbolt!"; // and thankfully didn't forget anything!
	}
	
	int charge;
	
	States
	{
		Spawn:
			TMEL A -1;
			stop;
		Select:
			HAND A 1 A_GHAGRaise();
			Loop;
		Deselect:
			HAND A 1 A_GHAGLower();
			Loop;
		Ready:
			HAND A 1 {
				A_WeaponReady(WRF_ALLOWUSER1);
				A_OverlaySpark();
			}
			Loop;
		Fire:
			TNT1 A 0
			{
				double anger = GHAGGardevoir(self).getRageValue();
				invoker.charge = 1000 / (anger >= 100 ? int(anger) : 100);
				invoker.charge = max(1, invoker.charge) * 2;
				A_StartSound("Attack/ThunderCharge", CHAN_AUTO);
			}
		Fire.Loop:
			THUN FGH 2
			{
				--invoker.charge;
				int rngrange = 2;
				A_OverlayOffset(0, random(-rngrange, rngrange), 43 + random(-rngrange, rngrange), WOF_INTERPOLATE);
			}
			TNT1 A 0 A_JumpIf(invoker.charge > 1, 'Fire.Loop');
			TNT1 A 0 {
				A_Thunderbolt();
				A_StartSound("Attack/Thunder", CHAN_AUTO);
			}
			HAND J 12 Offset(0, 5);
			TNT1 A 0 A_Refire();
			Goto Ready;
		Overlay.ThunSpark:
			SPRK AB 1 Bright A_SetTics(random(1, 3));
			TNT1 A 1 A_SetTics(random(1, 3));
			SPRK BC 1 Bright A_SetTics(random(1, 3));
			TNT1 A 1 A_SetTics(random(1, 3));
			SPRK CA 1 Bright A_SetTics(random(1, 3));
			TNT1 A 1 A_SetTics(random(1, 3));
			stop;
	}
	
	Action Void A_OverlaySpark()
	{
		A_Overlay(-1, "Overlay.ThunSpark", true);
	}
	
	Action Void A_Thunderbolt()
	{
		FLineTraceData shot;
		bool hit = GHAGGardevoir(self).LineTrace(GHAGGardevoir(self).angle, 4096, GHAGGardevoir(self).pitch, TRF_THRUBLOCK | TRF_NOSKY, GHAGGardevoir(self).height - 12, 0, 0, shot);
		if (hit)
		{
			if (shot.hitActor)
			{
				let bolt = GHAGThunderboltSpawn(Actor.spawn("GHAGThunderboltSpawn", shot.hitactor.pos));
			} 
			else 
			{
				let bolt = GHAGThunderboltSpawn(Actor.spawn("GHAGThunderboltSpawn", shot.hitLocation));
			}
			GHAGGardevoir(self).subtractAnger(150);
		}
	}
}

Class GHAGThunderboltSpawn : Actor
{
	int frame;

	States
	{
		Spawn:
			TNT1 A 0 NoDelay
			{
				A_StartSound("Attack/Thunder", CHAN_AUTO);
				invoker.frame = 0;
			}
			THUN ABCDE 2 Bright
			{
				let gardie = GHAGGardevoir(players[consoleplayer].mo);
				double modifier = gardie.getRageModifier();
				A_ThunderBlast(BF_AFFECTBOSSES | BF_NOIMPACTDAMAGE | BF_ONLYVISIBLETHINGS, Max(255 * modifier, 25), (64 + (512 * modifier)) * (double(invoker.frame) / 5), Max(64 * modifier, 8));
				++invoker.frame;
			}
			stop;
	}
	
	Action void A_ThunderBlast(int blastflags = 0, double strength = 255, double radius = 255, double speed = 20, class<Actor> blasteffect = "BlastEffect", sound blastsound = "BlastRadius")
	{
		A_StartSound (blastsound, CHAN_AUTO);

		if (!(blastflags & BF_DONTWARN))
		{
			SoundAlert (self);
		}
		ThinkerIterator it = ThinkerIterator.Create("Actor");
		Actor mo;
		while ( (mo = Actor(it.Next ())) )
		{
			//ignore player
			if (GHAGGardevoir(mo)) continue;
			if (mo == self || (mo.bBoss && !(blastflags & BF_AFFECTBOSSES)) || mo.bDormant || mo.bDontBlast)
			{ // Not a valid monster: originator, boss, dormant, or otherwise protected
				continue;
			}
			if (mo.bIceCorpse || mo.bCanBlast)
			{
				// Let these special cases go
			}
			else if (mo.bIsMonster && mo.health <= 0)
			{
				continue;
			}
			else if (!mo.player && !mo.bMissile && (!mo.bIsMonster && !BossBrain(mo)) && !mo.bCanBlast && !mo.bTouchy && !mo.bVulnerable)
			{	// Must be monster, player, missile, touchy or vulnerable
				continue;
			}
			if (Distance2D(mo) > radius)
			{ // Out of range
				continue;
			}
			if (mo.CurSector.PortalGroup != CurSector.PortalGroup && !CheckSight(mo))
			{
				// in another region and cannot be seen.
				continue;
			}
			if ((blastflags & 16) && !isVisible(mo, true)) 
			{
				//only blast if target can bee seen by calling actor
				continue;
			}
			A_MoonBlastActor(mo, strength, speed, blasteffect, !!(blastflags & BF_NOIMPACTDAMAGE));
		}
	}
	Action Void A_MoonBlastActor (Actor victim, double strength, double speed, Class<Actor> blasteffect, bool dontdamage)
	{
		if (!victim.SpecialBlastHandling (self, strength))
		{
			return;
		}

		double ang = AngleTo(victim);
		Vector2 move = AngleToVector(ang, speed);
		victim.Vel.XY = move;

		// Spawn blast puff
		ang -= 180.;
		Vector3 spawnpos = victim.Vec3Offset(
			(victim.radius + 1) * cos(ang),
			(victim.radius + 1) * sin(ang),
			(victim.Height / 2) - victim.Floorclip);
		Actor mo = blasteffect? Spawn (blasteffect, spawnpos, ALLOW_REPLACE) : null;
		if (mo)
		{
			mo.Vel.XY = victim.Vel.XY;
		}
		if (victim.bMissile)
		{
			// [RH] Floor and ceiling huggers should not be blasted vertically.
			if (!victim.bFloorHugger && !victim.bCeilingHugger)
			{
				victim.Vel.Z = 8;
				if (mo != null) mo.Vel.Z = 8;
			}
		}
		else
		{
			victim.Vel.Z = 1000. / victim.Mass;
		}
		if (victim.player)
		{
			// Players handled automatically
		}
		else if (!dontdamage)
		{
			victim.bBlasted = true;
		}
		if (victim.bTouchy)
		{ // Touchy objects die when blasted
			victim.bArmed = false; // Disarm
			victim.DamageMobj(self, self, victim.health, 'Melee', DMG_FORCED|DMG_EXPLOSION);
		} else {
			victim.DamageMobj(self, GHAGGardevoir(players[consoleplayer].mo), 128 + Int(strength), "Explosive");
			if (victim.health > 0) victim.SetStateLabel('Pain');
		}
	}
}