Skip to content

Commit 604e2a3

Browse files
authored
Merge pull request #27 from SnipUndercover/spike-refill-controller
Implement Spike Refill Controllers
2 parents 1297e45 + 6108e5a commit 604e2a3

File tree

5 files changed

+92
-1
lines changed

5 files changed

+92
-1
lines changed

Entities/SpikeRefillController.cs

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using Celeste.Mod.Entities;
2+
using Microsoft.Xna.Framework;
3+
using Mono.Cecil.Cil;
4+
using Monocle;
5+
using MonoMod.Cil;
6+
using MonoMod.RuntimeDetour;
7+
using System;
8+
using System.Reflection;
9+
10+
namespace Celeste.Mod.MaxHelpingHand.Entities {
11+
[Tracked]
12+
[CustomEntity("MaxHelpingHand/SpikeRefillController")]
13+
public class SpikeRefillController : Entity {
14+
private static readonly MethodInfo m_OrigUpdate = typeof(Player).GetMethod("orig_Update");
15+
private static ILHook Hook_OrigUpdate;
16+
17+
public string Flag { get; private set; }
18+
public bool FlagInverted { get; private set; }
19+
20+
private bool IsFlagSatisfied => string.IsNullOrWhiteSpace(Flag) || (FlagInverted ^ SceneAs<Level>().Session.GetFlag(Flag));
21+
22+
public SpikeRefillController(EntityData data, Vector2 offset) : base(data.Position + offset) {
23+
Flag = data.Attr("flag");
24+
FlagInverted = data.Bool("flagInverted");
25+
}
26+
27+
public static void Load() {
28+
Hook_OrigUpdate = new ILHook(m_OrigUpdate, HookSpikeRefillPrevention);
29+
}
30+
31+
public static void Unload() {
32+
Hook_OrigUpdate?.Dispose();
33+
}
34+
35+
private static void HookSpikeRefillPrevention(ILContext il) {
36+
ILCursor cursor = new ILCursor(il);
37+
38+
if (!cursor.TryGotoNext(MoveType.After, instr => instr.MatchCall("Monocle.Entity", "System.Boolean CollideCheck<Celeste.Spikes>(Microsoft.Xna.Framework.Vector2)"))) {
39+
Logger.Log(LogLevel.Error, "MaxHelpingHand/SpikeRefillController",
40+
$"Could not find CollideCheck<Spikes> in {il.Method.FullName}!");
41+
return;
42+
}
43+
44+
Logger.Log(LogLevel.Verbose, "MaxHelpingHand/SpikeRefillController",
45+
$"Hooking CollideCheck<Spikes> in {il.Method.FullName} @ {InstructionToString(cursor.Next)}");
46+
47+
cursor.Emit(OpCodes.Ldarg_0);
48+
cursor.EmitDelegate(OverrideRefillPreventionInSpikes);
49+
}
50+
51+
private static bool OverrideRefillPreventionInSpikes(bool collidedWithSpikes, Player self) {
52+
// return true to prevent refills
53+
if (!collidedWithSpikes)
54+
return collidedWithSpikes;
55+
56+
return !(self.Scene.Tracker.GetEntity<SpikeRefillController>()?.IsFlagSatisfied ?? false);
57+
}
58+
59+
// stringifying branch instructions crashes because of monomod, very cool
60+
private static string InstructionToString(Instruction instr) {
61+
Instruction toStringify = instr;
62+
if (instr.Operand is ILLabel target) {
63+
toStringify = Instruction.Create(toStringify.OpCode, target.Target);
64+
toStringify.Offset = instr.Offset;
65+
}
66+
return toStringify.ToString();
67+
}
68+
}
69+
}
Loading
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
local spikeRefillController = {}
2+
3+
spikeRefillController.name = "MaxHelpingHand/SpikeRefillController"
4+
spikeRefillController.justification = { 0.5, 0.5 }
5+
spikeRefillController.placements = {
6+
name = 'normal',
7+
data = {
8+
flag = "",
9+
flagInverted = false
10+
}
11+
}
12+
13+
spikeRefillController.texture = "objects/MaxHelpingHand/spikeRefillController/controller"
14+
15+
return spikeRefillController

Loenn/lang/en_gb.lang

+6-1
Original file line numberDiff line numberDiff line change
@@ -1392,4 +1392,9 @@ entities.MaxHelpingHand/ReverseJelly.attributes.description.tutorial=Whether the
13921392
entities.MaxHelpingHand/ReverseJelly.attributes.description.glow=Whether the entity should glow in the dark.
13931393

13941394
# Reversible Retention Booster
1395-
entities.MaxHelpingHand/ReversibleRetentionBooster.placements.name.booster=Reversible Retention Booster
1395+
entities.MaxHelpingHand/ReversibleRetentionBooster.placements.name.booster=Reversible Retention Booster
1396+
1397+
# Spike Refill Controller
1398+
entities.MaxHelpingHand/SpikeRefillController.placements.name.normal=Spike Refill Controller
1399+
entities.MaxHelpingHand/SpikeRefillController.attributes.description.flag=The flag this controller should check to determine whether it's active.
1400+
entities.MaxHelpingHand/SpikeRefillController.attributes.description.flagInverted=If checked, the controller will be active if the flag is disabled.

Module/MaxHelpingHandModule.cs

+2
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ public override void Load() {
102102
FrozenJelly.Load();
103103
ReverseJelly.Load();
104104
ReversibleRetentionBooster.Load();
105+
SpikeRefillController.Load();
105106

106107
Everest.Events.Level.OnLoadBackdrop += onLoadBackdrop;
107108

@@ -186,6 +187,7 @@ public override void Unload() {
186187
ReverseJelly.Unload();
187188
ReversibleRetentionBooster.Unload();
188189
UpsideDownMovingPlatformGravityHelper.Unload();
190+
SpikeRefillController.Unload();
189191

190192
Everest.Events.Level.OnLoadBackdrop -= onLoadBackdrop;
191193

0 commit comments

Comments
 (0)