From 10aa02d4b06216433f4675a314ed0042df3566a0 Mon Sep 17 00:00:00 2001
From: vitellaryjr <43586575+vitellaryjr@users.noreply.github.com>
Date: Wed, 1 Jan 2025 18:03:48 -0700
Subject: [PATCH 1/2] didnt feel like making a new branch

- 'renderEye' option for custom puffer
- made trigger trigger On Input check during freeze frames
- fix custom wind overriding vanilla wind on room restart
---
 Code/FLCC/CustomPuffer.cs          |  6 ++--
 Code/TriggerTrigger.cs             | 44 ++++++++++++++++++++++++++++++
 Code/VitModule.cs                  | 18 +++++++-----
 Loenn/entities/custom_puffer.lua   |  2 ++
 Loenn/triggers/trigger_trigger.lua |  8 ++++++
 5 files changed, 69 insertions(+), 9 deletions(-)

diff --git a/Code/FLCC/CustomPuffer.cs b/Code/FLCC/CustomPuffer.cs
index f9f5409..278521a 100644
--- a/Code/FLCC/CustomPuffer.cs
+++ b/Code/FLCC/CustomPuffer.cs
@@ -78,6 +78,7 @@ public enum BoostModes
         private bool legacyBoost = true;
         private bool absoluteVector = false;
         private bool launchState = true;
+        private bool renderEye = true;
 
 		public CustomPuffer(Vector2 position, bool faceRight, float angle = 0f, float radius = 32f, float launchSpeed = 280f, string spriteName = "pufferFish")
 			: base(position)
@@ -136,6 +137,7 @@ public CustomPuffer(EntityData data, Vector2 offset, EntityID id)
             legacyBoost = data.Bool("legacyBoost", true);
             absoluteVector = data.Bool("absoluteVector", false);
             launchState = data.Bool("setLaunchState", true);
+            renderEye = data.Bool("renderEye", true);
 
 			if (data.Bool("holdable"))
 			{
@@ -494,7 +496,7 @@ public override void Render()
 				}
 			}
 			base.Render();
-			if (!isHappy && sprite.CurrentAnimationID == "alerted")
+			if (renderEye && !isHappy && sprite.CurrentAnimationID == "alerted")
 			{
 				Vector2 vector3 = Position + new Vector2(3f, (Facing.X < 0f) ? (-5) : (-4)) * sprite.Scale;
 				Vector2 to = lastPlayerPos + new Vector2(0f, -4f);
@@ -733,7 +735,7 @@ private void OnPlayer(Player player)
 			{
 				return;
 			}
-			if (Hold != null && Input.Grab.Check && !player.Ducking && !player.IsTired)
+			if (Hold != null && Input.Grab.Check && !player.Ducking && !player.IsTired && (player.Holding == null))
 				return;
 			if (cannotHitTimer <= 0f)
 			{
diff --git a/Code/TriggerTrigger.cs b/Code/TriggerTrigger.cs
index 91e1ba8..9993737 100644
--- a/Code/TriggerTrigger.cs
+++ b/Code/TriggerTrigger.cs
@@ -3,6 +3,7 @@
 using FMOD;
 using Microsoft.Xna.Framework;
 using Monocle;
+using MonoMod.Cil;
 using System;
 using System.Collections;
 using System.Collections.Generic;
@@ -16,12 +17,14 @@ public static void Load() {
             On.Celeste.Level.LoadLevel += Level_LoadLevel;
             On.Celeste.Player.Jump += Player_Jump;
             On.Celeste.PlayerCollider.Check += PlayerCollider_Check;
+            IL.Monocle.Engine.Update += Engine_Update;
         }
 
         public static void Unload() {
             On.Celeste.Level.LoadLevel -= Level_LoadLevel;
             On.Celeste.Player.Jump -= Player_Jump;
             On.Celeste.PlayerCollider.Check -= PlayerCollider_Check;
+            IL.Monocle.Engine.Update -= Engine_Update;
         }
 
         private static readonly HashSet<Entity> collidedEntities = new();
@@ -67,7 +70,9 @@ public TriggerTrigger(EntityData data, Vector2 offset) : base(data, offset) {
                         break;
                 }
             }
+            excludeTalkers = data.Bool("excludeTalkers", false);
             ifSafe = data.Bool("onlyIfSafe", false);
+            includeCoyote = data.Bool("includeCoyote", false);
             playerState = data.Int("playerState", 0);
             if (string.IsNullOrEmpty(data.Attr("entityType", ""))) {
                 collideType = data.Attr("entityTypeToCollide", "Celeste.Strawberry");
@@ -320,6 +325,8 @@ public bool GetActivateCondition(Player player) {
                     result = player.OnGround();
                     if (ifSafe)
                         result &= player.OnSafeGround;
+                    if (includeCoyote)
+                        result |= player.jumpGraceTimer > 0f;
                     break;
                 case ActivationTypes.OnPlayerState:
                     result = player.StateMachine.State == playerState;
@@ -330,6 +337,11 @@ public bool GetActivateCondition(Player player) {
             }
             if (externalActivation) {
                 result = true;
+                if (resetActivation)
+                {
+                    externalActivation = false;
+                    resetActivation = false;
+                }
             }
             if (invertCondition) {
                 result = !result;
@@ -462,6 +474,10 @@ private bool CheckInput(InputTypes inputType, bool held) {
                 case InputTypes.Dash:
                     return (held ? Input.Dash.Check : Input.Dash.Pressed);
                 case InputTypes.Interact:
+                    if (excludeTalkers && TalkComponent.PlayerOver != null)
+                    {
+                        return false;
+                    }
                     return (held ? Input.Talk.Check : Input.Talk.Pressed);
                 case InputTypes.CrouchDash:
                     return (held ? Input.CrouchDash.Check : Input.CrouchDash.Pressed);
@@ -532,6 +548,31 @@ private static bool PlayerCollider_Check(On.Celeste.PlayerCollider.orig_Check or
             return result;
         }
 
+        private static void Engine_Update(MonoMod.Cil.ILContext il)
+        {
+            // code taken from communal helper's AbstractInputController
+            // https://github.com/CommunalHelper/CommunalHelper/blob/dev/src/Entities/Misc/AbstractInputController.cs
+
+            ILCursor cursor = new(il);
+            if (cursor.TryGotoNext(instr => instr.MatchLdsfld<Engine>("FreezeTimer"),
+                instr => instr.MatchCall<Engine>("get_RawDeltaTime")))
+            {
+                cursor.EmitDelegate<Action>(UpdateFreezeInput);
+            }
+        }
+
+        public static void UpdateFreezeInput()
+        {
+            foreach (TriggerTrigger trigger in Engine.Scene.Tracker.GetEntities<TriggerTrigger>())
+            {
+                if (trigger.activationType == ActivationTypes.OnInput && !trigger.inputHeld && trigger.CheckInput(trigger.inputType, false))
+                {
+                    trigger.externalActivation = true;
+                    trigger.resetActivation = true;
+                }
+            }
+        }
+
         public bool Global;
         public bool Activated;
 
@@ -548,12 +589,15 @@ private static bool PlayerCollider_Check(On.Celeste.PlayerCollider.orig_Check or
         private Session.CoreModes coreMode;
         private InputTypes inputType;
         private bool inputHeld;
+        private bool excludeTalkers;
         private bool ifSafe;
+        private bool includeCoyote;
         private int playerState;
         private TalkComponent talker;
         private List<Entity> entitiesInside;
         private string collideSolid;
         public bool externalActivation;
+        public bool resetActivation;
         private bool invertCondition;
         private ComparisonTypes comparisonType;
         private bool absoluteValue;
diff --git a/Code/VitModule.cs b/Code/VitModule.cs
index 41ce6aa..62924bc 100644
--- a/Code/VitModule.cs
+++ b/Code/VitModule.cs
@@ -597,14 +597,18 @@ private void Level_LoadLevel(On.Celeste.Level.orig_LoadLevel orig, Level self, P
         private void Level_Reload(On.Celeste.Level.orig_Reload orig, Level self)
         {
             orig(self);
-            CustomWindController customWind = self.Entities.FindFirst<CustomWindController>();
-            if (customWind != null)
+            if (!self.Completed)
             {
-                customWind.SnapWind();
-            }
-            else
-            {
-                self.Wind = Vector2.Zero;
+                CustomWindController customWind = self.Entities.FindFirst<CustomWindController>();
+                WindController vanillaWind = self.Entities.FindFirst<WindController>();
+                if (customWind != null)
+                {
+                    customWind.SnapWind();
+                }
+                else if (vanillaWind == null)
+                {
+                    self.Wind = Vector2.Zero;
+                }
             }
         }
 
diff --git a/Loenn/entities/custom_puffer.lua b/Loenn/entities/custom_puffer.lua
index f537f59..6d7ab95 100644
--- a/Loenn/entities/custom_puffer.lua
+++ b/Loenn/entities/custom_puffer.lua
@@ -23,6 +23,7 @@ customPuffer.placements = {
             boostMode = "SetSpeed",
             legacyBoost = false,
             absoluteVector = false,
+            renderEye = true,
         }
     },
     {
@@ -46,6 +47,7 @@ customPuffer.placements = {
             boostMode = "SetSpeed",
             legacyBoost = false,
             absoluteVector = false,
+            renderEye = true,
         }
     }
 }
diff --git a/Loenn/triggers/trigger_trigger.lua b/Loenn/triggers/trigger_trigger.lua
index fcd51d5..2bebfa7 100644
--- a/Loenn/triggers/trigger_trigger.lua
+++ b/Loenn/triggers/trigger_trigger.lua
@@ -91,8 +91,10 @@ function triggerTrigger.ignoredFields(entity)
         "entityType",
         "inputType",
         "holdInput",
+        "excludeTalkers",
         "onlyIfSafe",
         "playerState",
+        "includeCoyote"
     }
 
     local function doNotIgnore(value)
@@ -137,8 +139,12 @@ function triggerTrigger.ignoredFields(entity)
     elseif atype == "OnInput" then
         doNotIgnore("inputType")
         doNotIgnore("holdInput")
+        if entity.inputType == "Interact" then
+            doNotIgnore("excludeTalkers")
+        end
     elseif atype == "OnGrounded" then
         doNotIgnore("onlyIfSafe")
+        doNotIgnore("includeCoyote")
     elseif atype == "OnPlayerState" then
         doNotIgnore("playerState")
     end
@@ -180,8 +186,10 @@ for _, mode in pairs(activationTypes) do
             entityType = "",
             inputType = "Grab",
             holdInput = false,
+            excludeTalkers = false,
             onlyIfSafe = false,
             playerState = 0,
+            includeCoyote = false,
         }
     }
     table.insert(triggerTrigger.placements, placement)

From d3129390c11cb31a41dde247c6f03fef62541c3d Mon Sep 17 00:00:00 2001
From: vitellaryjr <43586575+vitellaryjr@users.noreply.github.com>
Date: Wed, 1 Jan 2025 18:04:56 -0700
Subject: [PATCH 2/2] Update everest.yaml

---
 everest.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/everest.yaml b/everest.yaml
index ba5792c..8452501 100644
--- a/everest.yaml
+++ b/everest.yaml
@@ -1,5 +1,5 @@
 - Name: CrystallineHelper
-  Version: 1.16.3
+  Version: 1.16.4
   DLL: Code/bin/vitmod.dll
   Dependencies:
     - Name: EverestCore