Add bounded aircraft control and verify current packaged runtime closure
This commit is contained in:
@@ -86,5 +86,15 @@ GenericEntity {
|
||||
coords 0 -0.1 -6
|
||||
angles 0 0 0
|
||||
}
|
||||
DecalEntity : "{4AD6EB80A8B1FA3A}Prefabs/Decals/Dirt/Decal_Dirt_Patch_03.et" {
|
||||
ID "FCFBA935CC13E016"
|
||||
components {
|
||||
Hierarchy "{EF4B704D646D1759}" {}
|
||||
}
|
||||
coords 0 0 0
|
||||
angles -90 0 0
|
||||
scale 10
|
||||
FarPlane 1.5
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,11 @@ class ERR_UnlockPrisonAction : ScriptedUserAction
|
||||
override bool CanBePerformedScript(IEntity user)
|
||||
{
|
||||
ERR_GameMode mode = ERR_GameMode.Get();
|
||||
return mode && mode.Phase() == ERR_Phase.PRISON && ERR_Actors.CanFight(user);
|
||||
SetCannotPerformReason(string.Empty);
|
||||
if (!mode) { SetCannotPerformReason("Mission is not ready"); return false; }
|
||||
if (mode.Phase() != ERR_Phase.PRISON) { SetCannotPerformReason("Prison lock is not available in this mission phase"); return false; }
|
||||
if (!ERR_Actors.CanFight(user)) { SetCannotPerformReason("You must be alive and conscious"); return false; }
|
||||
return true;
|
||||
}
|
||||
override void PerformAction(IEntity pOwnerEntity, IEntity pUserEntity)
|
||||
{
|
||||
@@ -28,7 +32,15 @@ class ERR_PrisonDoorAction : SCR_DoorUserAction
|
||||
override bool CanBePerformedScript(IEntity user)
|
||||
{
|
||||
ERR_GameMode mode = ERR_GameMode.Get();
|
||||
return mode && mode.Phase() > ERR_Phase.PRISON && super.CanBePerformedScript(user);
|
||||
SetCannotPerformReason(string.Empty);
|
||||
if (!mode) { SetCannotPerformReason("Mission is not ready"); return false; }
|
||||
if (mode.Phase() <= ERR_Phase.PRISON)
|
||||
{
|
||||
SetCannotPerformReason("Pick the prison lock before opening the gate");
|
||||
return false;
|
||||
}
|
||||
// Vanilla owns any obstruction/door-specific reason after unlocking.
|
||||
return super.CanBePerformedScript(user);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +50,21 @@ class ERR_TuneRadioAction : ScriptedUserAction
|
||||
{
|
||||
ERR_GameMode mode = ERR_GameMode.Get();
|
||||
ERR_LocationComponent location = ERR_LocationComponent.Cast(GetOwner().FindComponent(ERR_LocationComponent));
|
||||
return mode && mode.Phase() == ERR_Phase.RADIO_SEARCH && location && location.Knowledge() == 2 && ERR_Actors.CanFight(user);
|
||||
SetCannotPerformReason(string.Empty);
|
||||
if (!mode) { SetCannotPerformReason("Mission is not ready"); return false; }
|
||||
if (mode.Phase() != ERR_Phase.RADIO_SEARCH)
|
||||
{
|
||||
string reason = "Radio is not available in this mission phase";
|
||||
if (mode.Phase() == ERR_Phase.PRISON) reason = "Escape the prison first";
|
||||
if (mode.Phase() == ERR_Phase.RADIO_DEFENCE) reason = "Transmission is already in progress; defend the radio";
|
||||
if (mode.Phase() == ERR_Phase.EXTRACTION) reason = "Transmission is complete; reach the extraction helicopter";
|
||||
SetCannotPerformReason(reason);
|
||||
return false;
|
||||
}
|
||||
if (!location) { SetCannotPerformReason("Radio location is unavailable"); return false; }
|
||||
if (location.Knowledge() != 2) { SetCannotPerformReason("Identify this radio through recovered intel or close reconnaissance first"); return false; }
|
||||
if (!ERR_Actors.CanFight(user)) { SetCannotPerformReason("You must be alive and conscious"); return false; }
|
||||
return true;
|
||||
}
|
||||
override void PerformAction(IEntity pOwnerEntity, IEntity pUserEntity)
|
||||
{
|
||||
|
||||
@@ -55,6 +55,147 @@ class ERR_OrdinaryScenarioLaunchRequest : Managed
|
||||
|
||||
}
|
||||
|
||||
// One optional capture request per world, with no camera or gameplay mutation.
|
||||
// Managed callback ownership matches the ordinary launch request above.
|
||||
class ERR_OrdinaryScreenshotRequest : Managed
|
||||
{
|
||||
protected static ref ERR_OrdinaryScreenshotRequest s_Request;
|
||||
protected static bool s_Attempted;
|
||||
protected ERR_GameMode m_Mode;
|
||||
protected PlayerController m_Controller;
|
||||
protected IEntity m_Actor;
|
||||
protected ref ERR_PlayerLife m_Life;
|
||||
protected UUID m_Account;
|
||||
protected int m_PlayerId;
|
||||
protected bool m_Finished;
|
||||
|
||||
protected static bool Enabled()
|
||||
{
|
||||
string project, screenshot;
|
||||
if (!Replication.IsServer() || System.IsConsoleApp()) return false;
|
||||
if (!System.GetCLIParam("errOrdinaryScenario", project) || (project != "core" && project != "chat")) return false;
|
||||
return System.GetCLIParam("errOrdinaryScreenshot", screenshot) && screenshot == "1";
|
||||
}
|
||||
static void Queue(ERR_GameMode mode, PlayerController controller, IEntity actor)
|
||||
{
|
||||
if (s_Attempted || !Enabled() || !mode || !controller || !actor || !mode.Players()) return;
|
||||
ERR_PlayerLife life = mode.Players().CurrentActor(actor);
|
||||
if (!life) return;
|
||||
ERR_OrdinaryScreenshotRequest request = new ERR_OrdinaryScreenshotRequest();
|
||||
request.m_Mode = mode; request.m_Controller = controller; request.m_Actor = actor;
|
||||
request.m_Life = life; request.m_Account = life.AccountId; request.m_PlayerId = controller.GetPlayerId();
|
||||
if (!request.Valid()) return;
|
||||
s_Attempted = true; s_Request = request;
|
||||
mode.OnStop().Insert(request.Cancel);
|
||||
GetGame().GetCallqueue().CallLater(request.Capture, 3000, false);
|
||||
Print("ERR ORDINARY: optional prisoner screenshot queued after finalized admission");
|
||||
}
|
||||
protected bool Valid()
|
||||
{
|
||||
if (!Enabled() || !GetGame() || !m_Mode || m_Mode != ERR_GameMode.Get()) return false;
|
||||
if (!GetGame().GetWorld() || m_Mode.GetWorld() != GetGame().GetWorld() || !m_Mode.Active() || m_Mode.Phase() != ERR_Phase.PRISON) return false;
|
||||
if (!m_Controller || m_Controller != GetGame().GetPlayerController() || m_Controller.GetPlayerId() != m_PlayerId || m_PlayerId <= 0) return false;
|
||||
PlayerManager manager = GetGame().GetPlayerManager();
|
||||
if (!manager || manager.GetPlayerController(m_PlayerId) != m_Controller || manager.GetPlayerControlledEntity(m_PlayerId) != m_Actor || m_Controller.GetControlledEntity() != m_Actor) return false;
|
||||
if (!ERR_Actors.Alive(m_Actor) || !m_Mode.Players()) return false;
|
||||
ERR_PlayerLife current = m_Mode.Players().CurrentActor(m_Actor);
|
||||
return current && current == m_Life && current.AccountId == m_Account;
|
||||
}
|
||||
void Cancel()
|
||||
{
|
||||
if (m_Finished) return;
|
||||
m_Finished = true;
|
||||
if (GetGame() && GetGame().GetCallqueue()) GetGame().GetCallqueue().Remove(Capture);
|
||||
if (m_Mode) m_Mode.OnStop().Remove(Cancel);
|
||||
m_Mode = null; m_Controller = null; m_Actor = null; m_Life = null;
|
||||
}
|
||||
// Read-only projection evidence, only inside the already validated capture.
|
||||
// World AABB corners transformed to prison space are an envelope, not a
|
||||
// promise that the material's irregular clutter mask fills that envelope.
|
||||
protected void YardDiagnostic()
|
||||
{
|
||||
array<ERR_LocationComponent> locations = {};
|
||||
m_Mode.Locations(locations);
|
||||
if (locations.Count() > 64) return;
|
||||
IEntity prison;
|
||||
foreach (ERR_LocationComponent location : locations)
|
||||
{
|
||||
if (!location || location.Kind() != ERR_LocationKind.PRISON || location.Id() != "everon-prison-1") continue;
|
||||
IEntity owner = location.GetOwner();
|
||||
if (!owner || owner.GetWorld() != m_Mode.GetWorld() || !owner.GetPrefabData()) continue;
|
||||
if (owner.GetPrefabData().GetPrefabName() != "{BE6B8D56349038A6}Prefabs/ERR/Prison.et") continue;
|
||||
if (prison) { Print("ERR YARD: ambiguous registered prison; no measurement"); return; }
|
||||
prison = owner;
|
||||
}
|
||||
if (!prison) { Print("ERR YARD: exact registered prison missing; no measurement"); return; }
|
||||
vector prisonTransform[4]; prison.GetWorldTransform(prisonTransform);
|
||||
PrintFormat("ERR YARD: prison world origin=%1 basisX=%2 basisY=%3 basisZ=%4", prisonTransform[3], prisonTransform[0], prisonTransform[1], prisonTransform[2]);
|
||||
array<IEntity> entities = {prison};
|
||||
array<int> depths = {0};
|
||||
int decals;
|
||||
for (int index = 0; index < entities.Count(); index++)
|
||||
{
|
||||
IEntity entity = entities[index];
|
||||
if (!entity) { Print("ERR YARD: hierarchy changed; partial measurement"); return; }
|
||||
DecalEntity decal = DecalEntity.Cast(entity);
|
||||
if (decal)
|
||||
{
|
||||
decals++;
|
||||
vector mins, maxs; decal.GetWorldBounds(mins, maxs);
|
||||
vector worldTransform[4]; decal.GetWorldTransform(worldTransform);
|
||||
string nativeType = decal.Type().ToString();
|
||||
ResourceName prefab;
|
||||
if (decal.GetPrefabData()) prefab = decal.GetPrefabData().GetPrefabName();
|
||||
PrintFormat("ERR YARD: decal=%1 type=%2 prefab=%3 worldMin=%4 worldMax=%5", decals, nativeType, prefab, mins, maxs);
|
||||
PrintFormat("ERR YARD: decal=%1 world origin=%2 basisX=%3 basisY=%4 basisZ=%5", decals, worldTransform[3], worldTransform[0], worldTransform[1], worldTransform[2]);
|
||||
for (int x = 0; x < 2; x++)
|
||||
for (int y = 0; y < 2; y++)
|
||||
for (int z = 0; z < 2; z++)
|
||||
{
|
||||
vector corner = mins;
|
||||
if (x == 1) corner[0] = maxs[0];
|
||||
if (y == 1) corner[1] = maxs[1];
|
||||
if (z == 1) corner[2] = maxs[2];
|
||||
vector localCorner = prison.CoordToLocal(corner);
|
||||
PrintFormat("ERR YARD: decal=%1 corner=%2/%3/%4 prisonLocal=%5", decals, x, y, z, localCorner);
|
||||
}
|
||||
}
|
||||
IEntity child = entity.GetChildren();
|
||||
while (child)
|
||||
{
|
||||
if (depths[index] >= 8 || entities.Count() >= 64 || entities.Contains(child))
|
||||
{
|
||||
Print("ERR YARD: hierarchy bound or duplicate reached; partial measurement");
|
||||
return;
|
||||
}
|
||||
entities.Insert(child); depths.Insert(depths[index] + 1);
|
||||
child = child.GetSibling();
|
||||
}
|
||||
}
|
||||
PrintFormat("ERR YARD: measurement complete nodes=%1 decals=%2; bounds do not certify clutter-mask coverage", entities.Count(), decals);
|
||||
}
|
||||
protected void Capture()
|
||||
{
|
||||
if (m_Finished) return;
|
||||
bool valid = Valid();
|
||||
if (valid) YardDiagnostic();
|
||||
Cancel();
|
||||
if (!valid)
|
||||
{
|
||||
Print("ERR ORDINARY: optional prisoner screenshot cancelled; original admission no longer current");
|
||||
return;
|
||||
}
|
||||
System.MakeScreenshot("$logs:err-ordinary-prison");
|
||||
Print("ERR ORDINARY: optional prisoner screenshot requested without camera or input changes");
|
||||
}
|
||||
static void ClearWorld()
|
||||
{
|
||||
if (s_Request) s_Request.Cancel();
|
||||
s_Request = null;
|
||||
s_Attempted = false;
|
||||
}
|
||||
}
|
||||
|
||||
modded class ArmaReforgerScripted
|
||||
{
|
||||
protected ref ERR_OrdinaryScenarioLaunchRequest m_ERRDiagnosticLaunchRequest;
|
||||
@@ -106,6 +247,7 @@ modded class ArmaReforgerScripted
|
||||
|
||||
override protected void OnBeforeWorldCleanup()
|
||||
{
|
||||
ERR_OrdinaryScreenshotRequest.ClearWorld();
|
||||
if (m_ERRDiagnosticLaunchRequest) m_ERRDiagnosticLaunchRequest.Cancel();
|
||||
m_ERRDiagnosticLaunchRequest = null;
|
||||
super.OnBeforeWorldCleanup();
|
||||
@@ -124,6 +266,7 @@ modded class ERR_GameMode
|
||||
if (!local || local.GetPlayerId() != id || local.GetControlledEntity() != actor || !ERR_Actors.Alive(actor)) return;
|
||||
if (!Players().CurrentActor(actor) || Phase() != ERR_Phase.PRISON) return;
|
||||
PrintFormat("ERR ORDINARY: local participant verified project=%1 phase=prison", project);
|
||||
ERR_OrdinaryScreenshotRequest.Queue(this, local, actor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -120,6 +120,10 @@ class ERR_SpawnLogic : SCR_SpawnLogic
|
||||
Observe(playerId, reason);
|
||||
return;
|
||||
}
|
||||
// Every active, eligible admission consumes one attempt, even when native
|
||||
// prerequisites or all safe positions are unavailable. Preparing and an
|
||||
// already-pending request return above without spending this budget.
|
||||
m_Attempts.Set(playerId, attempts + 1);
|
||||
SCR_PlayerFactionAffiliationComponent affiliation = GetPlayerFactionComponent_S(playerId);
|
||||
SCR_RespawnComponent respawn = GetPlayerRespawnComponent_S(playerId);
|
||||
Faction faction = mode.PlayerFaction();
|
||||
@@ -127,7 +131,6 @@ class ERR_SpawnLogic : SCR_SpawnLogic
|
||||
affiliation.RequestFaction(faction);
|
||||
vector position;
|
||||
if (!SpawnPosition(mode, position)) { RetryLater(playerId); return; }
|
||||
m_Attempts.Set(playerId, attempts + 1);
|
||||
SCR_FreeSpawnData request = new SCR_FreeSpawnData(mode.Factions().PrisonerPrefab, position);
|
||||
if (!respawn.CanSpawn(request)) { RetryLater(playerId); return; }
|
||||
m_AuthorizedPositions.Set(playerId, position);
|
||||
|
||||
Reference in New Issue
Block a user