Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Code/EeveeHelper.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<AssemblyName>EeveeHelper</AssemblyName>
<RootNamespace>Celeste.Mod.EeveeHelper</RootNamespace>
<LangVersion>latest</LangVersion>
Expand Down
11 changes: 6 additions & 5 deletions Code/EeveeHelperModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public override void Load()
PatientBooster.Load();
CoreZone.Load();

Everest.Events.Level.OnLoadBackdrop += this.OnLoadBackdrop;
Everest.Events.Level.OnLoadBackdrop += OnLoadBackdrop;

EntityHandler.RegisterInherited<Water>((entity, container) => new WaterHandler(entity));
EntityHandler.RegisterInherited<TrackSpinner>((entity, container) => new TrackSpinnerHandler(entity));
Expand All @@ -64,6 +64,8 @@ public override void Unload()
HoldableTiles.Unload();
PatientBooster.Unload();
CoreZone.Unload();

Everest.Events.Level.OnLoadBackdrop -= OnLoadBackdrop;
}

public override void Initialize()
Expand Down Expand Up @@ -105,12 +107,11 @@ public override void Initialize()
}
}

private Backdrop OnLoadBackdrop(MapData map, BinaryPacker.Element child, BinaryPacker.Element above)
private static Backdrop OnLoadBackdrop(MapData map, BinaryPacker.Element child, BinaryPacker.Element above)
{
if (child.Name.Equals("EeveeHelper/SeededStarfield", StringComparison.OrdinalIgnoreCase))
{
return new SeededStarfield(Calc.HexToColor(child.Attr("color")), child.AttrFloat("speed", 1f), child.AttrInt("seed"));
}
return new SeededStarfield(Calc.HexToColor(child.Attr("color", "ffffff")) * child.AttrFloat("alpha", 1f), child.AttrFloat("speed", 1f), child.AttrInt("seed", 0), child.Attr("textureDir", "particles/starfield"));

return null;
}

Expand Down
90 changes: 45 additions & 45 deletions Code/Effects/SeededStarfield.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
using System.Collections.Generic;

namespace Celeste.Mod.EeveeHelper.Effects;

public class SeededStarfield : Backdrop
{
public struct Star
private struct Star
{
public MTexture Texture;
public Vector2 Position;
Expand All @@ -17,15 +18,16 @@ public struct Star
public float Sine;
}

public const int StepSize = 32;
public const int Steps = 15;
public const float MinDist = 4f;
public const float MaxDist = 24f;
public float FlowSpeed;
public List<float> YNodes = new();
public Star[] Stars = new Star[128];
private const int NodeDistance = 32;
private const int NodeCount = 15;
private const float MinDist = 4f;
private const float MaxDist = 24f;

private readonly float FlowSpeed;
private readonly List<float> YNodes = [];
private readonly Star[] Stars = new Star[128];

public SeededStarfield(Color color, float speed = 1f, int seed = 0)
public SeededStarfield(Color color, float speed = 1f, int seed = 0, string textureDir = "particles/starfield")
{
Color = color;
FlowSpeed = speed;
Expand All @@ -35,31 +37,30 @@ public SeededStarfield(Color color, float speed = 1f, int seed = 0)
Calc.PushRandom(seed);
}

var num = Calc.Random.NextFloat(180f);
var num2 = 0;
while (num2 < 15)
float starY = Calc.Random.NextFloat(180f);
for (int i = 0; i < NodeCount; i++)
{
YNodes.Add(num);
num2++;
num += Calc.Random.Choose(-1, 1) * (16f + Calc.Random.NextFloat(24f));
YNodes.Add(starY);
starY += Calc.Random.Choose(-1, 1) * (16f + Calc.Random.NextFloat(24f));
}
for (var i = 0; i < 4; i++)

for (int i = 0; i < 4; i++)
{
YNodes[YNodes.Count - 1 - i] = Calc.LerpClamp(YNodes[YNodes.Count - 1 - i], YNodes[0], 1f - i / 4f);
}

var atlasSubtextures = GFX.Game.GetAtlasSubtextures("particles/starfield/");
for (var j = 0; j < Stars.Length; j++)
var atlasSubtextures = GFX.Game.GetAtlasSubtextures(textureDir + "/");
for (int i = 0; i < Stars.Length; i++)
{
var num3 = Calc.Random.NextFloat(1f);
Stars[j].NodeIndex = Calc.Random.Next(YNodes.Count - 1);
Stars[j].NodePercent = Calc.Random.NextFloat(1f);
Stars[j].Distance = 4f + num3 * 20f;
Stars[j].Sine = Calc.Random.NextFloat((float)Math.PI * 2f);
Stars[j].Position = GetTargetOfStar(ref Stars[j]);
Stars[j].Color = Color.Lerp(Color, Color.Transparent, num3 * 0.5f);
var index = (int)Calc.Clamp(Ease.CubeIn(1f - num3) * atlasSubtextures.Count, 0f, atlasSubtextures.Count - 1);
Stars[j].Texture = atlasSubtextures[index];
float smallness = Calc.Random.NextFloat(1f);
Stars[i].NodeIndex = Calc.Random.Next(YNodes.Count - 1);
Stars[i].NodePercent = Calc.Random.NextFloat(1f);
Stars[i].Distance = MinDist + smallness * (MaxDist - MinDist);
Stars[i].Sine = Calc.Random.NextFloat((float)Math.PI * 2f);
Stars[i].Position = GetTargetOfStar(ref Stars[i]);
Stars[i].Color = Color.Lerp(Color, Color.Transparent, smallness * 0.5f);
int textureIndex = (int)Calc.Clamp(Ease.CubeIn(1f - smallness) * atlasSubtextures.Count, 0f, atlasSubtextures.Count - 1);
Stars[i].Texture = atlasSubtextures[textureIndex];
}

if (seed != 0)
Expand All @@ -71,7 +72,7 @@ public SeededStarfield(Color color, float speed = 1f, int seed = 0)
public override void Update(Scene scene)
{
base.Update(scene);
for (var i = 0; i < Stars.Length; i++)
for (int i = 0; i < Stars.Length; i++)
{
UpdateStar(ref Stars[i]);
}
Expand All @@ -88,37 +89,36 @@ private void UpdateStar(ref Star star)
if (star.NodeIndex >= YNodes.Count - 1)
{
star.NodeIndex = 0;
star.Position.X -= 448f;
star.Position.X -= (NodeCount - 1) * NodeDistance;
}
}
star.Position += (GetTargetOfStar(ref star) - star.Position) / 50f;
}

private Vector2 GetTargetOfStar(ref Star star)
{
var vector = new Vector2(star.NodeIndex * 32, YNodes[star.NodeIndex]);
var value = new Vector2((star.NodeIndex + 1) * 32, YNodes[star.NodeIndex + 1]);
var value2 = vector + (value - vector) * star.NodePercent;
var vector2 = (value - vector).SafeNormalize();
var value3 = new Vector2(0f - vector2.Y, vector2.X);
return value2 + value3 * star.Distance * (float)Math.Sin(star.Sine);
var startNode = new Vector2(star.NodeIndex * NodeDistance, YNodes[star.NodeIndex]);
var endNode = new Vector2((star.NodeIndex + 1) * NodeDistance, YNodes[star.NodeIndex + 1]);
var lerpedNode = startNode + (endNode - startNode) * star.NodePercent;
var direction = (endNode - startNode).SafeNormalize();
var perpendicular = new Vector2(0f - direction.Y, direction.X);
return lerpedNode + perpendicular * star.Distance * (float)Math.Sin(star.Sine);
}

public override void Render(Scene scene)
{
var position = (scene as Level).Camera.Position;
for (var i = 0; i < Stars.Length; i++)
for (int i = 0; i < Stars.Length; i++)
{
var vector = new Vector2();
vector.X = -64f + Mod(Stars[i].Position.X - position.X * Scroll.X, 448f);
vector.Y = -16f + Mod(Stars[i].Position.Y - position.Y * Scroll.Y, 212f);
var position2 = vector;
Stars[i].Texture.DrawCentered(position2, Stars[i].Color * FadeAlphaMultiplier);
var renderPosition = new Vector2()
{
X = -64f + Mod(Stars[i].Position.X - position.X * Scroll.X, (NodeCount - 1) * NodeDistance),
Y = -16f + Mod(Stars[i].Position.Y - position.Y * Scroll.Y, 180f + 32f)
};

Stars[i].Texture.DrawCentered(renderPosition, Stars[i].Color * FadeAlphaMultiplier);
}
}

private float Mod(float x, float m)
{
return (x % m + m) % m;
}
private static float Mod(float x, float m) => (x % m + m) % m;
}
35 changes: 35 additions & 0 deletions Loenn/effects/seededStarfield.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
local seededStarfield = {}

seededStarfield.name = "EeveeHelper/SeededStarfield"

seededStarfield.defaultData = {
textureDir = "particles/starfield",
color = "ffffff",
alpha = 1.0,
scrollx = 1.0,
scrolly = 1.0,
speed = 1.0,
seed = 0
}

seededStarfield.fieldOrder = {
"only", "exclude", "tag", "flag",
"textureDir", "color", "alpha", "notflag",
"seed", "speed", "scrollx", "scrolly"
}

seededStarfield.fieldInformation = {
color = {
fieldType = "color",
allowEmpty = true
},
alpha = {
minimumValue = 0.0,
maximumValue = 1.0
},
seed = {
fieldType = "integer"
}
}

return seededStarfield
12 changes: 12 additions & 0 deletions Loenn/lang/en_gb.lang
Original file line number Diff line number Diff line change
Expand Up @@ -287,3 +287,15 @@ entities.EeveeHelper/RefillShard.attributes.description.spawnRefill=Whether the
entities.EeveeHelper/RefillShard.attributes.description.oneUse=Whether the shards respawn after collection / Whether the spawned refill is single-use.
entities.EeveeHelper/RefillShard.attributes.description.resetOnGround=Whether touching the ground causes the shards to reset (normal seed behavior).
entities.EeveeHelper/RefillShard.attributes.description.twoDashes=Whether the refill gives you two dashes.

# Seeded Starfield
style.effects.EeveeHelper/SeededStarfield.name=Seeded Starfield
style.effects.EeveeHelper/SeededStarfield.attribute.scrollx=Scroll X
style.effects.EeveeHelper/SeededStarfield.attribute.scrolly=Scroll Y
style.effects.EeveeHelper/SeededStarfield.description.color=The color of the stars.
style.effects.EeveeHelper/SeededStarfield.description.alpha=The alpha of the stars.
style.effects.EeveeHelper/SeededStarfield.description.textureDir=The path to the folder containing the star textures, relative to Graphics/Atlases/Gameplay/.
style.effects.EeveeHelper/SeededStarfield.description.scrollx=Determines the parallax scrolling of the stars along the X axis.
style.effects.EeveeHelper/SeededStarfield.description.scrolly=Determines the parallax scrolling of the stars along the Y axis.
style.effects.EeveeHelper/SeededStarfield.description.speed=A multiplier to apply to the speed of the stars.
style.effects.EeveeHelper/SeededStarfield.description.seed=The random seed used to determine the initial appearance of the starfield.\nSetting this to 0 will cause the starfield to be different every time the map is loaded.