-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathRainbowKnight.cs
219 lines (185 loc) · 7.95 KB
/
RainbowKnight.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
using System;
using System.Collections.Generic;
using ChromaSDK;
using Modding;
using RazerAPI;
namespace RainbowKnight
{
public class RainbowKnight : Mod
{
private RainbowChromaHelper _chromaHelper;
private readonly Dictionary<string, bool> _animState = new Dictionary<string, bool>();
private bool _stateRequestsBackground;
private int _frameCount;
public RainbowKnight() : base("RainbowKnight")
{
}
public override string GetVersion()
{
return "0.2.0";
}
public override void Initialize()
{
Log("Start RainbowKnight Init");
_chromaHelper = new RainbowChromaHelper();
if (!_chromaHelper.Start()) return; // There was an error at startup, don't register any hook
Log("Razer SDK init: " + RazerErrors.GetResultString(_chromaHelper.GetInitResult()));
ModHooks.Instance.TakeHealthHook += OnTakeHealth;
ModHooks.Instance.BeforePlayerDeadHook += OnPlayerDead;
ModHooks.Instance.ApplicationQuitHook += OnApplicationQuit;
ModHooks.Instance.HeroUpdateHook += OnHeroUpdate;
ModHooks.Instance.LanguageGetHook += OnLanguageGet;
ModHooks.Instance.SetPlayerBoolHook += OnSetPlayerBool;
_chromaHelper.PlayBackground();
}
/// <summary>
/// Triggers or stops an animation when the condition is toggled
/// </summary>
/// <param name="condition">Condition to test</param>
/// <param name="state">An arbitrary string key to differentiate calls to this function</param>
/// <param name="animation">The animation to be triggered when `condition` becomes true</param>
/// <returns>true if the animation was triggered, false if nothing was done or Background was resumed</returns>
private bool BooleanAnimationUpdate(bool condition, string state, Action animation)
{
var stateActive = _animState.ContainsKey(state) && _animState[state];
switch (condition) {
case true when !stateActive:
LogDebug("Triggering " + state + " animation");
_animState[state] = true;
_stateRequestsBackground = false; // Cancel any in-progress "background resume" request
animation();
return true;
case false when stateActive:
LogDebug("Requesting background resume " + state + " ended");
_animState[state] = false;
_stateRequestsBackground = true;
return false;
}
return false;
}
private string OnLanguageGet(string key, string sheet)
{
// This is a "hack" to detect when we're back to the main menu, so that we can reset all lighting
if (key == "MAIN_OPTIONS")
_chromaHelper.PlayBackground();
return Language.Language.GetInternal(key, sheet);
}
private bool UpdateCrystalDashLoadState()
{
return BooleanAnimationUpdate(
HeroController.instance.superDash.ActiveStateName.StartsWith("Ground Charge") ||
HeroController.instance.superDash.ActiveStateName.StartsWith("Wall Charge"),
"Cdash_charge",
_chromaHelper.PlayFullPinkLoad
);
}
private bool UpdateCrystalDashFlyState()
{
return BooleanAnimationUpdate(
HeroController.instance.cState.superDashing,
"Cdash_fly",
_chromaHelper.PlayFullPinkFlash
);
}
private bool UpdateSpellState()
{
return BooleanAnimationUpdate(
HeroController.instance.spellControl.ActiveStateName != "Inactive" &&
HeroController.instance.spellControl.ActiveStateName != "Button Down",
"Spell",
_chromaHelper.PlayColouredRing
);
}
private bool UpdateNailChargeState()
{
return BooleanAnimationUpdate(
HeroController.instance.cState.nailCharging,
"Nail_charging",
_chromaHelper.PlayFullWhite
);
}
private bool UpdateMovementState()
{
return BooleanAnimationUpdate(
HeroController.instance.cState.bouncing ||
HeroController.instance.cState.doubleJumping ||
HeroController.instance.cState.dashing ||
HeroController.instance.cState.shroomBouncing,
"Double_Jumping",
_chromaHelper.PlayWhiteBars
);
}
/**
* Updates for things I didn't find a cleaner trigger for (either a dedicated hook or an Int / Bool value)
*/
private void OnHeroUpdate()
{
// Don't update things too frequently, we don't want to burn people's CPUs
if (++_frameCount < 10) return;
_frameCount = 0;
// These "if → return" make sure we only trigger one animation per cycle.
// Not that there is anything wrong with triggering several, but it allows to set a priority for which
// animation should be triggered if its state is active
if (UpdateMovementState()) return;
if (UpdateCrystalDashFlyState()) return;
if (UpdateCrystalDashLoadState()) return;
if (UpdateSpellState()) return;
if (UpdateDreamNailSlashState()) return;
if (UpdateDreamNailChargeState()) return;
if (UpdateNailChargeState()) return;
// Resuming the background should have the absolute lowest priority, which is why we don't resume it in
// each `Update*` function directly, but only ask for it to be resumed (which might end up not being
// necessary if another animation needs to run instead)
if (_stateRequestsBackground && !_animState.ContainsValue(true)) {
LogDebug("Effectively resuming background animation");
_stateRequestsBackground = false;
_chromaHelper.PlayBackground();
}
}
private static PlayMakerFSM DreamFSM()
{
return HeroController.instance.gameObject.LocateMyFSM("Dream Nail");
}
private bool UpdateDreamNailChargeState()
{
var state = DreamFSM().ActiveStateName;
return BooleanAnimationUpdate(
state.Contains("Charge") || state == "Slash Antic",
"Dream_Nail_charging",
_chromaHelper.PlayYellowDiskLoad
);
}
private bool UpdateDreamNailSlashState()
{
var state = DreamFSM().ActiveStateName;
return BooleanAnimationUpdate(
state == "Slash" || state == "Warp Effect" || state == "Set Antic",
"Dream_Nailing_slashing",
_chromaHelper.PlayYellowFlash
);
}
private void OnPlayerDead()
{
_chromaHelper.PlayFullRed();
}
private int OnTakeHealth(int damage)
{
_chromaHelper.PlayRedRing();
return damage;
}
private void OnSetPlayerBool(string set, bool value)
{
BooleanAnimationUpdate(
set == "atBench",
"Benching",
_chromaHelper.PlayFullWhite
);
PlayerData.instance.SetBoolInternal(set, value);
}
// Uninitialize Razer's SDK if the game gracefully exits
private void OnApplicationQuit()
{
_chromaHelper.OnApplicationQuit();
}
}
}