Enable finite automatic convoy startup and scoped gunner skill

This commit is contained in:
2026-09-20 08:23:19 +02:00
parent 782c163c68
commit 5bd66d76ca
44 changed files with 3694 additions and 48 deletions
@@ -176,7 +176,12 @@ class ERR_AdminService
if (!mode.Settings()) { replies.Insert("Mission settings are not ready."); return; }
if (arguments == "settings")
{
foreach (string key : ERR_Settings.Keys()) replies.Insert(key + "=" + mode.Settings().Get(key).ToString());
foreach (string key : ERR_Settings.Keys())
{
string line = key + "=" + mode.Settings().Get(key).ToString();
if (key == "automaticConvoyEnabled") line += " (saved for next round; current startup unchanged)";
replies.Insert(line);
}
return;
}
if (Extension(mode, arguments, replies)) return;
@@ -33,10 +33,19 @@ class ERR_EscapeGameOverScreenInfo : SCR_BaseGameOverScreenInfo
modded class SCR_GameOverScreenContentUIComponent
{
protected bool m_ERREscapeContent;
protected ERR_GameMode m_ERRFailureMode;
override void InitContent(SCR_GameOverScreenUIContentData endScreenUIContent)
{
SCR_PlayerController.ERR_OnEscapeResultChanged().Remove(ERR_RefreshEscapeContent);
if (m_ERRFailureMode) m_ERRFailureMode.OnEndReasonChanged().Remove(ERR_RefreshFailureContent);
m_ERRFailureMode = null;
super.InitContent(endScreenUIContent);
if (ERR_FailureGameOverScreenInfo.Cast(endScreenUIContent.m_GameOverInfo))
{
m_ERRFailureMode = ERR_GameMode.Get();
if (m_ERRFailureMode) m_ERRFailureMode.OnEndReasonChanged().Insert(ERR_RefreshFailureContent);
ERR_RefreshFailureContent();
}
m_ERREscapeContent = ERR_EscapeGameOverScreenInfo.Cast(endScreenUIContent.m_GameOverInfo) != null;
if (!m_ERREscapeContent) return;
SCR_PlayerController.ERR_OnEscapeResultChanged().Insert(ERR_RefreshEscapeContent);
@@ -54,10 +63,20 @@ modded class SCR_GameOverScreenContentUIComponent
if (title) title.SetText(info.GetTitle(playerId, null));
if (debrief) debrief.SetText(info.GetDebriefing(playerId, null));
}
// Native end data can open the defeat screen before the mission reason arrives.
protected void ERR_RefreshFailureContent()
{
if (!m_ERRFailureMode || m_ERRFailureMode != ERR_GameMode.Get() || !m_wRoot) return;
ERR_FailureGameOverScreenInfo info = new ERR_FailureGameOverScreenInfo();
TextWidget debrief = TextWidget.Cast(m_wRoot.FindAnyWidget(m_sDebriefingName));
if (debrief) debrief.SetText(info.GetDebriefing(-1, null));
}
override void HandlerDeattached(Widget w)
{
SCR_PlayerController.ERR_OnEscapeResultChanged().Remove(ERR_RefreshEscapeContent);
m_ERREscapeContent = false;
if (m_ERRFailureMode) m_ERRFailureMode.OnEndReasonChanged().Remove(ERR_RefreshFailureContent);
m_ERRFailureMode = null;
super.HandlerDeattached(w);
}
}
+4 -1
View File
@@ -30,7 +30,7 @@ class ERR_GameMode : SCR_BaseGameMode
protected ref array<ERR_LocationComponent> m_Locations = {};
protected ref array<IEntity> m_OwnedEntities = {};
protected ref ERR_ExtractionService m_Extraction;
[RplProp()]
[RplProp(onRplName: "ERR_OnEndReasonReplicated")]
protected string m_EndReason;
protected ref ERR_RadioDefenceService m_RadioDefence;
[RplProp()]
@@ -44,6 +44,7 @@ class ERR_GameMode : SCR_BaseGameMode
protected bool m_Stopped;
protected bool m_NativeEndHandled;
protected float m_NoSurvivorsSince = -1;
protected ref ScriptInvoker m_OnEndReasonChanged = new ScriptInvoker();
protected ref ScriptInvoker m_OnPhaseChanged = new ScriptInvoker();
protected ref ScriptInvoker m_OnTick = new ScriptInvoker();
protected ref ScriptInvoker m_OnStop = new ScriptInvoker();
@@ -71,6 +72,8 @@ class ERR_GameMode : SCR_BaseGameMode
ERR_Objectives Objectives() { return m_Objectives; }
ERR_ExtractionService Extraction() { return m_Extraction; }
string EndReason() { return m_EndReason; }
ScriptInvoker OnEndReasonChanged() { return m_OnEndReasonChanged; }
protected void ERR_OnEndReasonReplicated() { m_OnEndReasonChanged.Invoke(); }
Vehicle ExtractionVehicle()
{
if (!m_Extraction) return null;
+4 -1
View File
@@ -8,11 +8,12 @@ class ERR_Settings
static array<string> Keys()
{
return {"reportIntervalSeconds", "supportSquadLimit", "responseRadiusMetres", "aiIntelChancePercent", "intelRevealChancePercent", "radioDefenceSeconds", "startTimeMinutes", "timeMultiplier", "startDateCode", "weatherProfile", "stingerChanceOneIn"};
return {"reportIntervalSeconds", "supportSquadLimit", "responseRadiusMetres", "aiIntelChancePercent", "intelRevealChancePercent", "radioDefenceSeconds", "startTimeMinutes", "timeMultiplier", "startDateCode", "weatherProfile", "stingerChanceOneIn", "automaticConvoyEnabled"};
}
static bool Valid(string key, int value)
{
if (key == "automaticConvoyEnabled") return value == 0 || value == 1;
if (key == "stingerChanceOneIn") return value >= 0 && value <= 10000;
if (key == "reportIntervalSeconds") return value >= 5 && value <= 60;
if (key == "supportSquadLimit") return value >= 0 && value <= 8;
@@ -45,6 +46,7 @@ class ERR_Settings
static int AddedDefault(string key)
{
if (key == "automaticConvoyEnabled") return 1;
if (key == "stingerChanceOneIn") return 15;
if (key == "startTimeMinutes") return 840;
if (key == "timeMultiplier") return 1;
@@ -66,6 +68,7 @@ class ERR_Settings
m_Values.Set("startDateCode", AddedDefault("startDateCode"));
m_Values.Set("weatherProfile", AddedDefault("weatherProfile"));
m_Values.Set("stingerChanceOneIn", AddedDefault("stingerChanceOneIn"));
m_Values.Set("automaticConvoyEnabled", AddedDefault("automaticConvoyEnabled"));
if (!Replication.IsServer()) { m_ReadOnly = true; return; }
map<string, int> loaded;
if (Read(m_Path, loaded) || Read(m_Path + ".bak", loaded)) m_Values = loaded;