Skip to content

Commit ae40fd3

Browse files
Editor: Restrict level end trigger chars
1 parent 1cb49b8 commit ae40fd3

File tree

1 file changed

+86
-4
lines changed

1 file changed

+86
-4
lines changed

BetterLevelEditor/Main.cs

Lines changed: 86 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Collections.Generic;
88
using System.IO;
99
using System.Linq;
10+
using System.Reflection.Emit;
1011
using UnityEngine;
1112
using UnityEngine.UI;
1213

@@ -21,6 +22,17 @@ public class Main : BaseUnityPlugin
2122

2223
internal static ManualLogSource StaticLogger;
2324

25+
private static bool isSpawning = false;
26+
private static MiCharacter.CharacterType optionUsableByCharType;
27+
private static MiCharacter.CharacterType[] playerChars =
28+
{
29+
MiCharacter.CharacterType.Cooper,
30+
MiCharacter.CharacterType.McCoy,
31+
MiCharacter.CharacterType.Trapper,
32+
MiCharacter.CharacterType.Kate,
33+
MiCharacter.CharacterType.Voodoo,
34+
};
35+
2436
public ConfigEntry<KeyboardShortcut> ShowHotkey { get; private set; }
2537
public ConfigEntry<KeyboardShortcut> SpawnHotkey { get; private set; }
2638
private ConfigEntry<Favorites> FavoritesConfig { get; set; }
@@ -43,11 +55,14 @@ public class Main : BaseUnityPlugin
4355
public Main()
4456
{
4557
_windowId = GetHashCode();
58+
optionUsableByCharType = playerChars.Aggregate((a, b) => a | b);
4659
}
4760

4861
private bool _show = false;
49-
public bool Show {
50-
get => _show; set {
62+
public bool Show
63+
{
64+
get => _show; set
65+
{
5166
if (Show != value)
5267
{
5368
_show = value;
@@ -64,7 +79,7 @@ public bool Show {
6479
panel.transform.SetParent(_clickBlockerCanvas.transform);
6580
_clickBlockerRect = panel.GetComponent<RectTransform>();
6681
UpdateClickBlockerSize();
67-
panel.GetComponent<Image>().color = new Color(0, 0, 0, 0.3f);
82+
panel.GetComponent<Image>().color = new Color(0, 0, 0, 0.8f);
6883
}
6984
else
7085
{
@@ -113,19 +128,25 @@ private void Awake()
113128
error = "Failed to load 'spawn_codes.txt': " + e;
114129
Logger.LogError(error);
115130
}
131+
132+
Harmony.CreateAndPatchAll(typeof(Patch));
116133
}
117134

118135
private void Update()
119136
{
120137
if (Input.GetKeyDown(ShowHotkey.Value.MainKey))
138+
{
121139
Show = !Show;
140+
}
122141

123142
if (Input.GetKeyDown(SpawnHotkey.Value.MainKey) && selectedCode != -1 && MiGameInput.instance.iPlayerCharacterCount > 0)
124143
{
125144
var inputs = AccessTools.Field(typeof(UIManager), "m_dicPlayerInputs").GetValue(UIManager.instance) as Dictionary<GameUser, MiPlayerInput>;
126145
foreach (var input in inputs.Values)
127146
{
147+
isSpawning = true;
128148
input.devSpawn(selectedCode / 100, selectedCode % 100);
149+
isSpawning = false;
129150
break;
130151
}
131152
}
@@ -180,17 +201,34 @@ private void DisplayWindow(int id)
180201
GUILayout.EndHorizontal();
181202
}
182203
GUILayout.EndScrollView();
204+
DrawOptions();
183205
GUILayout.EndVertical();
184206

185207
GUI.DragWindow();
186208
UpdateClickBlockerSize();
187209
}
188210

211+
private void DrawOptions()
212+
{
213+
// TODO: Enemy health?
214+
if (selectedCode == 6118)
215+
{
216+
GUILayout.BeginVertical("box");
217+
foreach (var c in playerChars)
218+
{
219+
var isActive = (optionUsableByCharType & c) != 0;
220+
var shouldActive = GUILayout.Toggle(isActive, c.ToNiceString());
221+
if (shouldActive != isActive) optionUsableByCharType ^= c;
222+
}
223+
GUILayout.EndVertical();
224+
}
225+
}
226+
189227
private void UpdateClickBlockerSize()
190228
{
191229
if (_clickBlockerRect == null) return;
192230
_clickBlockerRect.anchorMin = new Vector2(WindowRect.x / Screen.width, 1 - WindowRect.y / Screen.height);
193-
_clickBlockerRect.anchorMax = new Vector2(WindowRect.xMax / Screen.width, 1- WindowRect.yMax / Screen.height);
231+
_clickBlockerRect.anchorMax = new Vector2(WindowRect.xMax / Screen.width, 1 - WindowRect.yMax / Screen.height);
194232
_clickBlockerRect.offsetMin = Vector2.zero;
195233
_clickBlockerRect.offsetMax = Vector2.zero;
196234
_clickBlockerRect.offsetMax = Vector2.zero;
@@ -215,6 +253,34 @@ private bool IsFavorite(int code)
215253
{
216254
return favorites.Set.Contains(code);
217255
}
256+
257+
public static void PostSpawnUsable(GameObject go)
258+
{
259+
if (!isSpawning) return;
260+
MiUsable usable = go.GetComponent<MiUsable>();
261+
usable.m_eCanUsedBy = optionUsableByCharType;
262+
}
263+
}
264+
265+
[HarmonyPatch]
266+
class Patch
267+
{
268+
[HarmonyTranspiler]
269+
[HarmonyPatch(typeof(MiGameInput), nameof(MiGameInput.devSpawnUsable))]
270+
public static IEnumerable<CodeInstruction> MiGameInput_devSpawnUsable_Transpiler(IEnumerable<CodeInstruction> instructions)
271+
{
272+
return new CodeMatcher(instructions)
273+
.MatchForward(false,
274+
new CodeMatch(OpCodes.Ldc_I4_1),
275+
new CodeMatch(OpCodes.Ret))
276+
.Repeat(matcher => matcher
277+
.InsertAndAdvance(
278+
new CodeInstruction(OpCodes.Ldloc_1),
279+
new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(Main), nameof(Main.PostSpawnUsable))))
280+
.Advance(2)
281+
)
282+
.InstructionEnumeration();
283+
}
218284
}
219285

220286
public struct SpawnCode
@@ -252,4 +318,20 @@ public Favorites(List<int> favorites)
252318
Set = new HashSet<int>(List);
253319
}
254320
}
321+
322+
static class Extensions
323+
{
324+
public static String ToNiceString(this MiCharacter.CharacterType c)
325+
{
326+
switch (c)
327+
{
328+
case MiCharacter.CharacterType.Cooper: return "Cooper";
329+
case MiCharacter.CharacterType.McCoy: return "McCoy";
330+
case MiCharacter.CharacterType.Trapper: return "Hector";
331+
case MiCharacter.CharacterType.Kate: return "Kate";
332+
case MiCharacter.CharacterType.Voodoo: return "Isabelle";
333+
default: return "Non-player character";
334+
}
335+
}
336+
}
255337
}

0 commit comments

Comments
 (0)