diff --git a/Code/Entities/ColorSwitch.cs b/Code/Entities/ColorSwitch.cs index f8817ca..30d3995 100644 --- a/Code/Entities/ColorSwitch.cs +++ b/Code/Entities/ColorSwitch.cs @@ -29,12 +29,14 @@ public class ColorSwitch : Solid private int nextColorIndex = 0; private readonly bool singleColor, random; + private readonly bool holdableActivated; + public ColorSwitch(EntityData data, Vector2 offset) : this(data.Position + offset, data.Width, data.Height, - data.Bool("blue"), data.Bool("rose"), data.Bool("orange"), data.Bool("lime"), data.Bool("random")) + data.Bool("blue"), data.Bool("rose"), data.Bool("orange"), data.Bool("lime"), data.Bool("random"), data.Bool("holdableActivated")) { } - public ColorSwitch(Vector2 position, int width, int height, bool blue, bool rose, bool orange, bool lime, bool random) + public ColorSwitch(Vector2 position, int width, int height, bool blue, bool rose, bool orange, bool lime, bool random, bool holdableActivated) : base(position, width, height, true) { this.SurfaceSoundIndex = SurfaceIndex.ZipMover; @@ -78,6 +80,7 @@ public ColorSwitch(Vector2 position, int width, int height, bool blue, bool rose SetEdgeColor(this.EdgeColor, this.EdgeColor); SetBackgroundColor(col, col); + this.holdableActivated = holdableActivated; this.OnDashCollide = Dashed; } @@ -267,4 +270,41 @@ private void SmashParticles(Vector2 dir, ParticleType smashParticle) num += 2; SceneAs().Particles.Emit(smashParticle, num, position, positionRange, direction); } + + internal static class Hooks + { + public static void Hook() + { + On.Celeste.TheoCrystal.OnCollideH += TheoCrystal_OnCollideH; + On.Celeste.TheoCrystal.OnCollideV += TheoCrystal_OnCollideV; + On.Celeste.Glider.OnCollideH += Glider_OnCollideH; + On.Celeste.Glider.OnCollideV += Glider_OnCollideV; + } + + public static void Unhook() + { + On.Celeste.TheoCrystal.OnCollideH -= TheoCrystal_OnCollideH; + On.Celeste.TheoCrystal.OnCollideV -= TheoCrystal_OnCollideV; + On.Celeste.Glider.OnCollideH -= Glider_OnCollideH; + On.Celeste.Glider.OnCollideV -= Glider_OnCollideV; + } + + private static void ActivateSwitch(Action callOrig, CollisionData data, Func speedChecker) + { + if (data.Hit is ColorSwitch colorSwitch + && colorSwitch.holdableActivated + && !colorSwitch.colors[colorSwitch.nextColorIndex].IsActive() + && speedChecker()) + { + colorSwitch.Switch(data.Direction); + } + + callOrig(); + } + + private static void TheoCrystal_OnCollideH(On.Celeste.TheoCrystal.orig_OnCollideH orig, TheoCrystal self, CollisionData data) => ActivateSwitch(() => orig(self, data), data, () => true); + private static void TheoCrystal_OnCollideV(On.Celeste.TheoCrystal.orig_OnCollideV orig, TheoCrystal self, CollisionData data) => ActivateSwitch(() => orig(self, data), data, () => self.Speed.Y > 160f || self.Speed.Y < 0f); + private static void Glider_OnCollideH(On.Celeste.Glider.orig_OnCollideH orig, Glider self, CollisionData data) => ActivateSwitch(() => orig(self, data), data, () => true); + private static void Glider_OnCollideV(On.Celeste.Glider.orig_OnCollideV orig, Glider self, CollisionData data) => ActivateSwitch(() => orig(self, data), data, () => self.Speed.Y < 0f); + } } diff --git a/Code/Entities/ColorSwitchFlagsController.cs b/Code/Entities/ColorSwitchFlagsController.cs new file mode 100644 index 0000000..6556c05 --- /dev/null +++ b/Code/Entities/ColorSwitchFlagsController.cs @@ -0,0 +1,50 @@ +using Monocle; +using Microsoft.Xna.Framework; +using System.Collections.Generic; + +namespace Celeste.Mod.VortexHelper.Entities; + +public class ColorSwitchFlagsController : Entity +{ + private static readonly Dictionary colorsToFlagNames = new() { + { VortexHelperSession.SwitchBlockColor.Blue, "VortexHelper/SwitchBlockColor_Blue" }, + { VortexHelperSession.SwitchBlockColor.Rose, "VortexHelper/SwitchBlockColor_Rose" }, + { VortexHelperSession.SwitchBlockColor.Lime, "VortexHelper/SwitchBlockColor_Lime" }, + { VortexHelperSession.SwitchBlockColor.Orange, "VortexHelper/SwitchBlockColor_Orange" }, + }; + + public ColorSwitchFlagsController() : base(Vector2.Zero) + { + Depth = -int.MaxValue; // update last + Tag = Tags.Global | Tags.TransitionUpdate; + } + + public override void Update() + { + Session session = SceneAs().Session; + VortexHelperSession.SwitchBlockColor current = VortexHelperModule.SessionProperties.SessionSwitchBlockColor; + + foreach (var color in colorsToFlagNames) + { + if (current != color.Key && session.GetFlag(color.Value)) + session.SetFlag(color.Value, false); + else if (current == color.Key && !session.GetFlag(color.Value)) + session.SetFlag(color.Value, true); + } + } + + internal static class Hooks + { + public static void Hook() + { + Everest.Events.LevelLoader.OnLoadingThread += OnLoadingThread; + } + + public static void Unhook() + { + Everest.Events.LevelLoader.OnLoadingThread -= OnLoadingThread; + } + + private static void OnLoadingThread(Level level) => level.Add(new ColorSwitchFlagsController()); + } +} \ No newline at end of file diff --git a/Code/VortexHelperModule.cs b/Code/VortexHelperModule.cs index c5fd84d..8d2b521 100644 --- a/Code/VortexHelperModule.cs +++ b/Code/VortexHelperModule.cs @@ -67,10 +67,12 @@ public override void Load() BowlPuffer.Hooks.Hook(); PufferBarrierRenderer.Hooks.Hook(); StaticMoverWithLiftSpeed.Hooks.Hook(); + ColorSwitch.Hooks.Hook(); + ColorSwitchFlagsController.Hooks.Hook(); MiscHooks.Hook(); Util.LoadDelegates(); - + typeof(GravityHelperInterop.Imports).ModInterop(); } @@ -84,6 +86,8 @@ public override void Unload() BowlPuffer.Hooks.Unhook(); PufferBarrierRenderer.Hooks.Unhook(); StaticMoverWithLiftSpeed.Hooks.Unhook(); + ColorSwitch.Hooks.Unhook(); + ColorSwitchFlagsController.Hooks.Unhook(); MiscHooks.Unhook(); } diff --git a/Loenn/entities/color_switch.lua b/Loenn/entities/color_switch.lua index ec6acca..57bdc1d 100644 --- a/Loenn/entities/color_switch.lua +++ b/Loenn/entities/color_switch.lua @@ -7,6 +7,12 @@ colorSwitch.name = "VortexHelper/ColorSwitch" colorSwitch.resizable = {true, true} colorSwitch.minimumSize = {16, 16} +colorSwitch.fieldOrder = { + "x", "y", "width", "height", + "blue", "rose", "orange", "lime", "random", + "holdableActivated" +} + colorSwitch.placements = { { name = "all_cycle", @@ -17,7 +23,8 @@ colorSwitch.placements = { rose = true, orange = true, lime = true, - random = false + random = false, + holdableActivated = false } }, { @@ -29,7 +36,8 @@ colorSwitch.placements = { rose = true, orange = true, lime = true, - random = true + random = true, + holdableActivated = false } } } diff --git a/Loenn/lang/en_gb.lang b/Loenn/lang/en_gb.lang index cfc6e4f..28b73e2 100644 --- a/Loenn/lang/en_gb.lang +++ b/Loenn/lang/en_gb.lang @@ -35,6 +35,7 @@ entities.VortexHelper/ColorSwitch.attributes.description.rose=Enables switch to entities.VortexHelper/ColorSwitch.attributes.description.orange=Enables switch to ORANGE through this Color Switch. entities.VortexHelper/ColorSwitch.attributes.description.lime=Enables switch to LIME through this Color Switch. entities.VortexHelper/ColorSwitch.attributes.description.random=Makes this Color Switch randomly pick one of its enabled colors. +entities.VortexHelper/ColorSwitch.attributes.description.holdableActivated=Makes collisions with holdables (Jellyfish and Theo Crystals) activate this Color Switch. # Vortex Switch Gate entities.VortexHelper/VortexSwitchGate.placements.name.crush=Custom Switch Gate (Crush)