Skip to content

Commit

Permalink
Merge pull request #27 from SnipUndercover/spike-refill-controller
Browse files Browse the repository at this point in the history
Implement Spike Refill Controllers
  • Loading branch information
maddie480 authored Aug 12, 2024
2 parents 1297e45 + 6108e5a commit 604e2a3
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 1 deletion.
69 changes: 69 additions & 0 deletions Entities/SpikeRefillController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using Celeste.Mod.Entities;
using Microsoft.Xna.Framework;
using Mono.Cecil.Cil;
using Monocle;
using MonoMod.Cil;
using MonoMod.RuntimeDetour;
using System;
using System.Reflection;

namespace Celeste.Mod.MaxHelpingHand.Entities {
[Tracked]
[CustomEntity("MaxHelpingHand/SpikeRefillController")]
public class SpikeRefillController : Entity {
private static readonly MethodInfo m_OrigUpdate = typeof(Player).GetMethod("orig_Update");
private static ILHook Hook_OrigUpdate;

public string Flag { get; private set; }
public bool FlagInverted { get; private set; }

private bool IsFlagSatisfied => string.IsNullOrWhiteSpace(Flag) || (FlagInverted ^ SceneAs<Level>().Session.GetFlag(Flag));

public SpikeRefillController(EntityData data, Vector2 offset) : base(data.Position + offset) {
Flag = data.Attr("flag");
FlagInverted = data.Bool("flagInverted");
}

public static void Load() {
Hook_OrigUpdate = new ILHook(m_OrigUpdate, HookSpikeRefillPrevention);
}

public static void Unload() {
Hook_OrigUpdate?.Dispose();
}

private static void HookSpikeRefillPrevention(ILContext il) {
ILCursor cursor = new ILCursor(il);

if (!cursor.TryGotoNext(MoveType.After, instr => instr.MatchCall("Monocle.Entity", "System.Boolean CollideCheck<Celeste.Spikes>(Microsoft.Xna.Framework.Vector2)"))) {
Logger.Log(LogLevel.Error, "MaxHelpingHand/SpikeRefillController",
$"Could not find CollideCheck<Spikes> in {il.Method.FullName}!");
return;
}

Logger.Log(LogLevel.Verbose, "MaxHelpingHand/SpikeRefillController",
$"Hooking CollideCheck<Spikes> in {il.Method.FullName} @ {InstructionToString(cursor.Next)}");

cursor.Emit(OpCodes.Ldarg_0);
cursor.EmitDelegate(OverrideRefillPreventionInSpikes);

Check failure on line 48 in Entities/SpikeRefillController.cs

View workflow job for this annotation

GitHub Actions / build

The type arguments for method 'ILCursor.EmitDelegate<T>(T)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
}

private static bool OverrideRefillPreventionInSpikes(bool collidedWithSpikes, Player self) {
// return true to prevent refills
if (!collidedWithSpikes)
return collidedWithSpikes;

return !(self.Scene.Tracker.GetEntity<SpikeRefillController>()?.IsFlagSatisfied ?? false);
}

// stringifying branch instructions crashes because of monomod, very cool
private static string InstructionToString(Instruction instr) {
Instruction toStringify = instr;
if (instr.Operand is ILLabel target) {
toStringify = Instruction.Create(toStringify.OpCode, target.Target);
toStringify.Offset = instr.Offset;
}
return toStringify.ToString();
}
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions Loenn/entities/spikeRefillController.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
local spikeRefillController = {}

spikeRefillController.name = "MaxHelpingHand/SpikeRefillController"
spikeRefillController.justification = { 0.5, 0.5 }
spikeRefillController.placements = {
name = 'normal',
data = {
flag = "",
flagInverted = false
}
}

spikeRefillController.texture = "objects/MaxHelpingHand/spikeRefillController/controller"

return spikeRefillController
7 changes: 6 additions & 1 deletion Loenn/lang/en_gb.lang
Original file line number Diff line number Diff line change
Expand Up @@ -1392,4 +1392,9 @@ entities.MaxHelpingHand/ReverseJelly.attributes.description.tutorial=Whether the
entities.MaxHelpingHand/ReverseJelly.attributes.description.glow=Whether the entity should glow in the dark.

# Reversible Retention Booster
entities.MaxHelpingHand/ReversibleRetentionBooster.placements.name.booster=Reversible Retention Booster
entities.MaxHelpingHand/ReversibleRetentionBooster.placements.name.booster=Reversible Retention Booster

# Spike Refill Controller
entities.MaxHelpingHand/SpikeRefillController.placements.name.normal=Spike Refill Controller
entities.MaxHelpingHand/SpikeRefillController.attributes.description.flag=The flag this controller should check to determine whether it's active.
entities.MaxHelpingHand/SpikeRefillController.attributes.description.flagInverted=If checked, the controller will be active if the flag is disabled.
2 changes: 2 additions & 0 deletions Module/MaxHelpingHandModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ public override void Load() {
FrozenJelly.Load();
ReverseJelly.Load();
ReversibleRetentionBooster.Load();
SpikeRefillController.Load();

Everest.Events.Level.OnLoadBackdrop += onLoadBackdrop;

Expand Down Expand Up @@ -186,6 +187,7 @@ public override void Unload() {
ReverseJelly.Unload();
ReversibleRetentionBooster.Unload();
UpsideDownMovingPlatformGravityHelper.Unload();
SpikeRefillController.Unload();

Everest.Events.Level.OnLoadBackdrop -= onLoadBackdrop;

Expand Down

0 comments on commit 604e2a3

Please sign in to comment.