Skip to content

Commit 7dec6f9

Browse files
committed
v1.4.8, add support for almost all stun related hazards
1 parent d6375f3 commit 7dec6f9

13 files changed

+254
-28
lines changed

Diff for: Entities/SimplifiedSpinner.cs

+111-5
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using Monocle;
55
using System.Reflection;
66
using TAS.EverestInterop.Hitboxes;
7+
using ChronoEntities = Celeste.Mod.ChronoHelper.Entities;
78
using VivEntities = VivHelper.Entities;
89

910
namespace Celeste.Mod.TASHelper.Entities;
@@ -15,12 +16,12 @@ internal static class SimplifiedSpinner {
1516

1617
public static void Load() {
1718
On.Monocle.Entity.DebugRender += PatchDebugRender;
18-
On.Celeste.Level.BeforeRender += OnSceneBeforeRender;
19+
On.Celeste.Level.BeforeRender += OnLevelBeforeRender;
1920
}
2021

2122
public static void Unload() {
2223
On.Monocle.Entity.DebugRender -= PatchDebugRender;
23-
On.Celeste.Level.BeforeRender -= OnSceneBeforeRender;
24+
On.Celeste.Level.BeforeRender -= OnLevelBeforeRender;
2425
}
2526

2627
public static void Initialize() {
@@ -39,9 +40,40 @@ public static void Initialize() {
3940
cursor.EmitDelegate<Action<Level>>(VivBeforeRender);
4041
});
4142
}
43+
44+
if (ModUtils.ChronoHelperInstalled) {
45+
typeof(Level).GetMethod("BeforeRender").IlHook((cursor, _) => {
46+
cursor.Emit(OpCodes.Ldarg_0);
47+
cursor.EmitDelegate<Action<Level>>(ChronoBeforeRender);
48+
});
49+
}
50+
51+
if (ModUtils.BrokemiaHelperInstalled) {
52+
typeof(Level).GetMethod("LoadLevel").IlHook((cursor, _) => {
53+
cursor.Emit(OpCodes.Ldarg_0);
54+
cursor.EmitDelegate(TrackCassetteSpinner);
55+
});
56+
typeof(Level).GetMethod("BeforeRender").IlHook((cursor, _) => {
57+
cursor.Emit(OpCodes.Ldarg_0);
58+
cursor.EmitDelegate<Action<Level>>(BrokemiaBeforeRender);
59+
});
60+
}
61+
62+
if (ModUtils.IsaGrabBagInstalled) {
63+
typeof(Level).GetMethod("LoadLevel").IlHook((cursor, _) => {
64+
cursor.Emit(OpCodes.Ldarg_0);
65+
cursor.EmitDelegate(TrackDreamSpinnerRenderer);
66+
});
67+
typeof(Level).GetMethod("BeforeRender").IlHook((cursor, _) => {
68+
cursor.Emit(OpCodes.Ldarg_0);
69+
cursor.EmitDelegate<Action<Level>>(IsaGrabBagBeforeRender);
70+
});
71+
}
4272
}
4373

44-
private static void OnSceneBeforeRender(On.Celeste.Level.orig_BeforeRender orig, Level self) {
74+
private static void OnLevelBeforeRender(On.Celeste.Level.orig_BeforeRender orig, Level self) {
75+
// here i assume all the components are always visible
76+
// if that's not the case, then this implementation has bug
4577
foreach (Entity dust in self.Tracker.GetEntities<DustStaticSpinner>()) {
4678
dust.UpdateComponentVisiblity();
4779
}
@@ -85,7 +117,82 @@ private static void VivBeforeRender(Level self) {
85117
}
86118
}
87119
}
120+
// viv use Inherited(true) so all subclass of custom spinners are added to TrackedEntityTypes
121+
// so AnimatedSpinner is standalone, can't be fetched by track CustomSpinners
122+
foreach (Entity customSpinner in self.Tracker.GetEntities<VivEntities.AnimatedSpinner>()) {
123+
customSpinner.UpdateComponentVisiblity();
124+
foreach (FieldInfo getter in VivSpinnerExtraComponentGetter) {
125+
object obj = getter.GetValue(customSpinner);
126+
if (obj != null) {
127+
obj.SetFieldValue("Visible", !SpritesCleared);
128+
}
129+
}
130+
}
131+
foreach (Entity customSpinner in self.Tracker.GetEntities<VivEntities.MovingSpinner>()) {
132+
customSpinner.UpdateComponentVisiblity();
133+
foreach (FieldInfo getter in VivSpinnerExtraComponentGetter) {
134+
object obj = getter.GetValue(customSpinner);
135+
if (obj != null) {
136+
obj.SetFieldValue("Visible", !SpritesCleared);
137+
}
138+
}
139+
}
88140
}
141+
private static void ChronoBeforeRender(Level self) {
142+
List<FieldInfo> ChronoSpinnerExtraComponentGetter = new() {
143+
typeof(ChronoEntities.ShatterSpinner).GetField("border", BindingFlags.NonPublic | BindingFlags.Instance),
144+
typeof(ChronoEntities.ShatterSpinner).GetField("filler", BindingFlags.NonPublic | BindingFlags.Instance)
145+
};
146+
foreach (Entity spinner in self.Tracker.GetEntities<ChronoEntities.ShatterSpinner>()) {
147+
spinner.UpdateComponentVisiblity();
148+
foreach (FieldInfo getter in ChronoSpinnerExtraComponentGetter) {
149+
object obj = getter.GetValue(spinner);
150+
if (obj != null) {
151+
obj.SetFieldValue("Visible", !SpritesCleared);
152+
}
153+
}
154+
}
155+
}
156+
157+
private static void TrackCassetteSpinner(Level self) {
158+
Type t = typeof(BrokemiaHelper.CassetteSpinner);
159+
if (!Tracker.TrackedEntityTypes.ContainsKey(t)) {
160+
Tracker.TrackedEntityTypes.Add(t, new List<Type>());
161+
Tracker.TrackedEntityTypes[t].Add(t);
162+
}
163+
if (!self.Tracker.Entities.ContainsKey(t)) {
164+
self.Tracker.Entities.Add(t, new List<Entity>());
165+
}
166+
}
167+
private static void BrokemiaBeforeRender(Level self) {
168+
foreach (Entity spinner in self.Tracker.GetEntities<BrokemiaHelper.CassetteSpinner>()) {
169+
spinner.UpdateComponentVisiblity();
170+
foreach (FieldInfo getter in CrysExtraComponentGetter) {
171+
object obj = getter.GetValue(spinner);
172+
if (obj != null) {
173+
obj.SetFieldValue("Visible", !SpritesCleared);
174+
}
175+
}
176+
}
177+
}
178+
179+
private static void TrackDreamSpinnerRenderer(Level self) {
180+
Type t = typeof(IsaGrabBag.DreamSpinnerRenderer);
181+
if (!Tracker.TrackedEntityTypes.ContainsKey(t)) {
182+
Tracker.TrackedEntityTypes.Add(t, new List<Type>());
183+
Tracker.TrackedEntityTypes[t].Add(t);
184+
}
185+
if (!self.Tracker.Entities.ContainsKey(t)) {
186+
self.Tracker.Entities.Add(t, new List<Entity>());
187+
}
188+
}
189+
190+
private static void IsaGrabBagBeforeRender(Level self) {
191+
foreach (Entity renderer in self.Tracker.GetEntities<IsaGrabBag.DreamSpinnerRenderer>()) {
192+
renderer.Visible = !SpritesCleared;
193+
}
194+
}
195+
89196
private static void UpdateComponentVisiblity(this Entity self) {
90197
foreach (Component component in self.Components) {
91198
component.Visible = !SpritesCleared;
@@ -113,9 +220,8 @@ private static void PatchDebugRender(On.Monocle.Entity.orig_DebugRender orig, En
113220
orig(self, camera);
114221
return;
115222
}
116-
float offset = SpinnerHelper.GetOffset(self).Value;
117223

118-
RenderHelper.SpinnerColorIndex index = RenderHelper.CycleHitboxColorIndex(self, SpinnerHelper.TimeActive, offset, PlayerHelper.CameraPosition);
224+
RenderHelper.SpinnerColorIndex index = RenderHelper.CycleHitboxColorIndex(self, SpinnerHelper.TimeActive, SpinnerHelper.GetOffset(self).Value, PlayerHelper.CameraPosition);
119225
Color color = RenderHelper.GetSpinnerColor(index);
120226
// camera.Position is a bit different from CameraPosition, if you use CelesteTAS's center camera
121227
if (!SpinnerHelper.isLightning(self) && TasHelperSettings.EnableSimplifiedSpinner) {

Diff for: Libs/BrokemiaHelper.dll

146 KB
Binary file not shown.

Diff for: Libs/ChronoHelper.dll

91.5 KB
Binary file not shown.

Diff for: Libs/IsaMods.dll

67 KB
Binary file not shown.

Diff for: Module/GlobalUsings.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
global using static Celeste.Mod.TASHelper.Module.GlobalVariables;
2+
using Monocle;
23
using TAS.EverestInterop.Hitboxes;
34
using TAS.Module;
4-
using Monocle;
55

66
namespace Celeste.Mod.TASHelper.Module;
77

Diff for: Module/TASHelperSettings.cs

+6-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using Microsoft.Xna.Framework.Input;
2-
using TAS.EverestInterop;
32
using static TAS.EverestInterop.Hotkeys;
43

54
namespace Celeste.Mod.TASHelper.Module;
@@ -46,7 +45,7 @@ public SpinnerMainSwitchModes SpinnerMainSwitch {
4645
}
4746
spinnerMainSwitch = value;
4847
switch (value) {
49-
case SpinnerMainSwitchModes.Off:
48+
case SpinnerMainSwitchModes.Off:
5049
Sleep();
5150
UpdateAuxiliaryVariable();
5251
return;
@@ -161,7 +160,7 @@ public CountdownModes CountdownMode {
161160
SpinnerCountdownUpperBound = 99;
162161
SpinnerInterval = 0.25f;
163162
}
164-
163+
165164
if (UsingCountDown) {
166165
SpinnerEnabled = true;
167166
}
@@ -213,8 +212,8 @@ public LoadRangeModes LoadRangeMode {
213212
public int NearPlayerRangeWidth { get; set; } = 8;
214213

215214
private int loadRangeOpacity = 4;
216-
public int LoadRangeOpacity {
217-
get => loadRangeOpacity;
215+
public int LoadRangeOpacity {
216+
get => loadRangeOpacity;
218217
set {
219218
loadRangeOpacity = value;
220219
RangeAlpha = value * 0.1f;
@@ -262,7 +261,7 @@ public int SpinnerFillerOpacity {
262261
spinnerFillerOpacity = value;
263262
SpinnerFillerAlpha = value * 0.1f;
264263
}
265-
}
264+
}
266265
#endregion
267266

268267
private bool entityActivatorReminder = true;
@@ -276,7 +275,7 @@ public bool EntityActivatorReminder {
276275
public void UpdateAuxiliaryVariable() {
277276
// update the variables associated to variables govern by spinner main switch
278277
// it can happen their value is changed but not via the setter (i.e. change the Awake_...s)
279-
278+
280279
UsingNotInViewColor = (UsingNotInViewColorMode == UsingNotInViewColorModes.Always) || (UsingNotInViewColorMode == UsingNotInViewColorModes.WhenUsingInViewRange && UsingInViewRange);
281280
UsingCountDown = (CountdownMode != CountdownModes.Off);
282281
if (CountdownMode == CountdownModes._3fCycle) {

Diff for: README.md

+4-6
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ A Celeste Mod designed to be a tool in TAS making.
66

77
# Features:
88

9-
- In the following, hazards mean vanilla's CrystalStaticSpinner, Lightning and DustStaticSpinner, FrostHelper's CustomSpinner, and VivHelper's CustomSpinner.
9+
- In the following, hazards mean vanilla's CrystalStaticSpinner, Lightning and DustStaticSpinner, FrostHelper's CustomSpinner/AttachedLightning, VivHelper's CustomSpinner, and ChronoHelper's ShatterSpinner/DarkLightning.
1010

1111
- Cycle Hitbox Colors -> basically same as that in CelesteTAS mod, plus a bit modification when hazards are not in view or when spinner freezes.
1212

@@ -30,18 +30,16 @@ A Celeste Mod designed to be a tool in TAS making.
3030

3131
- FrostHelper's CustomSpinner may have "no cycle", which means they will turn on/off collidable every frame.
3232

33-
# WIP:
33+
- BrokemiaHelper's CassetteSpinner, is considered as "no cycle", since its collidablity is completely determined by cassette music. However, its visibility do have a 15f cycle (useless, it can't interact with collidablity).
3434

35-
- Support for other hazards.
35+
# WIP:
3636

3737
- Customizable colors.
3838

3939
# Known issues:
4040

4141
- Actual Collide Hitboxes are overridden -> it's actually bad to use actual collide hitboxes when doing a spinner stun, you really need the exact frame the hazard becomes collidable (opaque). So personnally i do not suggest using actual collide hitboxes in this case. Appended hitbox sounds good but current implement relies on opacity to show information. I have no good idea about it so it's set aside.
4242

43-
- Main Switch for Hazard-related is confusing -> will change it if I know how to make a subsubmenu.
44-
4543
- VivHelper spinner isn't fully supported if it's not a regular one -> maybe will add support for them.
4644

47-
- Laggy when there are too many spinners (e.g. Strawberry Jam GrandMaster HeartSide)
45+
- Laggy when there are too many spinners (e.g. Strawberry Jam GrandMaster HeartSide) -> Partially solved in v1.4.7

Diff for: TASHelper.csproj

+9
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,19 @@
1717
</ItemDefinitionGroup>
1818

1919
<ItemGroup>
20+
<Reference Include="BrokemiaHelper">
21+
<HintPath>Libs\BrokemiaHelper.dll</HintPath>
22+
</Reference>
2023
<Reference Include="Celeste">
2124
<HintPath>Libs\Celeste.exe</HintPath>
2225
</Reference>
2326
<Reference Include="CelesteTAS-EverestInterop">
2427
<HintPath>Libs\CelesteTAS-EverestInterop.dll</HintPath>
2528
<Private>False</Private>
2629
</Reference>
30+
<Reference Include="ChronoHelper">
31+
<HintPath>Libs\ChronoHelper.dll</HintPath>
32+
</Reference>
2733
<Reference Include="ExtendedVariantMode">
2834
<HintPath>Libs\ExtendedVariantMode.dll</HintPath>
2935
</Reference>
@@ -33,6 +39,9 @@
3339
<Reference Include="FrostTempleHelper">
3440
<HintPath>Libs\FrostTempleHelper.dll</HintPath>
3541
</Reference>
42+
<Reference Include="IsaMods">
43+
<HintPath>Libs\IsaMods.dll</HintPath>
44+
</Reference>
3645
<Reference Include="MMHOOK_Celeste">
3746
<HintPath>Libs\MMHOOK_Celeste.dll</HintPath>
3847
</Reference>

Diff for: Utils/ModUtils.cs

+9
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,22 @@ public static Assembly GetAssembly(string modName) {
3939
public static bool PandorasBoxInstalled = false;
4040

4141
public static bool ExtendedVariantInstalled = false;
42+
43+
public static bool ChronoHelperInstalled = false;
44+
45+
public static bool BrokemiaHelperInstalled = false;
46+
47+
public static bool IsaGrabBagInstalled = false;
4248
private static bool upsideDown => (bool)ExtendedVariantsModule.Instance.TriggerManager.GetCurrentVariantValue(ExtendedVariantsModule.Variant.UpsideDown);
4349
public static bool UpsideDown => ExtendedVariantInstalled && upsideDown;
4450
public static void InitializeAtFirst() {
4551
FrostHelperInstalled = IsInstalled("FrostHelper");
4652
VivHelperInstalled = IsInstalled("VivHelper");
4753
PandorasBoxInstalled = IsInstalled("PandorasBox");
4854
ExtendedVariantInstalled = IsInstalled("ExtendedVariantMode");
55+
ChronoHelperInstalled = IsInstalled("ChronoHelper");
56+
BrokemiaHelperInstalled = IsInstalled("BrokemiaHelper");
57+
IsaGrabBagInstalled = IsInstalled("IsaGrabBag");
4958
}
5059

5160
public static void LoadContent() {

Diff for: Utils/RenderHelper.cs

+17-7
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ public static void Unload() {
5353
private static Color NotInViewColor = Color.Lime;
5454
private static Color NeverActivateColor = new Color(0.25f, 1f, 1f);
5555
private static Color ActivatesEveryFrameColor = new Color(0.8f, 0f, 0f);
56+
// ActivatesEveryFrame now consists of 2 cases: (a) update collidability every frame (b) keep collidable forever. The latter is mainly used for some custom hazards
5657

5758
public enum SpinnerColorIndex { Default, Group1, Group2, Group3, NotInView, MoreThan3, NeverActivate, ActivatesEveryFrame };
5859
public static Color GetSpinnerColor(SpinnerColorIndex index) {
@@ -167,8 +168,7 @@ public static void DrawComplexSpinnerCollider(Entity spinner, Color color) {
167168
public static void DrawVanillaCollider(Vector2 Position, Color color, bool Collidable, float alpha) {
168169
color *= Collidable ? 1f : alpha;
169170
SpinnerColliderHelper.Vanilla.Outline.DrawCentered(Position, color);
170-
color *= TasHelperSettings.SpinnerFillerAlpha;
171-
SpinnerColliderHelper.Vanilla.Inside.DrawCentered(Position, color);
171+
SpinnerColliderHelper.Vanilla.Inside.DrawCentered(Position, color * TasHelperSettings.SpinnerFillerAlpha);
172172
}
173173

174174
public static void DrawLoadRangeCollider(Vector2 Position, float Width, float Height, Vector2 CameraPos, bool isLightning) {
@@ -185,11 +185,11 @@ public static void DrawLoadRangeCollider(Vector2 Position, float Width, float He
185185
// spinner use in view for visible, and near player for collidable
186186
// dust use in view for graphics establish, and near player for collidable
187187
// so we render the center when using load range
188-
Monocle.Draw.Point(Position, SpinnerCenterColor);
189-
Monocle.Draw.Point(Position + new Vector2(-1f, -1f), SpinnerCenterColor);
190-
Monocle.Draw.Point(Position + new Vector2(-1f, 1f), SpinnerCenterColor);
191-
Monocle.Draw.Point(Position + new Vector2(1f, -1f), SpinnerCenterColor);
192-
Monocle.Draw.Point(Position + new Vector2(1f, 1f), SpinnerCenterColor);
188+
Monocle.Draw.Point(Position, SpinnerCenterColor);
189+
Monocle.Draw.Point(Position + new Vector2(-1f, -1f), SpinnerCenterColor);
190+
Monocle.Draw.Point(Position + new Vector2(-1f, 1f), SpinnerCenterColor);
191+
Monocle.Draw.Point(Position + new Vector2(1f, -1f), SpinnerCenterColor);
192+
Monocle.Draw.Point(Position + new Vector2(1f, 1f), SpinnerCenterColor);
193193
}
194194
}
195195

@@ -284,23 +284,33 @@ public static string SpinnerColliderKey(string[] hitboxString, float scale) {
284284
public static void Initialize() {
285285
// learn from https://github.com/EverestAPI/Resources/wiki/Adding-Sprites#using-a-spritebank-file
286286

287+
// it's quite foolish, as it cant spot identical expressions, i have to manually add some after i find it not working properly
288+
287289
MTexture C6_o = GFX.Game["TASHelper/SpinnerCollider/C600_outline"];
288290
MTexture C6_i = GFX.Game["TASHelper/SpinnerCollider/C600_inside"];
291+
SpinnerColliderTextures.Add(SpinnerColliderKey("C:6", 1f), new SpinnerColliderValue(C6_o, C6_i));
289292
SpinnerColliderTextures.Add(SpinnerColliderKey("C:6;0,0", 1f), new SpinnerColliderValue(C6_o, C6_i));
290293

291294
MTexture vanilla_o = GFX.Game["TASHelper/SpinnerCollider/vanilla_outline"];
292295
MTexture vanilla_i = GFX.Game["TASHelper/SpinnerCollider/vanilla_inside"];
293296
Vanilla = new SpinnerColliderValue(vanilla_o, vanilla_i);
297+
SpinnerColliderTextures.Add(SpinnerColliderKey("C:6|R:16,4;-8,-3", 1f), Vanilla);
298+
SpinnerColliderTextures.Add(SpinnerColliderKey("C:6|R:16,4;-8,*1@-4", 1f), Vanilla);
299+
SpinnerColliderTextures.Add(SpinnerColliderKey("C:6|R:16,*4;-8,*-3", 1f), Vanilla);
294300
SpinnerColliderTextures.Add(SpinnerColliderKey("C:6;0,0|R:16,4;-8,*1@-4", 1f), Vanilla);
295301
SpinnerColliderTextures.Add(SpinnerColliderKey("C:6;0,0|R:16,*4;-8,*-3", 1f), Vanilla);
296302

297303
MTexture reverted_o = GFX.Game["TASHelper/SpinnerCollider/reverted_outline"];
298304
MTexture reverted_i = GFX.Game["TASHelper/SpinnerCollider/reverted_inside"];
305+
SpinnerColliderTextures.Add(SpinnerColliderKey("C:6|R:16,4;-8,-1", 1f), new SpinnerColliderValue(reverted_o, reverted_i));
306+
SpinnerColliderTextures.Add(SpinnerColliderKey("C:6|R:16,*4;-8,*-1", 1f), new SpinnerColliderValue(reverted_o, reverted_i));
307+
SpinnerColliderTextures.Add(SpinnerColliderKey("C:6|R:16,4;-8,*-1", 1f), new SpinnerColliderValue(reverted_o, reverted_i));
299308
SpinnerColliderTextures.Add(SpinnerColliderKey("C:6;0,0|R:16,*4;-8,*-1", 1f), new SpinnerColliderValue(reverted_o, reverted_i));
300309
SpinnerColliderTextures.Add(SpinnerColliderKey("C:6;0,0|R:16,4;-8,*-1", 1f), new SpinnerColliderValue(reverted_o, reverted_i));
301310

302311
MTexture C800_o = GFX.Game["TASHelper/SpinnerCollider/C800_outline"];
303312
MTexture C800_i = GFX.Game["TASHelper/SpinnerCollider/C800_inside"];
313+
SpinnerColliderTextures.Add(SpinnerColliderKey("C:8", 1f), new SpinnerColliderValue(C800_o, C800_i));
304314
SpinnerColliderTextures.Add(SpinnerColliderKey("C:8;0,0", 1f), new SpinnerColliderValue(C800_o, C800_i));
305315
}
306316
}

0 commit comments

Comments
 (0)