

class RAMP2024CustomBehavior
{
	static play void SetPlayerStartingHealth(Actor player)
	{
		player.health = 35;
		player.player.health = 35;
		player.player.mo.health = 35;
	}
}

class UniversalSwayInjectorInterpolationDataRAMP2024
{
	static UniversalSwayInjectorInterpolationDataRAMP2024 make(Vector2 bob,Vector2 move)
	{
		UniversalSwayInjectorInterpolationDataRAMP2024 temp = new("UniversalSwayInjectorInterpolationDataRAMP2024");
		temp.bob=bob;
		temp.move=move;
		return temp;
	}
	Vector2 bob;
	Vector2 move;
}

class UniversalSwayInjectorRAMP2024 : Inventory
{
	FollowingSpotLightRAMP2024 light1;
	FollowingSpotLightRAMP2024 light2;
	FollowingPointLightRAMP2024 light3;
	
	//data
	double zbob;
	Vector2 prevbob;
	Vector2 nextbob;
	Vector2 prevmove;
	Vector2 nextmove;
	Array<UniversalSwayInjectorInterpolationDataRAMP2024> memory;

	const LOOKSCALE = 0.1;
	const CONST_MOVESCALE_Y = 0.5;
	
	override void DoEffect()
	{
		zbob = owner.player.bob * sin(Level.maptime / (20 * GameTicRate / 35.) * 360.) * (owner.waterlevel > 1 ? 0.25f : 0.5f);
		
		Vector2 temp = nextbob;
        
		nextbob = (-(owner.player.cmd.yaw / 16),(owner.player.cmd.pitch / 16));
		nextbob *= LOOKSCALE;
		nextbob *= 0.25;
		
        prevbob = temp;
		temp = nextmove;
		
        Vector2 mvec = RotateVector((owner.vel.y, owner.vel.x), owner.angle);
        
		nextmove.x = mvec.x;//x
		nextmove.y = mvec.y;//y
		nextmove.y += owner.vel.z;//z
		nextmove.y *= CONST_MOVESCALE_Y;
        
		prevmove = temp;
        
		UniversalSwayInjectorInterpolationDataRAMP2024 avg = memory_average();
        
		memory_add(UniversalSwayInjectorInterpolationDataRAMP2024.make(nextbob, nextmove));
		nextbob += avg.bob;
        
		nextmove.y = abs(nextmove.y);
        
		nextmove += avg.move;
	}
	
	override void AttachToOwner(Actor other)
	{
		super.AttachToOwner(other);
		light1 = FollowingSpotLightRAMP2024(other.Spawn("InnerLightRAMP2024")).Init(PlayerPawn(other));
		light2 = FollowingSpotLightRAMP2024(other.Spawn("OuterLightRAMP2024")).Init(PlayerPawn(other));
		light3 = FollowingPointLightRAMP2024(other.Spawn("AreaLightRAMP2024")).Init(PlayerPawn(other));
	}
	
	override void OnDestroy()
	{
		if(light1) light1.Destroy();
		if(light2) light2.Destroy();
		if(light3) light3.Destroy();
	}

	UniversalSwayInjectorInterpolationDataRAMP2024 memory_average()
	{
		UniversalSwayInjectorInterpolationDataRAMP2024 acc = UniversalSwayInjectorInterpolationDataRAMP2024.make((0, 0), (0, 0));

		for(int i = 0; i < memory.size(); i++)
		{
			acc.bob += memory[i].bob;
			acc.move.x += memory[i].move.x;
			acc.move.y += abs(memory[i].move.y);
		}
		
		acc.bob /= memory.size();
		acc.move /= memory.size();
		return acc;
	}

	void memory_add(UniversalSwayInjectorInterpolationDataRAMP2024 data)
	{
		if(memory.size() > 5)
		{
			memory.resize(4);
		}
		memory.insert(0,data);
	}
    
	void ClearInertia()
	{
		prevbob=(0,0);
		nextbob=(0,0);
		prevmove=(0,0);
		nextmove=(0,0);
		memory.clear();
	}
    
	Vector2 vec2lerp(Vector2 v1,Vector2 v2,double f)
	{
		return v1+f*(v2-v1);
	}
	
	override Vector2 ModifyBob(Vector2 orig_bob, double ticfrac)
	{
		Vector2 sway = vec2lerp(prevbob, nextbob, ticfrac);
		sway.y -= 5;
		
		sway.y = -sway.y;
		
		sway.y += zbob * 0.25;
		sway += vec2lerp(prevmove, nextmove, ticfrac);
        
        sway.y = max(sway.y, 0);
		return sway;
	}
}

mixin class FollowingLightRAMP2024
{
	Color light_color;
	
	float color_mult;
	int intensity;
	float inner;
	float outer;
	
	Property LightColor:light_color;
	Property Intensity:intensity;
	Property Mult:color_mult;
	
	PlayerPawn toFollow;
	
	Vector3 offset;
	
	void InitLight(PlayerPawn p)
	{
		toFollow = p;
		
		args[0] = light_color.r * color_mult;
		args[1] = light_color.g * color_mult;
		args[2] = light_color.b * color_mult;
		args[3] = intensity;
		
		double zBump = toFollow.height / 15.0;
		
		offset = (0, 0, zBump);
	}
	
	override void Tick() {
		A_SetAngle(toFollow.angle, SPF_INTERPOLATE);
		A_SetPitch(toFollow.pitch, SPF_INTERPOLATE);
		SetOrigin(toFollow.pos + (RotateVector((offset.x, offset.y),toFollow.angle - 90.0), toFollow.player.viewheight + offset.z), true);
		Super.Tick();
	}
}

class FollowingPointLightRAMP2024 : PointLight
{
	mixin FollowingLightRAMP2024;
	
	Default
	{
		+DynamicLight.NOSHADOWMAP;
		+NOINTERACTION;
		FollowingPointLightRAMP2024.LightColor "b4965a";
		FollowingPointLightRAMP2024.Mult 1;
	}
	
	FollowingPointLightRAMP2024 Init(PlayerPawn p)
	{
		InitLight(p);
		
		return self;
	}
}

class FollowingSpotLightRAMP2024 : SpotLight
{
	mixin FollowingLightRAMP2024;
	
	Default
	{
		+DynamicLight.NOSHADOWMAP;
		+NOINTERACTION;
		FollowingSpotLightRAMP2024.LightColor "b4965a";
		FollowingSpotLightRAMP2024.Mult 1;
	}
	
	FollowingSpotLightRAMP2024 Init(PlayerPawn p)
	{
		InitLight(p);
		
		return self;
	}
}

class InnerLightRAMP2024 : FollowingSpotLightRAMP2024
{
	Default
	{
		DynamicLight.SpotInnerAngle 8;
		DynamicLight.SpotOuterAngle 16;
		FollowingSpotLightRAMP2024.Intensity 300;
	}
}


class OuterLightRAMP2024 : FollowingSpotLightRAMP2024
{
	Default
	{
		DynamicLight.SpotInnerAngle 25;
		DynamicLight.SpotOuterAngle 50;
		FollowingSpotLightRAMP2024.Intensity 180;
	}
}


class AreaLightRAMP2024 : FollowingPointLightRAMP2024
{
	Default
	{
		FollowingPointLightRAMP2024.LightColor "ffff00";
		FollowingPointLightRAMP2024.Intensity 96;
		FollowingPointLightRAMP2024.Mult 0.33;
	}
}

class RedLightFlare : Actor
{
	Default
	{
		+NOINTERACTION;
		+FORCEXYBILLBOARD;
		+BRIGHT;
		Radius 5;
	}
	
	States
	{
		Spawn:
			FLAR A 1 A_SetTics(random[FlareRand](3,6));
			FLAR B 1 A_SetTics(random[FlareRand](2,3));
			Loop;
	}
}






















