// Resolve from the scenario header even before a world exists: the backend asks // for its mission name during startup. Child scenario filenames are not terrains. class ERR_TerrainDisplayName { // GetWorldFile() returns a path, often $Addon:Worlds/..., not a GUID resource. // ResourceName.GetPath() asks the resource system to resolve it and logs a // zero-GUID warning on every call. Compare/display paths without that lookup. static string Path(string world) { if (world.Length() >= 18 && world.Substring(0, 1) == "{" && world.Substring(17, 1) == "}") return world.Substring(18, world.Length() - 18); return world; } static string Label(string world) { if (world.IsEmpty()) return ""; string name = FilePath.StripPath(Path(world)); int extension = name.IndexOf("."); if (extension >= 0) name = name.Substring(0, extension); // Packed worlds may hide their parent container before native world loading. // Strip conventional scenario wrappers for that early callback fallback. string lower = name; lower.ToLower(); foreach (string prefix : {"gm_", "err_", "conflict_", "combatops_", "campaign_"}) { if (lower.IndexOf(prefix) != 0) continue; name = name.Substring(prefix.Length(), name.Length() - prefix.Length()); lower = name; lower.ToLower(); break; } foreach (string suffix : {"_test", "_gm", "_exploration", "_conflict", "_combatops"}) { int start = lower.Length() - suffix.Length(); if (start < 0 || lower.Substring(start, suffix.Length()) != suffix) continue; name = name.Substring(0, start); lower = name; lower.ToLower(); break; } if (lower == "eden") return "Everon"; name.Replace("_", " "); name.Replace("\n", " "); name.Replace("\r", " "); name = name.Trim(); if (name.Length() > 80) name = name.Substring(0, 80); if (!name.IsEmpty()) { string first = name.Substring(0, 1); first.ToUpper(); name = first + name.Substring(1, name.Length() - 1); } return name; } static string Resolve(ResourceName world) { array seen = {}; for (int depth = 0; depth < 16 && !world.IsEmpty(); depth++) { if (seen.Contains(world)) break; seen.Insert(world); Resource resource = BaseContainerTools.LoadContainer(world); if (!resource || !resource.IsValid()) break; BaseContainer container = resource.GetResource().ToBaseContainer(); if (!container) break; ResourceName parent; if (!container.Get("Parent", parent) || parent.IsEmpty() || seen.Contains(parent)) break; world = parent; } return Label(world); } } // Scenario selection still loads the terrain's header. Advertise the configured // Escape mode through the native DS name callback, then update local metadata // only when the authority actually starts Escape or its bootstrap reaches a client. modded class ArmaReforgerScripted { protected ref SCR_MissionHeader m_ERRPresentedTerrainHeader; protected string m_ERROriginalTerrainTitle; protected string m_ERROriginalTerrainGameMode; protected string m_ERRAppliedTerrainTitle; protected string m_ERRTitleWorld; protected string m_ERRTerrainLabel; protected BaseWorld m_ERRPresentedTerrainWorld; protected bool m_ERRTitleLoaded; protected float m_ERRTerrainPresentationWait; string ERR_TerrainMissionTitle(SCR_MissionHeader header) { string world = header.GetWorldResourceName(); string loadedWorld = GetWorldFile(); // After the actual Escape bootstrap, the running world wins over a stale // source header. Before that, do not label an incoming scenario with the // outgoing world's terrain. A saved next-round selection is never consulted. bool confirmed = m_ERRPresentedTerrainHeader == header && m_ERRPresentedTerrainWorld && m_ERRPresentedTerrainWorld == GetWorld(); if (confirmed && !loadedWorld.IsEmpty()) world = loadedWorld; bool loaded = GetWorld() && GetWorld().GetNumSubScenes() > 0 && !world.IsEmpty() && ERR_TerrainDisplayName.Path(loadedWorld) == ERR_TerrainDisplayName.Path(world); if (loaded) world = GetWorld().GetSubSceneName(0); if (world != m_ERRTitleWorld || loaded != m_ERRTitleLoaded) { m_ERRTitleWorld = world; m_ERRTitleLoaded = loaded; m_ERRTerrainLabel = ERR_TerrainDisplayName.Resolve(world); } string title = "Co10 Escape Reintroduced"; if (!m_ERRTerrainLabel.IsEmpty()) title += " - " + m_ERRTerrainLabel; return title; } override string GetMissionName() { SCR_MissionHeader header = SCR_MissionHeader.Cast(GetMissionHeader()); // Our own presentation has already set GameMode=Escape. It still needs to // follow the running terrain when the root scene becomes available later. if (header && header == m_ERRPresentedTerrainHeader) { ERR_RefreshTerrainPresentation(); return header.m_sName; } // The engine requests this before the dedicated world has loaded. Preserve // authored Escape names and explicit opt-outs; do not change the scenario ID. if (Replication.IsServer() && header && header.m_sGameMode != "Escape" && m_ERRTerrainStage != ERR_TerrainTakeoverStage.FAILED && ERR_TerrainTakeoverSettings.Enabled()) return ERR_TerrainMissionTitle(header); return super.GetMissionName(); } void ERR_PresentTerrainTakeover() { SCR_MissionHeader header = SCR_MissionHeader.Cast(GetMissionHeader()); if (!header || SCR_Global.IsEditMode()) return; if (m_ERRPresentedTerrainHeader == header && m_ERRPresentedTerrainWorld == GetWorld()) { ERR_RefreshTerrainPresentation(); return; } ERR_RestoreTerrainPresentation(); m_ERRPresentedTerrainHeader = header; m_ERRPresentedTerrainWorld = GetWorld(); m_ERROriginalTerrainTitle = header.m_sName; m_ERROriginalTerrainGameMode = header.m_sGameMode; m_ERRAppliedTerrainTitle = ERR_TerrainMissionTitle(header); header.m_sName = m_ERRAppliedTerrainTitle; header.m_sGameMode = "Escape"; PrintFormat("Reintroduced [terrain presentation]: mission=%1; source scenario=%2", header.m_sName, header.GetHeaderResourceName()); } void ERR_RefreshTerrainPresentation() { SCR_MissionHeader header = SCR_MissionHeader.Cast(GetMissionHeader()); if (!header || header != m_ERRPresentedTerrainHeader || SCR_Global.IsEditMode()) return; if (m_ERRPresentedTerrainWorld != GetWorld() || header.m_sName != m_ERRAppliedTerrainTitle) return; string title = ERR_TerrainMissionTitle(header); if (title == m_ERRAppliedTerrainTitle) return; m_ERRAppliedTerrainTitle = title; header.m_sName = title; PrintFormat("Reintroduced [terrain presentation]: refreshed mission=%1; loaded world=%2", title, GetWorldFile()); } string ERR_TerrainLoadingTitle(SCR_MissionHeader requested) { if (!requested) return ""; SCR_MissionHeader header = SCR_MissionHeader.Cast(GetMissionHeader()); // The loading screen can hold a separate copy of the same scenario header. // Never replace another incoming scenario's title with the outgoing world. if (!header || header != m_ERRPresentedTerrainHeader || m_ERRPresentedTerrainWorld != GetWorld()) return requested.m_sName; if (requested != header && (requested.GetHeaderResourceName().IsEmpty() || requested.GetHeaderResourceName() != header.GetHeaderResourceName())) return requested.m_sName; ERR_RefreshTerrainPresentation(); return header.m_sName; } override void OnUpdate(BaseWorld world, float timeslice) { super.OnUpdate(world, timeslice); if (!m_ERRPresentedTerrainHeader) return; m_ERRTerrainPresentationWait += timeslice; if (m_ERRTerrainPresentationWait < 0.5) return; m_ERRTerrainPresentationWait = 0; ERR_RefreshTerrainPresentation(); } protected void ERR_RestoreTerrainPresentation() { if (m_ERRPresentedTerrainHeader) { // A later change by another system belongs to that system. if (m_ERRPresentedTerrainHeader.m_sName == m_ERRAppliedTerrainTitle) m_ERRPresentedTerrainHeader.m_sName = m_ERROriginalTerrainTitle; if (m_ERRPresentedTerrainHeader.m_sGameMode == "Escape") m_ERRPresentedTerrainHeader.m_sGameMode = m_ERROriginalTerrainGameMode; } m_ERRPresentedTerrainHeader = null; m_ERRPresentedTerrainWorld = null; m_ERROriginalTerrainTitle = ""; m_ERROriginalTerrainGameMode = ""; m_ERRAppliedTerrainTitle = ""; } override protected void OnBeforeWorldCleanup() { ERR_RestoreTerrainPresentation(); m_ERRTitleWorld = ""; m_ERRTerrainLabel = ""; m_ERRTitleLoaded = false; m_ERRTerrainPresentationWait = 0; super.OnBeforeWorldCleanup(); } } // Vanilla copies the header title once, before the replicated Escape bootstrap // may arrive. Refresh only the title; do not recreate loading widgets/hints. modded class SCR_LoadingScreenComponent { protected ref SCR_MissionHeader m_ERRLoadingTerrainHeader; protected string m_ERRLoadingTerrainTitle; protected float m_ERRLoadingTerrainWait; override void OnMissionDataRetrieved(SCR_MissionHeader header) { super.OnMissionDataRetrieved(header); m_ERRLoadingTerrainHeader = header; m_ERRLoadingTerrainTitle = ""; m_ERRLoadingTerrainWait = 0; ERR_RefreshLoadingTerrainTitle(); } protected void ERR_RefreshLoadingTerrainTitle() { if (!m_ERRLoadingTerrainHeader || !m_Widgets || !m_Widgets.m_wTitle || !GetGame()) return; string title = GetGame().ERR_TerrainLoadingTitle(m_ERRLoadingTerrainHeader); if (title == m_ERRLoadingTerrainTitle) return; m_ERRLoadingTerrainTitle = title; m_Widgets.m_wTitle.SetText(title); } override void Update(float timeSlice, float progress = 0, float minDurationRatio = 0) { super.Update(timeSlice, progress, minDurationRatio); m_ERRLoadingTerrainWait += timeSlice; if (m_ERRLoadingTerrainWait < 0.5) return; m_ERRLoadingTerrainWait = 0; ERR_RefreshLoadingTerrainTitle(); } }