Files
jakub cab998fb64 Combine Workshop addon and fix prison startup
Merge owned systems into one addon while preserving resource identities. Gate player admission on the replicated prison scene, restore the original framed door, and hold enemy AI until escape. Correct scenario branding and author metadata, include publishing assets, and retain regression and native verification evidence.
2026-09-20 16:42:52 +02:00

44 lines
3.0 KiB
Python

"""Execute physical node validity, including live consciousness during inventory cache lifetime."""
import os,re
from pathlib import Path
from policy_harness import ROOT,run
p=Path(os.environ.get('ERR_NETWORK_SOURCE', ROOT/'addons/core/Scripts/Game/ERR/10_AI/ERR_HQNetwork.c'))
s=p.read_text();a=s.index('bool Valid(');b=s.index('{',a);end=b+1;depth=1
while depth:depth+=(s[end]=='{')-(s[end]=='}');end+=1
code=s[a:end].replace('ERR_GameMode factions = ERR_GameMode.Get()', 'ERR_GameMode* factions = ERR_GameMode::Get()')
code=code.replace('ERR_Actors.', 'ERR_Actors::').replace('ERR_HQRadio.', 'ERR_HQRadio::').replace('Group.', 'Group->').replace('factions.', 'factions->')
code=code.replace('GetGame().GetWorld().GetWorldTime()', 'nativeNow')
run(r'''
#include <cassert>
struct SCR_AIGroup{int players=0,faction=1;int GetPlayerCount(bool){return players;}int GetFaction(){return faction;}};
struct IEntity{bool canFight=true;int capability=2;SCR_AIGroup*group=nullptr;};
struct ERR_GameMode{static inline ERR_GameMode*current=nullptr;static ERR_GameMode*Get(){return current;}int EnemyFaction(){return 1;}};
namespace ERR_Actors{bool CanFight(IEntity*a){return a&&a->canFight;}SCR_AIGroup*Group(IEntity*a){return a?a->group:nullptr;}}
namespace ERR_HQRadio{int reads=0;int Capability(IEntity*a){reads++;return a->capability;}}
float nativeNow=0;
struct Node{IEntity*Carrier=nullptr;SCR_AIGroup*Group=nullptr;float m_CheckedAt=-1;int m_LiveCapability=0;
'''+code+r'''
};
int main(){
ERR_GameMode mode;ERR_GameMode::current=&mode;SCR_AIGroup group,other;IEntity actor;actor.group=&group;
Node node;node.Carrier=&actor;node.Group=&group;
assert(node.Valid(true)&&ERR_HQRadio::reads==1);
nativeNow=100;assert(node.Valid()&&ERR_HQRadio::reads==1);
// No cached inventory result can make an incapacitated/dead carrier valid.
actor.canFight=false;nativeNow=200;assert(!node.Valid()&&ERR_HQRadio::reads==1);
actor.canFight=true;assert(node.Valid(true)&&ERR_HQRadio::reads==1);
// Exact original group/faction and absence of player members are always checked live.
actor.group=&other;assert(!node.Valid());actor.group=&group;
group.players=1;assert(!node.Valid());group.players=0;
group.faction=2;assert(!node.Valid());group.faction=1;
ERR_GameMode::current=nullptr;assert(!node.Valid());ERR_GameMode::current=&mode;
// Inventory capability is intentionally sampled at most once per second.
actor.capability=1;nativeNow=999;assert(node.Valid(true));assert(ERR_HQRadio::reads==1);
nativeNow=1000;assert(!node.Valid(true));assert(node.Valid());assert(ERR_HQRadio::reads==2);
actor.capability=0;nativeNow=2000;assert(!node.Valid());assert(ERR_HQRadio::reads==3);
actor.capability=2;nativeNow=1500;assert(node.Valid(true));assert(ERR_HQRadio::reads==4); // rewind refresh
node.Carrier=nullptr;assert(!node.Valid());node.Carrier=&actor;node.Group=nullptr;assert(!node.Valid());
}
''')
print('PASS: actual radio node rejects current incapacitation, death, ownership and faction changes despite cached inventory; one-second capability refresh remains explicit')