diff --git a/Celeste.Mod.mm/MonoModRules.cs b/Celeste.Mod.mm/MonoModRules.cs
index 565b20a44..b0f6ffda8 100644
--- a/Celeste.Mod.mm/MonoModRules.cs
+++ b/Celeste.Mod.mm/MonoModRules.cs
@@ -409,6 +409,12 @@ class PatchDeathEffectUpdateAttribute : Attribute { }
[MonoModCustomMethodAttribute(nameof(MonoModRules.PatchMiniTextboxRoutine))]
class PatchMiniTextboxRoutine : Attribute { }
+ ///
+ /// Patches the method to fix "$" not printed in PICO-8.
+ ///
+ [MonoModCustomMethodAttribute(nameof(MonoModRules.PatchEmulatorConstructor))]
+ class PatchEmulatorConstructorAttribute : Attribute { }
+
static class MonoModRules {
static bool IsCeleste;
@@ -2352,6 +2358,21 @@ public static void PatchMiniTextboxRoutine(MethodDefinition method, CustomAttrib
});
}
+ ///
+ ///
+ ///
+ public static void PatchEmulatorConstructor(ILContext il, CustomAttribute attrib) {
+ ILCursor cursor = new ILCursor(il);
+
+ string fontMap = null;
+ cursor.GotoNext(MoveType.Before,
+ instr => instr.MatchLdstr(out fontMap),
+ instr => instr.MatchStfld("Celeste.Pico8.Emulator", "fontMap"));
+ // devs forgot to press shift when typing "$" for some reason
+ fontMap = fontMap.Replace("#4%", "#$%");
+ cursor.Next.Operand = fontMap;
+ }
+
public static void PostProcessor(MonoModder modder) {
// Patch CrushBlock::AttackSequence's first alarm delegate manually because how would you even annotate it?
PatchCrushBlockFirstAlarm(modder.Module.GetType("Celeste.CrushBlock/<>c__DisplayClass41_0").FindMethod("b__1"));
diff --git a/Celeste.Mod.mm/Patches/Pico8/Emulator.cs b/Celeste.Mod.mm/Patches/Pico8/Emulator.cs
index 32ad13a0e..d41ec7e6f 100644
--- a/Celeste.Mod.mm/Patches/Pico8/Emulator.cs
+++ b/Celeste.Mod.mm/Patches/Pico8/Emulator.cs
@@ -18,7 +18,10 @@ public patch_Emulator(Scene returnTo, int levelX = 0, int levelY = 0)
// no-op. MonoMod ignores this - we only need this to make the compiler shut up.
}
+ [MonoModIgnore]
+ [PatchEmulatorConstructor]
public extern void orig_ctor(Scene returnTo, int levelX = 0, int levelY = 0);
+
[MonoModConstructor]
public void ctor(Scene returnTo, int levelX = 0, int levelY = 0) {
orig_ctor(returnTo, levelX, levelY);