Skip to content

Commit 226cfd8

Browse files
committed
Leave Theo Behind Trigger
1 parent e16056c commit 226cfd8

File tree

3 files changed

+86
-0
lines changed

3 files changed

+86
-0
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module SpringCollab2020LeaveTheoBehindTrigger
2+
3+
using ..Ahorn, Maple
4+
5+
@mapdef Trigger "SpringCollab2020/LeaveTheoBehindTrigger" LeaveTheoBehindTrigger(x::Integer, y::Integer, width::Integer=Maple.defaultTriggerWidth, height::Integer=Maple.defaultTriggerHeight,
6+
enable::Bool=false)
7+
8+
const placements = Ahorn.PlacementDict(
9+
"Leave Theo Behind (Spring Collab 2020)" => Ahorn.EntityPlacement(
10+
LeaveTheoBehindTrigger,
11+
"rectangle",
12+
),
13+
)
14+
15+
end

SpringCollab2020Module.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ public override void Load() {
3737
CameraCatchupSpeedTrigger.Load();
3838
ColorGradeFadeTrigger.Load();
3939
SpeedBasedMusicParamTrigger.Load();
40+
LeaveTheoBehindTrigger.Load();
4041
Everest.Events.Level.OnLoadBackdrop += onLoadBackdrop;
4142

4243
DecalRegistry.AddPropertyHandler("scale", (decal, attrs) => {
@@ -79,6 +80,7 @@ public override void Unload() {
7980
CameraCatchupSpeedTrigger.Unload();
8081
ColorGradeFadeTrigger.Unload();
8182
SpeedBasedMusicParamTrigger.Unload();
83+
LeaveTheoBehindTrigger.Unload();
8284
Everest.Events.Level.OnLoadBackdrop -= onLoadBackdrop;
8385
}
8486

Triggers/LeaveTheoBehindTrigger.cs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
using Celeste.Mod.Entities;
2+
using Microsoft.Xna.Framework;
3+
using Monocle;
4+
using MonoMod.Cil;
5+
using System;
6+
7+
namespace Celeste.Mod.SpringCollab2020.Triggers {
8+
[CustomEntity("SpringCollab2020/LeaveTheoBehindTrigger")]
9+
class LeaveTheoBehindTrigger : Trigger {
10+
private static bool leaveTheoBehind = false;
11+
12+
public static void Load() {
13+
IL.Celeste.Level.EnforceBounds += onLevelEnforceBounds;
14+
On.Celeste.Level.TransitionTo += onLevelTransitionTo;
15+
}
16+
17+
public static void Unload() {
18+
IL.Celeste.Level.EnforceBounds -= onLevelEnforceBounds;
19+
On.Celeste.Level.TransitionTo -= onLevelTransitionTo;
20+
}
21+
22+
private static void onLevelEnforceBounds(ILContext il) {
23+
ILCursor cursor = new ILCursor(il);
24+
25+
while (cursor.TryGotoNext(MoveType.After, instr => instr.MatchCallvirt<Tracker>("GetEntity"))) {
26+
// the only usage of GetEntity gets the TheoCrystal entity on the screen.
27+
Logger.Log("SpringCollab2020/LeaveTheoBehindTrigger", $"Adding hook to leave Theo behind at {cursor.Index} in IL for Level.EnforceBounds");
28+
cursor.EmitDelegate<Func<TheoCrystal, TheoCrystal>>(theo => {
29+
if (leaveTheoBehind) {
30+
return null; // pretend there is no Theo, so we can exit the room.
31+
}
32+
return theo;
33+
});
34+
}
35+
}
36+
37+
private static void onLevelTransitionTo(On.Celeste.Level.orig_TransitionTo orig, Level self, LevelData next, Vector2 direction) {
38+
if (leaveTheoBehind) {
39+
// freeze all Theo Crystals that the player isn't carrying, to prevent them from crashing the game or being weird.
40+
Player player = self.Tracker.GetEntity<Player>();
41+
foreach (TheoCrystal crystal in self.Tracker.GetEntities<TheoCrystal>()) {
42+
if (player?.Holding?.Entity != crystal) {
43+
crystal.RemoveTag(Tags.TransitionUpdate);
44+
}
45+
}
46+
}
47+
48+
orig(self, next, direction);
49+
}
50+
51+
52+
public LeaveTheoBehindTrigger(EntityData data, Vector2 offset) : base(data, offset) { }
53+
54+
public override void OnEnter(Player player) {
55+
base.OnEnter(player);
56+
leaveTheoBehind = true;
57+
}
58+
59+
public override void Removed(Scene scene) {
60+
base.Removed(scene);
61+
leaveTheoBehind = false;
62+
}
63+
64+
public override void SceneEnd(Scene scene) {
65+
base.SceneEnd(scene);
66+
leaveTheoBehind = false;
67+
}
68+
}
69+
}

0 commit comments

Comments
 (0)