//WARNING: This file is a mess. It works, but it's a mess
//I do not condone this coding horror and do not encourage its use

//Base projectile for nearly all enemy projectiles
class BabelFastProjectile : FastProjectile
{
	//Up to 3 randomly selected colors may be used for a trail
	Color particleColor1;
	Color particleColor2;
	Color particleColor3;
	
	//size of particles, range between first and second element
	int minSize;
	int maxSize;
	
	//lifetime of particles in tics, range between first and second element
	int minLifetime;
	int maxLifetime;
	
	int particleCounter;
	
	//what kind of offsets along the normal plane are allowed? X and Y values
	double cubeOffsetLow;
	double cubeOffsetHigh;
	
	//what kind of velocities along normal plane are allowed? X and Y values
	double cubeVelocityLow;
	double cubeVelocityHigh;
	
	//what kind of accelerations along normal plane are allowed? X and Y values
	double cubeAccelerationLow;
	double cubeAccelerationHigh;
	
	double lerpOffset; //adjusts where trail starts and ends to avoid drawing trail inside of projectile
	
	double trailDetail; //affects per-projectile trail detail. Higher = more particles
	double heightCorrection; //some projectile origins are not centered. Use this to correct
	double density; //CVar for trail detail stored here
	double startingAlpha; //self-explanatory, starting alpha for particle trails
	bool trailSpawn; //set this to false once the projectile is supposed to stop spawning particles, usually done in Death state
	bool doParticles; //CVar for particle toggle goes here
	bool finalTrail; //internal switch to know when we've drawn the final piece of the trail
	
	bool variableDirection; //Does this projectile change direction or velocity mid-flight? If so, set this to true
	Vector3 previousPosition; //Used for variable-direction projectile trails
	
	Vector3 velStore; //Possible optimization for non-homing projectiles
	
	property ParticleColors: particleColor1, particleColor2, particleColor3;
	property ParticleSizeRange: minSize, maxSize;
	property ParticleLifeTime: minLifetime, maxLifetime;
	property ParticleCubeOffsets: cubeOffsetLow, cubeOffsetHigh;
	property ParticleCubeVelocities: cubeVelocityLow, cubeVelocityHigh;
	property ParticleCubeAccelerations: cubeAccelerationLow, cubeAccelerationHigh;
	property LerpOffset: lerpOffset;
	property TrailDetail: trailDetail;
	property HeightCorrection: heightCorrection;
	property VariableDirection: variableDirection;
	property StartingAlpha: startingAlpha;
	
	default
	{
		BabelFastProjectile.ParticleColors 0x000000, 0x000000, 0x000000;
		BabelFastProjectile.ParticleSizeRange 1, 1;
		BabelFastProjectile.ParticleLifeTime 35, 35;
		BabelFastProjectile.ParticleCubeOffsets 1, 1;
		BabelFastProjectile.ParticleCubeVelocities 0, 0;
		BabelFastProjectile.ParticleCubeAccelerations 0.1, 0.1;
		BabelFastProjectile.LerpOffset 0.0;
		BabelFastProjectile.TrailDetail 1;
		BabelFastProjectile.HeightCorrection 0.0;
		BabelFastProjectile.StartingAlpha 0.98;
		BabelFastProjectile.VariableDirection false;
	}
	
	//Initialize ALL variable to sane defaults
	//Most will be overridden in derived classes
	override void BeginPlay()
	{
		super.BeginPlay();
		density = CVar.FindCVar("egr_particle_density").GetInt();
		doParticles = (CVar.FindCVar("egr_particle_toggle").GetInt() == 1);
		trailSpawn = true;
		finalTrail = false;
	}
	
	/* Copy this def into each projectile and set it up, erase anything you didn't change
	
	override void BeginPlay()
	{
		super.BeginPlay();
		heightCorrection = 0.0;
		lerpOffset = 0.0;
		trailDetail = 10;
		particleColor1 = Color(255, 255, 255, 255);
		particleColor2 = Color(255, 255, 255, 255); 
		particleColor3 = Color(255, 255, 255, 255); 
		minSize = 1;
		maxSize = 1;
		minLifetime = 35;
		maxLifetime = 35;
		cubeOffsetLow = 1;
		cubeOffsetHigh = 1;
		cubeVelocityLow = 0;
		cubeVelocityHigh = 0;
		cubeAccelerationLow = 0.1;
		cubeAccelerationHigh = 0.1;
		startingAlpha = 0.98;
		trailSpawn = true;
		variableDirection = false;
	}
	
	*/
	
	action void A_SetBFPHeightCorrectionLerpOffset(double hc, double lo)
	{
		invoker.heightCorrection = hc;
		invoker.lerpOffset = lo;
	}
	
	action void A_SetBFPTrailDetail(double detail)
	{
		invoker.trailDetail = detail;
	}
	
	action void A_SetBFPParticleColors(Color c1, Color c2, Color c3)
	{
		invoker.particleColor1 = c1;
		invoker.particleColor2 = c2; 
		invoker.particleColor3 = c3;
	}
	
	action void A_SetBFPParticleSizeRange(int minSize, int maxSize)
	{
		invoker.minSize = minSize;
		invoker.maxSize = maxSize;
	}
	
	action void A_SetBFPParticleLifetimeRange(int minTime, int maxTime)
	{
		invoker.minLifetime = minTime;
		invoker.maxLifetime = maxTime;
	}
	
	action void A_SetBFPCubeOffset(double minOffset, double maxOffset)
	{
		invoker.cubeOffsetLow = minOffset;
		invoker.cubeOffsetHigh = maxOffset;
	}
	
	action void A_SetBFPCubeVelocity(double minVelocity, double maxVelocity)
	{
		invoker.cubeVelocityLow = minVelocity;
		invoker.cubeVelocityHigh = maxVelocity;
	}
	
	action void A_SetBFPCubeAccel(double minAccel, double maxAccel)
	{
		invoker.cubeAccelerationLow = minAccel;
		invoker.cubeAccelerationHigh = maxAccel;
	}
	
	//Basically just a shorthand for the other 3
	action void A_SetBFPCubeParams(double minOffset, double maxOffset, double minVelocity, double maxVelocity, double minAccel, double maxAccel)
	{
		invoker.cubeOffsetLow = minOffset;
		invoker.cubeOffsetHigh = maxOffset;
		invoker.cubeVelocityLow = minVelocity;
		invoker.cubeVelocityHigh = maxVelocity;
		invoker.cubeAccelerationLow = minAccel;
		invoker.cubeAccelerationHigh = maxAccel;
	}
	
	action void A_SetBFPStartingAlpha(double alpha)
	{
		invoker.startingAlpha = alpha;
	}
	
	action void A_SetBFPTrailSpawn(bool b)
	{
		invoker.trailSpawn = b;
	}
	
	action void A_SetBFPVariableDirection(bool b)
	{
		invoker.variableDirection = b;
	}
	
	action void A_InflictSelfFear(int amount)
	{
		BabelLib.InflictFear(invoker, "BabelMonster", amount);
	}
	
	//Set up an optimization for making nice trails
	override void PostBeginPlay()
	{
		//Initialize our previous position
		velStore = self.vel;
		if(variableDirection)
		{
			previousPosition = self.pos;
		}
		super.PostBeginPlay();
	}
	override void Tick()
	{
		super.Tick();
		//if (level.frozen || globalfreeze) return; Deprecated since 3.8
		if(doParticles)
		{
			if(level.isFrozen() > 0) return; //Do not do ANYTHING in here when frozen
			//Draw fancy effects, god help us all
			if(trailSpawn)
			{
				//Draw the trail at a certain density from a point reasonably outside the projectile (lerpOffset) to the appropriate end poing
				for (double i = 0+lerpOffset; i < 1.0+lerpOffset; i+=1.0/(trailDetail+density))//(self.radius/self.speed)//-(self.radius/self.speed)
				{
					//if we somehow overshoot, correct to the expected maximum
					if(i > 1.0+lerpOffset)
					{
						i = 1.0+lerpOffset;
					}
					//If we know our vector will not change, we can do nicer trails since they're purely linear by lerping along our velocity
					if(!variableDirection)
					{
						A_SpawnParticle (
							randompick(particleColor1, particleColor2, particleColor3), 		//color
							SPF_FULLBRIGHT, 					//flags
							random(minLifetime, maxLifetime), 	//lifetime
							random(minSize,maxSize),  			//size
							frandom(0,360),			   			//angle
							
							BabelLib.Lerp(-velStore.x*0.5, -velStore.x*1.5, i)+frandom(-cubeOffsetLow, cubeOffsetHigh),						 //xpos
							BabelLib.Lerp(-velStore.y*0.5, -velStore.y*1.5, i)+frandom(-cubeOffsetLow, cubeOffsetHigh),						 //ypos
							BabelLib.Lerp(-velStore.z*0.5, -velStore.z*1.5, i)+frandom(-cubeOffsetLow, cubeOffsetHigh)+heightCorrection,      //zpos
							
							frandom(-cubeVelocityLow, cubeVelocityHigh), 	 	       //xvel
							frandom(-cubeVelocityLow, cubeVelocityHigh), 			   //yvel
							frandom(-cubeVelocityLow, cubeVelocityHigh),             //zvel
							
							frandom(-cubeAccelerationLow, cubeAccelerationHigh),      //xacc
							frandom(-cubeAccelerationLow, cubeAccelerationHigh),      //yacc
							frandom(-cubeAccelerationLow, cubeAccelerationHigh), 	 //zacc
							
							0.98, 					   //startalpha
							-1)					 	   //fadespeed
							;
					}
					//if not, we have to use our previous position and lerp along that (could do bezier but why? Lag for nothing)
					else
					{
						//God why do I do this to myself, fix for homing rounds, fuck.
						A_SpawnParticle (
							randompick(particleColor1, particleColor2, particleColor3), 		//color
							SPF_FULLBRIGHT, 					//flags
							random(minLifetime, maxLifetime), 	//lifetime
							random(minSize,maxSize),  			//size
							frandom(0,360),			   			//angle
							
							BabelLib.Lerp(pos.x - previousPosition.x, 0, i)+frandom(-cubeOffsetLow, cubeOffsetHigh),						 //xpos
							BabelLib.Lerp(pos.y - previousPosition.y, 0, i)+frandom(-cubeOffsetLow, cubeOffsetHigh),						 //ypos
							BabelLib.Lerp(pos.z - previousPosition.z, 0, i)+frandom(-cubeOffsetLow, cubeOffsetHigh)+heightCorrection,      //zpos
							
							frandom(-cubeVelocityLow, cubeVelocityHigh), 	 	       //xvel
							frandom(-cubeVelocityLow, cubeVelocityHigh), 			   //yvel
							frandom(-cubeVelocityLow, cubeVelocityHigh),             //zvel
							
							frandom(-cubeAccelerationLow, cubeAccelerationHigh),      //xacc
							frandom(-cubeAccelerationLow, cubeAccelerationHigh),      //yacc
							frandom(-cubeAccelerationLow, cubeAccelerationHigh), 	 //zacc
							
							0.98, 					   //startalpha
							-1)					 	   //fadespeed
							;
						previousPosition = self.pos;
					}
				}
				
			}
			//One we hit something, lerp from last known point to impact point
			else if(!trailSpawn && !finalTrail)
			{
				for (double i = 0; i < 1.0+lerpOffset; i+=1.0/(trailDetail+density))
				{
					if(i > 1.0+lerpOffset)
					{
						i = 1.0+lerpOffset;
					}
					if(!variableDirection)
					{
						A_SpawnParticle (
							randompick(particleColor1, particleColor2, particleColor3), 		//color
							SPF_FULLBRIGHT, 					//flags
							random(minLifetime, maxLifetime), 	//lifetime
							random(minSize,maxSize),  			//size
							frandom(0,360),			   			//angle
							
							BabelLib.Lerp(0, -velStore.x, i)+frandom(-cubeOffsetLow, cubeOffsetHigh),						 //xpos
							BabelLib.Lerp(0, -velStore.y, i)+frandom(-cubeOffsetLow, cubeOffsetHigh),						 //ypos
							BabelLib.Lerp(0, -velStore.z, i)+frandom(-cubeOffsetLow, cubeOffsetHigh)+heightCorrection,      //zpos
							
							frandom(-cubeVelocityLow, cubeVelocityHigh), 	 	       //xvel
							frandom(-cubeVelocityLow, cubeVelocityHigh), 			   //yvel
							frandom(-cubeVelocityLow, cubeVelocityHigh),             //zvel
							
							frandom(-cubeAccelerationLow, cubeAccelerationHigh),      //xacc
							frandom(-cubeAccelerationLow, cubeAccelerationHigh),      //yacc
							frandom(-cubeAccelerationLow, cubeAccelerationHigh), 	 //zacc
							
							0.98, 					   //startalpha
							-1)					 	   //fadespeed
							;
					}
					else
					{
						A_SpawnParticle (
							randompick(particleColor1, particleColor2, particleColor3), 		//color
							SPF_FULLBRIGHT, 					//flags
							random(minLifetime, maxLifetime), 	//lifetime
							random(minSize,maxSize),  			//size
							frandom(0,360),			   			//angle
							
							BabelLib.Lerp(pos.x - previousPosition.x, 0, i)+frandom(-cubeOffsetLow, cubeOffsetHigh),						 //xpos
							BabelLib.Lerp(pos.y - previousPosition.y, 0, i)+frandom(-cubeOffsetLow, cubeOffsetHigh),						 //ypos
							BabelLib.Lerp(pos.z - previousPosition.z, 0, i)+frandom(-cubeOffsetLow, cubeOffsetHigh)+heightCorrection,      //zpos
							
							frandom(-cubeVelocityLow, cubeVelocityHigh), 	 	       //xvel
							frandom(-cubeVelocityLow, cubeVelocityHigh), 			   //yvel
							frandom(-cubeVelocityLow, cubeVelocityHigh),             //zvel
							
							frandom(-cubeAccelerationLow, cubeAccelerationHigh),      //xacc
							frandom(-cubeAccelerationLow, cubeAccelerationHigh),      //yacc
							frandom(-cubeAccelerationLow, cubeAccelerationHigh), 	 //zacc
							
							0.98, 					   //startalpha
							-1)					 	   //fadespeed
							;
						previousPosition = self.pos;
					}
				}
				finalTrail = true;
			}
			else if(finalTrail)
			{
				//This did something once, but I cannot remember what
			}
		}
	}
}