Use direct buttons for fixed mission setting choices; record Workshop 0.0.149
continuous-integration/drone/push Build is passing

This commit is contained in:
2026-11-07 02:16:12 +01:00
parent e421dcfc15
commit 47cd4fa2bc
10 changed files with 156 additions and 129 deletions
@@ -47,13 +47,17 @@ class ERR_AdminMenu : ChimeraMenuBase
m_Controller = SCR_PlayerController.Cast(GetGame().GetPlayerController());
m_Mode = ERR_GameMode.Cast(GetGame().GetGameMode());
if (!m_Controller) { Close(); return; }
array<string> names = {"TelemetryOn", "TelemetryOff","SitesOn", "SitesOff", "PlaneOn", "PlaneOff", "Close", "PauseJournal", "JournalDetails", "LatestJournal", "KeepWeaponOn", "KeepWeaponOff", "SelfEpiOn", "SelfEpiOff", "IntelSummary", "RerollIntel", "RandomDay_startTimeMinutes", "Default_viewDistanceMetres", "RestartEmptyOn", "RestartEmptyOff", "RecommendedBoats", "RecommendedPlane", "RecommendedWeapons", "RecommendedDrones"};
array<string> names = {"CrashLootRandom", "CrashLootCustom", "TelemetryOn", "TelemetryOff","SitesOn", "SitesOff", "PlaneOn", "PlaneOff", "Close", "PauseJournal", "JournalDetails", "LatestJournal", "KeepWeaponOn", "KeepWeaponOff", "SelfEpiOn", "SelfEpiOff", "IntelSummary", "RerollIntel", "RandomDay_startTimeMinutes", "Default_viewDistanceMetres", "RestartEmptyOn", "RestartEmptyOff", "RecommendedBoats", "RecommendedPlane", "RecommendedWeapons", "RecommendedDrones"};
foreach (string mainButton : ERR_AdminMenuPages.MainButtons()) names.Insert(mainButton);
foreach (string pageButton : Navigation()) names.Insert(pageButton);
for (int density = 1; density <= 4; density++) names.Insert("GuardEvery_" + density.ToString());
for (int policy = 0; policy <= 2; policy++) names.Insert("GuardHQ_" + policy.ToString());
foreach (string key : ERR_AdminMenuFields.Keys())
{
array<string> choices = ERR_AdminMenuFields.Choices(key);
if (!choices.IsEmpty())
{
foreach (string choice : choices) names.Insert("Choice_" + key + "_" + choice);
continue;
}
names.Insert("Apply_" + key);
if (ERR_Settings.Randomizable(key)) names.Insert("Random_" + key);
}
@@ -162,8 +166,11 @@ class ERR_AdminMenu : ChimeraMenuBase
protected int m_SitesState = -1;
protected int m_RestartEmptyState = -1;
protected int m_TelemetryState = -1;
protected int m_CrashLootState = -1;
protected void UpdateActions()
{
ERR_SelectionStyle.Choice(SCR_ButtonTextComponent.GetButtonText("CrashLootRandom", GetRootWidget()), m_CrashLootState == 1);
ERR_SelectionStyle.Choice(SCR_ButtonTextComponent.GetButtonText("CrashLootCustom", GetRootWidget()), m_CrashLootState == 0);
ERR_SelectionStyle.Pair(GetRootWidget(), "TelemetryOn", "TelemetryOff", m_TelemetryState);
ERR_SelectionStyle.Pair(GetRootWidget(), "SitesOn", "SitesOff", m_SitesState);
ERR_SelectionStyle.Pair(GetRootWidget(), "SelfEpiOn", "SelfEpiOff", m_SelfEpiState);
@@ -172,17 +179,19 @@ class ERR_AdminMenu : ChimeraMenuBase
foreach (SCR_ButtonBaseComponent button : m_Buttons)
{
string name = button.GetRootWidget().GetName();
if (name.IndexOf("Apply_") == 0 || name.IndexOf("Random_") == 0 || name.IndexOf("RandomDay_") == 0 || name.IndexOf("Default_") == 0)
string choiceKey = ERR_AdminMenuFields.ChoiceKey(name);
if (!choiceKey.IsEmpty()) button.SetEnabled(m_Ready && m_AvailableFields.Contains(choiceKey) && ERR_AdminMenuFields.Available(choiceKey, m_HQ, m_Intel));
else if (name.IndexOf("Apply_") == 0 || name.IndexOf("Random_") == 0 || name.IndexOf("RandomDay_") == 0 || name.IndexOf("Default_") == 0)
{
int prefix = name.IndexOf("_") + 1;
string key = name.Substring(prefix, name.Length() - prefix);
button.SetEnabled(m_Ready && m_AvailableFields.Contains(key) && ERR_AdminMenuFields.Available(key, m_HQ, m_Intel));
}
else if (name == "PlaneOn" || name == "PlaneOff") button.SetEnabled(m_Ready && m_HQ && m_AvailableFields.Contains("planeReconEnabled"));
else if (name.IndexOf("GuardEvery_") == 0) button.SetEnabled(m_Ready && m_HQ && m_AvailableFields.Contains("objectGuardEvery"));
else if (name.IndexOf("GuardHQ_") == 0) button.SetEnabled(m_Ready && m_HQ && m_AvailableFields.Contains("objectGuardHQMode"));
else if (name == "RerollIntel" || name == "IntelSummary") button.SetEnabled(m_Ready && m_Intel);
else if (name == "LatestJournal") button.SetEnabled(m_Ready && m_HQ);
else if (name == "CrashLootRandom") button.SetEnabled(m_Ready && m_CrashLootState == 0);
else if (name == "CrashLootCustom") button.SetEnabled(m_Ready && m_CrashLootState == 1);
else if (name == "TelemetryOn") button.SetEnabled(m_Ready && m_TelemetryState == 0);
else if (name == "TelemetryOff") button.SetEnabled(m_Ready && m_TelemetryState == 1);
else if (name == "RestartEmptyOn") button.SetEnabled(m_Ready && m_RestartEmptyState == 0);
@@ -199,7 +208,7 @@ class ERR_AdminMenu : ChimeraMenuBase
{
if (!authorized) { Close(); return; }
if (!values) return;
m_HQ = false; m_Intel = false; m_AvailableFields.Clear(); m_KeepWeaponState = -1; m_SelfEpiState = -1; m_RestartEmptyState = -1; m_TelemetryState = -1;
m_HQ = false; m_Intel = false; m_AvailableFields.Clear(); m_KeepWeaponState = -1; m_SelfEpiState = -1; m_RestartEmptyState = -1; m_TelemetryState = -1; m_CrashLootState = -1;
foreach (string entry : values)
{
if (entry == "supports=hq") { m_HQ = true; continue; }
@@ -231,6 +240,13 @@ class ERR_AdminMenu : ChimeraMenuBase
if (ERR_AdminMenuFields.Keys().Contains(resolvedKey)) SetText("Saved_" + resolvedKey, "Saved: Random (using " + entry.Substring(divider + 1, entry.Length() - divider - 1) + ")");
continue;
}
if (key == "crashLootMode")
{
string lootMode = entry.Substring(divider + 1, entry.Length() - divider - 1);
if (lootMode == "0" || lootMode == "1") m_CrashLootState = lootMode.ToInt();
SetText("Saved_crashLootMode", "Next round: " + ERR_AdminMenuFields.Display(key, lootMode));
continue;
}
if (key == "planeReconEnabled")
{
int planeState = entry.Substring(divider + 1, entry.Length() - divider - 1).ToInt();
@@ -274,20 +290,18 @@ class ERR_AdminMenu : ChimeraMenuBase
}
if (!ERR_AdminMenuFields.Keys().Contains(key)) continue;
string saved = entry.Substring(divider + 1, entry.Length() - divider - 1);
if (ERR_Settings.Randomizable(key)) ERR_SelectionStyle.Choice(SCR_ButtonTextComponent.GetButtonText("Random_" + key, GetRootWidget()), saved == "-1");
if (ERR_Settings.Randomizable(key) && ERR_AdminMenuFields.Choices(key).IsEmpty()) ERR_SelectionStyle.Choice(SCR_ButtonTextComponent.GetButtonText("Random_" + key, GetRootWidget()), saved == "-1");
if (key == "startTimeMinutes") ERR_SelectionStyle.Choice(SCR_ButtonTextComponent.GetButtonText("RandomDay_startTimeMinutes", GetRootWidget()), saved == "-2");
if (key == "viewDistanceMetres") ERR_SelectionStyle.Choice(SCR_ButtonTextComponent.GetButtonText("Default_viewDistanceMetres", GetRootWidget()), saved == "0");
if (key == "objectGuardEvery")
for (int density = 1; density <= 4; density++)
ERR_SelectionStyle.Choice(SCR_ButtonTextComponent.GetButtonText("GuardEvery_" + density.ToString(), GetRootWidget()), saved.ToInt() == density);
if (key == "objectGuardHQMode")
for (int policy = 0; policy <= 2; policy++)
ERR_SelectionStyle.Choice(SCR_ButtonTextComponent.GetButtonText("GuardHQ_" + policy.ToString(), GetRootWidget()), saved.ToInt() == policy);
array<string> choices = ERR_AdminMenuFields.Choices(key);
foreach (string choice : choices)
ERR_SelectionStyle.Choice(SCR_ButtonTextComponent.GetButtonText("Choice_" + key + "_" + choice, GetRootWidget()), choice == ERR_AdminMenuFields.SavedChoice(key, saved));
string value = ERR_AdminMenuFields.Display(key, saved);
m_AvailableFields.Insert(key);
if (key == "startMode") SetText("Saved_" + key, ERR_AdminMenuFields.StartSummary(entry.Substring(divider + 1, entry.Length() - divider - 1).ToInt(), m_Mode.StartMode()));
else if (key == "aiDoctrine" || key == "aiShadow") SetText("Saved_" + key, "Next round: " + value);
else SetText("Saved_" + key, "Saved: " + value);
if (!choices.IsEmpty()) continue;
// Existing fields retain all draft text, including a temporarily empty edit.
if (!m_InitializedFields.Contains(key))
{
@@ -393,16 +407,14 @@ class ERR_AdminMenu : ChimeraMenuBase
return;
}
if (!m_Controller || !m_Ready || m_Age > 6 || m_ClickDelay > 0) return;
if (name.IndexOf("GuardEvery_") == 0 || name.IndexOf("GuardHQ_") == 0)
string choiceKey = ERR_AdminMenuFields.ChoiceKey(name);
if (!choiceKey.IsEmpty())
{
string guardKey = "objectGuardEvery";
if (name.IndexOf("GuardHQ_") == 0) guardKey = "objectGuardHQMode";
if (!m_HQ || !m_AvailableFields.Contains(guardKey)) return;
int guardPrefix = name.IndexOf("_") + 1;
SCR_EditBoxComponent guardEdit = SCR_EditBoxComponent.GetEditBoxComponent(guardKey, GetRootWidget());
if (guardEdit) guardEdit.SetValue(name.Substring(guardPrefix, name.Length() - guardPrefix));
SetText("Feedback", "Choice selected. Press Apply to save for next round. Green marks the saved choice.");
return;
if (!m_AvailableFields.Contains(choiceKey) || !ERR_AdminMenuFields.Available(choiceKey, m_HQ, m_Intel)) return;
int choicePrefix = choiceKey.Length() + 8;
string choice = name.Substring(choicePrefix, name.Length() - choicePrefix);
m_ClickDelay = 0.3; SetText("Feedback", "Saving selection for next round...");
m_Controller.ERR_AdminSubmit(ERR_AdminMenuFields.Command(choiceKey, choice), true); return;
}
if (name == "PlaneOn" || name == "PlaneOff")
{
@@ -411,6 +423,13 @@ class ERR_AdminMenu : ChimeraMenuBase
m_ClickDelay = 0.3; SetText("Feedback", "Saving reconnaissance plane selection for next round...");
m_Controller.ERR_AdminSubmit("mission plane set " + enabled, true); return;
}
if (name == "CrashLootRandom" || name == "CrashLootCustom")
{
if (m_CrashLootState < 0) return;
string lootMode = "custom"; if (name == "CrashLootRandom") lootMode = "random";
m_ClickDelay = 0.3; SetText("Feedback", "Saving crash-site loot mode for next round...");
m_Controller.ERR_AdminSubmit("mission crashloot set " + lootMode, true); return;
}
if (name == "TelemetryOn" || name == "TelemetryOff")
{
if (m_TelemetryState < 0) return;
@@ -3,7 +3,29 @@ class ERR_AdminMenuFields
{
static array<string> Keys()
{
return {"shoreBoatCount", "shoreBoatChancePercent", "shoreBoatCrossingChancePercent", "crashLootMode", "crashSiteCount", "crashHelicopterChancePercent", "crashRifleCount", "crashMagazineCount", "crashAntiAirChancePercent", "crashRocketChancePercent", "aiDoctrine", "aiShadow", "automaticEquipmentChancePercent", "sarkaAngerPerCar", "motorbikeCount", "droneReconCount", "droneCooldownSeconds", "planeAltitudeMetres", "planeReplacementSeconds", "planeSectorSeconds", "fieldCampCount", "fieldHospitalCount", "startWeaponCount", "startMagazineCount", "objectGuardCount", "objectGuardEvery", "objectGuardHQMode", "hunterSpawnDistanceMetres", "roadblockCount", "largeRoadblockCount", "mainRoadWidthMetres", "civilianTrafficCount", "garageVehicleCount", "garageChancePercent", "garageRadiusMetres", "garageSpawnIntervalSeconds", "emptyRestartHours", "startMode", "radioDefenceSeconds", "aiIntelChancePercent", "intelRevealChancePercent", "radioIntelSiteCount", "startTimeMinutes", "timeMultiplier", "startDateCode", "weatherProfile", "viewDistanceMetres", "reportIntervalSeconds", "supportSquadLimit", "responseRadiusMetres", "convoyCount", "antiAirChancePercent", "antiPersonnelMineChancePercent", "heliTimerMinutes"};
return {"shoreBoatCount", "shoreBoatChancePercent", "shoreBoatCrossingChancePercent", "crashSiteCount", "crashHelicopterChancePercent", "crashRifleCount", "crashMagazineCount", "crashAntiAirChancePercent", "crashRocketChancePercent", "aiDoctrine", "aiShadow", "automaticEquipmentChancePercent", "sarkaAngerPerCar", "motorbikeCount", "droneReconCount", "droneCooldownSeconds", "planeAltitudeMetres", "planeReplacementSeconds", "planeSectorSeconds", "fieldCampCount", "fieldHospitalCount", "startWeaponCount", "startMagazineCount", "objectGuardCount", "objectGuardEvery", "objectGuardHQMode", "hunterSpawnDistanceMetres", "roadblockCount", "largeRoadblockCount", "mainRoadWidthMetres", "civilianTrafficCount", "garageVehicleCount", "garageChancePercent", "garageRadiusMetres", "garageSpawnIntervalSeconds", "emptyRestartHours", "startMode", "radioDefenceSeconds", "aiIntelChancePercent", "intelRevealChancePercent", "radioIntelSiteCount", "startTimeMinutes", "timeMultiplier", "startDateCode", "weatherProfile", "viewDistanceMetres", "reportIntervalSeconds", "supportSquadLimit", "responseRadiusMetres", "convoyCount", "antiAirChancePercent", "antiPersonnelMineChancePercent", "heliTimerMinutes"};
}
// Only bounded named modes belong here; quantities and free-form values stay edits.
static array<string> Choices(string key)
{
if (key == "startMode") return {"prison", "crash"};
if (key == "aiDoctrine") return {"current", "coordinated"};
if (key == "aiShadow") return {"off", "on"};
if (key == "objectGuardEvery") return {"1", "2", "3", "4"};
if (key == "objectGuardHQMode") return {"0", "1", "2"};
if (key == "weatherProfile") return {"authored", "clear", "overcast", "rain", "random"};
return {};
}
static string ChoiceKey(string button)
{
if (!button.StartsWith("Choice_")) return "";
array<string> parts = {}; button.Split("_", parts, false);
if (parts.Count() != 3 || !Choices(parts[1]).Contains(parts[2])) return "";
return parts[1];
}
static string SavedChoice(string key, string saved)
{
string choice = Display(key, saved); choice.ToLower(); return choice;
}
static bool Available(string key, bool hq, bool intel)
{