Skip to content

Commit 0e9481c

Browse files
committed
first commit
1 parent 2938a19 commit 0e9481c

18 files changed

Lines changed: 808 additions & 17 deletions

ConfigEntryEnum.cs

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
using UnityEngine;
2+
3+
namespace SpawnControlModNS
4+
{
5+
public class ConfigEntryEnum<T> : ConfigEntryModalHelper where T : Enum
6+
{
7+
private int content; // access via BoxedValue
8+
private int defaultValue; // access via BoxedValue
9+
private CustomButton anchor; // this holds the ModOptionsScreen text that is clicked to open the menu
10+
11+
public delegate string OnDisplayAnchorText(); // the text seen in the main option screen
12+
public delegate string OnDisplayAnchorTooltip(); // the text seen in the main option screen
13+
public delegate string OnDisplayEnumText(T t);
14+
public delegate string OnDisplayEnumTooltip(T t);
15+
public OnDisplayAnchorText onDisplayAnchorText;
16+
public OnDisplayAnchorTooltip onDisplayAnchorTooltip;
17+
public OnDisplayEnumText onDisplayEnumText;
18+
public OnDisplayEnumTooltip onDisplayEnumTooltip;
19+
20+
public delegate bool OnChange(T newValue); // return false to prevent acceptance of newValue
21+
public OnChange onChange;
22+
23+
public string popupMenuTitleText; // the title bar text of the popup screen
24+
public string popupMenuHelpText; // the help text that appears below the title bar text
25+
26+
public string CloseButtonTextTerm = null; // if null, no close button is created
27+
public Color currentValueColor = Color.black;
28+
29+
public virtual T DefaultValue { get => (T)(object)defaultValue; set => defaultValue = (int)(object)value; }
30+
public virtual T Value { get => (T)(object)content; set => content = (int)(object)value; }
31+
32+
public override object BoxedValue
33+
{
34+
get => content;
35+
set => content = (int)value;
36+
}
37+
38+
public ConfigEntryEnum(string name, ConfigFile configFile, T defaultValue, ConfigUI ui = null)
39+
{
40+
Name = name;
41+
ValueType = typeof(System.Object); // to avoid shenanigans from ModOptionScreen's default processing of string/int/bool
42+
DefaultValue = defaultValue;
43+
Config = configFile;
44+
if (Config.Data.TryGetValue(name, out _))
45+
{
46+
BoxedValue = Config.GetValue<int>(name); // store as int to make it easier to reload.
47+
}
48+
else
49+
{
50+
BoxedValue = defaultValue;
51+
}
52+
UI = new ConfigUI()
53+
{
54+
Hidden = true,
55+
Name = ui?.Name,
56+
NameTerm = ui?.NameTerm ?? name,
57+
Tooltip = ui?.Tooltip,
58+
TooltipTerm = ui?.TooltipTerm,
59+
PlaceholderText = ui?.PlaceholderText,
60+
RestartAfterChange = ui?.RestartAfterChange ?? false,
61+
ExtraData = ui?.ExtraData,
62+
OnUI = delegate (ConfigEntryBase c)
63+
{
64+
anchor = DefaultButton(I.MOS.ButtonsParent,
65+
onDisplayAnchorText != null ? onDisplayAnchorText() : c.UI.GetName(),
66+
onDisplayAnchorTooltip != null ? onDisplayAnchorTooltip() : c.UI.GetTooltip());
67+
anchor.Clicked += delegate
68+
{
69+
OpenMenu();
70+
};
71+
}
72+
};
73+
configFile.Entries.Add(this);
74+
}
75+
76+
private string EntryText(T entry)
77+
{
78+
string text = onDisplayEnumText != null ? onDisplayEnumText(entry) : Enum.GetName(typeof(T), entry);
79+
if (currentValueColor != null && EqualityComparer<T>.Default.Equals(entry, (T)BoxedValue))
80+
{
81+
text = ColorText(currentValueColor, text);
82+
}
83+
return text;
84+
}
85+
86+
private string EntryTooltip(T entry)
87+
{
88+
return onDisplayEnumTooltip != null ? onDisplayEnumTooltip(entry) : null;
89+
}
90+
91+
private void OpenMenu()
92+
{
93+
if (GameCanvas.instance.ModalIsOpen) return;
94+
ModalScreen.instance.Clear();
95+
popup = ModalScreen.instance;
96+
popup.SetTexts(I.Xlat(popupMenuTitleText), I.Xlat(popupMenuHelpText));
97+
foreach (T t in Enum.GetValues(typeof(T)))
98+
{
99+
T thisEntry = t; // so the delegate grabs the correct value, not the loop variable
100+
CustomButton btn = DefaultButton(popup.ButtonParent,
101+
EntryText(thisEntry),
102+
EntryTooltip(thisEntry));
103+
btn.Clicked += delegate ()
104+
{
105+
if (onChange == null || onChange(thisEntry))
106+
{
107+
Config.Data[Name] = (int)(object)thisEntry;
108+
content = (int)(object)thisEntry;
109+
anchor.TextMeshPro.text = onDisplayAnchorText != null ? onDisplayAnchorText() : UI.GetName();
110+
CloseMenu();
111+
}
112+
};
113+
}
114+
if (CloseButtonTextTerm != null)
115+
{
116+
CustomButton btnClose = DefaultButton(ModalScreen.instance.ButtonParent, RightAlign(I.Xlat(CloseButtonTextTerm)));
117+
btnClose.Clicked += CloseMenu;
118+
}
119+
GameCanvas.instance.OpenModal();
120+
}
121+
122+
public override void SetDefaults()
123+
{
124+
Config.Data[Name] = content = defaultValue;
125+
anchor.TextMeshPro.text = onDisplayAnchorText != null ? onDisplayAnchorText() : UI.GetName();
126+
anchor.TooltipText = onDisplayAnchorTooltip != null ? onDisplayAnchorTooltip() : UI.GetTooltip();
127+
}
128+
}
129+
}

ConfigEntryHelper.cs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
using Newtonsoft.Json.Linq;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Text;
5+
using UnityEngine;
6+
7+
namespace SpawnControlModNS
8+
{
9+
public abstract class ConfigEntryHelper : ConfigEntryBase
10+
{
11+
public virtual void SetDefaults() { }
12+
13+
public static string CenterAlign(string txt)
14+
{
15+
return "<align=center>" + txt + "</align>";
16+
}
17+
18+
public static string RightAlign(string txt)
19+
{
20+
return "<align=right>" + txt + "</align>";
21+
}
22+
23+
public static string ColorText(string color, string txt)
24+
{
25+
return $"<color={color}>" + txt + "</color>";
26+
}
27+
28+
public static string ColorText(Color color, string txt)
29+
{
30+
return $"<color=#{ColorUtility.ToHtmlStringRGBA(color)}>" + txt + "</color>";
31+
}
32+
33+
public static string SizeText(int pixels, string txt)
34+
{
35+
if (pixels <= 0) return txt;
36+
return $"<size={pixels}>" + txt + "</size>";
37+
}
38+
39+
public CustomButton DefaultButton(RectTransform parent, string text, string tooltip = null)
40+
{
41+
CustomButton btn = UnityEngine.Object.Instantiate(I.PFM.ButtonPrefab);
42+
btn.transform.SetParent(parent);
43+
btn.transform.localPosition = Vector3.zero;
44+
btn.transform.localScale = Vector3.one;
45+
btn.transform.localRotation = Quaternion.identity;
46+
btn.TextMeshPro.text = text;
47+
btn.TooltipText = tooltip;
48+
return btn;
49+
}
50+
51+
public T LoadConfigEntry<T>(string key, T defValue)
52+
{
53+
if (Config.Data.TryGetValue(key, out JToken value))
54+
{
55+
return value.Value<T>();
56+
}
57+
return defValue;
58+
}
59+
}
60+
61+
public class ConfigEmtySpace : ConfigEntryBase
62+
{
63+
private RectTransform spacer1, spacer2;
64+
public override object BoxedValue { get => new object(); set => _ = value; }
65+
66+
public ConfigEmtySpace(ConfigFile Config)
67+
{
68+
Name = "none";
69+
ValueType = typeof(object);
70+
Config.Entries.Add(this);
71+
UI = new ConfigUI()
72+
{
73+
Hidden = true,
74+
OnUI = delegate {
75+
spacer1 = UnityEngine.Object.Instantiate(I.MOS.SpacerPrefab, I.MOS.ButtonsParent);
76+
spacer2 = UnityEngine.Object.Instantiate(I.MOS.SpacerPrefab, I.MOS.ButtonsParent);
77+
}
78+
};
79+
}
80+
81+
}
82+
}

ConfigEntryModalHelper.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
using UnityEngine;
5+
6+
namespace SpawnControlModNS
7+
{
8+
// Base class for Configuration Entries that open a modal dialog.
9+
public abstract class ConfigEntryModalHelper : ConfigEntryHelper
10+
{
11+
protected static ModalScreen popup;
12+
protected CustomButton AnchorButton;
13+
14+
public void CloseMenu()
15+
{
16+
GameCanvas.instance.CloseModal();
17+
popup = null;
18+
}
19+
}
20+
}

ConfigFreeText.cs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using UnityEngine;
2+
using UnityEngine.UI;
3+
4+
namespace SpawnControlModNS
5+
{
6+
public class ConfigFreeText : ConfigEntryHelper
7+
{
8+
public string Text;
9+
public override object BoxedValue { get => new object(); set => _ = value; }
10+
11+
public Action<ConfigEntryBase, CustomButton> Clicked;
12+
13+
/**
14+
* Create a header line in the config screen. Also useful for stuff like "Close" in ModalScreen
15+
**/
16+
public ConfigFreeText(string name, ConfigFile config, string text, string tooltip = null)
17+
{
18+
Name = name;
19+
Config = config;
20+
ValueType = typeof(object);
21+
UI = new ConfigUI()
22+
{
23+
NameTerm = text,
24+
Hidden = true,
25+
OnUI = delegate (ConfigEntryBase c)
26+
{
27+
CustomButton btn = UnityEngine.Object.Instantiate(I.PFM.ButtonPrefab, I.MOS.ButtonsParent);
28+
btn.transform.localScale = Vector3.one;
29+
btn.transform.localPosition = Vector3.zero;
30+
btn.transform.localRotation = Quaternion.identity;
31+
btn.TextMeshPro.text = RightAlign(I.Xlat(UI.NameTerm));
32+
btn.TooltipText = I.Xlat(tooltip);
33+
btn.EnableUnderline = false;
34+
btn.Clicked += delegate ()
35+
{
36+
Clicked?.Invoke(this, btn);
37+
};
38+
}
39+
};
40+
config.Entries.Add(this);
41+
}
42+
}
43+
}

ConfigSpawnSites.cs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
using HarmonyLib;
2+
using System;
3+
using System.Collections.Generic;
4+
using System.Text;
5+
using UnityEngine;
6+
7+
namespace SpawnControlModNS
8+
{
9+
public partial class SpawnControlMod : Mod
10+
{
11+
public ConfigSpawnSites configSpawnSites;
12+
13+
public float Xconfine => UnityEngine.Random.Range(lowX, highX);
14+
public float Zconfine => UnityEngine.Random.Range(lowZ, highZ);
15+
16+
private float lowX = 0f, highX = 1f;
17+
private float lowZ = 0f, highZ = 1f;
18+
public void ApplySpawnSites()
19+
{
20+
switch (configSpawnSites.Value)
21+
{
22+
case SpawnSites.Anywhere: lowX = lowZ = 0.1f; highX = highZ = 0.9f; break;
23+
case SpawnSites.Center: lowX = lowZ = 0.4f; highX = highZ = 0.6f; break;
24+
case SpawnSites.LowerLeft: lowX = lowZ = 0.1f; highX = highZ = 0.3f; break;
25+
case SpawnSites.UpperRight: lowX = lowZ = 0.7f; highX = highZ = 0.9f; break;
26+
case SpawnSites.LowerRight: lowX = 0.7f; lowZ = 0.1f; highX = 0.9f; highZ = 0.3f; break;
27+
case SpawnSites.UpperLeft: lowX = 0.1f; lowZ = 0.7f; highX = 0.3f; highZ = 0.9f; break;
28+
}
29+
Log($"Spawn Location Ranges: X({lowX:F1} to {highX:F1}), Y({lowZ:F1} to {highZ:F1})");
30+
}
31+
32+
public string YesNo(bool b) { return b ? "Yes" : "No"; }
33+
}
34+
35+
public enum SpawnSites
36+
{
37+
Anywhere, Center, UpperLeft, UpperRight, LowerLeft, LowerRight
38+
};
39+
40+
public class ConfigSpawnSites : ConfigEntryEnum<SpawnSites>
41+
{
42+
public ConfigSpawnSites(string name, ConfigFile configFile, SpawnSites defaultValue, ConfigUI ui = null)
43+
: base(name, configFile, defaultValue, ui)
44+
{
45+
currentValueColor = Color.blue;
46+
onDisplayAnchorText = delegate ()
47+
{
48+
return I.Xlat("spawncontrolmod_config_anchor") + " " + ColorText(currentValueColor, I.Xlat($"spawncontrolmod_config_{(SpawnSites)Value}"));
49+
};
50+
onDisplayAnchorTooltip = delegate ()
51+
{
52+
return I.Xlat("spawncontrolmod_config_anchor_tooltip");
53+
};
54+
onDisplayEnumText = delegate (SpawnSites s)
55+
{
56+
return I.Xlat($"spawncontrolmod_config_{s}");
57+
};
58+
onDisplayEnumTooltip = delegate (SpawnSites s)
59+
{
60+
SokTerm term = SokLoc.instance.CurrentLocSet.GetTerm($"spawncontrolmod_config_tooltip_{s}");
61+
if (term == null) return null;
62+
return I.Xlat($"spawncontrolmod_config_tooltip_{s}");
63+
};
64+
popupMenuTitleText = "spawncontrolmod_config_menu_text";
65+
popupMenuHelpText = "spawncontrolmod_config_menu_tooltip";
66+
67+
CloseButtonTextTerm = "spawncontrolmod_closemenu";
68+
}
69+
}
70+
71+
[HarmonyPatch(typeof(WorldManager), nameof(WorldManager.GetRandomSpawnPosition))]
72+
internal class SpawnPosition_Patch
73+
{
74+
static bool Prefix(WorldManager __instance, ref Vector3 __result)
75+
{
76+
Bounds worldBounds = __instance.CurrentBoard.WorldBounds;
77+
// SpawnControlMod.Log($"GetRandomSpawnPosition() Min/Max X {worldBounds.min.x}/{worldBounds.max.x} Min/Max Z {worldBounds.min.z}/{worldBounds.max.z}");
78+
float x = Mathf.Lerp(worldBounds.min.x, worldBounds.max.x, SpawnControlMod.instance.Xconfine);
79+
float z = Mathf.Lerp(worldBounds.min.z, worldBounds.max.z, SpawnControlMod.instance.Zconfine);
80+
__result = new Vector3(x, 0f, z);
81+
// SpawnControlMod.Log($"GetRandomSpawnPosition() {__result}");
82+
return false;
83+
}
84+
}
85+
86+
}

0 commit comments

Comments
 (0)