Capture current mission, AI, map and administration development

Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
This commit is contained in:
2026-10-13 22:52:53 +02:00
parent a951a96edc
commit 6a667d8deb
8104 changed files with 2124945 additions and 2061 deletions
@@ -0,0 +1,73 @@
--- a/addons/core/Scripts/Game/ERR/20_Intel/ERR_IntelDiscoveryFeedback.c
+++ b/addons/core/Scripts/Game/ERR/20_Intel/ERR_IntelDiscoveryFeedback.c
@@ -5,6 +5,7 @@
protected ref map<ERR_LocationComponent, int> m_ERRIntelSeen = new map<ERR_LocationComponent, int>();
protected ref map<ERR_LocationComponent, int> m_ERRIntelPending = new map<ERR_LocationComponent, int>();
protected float m_ERRIntelMessageAt;
+ protected float m_ERRIntelExhaustedAt;
protected bool m_ERRIntelFeedbackStopped;
protected int m_ERRIntelMessageSequence;
protected int m_ERRIntelReceivedSequence;
@@ -63,6 +64,11 @@
void ERR_IntelExhausted(bool duplicate = false)
{
if (!Replication.IsServer() || m_ERRIntelFeedbackStopped || !Active()) return;
+ // Recover scans a whole inventory; surplus folders share one team notice.
+ // Keep useful new discoveries on their independent coalescing schedule.
+ float now = GetWorld().GetWorldTime();
+ if (now < m_ERRIntelExhaustedAt) return;
+ m_ERRIntelExhaustedAt = now + 5000;
string message = "Every known location has already been identified. This intel doesn't help us.";
if (duplicate) message = "This document concerns a location we have already identified.";
m_ERRIntelMessageSequence++;
@@ -75,6 +81,7 @@
m_ERRIntelPending.Clear();
m_ERRIntelSeen.Clear();
m_ERRIntelMessageAt = 0;
+ m_ERRIntelExhaustedAt = 0;
OnLocationDiscovered().Remove(ERR_QueueDiscoveryFeedback);
OnTick().Remove(ERR_FlushDiscoveryFeedback);
}
--- a/tests/test_intel_discovery_feedback.py
+++ b/tests/test_intel_discovery_feedback.py
@@ -1,6 +1,8 @@
"""Execute production feedback queue/delivery bodies with fake engine boundaries."""
from policy_harness import ROOT, body, run
-P=ROOT/'addons/core/Scripts/Game/ERR/20_Intel/ERR_IntelDiscoveryFeedback.c'
+from pathlib import Path
+import os
+P=Path(os.environ.get('ERR_INTEL_FEEDBACK_SOURCE',ROOT/'addons/core/Scripts/Game/ERR/20_Intel/ERR_IntelDiscoveryFeedback.c'))
source=P.read_text()
def cpp(s):
s=s.replace('protected ', '').replace('static ', '')
@@ -42,7 +44,7 @@
static ERR_GameMode* current;static ERR_GameMode* Get(){return current;}
bool active=true;int phase=ERR_Phase::RADIO_SEARCH;bool Active(){return active;}int Phase(){return phase;}World* GetWorld(){return &world;}
Map<ERR_LocationComponent*,int> m_ERRIntelSeen,m_ERRIntelPending;
- float m_ERRIntelMessageAt=0;bool m_ERRIntelFeedbackStopped=false;int m_ERRIntelMessageSequence=0,m_ERRIntelReceivedSequence=0;
+ float m_ERRIntelMessageAt=0,m_ERRIntelExhaustedAt=0;bool m_ERRIntelFeedbackStopped=false;int m_ERRIntelMessageSequence=0,m_ERRIntelReceivedSequence=0;
Events discovered,tick;Events& OnLocationDiscovered(){return discovered;}Events& OnTick(){return tick;}
int rpcCount=0;void Rpc(int sequence,string message){rpcCount++;ERR_ReceiveDiscoveryFeedback(sequence,message);}
'''+methods+r'''
@@ -79,6 +81,21 @@
assert(ERR_IntelDiscoveryText::Type(ERR_LocationKind::MORTAR,"any")=="mortar site");
ERR_GameMode::current=&m;m.ERR_IntelExhausted();assert(SCR_ChatComponent::messages.back()=="Every known location has already been identified. This intel doesn't help us.");
assert(ERR_IntelDiscoveryText::Message(0,0,"secret").empty());assert(ERR_IntelDiscoveryText::Message(1,0,"")=="Hey! A location was identified in the intel!");
+ // Recovering a stack of spent-topic folders performs one exhaustion broadcast,
+ // not one chat line/RPC per physical document. Both variants share the budget.
+ ERR_GameMode surplus;ERR_GameMode::current=&surplus;world.time=10000;
+ for(int i=0;i<20;i++)surplus.ERR_IntelExhausted(i%2==0);
+ assert(surplus.rpcCount==1&&surplus.m_ERRIntelMessageSequence==1);
+ // Actual new discovery still follows its own coalescing window immediately.
+ world.time=10000;ERR_LocationComponent fresh;surplus.ERR_QueueDiscoveryFeedback(&fresh,0,1);
+ surplus.ERR_FlushDiscoveryFeedback(11500);assert(surplus.rpcCount==2);
+ assert(SCR_ChatComponent::messages.back()=="New location marked. Type unknown.");
+ world.time=14999;surplus.ERR_IntelExhausted();assert(surplus.rpcCount==2);
+ world.time=15000;surplus.ERR_IntelExhausted();assert(surplus.rpcCount==3&&surplus.m_ERRIntelMessageSequence==3);
+ world.time=20000;Replication::server=false;surplus.ERR_IntelExhausted();assert(surplus.rpcCount==3);Replication::server=true;
+ surplus.ERR_StopDiscoveryFeedback();surplus.ERR_IntelExhausted();assert(surplus.rpcCount==3);
+ ERR_GameMode freshRound;ERR_GameMode::current=&freshRound;world.time=0;freshRound.ERR_IntelExhausted();assert(freshRound.rpcCount==1);
+
}
''')
for required in ('OnLocationDiscovered().Insert(ERR_QueueDiscoveryFeedback)', 'OnTick().Insert(ERR_FlushDiscoveryFeedback)', 'OnStop().Insert(ERR_StopDiscoveryFeedback)', '[RplRpc(RplChannel.Reliable, RplRcver.Broadcast)]'):
@@ -0,0 +1 @@
PASS: production Intel feedback coalescing, rough secrecy, rate limit, bounded dedupe, local/remote delivery and round cleanup; native UI/RPC not exercised
@@ -0,0 +1,19 @@
check: /tmp/err-policy-vz34qdl0/check.cpp:142: int main(): Assertion `surplus.rpcCount==1&&surplus.m_ERRIntelMessageSequence==1' failed.
Traceback (most recent call last):
File "/tmp/erri-intel-exhaustion-feedback/tests/test_intel_discovery_feedback.py", line 21, in <module>
run(r'''
~~~^^^^^
#include <cassert>
^^^^^^^^^^^^^^^^^^
...<76 lines>...
}
^
''')
^^^^
File "/home/jakub/devel/escapistsrereintroduced/tests/policy_harness.py", line 14, in run
subprocess.run([str(p/'check')],check=True)
~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.14/subprocess.py", line 578, in run
raise CalledProcessError(retcode, process.args,
output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command '['/tmp/err-policy-vz34qdl0/check']' died with <Signals.SIGABRT: 6>.
@@ -0,0 +1,32 @@
--- a/addons/core/Scripts/Game/ERR/10_AI/ERR_EngineerMine.c
+++ b/addons/core/Scripts/Game/ERR/10_AI/ERR_EngineerMine.c
@@ -238,6 +238,11 @@
if (m_State == 2)
{
if (!m_Removal || m_Removal.Result < 0) { Stop(); return; }
+ // Observed transfer ends our custody; a later nearby drop cannot restore it.
+ // Original inventory ownership may still settle after the native callback.
+ InventoryItemComponent item = InventoryItemComponent.Cast(m_Mine.FindComponent(InventoryItemComponent));
+ bool attached = m_Mine.GetParent() || (item && item.GetParentSlot());
+ if (attached && !ERR_InfantryAmmoTransfer.StoredUnder(m_Mine, m_Actor)) { Stop(); return; }
if (!m_Removal.Result || !Grounded()) return;
if (vector.DistanceXZ(m_Actor.GetOrigin(), m_Position) > 3) { Stop(); return; }
// A callback proves removal, not continued custody of a distant loose item.
--- a/tests/test_engineer_mine.py
+++ b/tests/test_engineer_mine.py
@@ -117,7 +117,14 @@
Fixture refused;refused.inventory.accepted=false;refused.Prepare();assert(refused.controller.Finished()&&refused.inventory.calls==1);refused.inventory.callback->OnComplete();refused.Drop();refused.controller.Tick(13000);assert(!refused.trigger.calls&&!refused.mine.moves);
Fixture failed;failed.Prepare();failed.inventory.callback->OnFailed();failed.inventory.callback->OnComplete();failed.Drop();failed.controller.Tick(12001);assert(failed.controller.Finished()&&failed.inventory.callback->Result==-1&&!failed.mine.moves);
// ACK alone cannot establish custody. A stolen item is never positioned/armed.
- Fixture stolen;stolen.Prepare();stolen.inventory.callback->OnComplete();stolen.mine.parent=&stolen.actor;stolen.Drop();stolen.controller.Tick(12001);assert(stolen.controller.m_State==2&&!stolen.mine.moves);stolen.controller.Tick(181000);assert(stolen.controller.Finished());
+ Fixture stolen;stolen.Prepare();stolen.inventory.callback->OnComplete();Entity thief;stolen.mine.parent=&thief;stolen.Drop();stolen.controller.Tick(12001);assert(stolen.controller.Finished()&&!stolen.mine.moves);stolen.controller.Tick(181000);assert(stolen.controller.Finished());
+ // Observed foreign custody is terminal even if the same exact item returns nearby.
+ // Exercise both an acknowledged removal and an accepted, still-pending removal.
+ for(int ack=0;ack<2;ack++)for(int slotOnly=0;slotOnly<2;slotOnly++){Fixture f;f.Prepare();f.Drop();Entity holder;if(slotOnly)f.item.slot=&holder;else f.mine.parent=&holder;f.mine.stored=true;f.mine.storageOwner=&holder;if(ack)f.inventory.callback->OnComplete();
+ f.controller.Tick(12001);assert(f.controller.Finished()&&!f.mine.moves&&!f.trigger.calls);
+ f.mine.parent=nullptr;f.Drop();f.inventory.callback->OnComplete();f.controller.Tick(12002);f.actor.position={0,0,0};f.controller.Tick(14000);assert(!f.mine.moves&&!f.trigger.calls&&f.inventory.calls==1);}
+ // Native ownership still attached to the original actor may settle normally.
+ Fixture settling;settling.Prepare();settling.inventory.callback->OnComplete();settling.controller.Tick(12001);assert(!settling.controller.Finished()&&!settling.mine.moves);settling.Drop();settling.controller.Tick(12002);assert(settling.controller.m_State==3&&settling.mine.moves==1);
// Cancellation retains callback and item tombstone and only completes own action.
Fixture stopped;stopped.Prepare();SCR_AIBehaviorBase unrelated;stopped.utility.actions.Insert(&unrelated);auto owned=stopped.controller.m_Action;stopped.controller.Stop();stopped.controller.Stop();stopped.Drop();stopped.inventory.callback->OnComplete();stopped.controller.Tick(13000);assert(owned->completed==1&&!unrelated.completed&&!stopped.mine.moves&&!stopped.trigger.calls&&stopped.attempted.Contains(&stopped.mine));
// Original identity changes abort before irreversible work, including replacement
@@ -0,0 +1 @@
PASS: actual engineer mine preparation/deadline, original custody/identity, once-only callback removal, cancellation quarantine, withdrawal/clearance, native refusal and owned-action cleanup; native execution untested
@@ -0,0 +1,19 @@
check: /tmp/err-policy-uez5loun/check.cpp:307: int main(): Assertion `f.controller.Finished()&&!f.mine.moves&&!f.trigger.calls' failed.
Traceback (most recent call last):
File "/tmp/erri-engineer-custody/tests/test_engineer_mine.py", line 31, in <module>
run(r'''
~~~^^^^^
#include <cassert>
^^^^^^^^^^^^^^^^^^
...<132 lines>...
}
^
''')
^^^^
File "/home/jakub/devel/escapistsrereintroduced/tests/policy_harness.py", line 14, in run
subprocess.run([str(p/'check')],check=True)
~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.14/subprocess.py", line 578, in run
raise CalledProcessError(retcode, process.args,
output=stdout, stderr=stderr)
subprocess.CalledProcessError: Command '['/tmp/err-policy-uez5loun/check']' died with <Signals.SIGABRT: 6>.
@@ -0,0 +1,55 @@
{
"README.md": "c2c106797809f3c103e340f834d327aa2fb3295776cc5a2aec7f3f1511a97dd8",
"addons/core/Prefabs/ERR/Prison.et": "c0ca5219aa2d6322ba7d094b92000640b259112ff6611a745c0713c8875d09d4",
"addons/core/Prefabs/ERR/PrisonWall.et": "9b410b7c85bb001be4601ad93f750e17b8318b850306d84f29c4dc1b02723d7c",
"addons/core/Scripts/Game/ERR/00_Core/ERR_AdminMenu.c": "d39dc876487b445efc5c3fadc19e1e06c6900c5cd57c93a01f35c32aa27d6039",
"addons/core/Scripts/Game/ERR/00_Core/ERR_AdminService.c": "c3e008c8bbf538c5bca3a82a975decc7a283a38543a9d2639d90a81ce592c51e",
"addons/core/Scripts/Game/ERR/00_Core/ERR_AirfieldPlacement.c": "0c2f4d31a2abc8f3f90bda20546543f2a1cf9306e9bf93351dda1883b990770e",
"addons/core/Scripts/Game/ERR/00_Core/ERR_EscapeGameOverScreenInfo.c": "6e3c65e55b05cf205040c310b9086faa41b88582c7f9faf49c010afd59da5b07",
"addons/core/Scripts/Game/ERR/00_Core/ERR_GameMode.c": "251d55779509cb76f66938221b4dc8face53e187a82c9f2c651e6b1d13216c27",
"addons/core/Scripts/Game/ERR/00_Core/ERR_GeneratedSites.c": "4a23058f27e3ab074df6f8f7bb6f08a8fd26fbadb8943c6fb8d64dcc9c221751",
"addons/core/Scripts/Game/ERR/00_Core/ERR_JournalText.c": "87a6c19429f12c5630ed73170ca9a8a6d2255d6cd38b130166a78aacd15f2de0",
"addons/core/Scripts/Game/ERR/00_Core/ERR_NativeAdminMenuProbe.c": "ec8d04b6550b39b9688ef67b40cb2f14a9d98c8fff62b6dfb8d4a43e19b4e4c6",
"addons/core/Scripts/Game/ERR/00_Core/ERR_NativeAdminSettingsProbe.c": "73e58561e08e50008d33f81eed606dd4e8109fb69a627e892d28ca468d641f7d",
"addons/core/Scripts/Game/ERR/00_Core/ERR_NativeEnvironmentProbe.c": "9e2e66ac5d9778a1c65445348e3300cbb90b68b3f669f3ddf1d2b78a858430eb",
"addons/core/Scripts/Game/ERR/00_Core/ERR_NativeMedicalProbe.c": "4b73e7cf35e9c8fddb089678a320ea58272e1b6611318d0a762754c171eff785",
"addons/core/Scripts/Game/ERR/00_Core/ERR_NativeOptionalSiteProbe.c": "19fc19e22348e6213827f620f4fdb5dc26144ea2ce0032de773e79c1fb155a26",
"addons/core/Scripts/Game/ERR/00_Core/ERR_NativeResultProbe.c": "c9a89cae067f221b9f33965b4d3ab311b78ba79ea383ca65032c4001df44b472",
"addons/core/Scripts/Game/ERR/00_Core/ERR_ObjectiveText.c": "8d75b35ab977be0cb1a2e3d3d1cb8ef875cdbfba69c35784c3d195451ef944c6",
"addons/core/Scripts/Game/ERR/00_Core/ERR_Observer.c": "7422f79bfa5ecf9b13c37b7ad0cf0b23469ed7059e85462ff96b7704084d29d9",
"addons/core/Scripts/Game/ERR/00_Core/ERR_PlayerMedical.c": "e353ece5e1f3a6731875d8080c00fa9511446c309ff2a1454911e53c01f536f9",
"addons/core/Scripts/Game/ERR/00_Core/ERR_ScenarioComponent.c": "81bf30d358c7b100248be17cbc2e6beb2f107300c939aede8a92d273eb7dae1f",
"addons/core/Scripts/Game/ERR/00_Core/ERR_Settings.c": "e73b3654ea115568ab24456d43dfe0c6419d3ccfeaf53e5b7752d31f2950b58d",
"addons/core/Scripts/Game/ERR/00_Core/ERR_SiteDefinition.c": "2088c45798f0eced702e0abd97550b8d1fc97ebcc34c3d497978b7424f6c670d",
"addons/core/Scripts/Game/ERR/00_Core/ERR_UnconsciousCameraProbe.c": "7d5ff3389ee806ac213db5be3a68288b3399142ccc29806df0d65b34a0b2fc3c",
"addons/core/Scripts/Game/ERR/10_AI/ERR_BodyRecovery.c": "47d9374095d04f5f1339c220caf518a40938ffc20f891b1b51ae38579e7e1c25",
"addons/core/Scripts/Game/ERR/10_AI/ERR_MortarFiring.c": "f2597d44c10d10de2462aa5e5450a22b8a5ad0eb99bd0cc09a8cf1ca2dd4a350",
"addons/core/Scripts/Game/ERR/10_AI/ERR_MortarLogistics.c": "b3624e4a00a2bdef16f6c100bbd79910e3bb8c2ae8ec5fe2ad5aa70bffecd303",
"addons/core/Scripts/Game/ERR/10_AI/ERR_NativeAirLogisticsProbe.c": "58fe863775d0ad575cb566c78cef696c9826691cf49ef9adde76376be7316db1",
"addons/core/Scripts/Game/ERR/10_AI/ERR_NativeMortarSalvoProbe.c": "fb9ccc6b36247ab3ad828ffbb2556abf5c2838d93ea6cd1ad259c0a015142f5e",
"addons/core/Scripts/Game/ERR/10_AI/ERR_ReconAirports.c": "7551347d776d6e0eec818d6468cacbca7ac53daee7317e0a1618ca3d39ebc762",
"addons/core/Scripts/Game/ERR/10_AI/ERR_ReconFlightComponent.c": "4966dad504b3f8f28a9ffc8ac17cc548b00066fe05213c49c662ea56de34c9d4",
"addons/core/Scripts/Game/ERR/10_AI/ERR_ScoutSystem.c": "63287a252e4e7d5aefce840279f26ce3e1f286cb79cadb32596c37897cec7119",
"addons/core/Scripts/Game/ERR/40_Chat/ERR_NativeHQMemoryProbe.c": "d8fec6c138bb0f5bdbf99ee82ffc3ac9b44d1045d8833da63f8aa5f39beeb7e5",
"addons/core/UI/layouts/ERR/AdminMenu.layout": "997e4f33660de5bb54c2939898cacc8857736a73db2c6919888ae0e762050e5c",
"docs/environment.md": "2a58f8a969348e42e09e45b906a3d61fb65d887ae2814547605a01987747ab6c",
"docs/field-sites.md": "9c3928a04b4b242dcf806d7b20ecf2f4cc636aff9a31ed90d9fd75cfaf776aa0",
"docs/prison-opening.md": "be60fee1542185bfae38cba9bacf1f181acf2a032af33d5eb853468a036cc54a",
"docs/recovery.md": "026b513982530b8d65a6a1459e8707cd4abaf56450abc00f8449cf01fc660d0d",
"docs/spectator-guidance.md": "700840fb639152c61785238ebc383fade6cf34f5d888496204569c60ad6d091d",
"docs/vanilla-resources.json": "d80edf67d429b578051cad1630d3c44fae70714d14a277e40294242f9b439783",
"tests/test_admin_menu.py": "e7adf7c3ad76274e29135b56223facdd0f9e01911d7a690787949d695073bfba",
"tests/test_command_maintenance.py": "be2c942aa11a5f874448e94f06925f2f1de2210a14881fb7e486842119cb673c",
"tests/test_escape_result_wording.py": "7b3613cccd4f24d3ef4665dfc1854cfc958a69018a59f9b8090617f0185a82a8",
"tests/test_field_sites.py": "fddb0e44e72fdfe32bb94347a14da64efbd2208e4f252754e80c620fbecda56c",
"tests/test_headless_game_runner.py": "0d84160076ec9961e7315ccd50d6ce45ff971328c298649505fbba6305c22f31",
"tests/test_journal_readability.py": "47764126522e7d7a90100cd9beff741bf49e4d8390111f977919d3e323a5c7df",
"tests/test_native_end_lifecycle.py": "8b187723c9039e68e3e590c812c91dcffe1e5917d4e450ed798dc177888fda7a",
"tests/test_player_medical.py": "e4b3140a3afc0161db53f261e5480e51f1ca09f85657e25b0efb7dbba3336e3f",
"tests/test_settings_migration.py": "5fdfc8815f49f900a1aeda73ec3954cfd767019e702c48c77411dbb7dc016c2f",
"tests/test_spectator_recovery.py": "8bb59c51df003e24532ad9476af4c8ff3b7f4276dca25e8162b91eb77c7b67c2",
"tools/check.py": "ac4e38114e1796829afa58ef8ac00e1fa6433b129e29955a6d69162fd78bf0a0",
"tools/headless_game.py": "e7cab472ee51497343174cb460022b3e4591f148d4acbc6e6f881fc68c0fda1b",
"tools/headless_workbench.py": "37651b5601add5689143767ab1592f6753f2145177b1d8055babca1789eb6265",
"tools/import_settings.py": "c44490a568893b0076c73423cae09a174ce9c808d83b959987e06af072d38567"
}
@@ -0,0 +1,26 @@
{
"changes": [
"Observed foreign mine custody permanently cancels the original engineer attempt; later nearby redrop cannot restore ownership. Original actor inventory settling remains allowed.",
"Surplus intel notices share a separate five-second team-message budget, preserving useful discovery delivery."
],
"dependencies": "Existing direct RHS Status Quo, WCS Armaments and WCS BMP-1 dependencies verified; separately installed audited closure retained.",
"regression_programs": 260,
"failed_initial_package_attempt": "docs/evidence/package-2026-10-01-dependency-review-failed/review.json",
"actual_method_red_before_green_after": true,
"implementation_sha256": {
"addons/core/Scripts/Game/ERR/10_AI/ERR_EngineerMine.c": "11c2a85f390b52c1f24791995e0bdfa1640866ffbaeb49dbb1d3099c73479e5c",
"addons/core/Scripts/Game/ERR/20_Intel/ERR_IntelDiscoveryFeedback.c": "62f2c408383f410782d9d41fa50acd6bd8cf66eeb80d2b79f91852b9d2cf8d97",
"tests/test_engineer_mine.py": "c137113e6e43d7b4fd5fddc8ab89e08157a29fe3989ae5585f1a1d7e20f07d89",
"tests/test_intel_discovery_feedback.py": "49b2fedd8704ec67af60a6bb3dd156ddca28eb334d18b20692ab1e4659f439c5"
},
"prior_unstaged_files_preserved": 53,
"original_reference_files_preserved": 533,
"previous_handoff_unchanged": true,
"native_route": "docs/evidence/native-2026-10-01-dependency-review/report.json",
"handoff": ".build/playtest-2026-10-01-dependency-review",
"limitations": [
"Observed custody checks cannot detect pickup and redrop wholly between controller ticks.",
"Physical mine placement/arming, mounted rearming and remote presentation remain unverified.",
"Human escape, twelve-player multiplayer, equivalent-workload FPS and clean release qualification remain incomplete."
]
}