Class GHAGBlackHole : GHAGPokemonMove
{
	Default
	{
		Weapon.slotNumber 8;
		+Weapon.Ammo_Optional;
		+Weapon.No_Auto_Switch;
		Weapon.SelectionOrder 5000;
		+FloatBob;
		
		Tag "Black Hole";
		Inventory.PickupMessage "\cmBlack Hole.\c- The Demonlitionist learned this from me.";
	}
	
	int charge;
	double zoom;
	PointLight glowy;
	GHAGLightningFizzle fizzy;
	
	override void BeginPlay()
	{
		super.BeginPlay();
		
		charge = 0;
		zoom = 1;
	}
	
	states
	{
		Spawn:
			TMBH ABCDEDCB 5;
			Loop;
		Select:
			MPUN A 1 A_GHAGRaise();
			Loop;
		Deselect:
			MPUN A 1 A_GHAGLower();
			Loop;
		Ready.Failure:
			MPUN A 15;
		Ready:
			MPUN A 1 A_WeaponReady();
			Loop;
		Fire:
			TNT1 A 0
			{
				if (GHAGGardevoir(self).rageValue < 0)
				{
					A_StartSound("gardie/Pain", CHAN_AUTO, 0, 1, ATTN_NORM, 0.5);
					return resolveState('Ready.Failure');
				}
				return resolveState(null);
			}
			TNT1 A 0 A_StartSound("blackhole/POWERON", CHAN_WEAPON);
		Fire.BlackHoleCharge:
			HAND H 1;
			HAND H 0 A_ChargeBlackHole();
		Fire.release:
			TNT1 A 0 A_ZoomFactor(1);
			HAND K 48
			{
				A_Overlay(-1, "Fire.OverlayMirror");
				A_OverlayFlags(-1, PSPF_FLIP | PSPF_MIRROR, true);
			}
			goto Ready;
		Fire.HandOverlay:
			HAND H 1;
			stop;
		Fire.ChargeBlackHole:
			BLKH ABCDEFGHIJ 2 Bright;
			Stop;
		Fire.OverlayMirror:
			HAND K 48;
			stop;
		
	}
	
	Action State A_ChargeBlackHole()
	{
		invoker.charge += 10;
	
		int intensity = Int(10 * (double(invoker.charge) / 125));
		double scale = round((0.1 + (intensity * 0.1) * 80)) / 1000;
	
		if (invoker.charge < 1000)
		{
			GHAGGardevoir(self).subtractAnger(10, true);
			
			int rngrange = 2;
			A_Overlay(-1, "Fire.HandOverlay");
			A_OverlayOffset(0, random(-rngrange, rngrange), 43 + random(-rngrange, rngrange), WOF_INTERPOLATE);
			A_OverlayFlags(-1, PSPF_FLIP | PSPF_MIRROR, true);
			A_OverlayOffset(-1, random(-rngrange, rngrange), random(-rngrange, rngrange), WOF_INTERPOLATE);
			
			A_ZoomFactor(invoker.zoom -= 0.0025);
			
			A_Overlay(-2, "Fire.ChargeBlackHole", true);
			A_OverlayScale(-2, scale, scale);
			A_OverlayOffset(-2, 160, 100);
			A_OverlayPivot(-2);
			A_QuakeEx(intensity, intensity, intensity, 25, 0, invoker.charge, "", QF_SCALEDOWN);
			
			if (!invoker.glowy) {
				invoker.glowy = Pointlight(self.spawn("PointLight", self.pos));
				invoker.glowy.bSubtractive = true;
				invoker.glowy.bDontLightSelf = true;
				invoker.glowy.bNoShadowMap = true;
				invoker.glowy.args[0] = 0x6A * 3;
				invoker.glowy.args[1] = 0x06 * 3;
				invoker.glowy.args[2] = 0xAD * 3;
			}
			invoker.glowy.SetOrigin(self.pos, true);
			invoker.glowy.args[3] = Int(invoker.charge * 0.25);
			
			if (!invoker.fizzy)
			{
				invoker.fizzy = GHAGLightningFizzle(Self.spawn('GHAGLightningFizzle', self.pos));
			}
			
			return resolveState("Fire.BlackHoleCharge");
		}
		
		invoker.charge = 0;
		invoker.zoom = 1;
		
		let proj = SpawnPlayerMissile('GHAGBlackHoleProjectile', self.angle);
		if (proj)
		{
			proj.A_SetScale(scale * 2);
			GHAGBlackHoleProjectile(proj).glowy = invoker.glowy;
			GHAGBlackHoleProjectile(proj).fizzy = invoker.fizzy;
		}
	
		return resolveState(null);
	}
}

Class GHAGBlackHoleProjectile : Actor
{
	Default
	{
		Radius 5;
		Height 5;
		Speed 45;
		Projectile;
		+ThruActors;
		RenderStyle "Translucent";
		Alpha 0.9;
	}
	
	int life;
	double strength;
	double speed;
	double range;
	PointLight glowy;
	GHAGLightningFizzle fizzy;
	
	override void BeginPlay()
	{
		Super.BeginPlay();
		life = 4096;
		strength = -256;
		speed = 256;
		range = -256;
		
		A_StartSound("blackhole/MACHAMB", CHAN_AUTO, CHANF_LOOPING);
		A_StartSound("blackhole/ELECSUCK", CHAN_AUTO, CHANF_LOOPING);
	}
	
	override void Tick()
	{
		Super.tick();
		
		if (glowy)
		{
			glowy.SetOrigin(self.pos, true);
		}
		
		if (fizzy)
		{
			fizzy.SetOrigin(self.pos, true);
		}
	}
	
	States
	{
		Spawn:
			BLKH ABCDEFGHIJ 1 Bright A_BlackHoleDamage;
			Loop;
		Death:
			TNT1 A 0 A_QuakeEx(32, 32, 32, 35, 0, 4096);
		DeathLoop:
			BLKH ABCDEFGHIJ 1 Bright A_ImpactSuck();
			loop;
		ActualDeath:
			BLKH ABCDEFGHIJ 1 Bright A_FadeOut();
			loop;
	}
	
	Action void A_BlackHoleDamage()
	{
		ThinkerIterator it = ThinkerIterator.Create("Actor");
		Actor mo;
		
		if (gametic % 2 != 0) self.A_Blast(256, 256, 40);
		while ( (mo = Actor(it.Next ())) )
		{
			if (distance3D(mo) > 256) continue;
			if (mo.bIsMonster || mo.bMissile)
			{
				if (gametic % 2 == 0) mo.A_DamageSelf(999);
			}
		}
		
		let ball = self.spawn('GHAGBlackHoleTrail', self.pos);
		ball.A_SetScale(self.scale.x);
	}
	
	Action State A_ImpactSuck()
	{
		ThinkerIterator it = ThinkerIterator.Create("Actor");
		Actor mo;
		
		while ( (mo = Actor(it.Next ())) )
		{
			if (distance3D(mo) > abs(invoker.range * (invoker.range < 0 ? 4 : 1))) continue;
			if (mo is 'GHAGBlackHoleProjectile') continue;
			if (mo is "GHAGLightningFizzle" || mo is "GHAGFizzle") continue;
			if (mo.bIsMonster || mo.bMissile)
			{
				A_BlackHoleSuck(mo, invoker.speed); 
				
				mo.bSlidesOnWalls = true;
				
				if (distance3D(mo) < invoker.range / 2)
				{
					if (mo.bMissile)
					{
						switch (mo.getClassName())
						{
							case 'ArachnotronPlasma':
								mo.spawn("ArachnotronParticleProj", mo.pos);
								break;
							case 'BaronBall':
								mo.spawn("BruiserParticleProj", mo.pos);
								break;
							case 'CacodemonBall':
								mo.spawn("CacoParticleProj", mo.pos);
								break;
							case 'rocket':
								mo.spawn("RocketParticle", mo.pos);
								break;
							case 'FatShot':
								mo.spawn("FattyParticleProj", mo.pos);
								break;
							case 'RevenantTracer':
								mo.spawn("BonerParticleProj", mo.pos);
								break;
						}
						mo.destroy();
						invoker.life += 1;
					}
					else
					{
				
						mo.A_DamageSelf(25);
						if (invoker.speed < 0 && self.isVisible(mo, true))
						{
							if (!mo.bNoClip)
							{
								mo.bNoClip = true;
								self.A_SetScale(self.scale.x + 0.0005);
								
								if (invoker.glowy)
								{
									invoker.life += 10;
								}
							}
						}
					
						if (mo.tics <= -1)
						{
							switch (mo.getClassName())
							{
								case 'DoomImp':
									if (mo.health <= mo.gibhealth) mo.spawn("ImpParticleGib", mo.pos);
									else mo.spawn("ImpParticle", mo.pos);
									break;
								case 'Arachnotron':
									mo.spawn("ArachnotronParticle", mo.pos);
									break;
								case 'Demon':
									mo.spawn("PinkyParticle", mo.pos);
									break;
								case 'HellKnight':
									mo.spawn("KnightParticle", mo.pos);
									break;
								case 'BaronOfHell':
									mo.spawn("BaronParticle", mo.pos);
									break;
								case 'Cacodemon':
									mo.spawn("CacoParticle", mo.pos);
									break;
								case 'Cyberdemon':
									mo.spawn("CyberParticle", mo.pos);
									break;
								case 'ChaingunGuy':
									if (mo.health <= mo.gibhealth) mo.spawn("ChainParticleGib", mo.pos);
									else mo.spawn("ChainParticle", mo.pos);
									break;
								case 'Fatso':
									mo.spawn("FattyParticle", mo.pos);
									break;
								case 'LostSoul':
									mo.spawn("SoulParticle", mo.pos);
									break;
								case 'PainElemental':
									mo.spawn("PainParticle", mo.pos);
									break;
								case 'Revenant':
									mo.spawn("BonerParticle", mo.pos);
									break;
								case 'ShotgunGuy':
									if (mo.health <= mo.gibhealth) mo.spawn("ShottyParticleGib", mo.pos);
									else mo.spawn("ShottyParticle", mo.pos);
									break;
								case 'SpiderMastermind':
									mo.spawn("SpiderParticle", mo.pos);
									break;
								case 'WolfensteinSS':
									if (mo.health <= mo.gibhealth) mo.spawn("NaziParticleGib", mo.pos);
									else mo.spawn("NaziParticle", mo.pos);
									break;
								case 'Zombieman':
									if (mo.health <= mo.gibhealth) mo.spawn("ZombieParticleGib", mo.pos);
									else mo.spawn("ZombieParticle", mo.pos);
									break;
								case 'Archvile':
									mo.spawn("ArchvileParticle", mo.pos);
									break;
							}
							if (mo) mo.destroy();
						}
					}
				}
			}
			
			if (mo is "Inventory") {
				if (mo is "Key") continue;
				if (mo is "PowerUpGiver") continue;
				
				if (!mo.bNoClip && self.isVisible(mo, true))
				{
					mo.bNoClip = true;
				}
				
				A_BlackHoleSuck(mo, invoker.speed); 
				
				if (distance3D(mo) <= 64)
				{
					mo.touch(players[consoleplayer].mo);
					if (mo) {
						mo.destroy();
					}
				}
			}
		}
		
		if (invoker.speed > -96)
		{
			invoker.speed -= 8;
		}
		
		if (invoker.speed == 0)
		{
			invoker.range = 256;
			//invoker.speed = 16;
		}
		
		if (invoker.speed < 0.0)
		{
			invoker.range += 2 * (invoker.range < 0 ? 4 : 1);
		}
		
		invoker.life -= 1;
		
		if (invoker.life > 2048) invoker.life = 2048;
		
		if (invoker.life <= 0)
		{
			if (invoker.glowy) invoker.glowy.destroy();
			if (invoker.fizzy) invoker.fizzy.A_Clear();
			return resolveState('ActualDeath');
		}
		
		return resolveState(null);
	}
	
	action Void A_BlackHoleSuck (Actor victim, double speed)
	{
		double ang = AngleTo(victim);
		Vector2 move = AngleToVector(ang, speed * (invoker.range < 0 ? 4 : 1));
		victim.Vel.XY = move;
		if (invoker.range < 0) victim.vel.z = 32;
	}
}

Class GHAGBlackHoleTrail : Actor
{
	Default
	{
		+NoGravity;
	}
	
	States
	{
		Spawn:
			BLKH A 1 {
				A_FadeOut();
				A_SetScale(self.scale.x -= 0.1);
			}
			Loop;
	}
}

Class GHAGLightningFizzle : Actor
{
	Array<Actor> fizzies;
	
	States
	{
		Spawn :
			TNT1 A 1 NoDelay
			{
				invoker.fizzies.clear();
				for (int i = 0; i < 5; ++i)
				{
					invoker.fizzies.push(self.spawn('GHAGFizzle', self.pos));
				}
			}
		SpawnLoop:
			TNT1 A 1
			{
				for (int i = 0; i < invoker.fizzies.size(); ++i)
				{
						invoker.fizzies[i].setOrigin(self.pos, true);
				}
			}
			loop;
	}
	
	Action void A_Clear()
	{
		for (int i = 0; i < invoker.fizzies.size(); ++i)
		{
			invoker.fizzies[i].destroy();
		}
		self.destroy();
	}
}

Class GHAGFizzle : Actor
{
	default
	{
		+NoGravity;
		+RollSprite;
	}
	
	States
	{
		Spawn :
			LTNG A 2 Bright A_SetRoll(random(0, 359), SPF_INTERPOLATE);
			TNT1 A 0 A_SetTics(random(1, 15));
			LTNG B 2 Bright A_SetRoll(random(0, 359), SPF_INTERPOLATE);
			TNT1 A 0 A_SetTics(random(1, 15));
			LTNG C 2 Bright A_SetRoll(random(0, 359), SPF_INTERPOLATE);
			TNT1 A 0 A_SetTics(random(1, 15));
			loop;
	}
}

