|
|
|
@@ -0,0 +1,105 @@
|
|
|
|
|
"""Run production marker transitions and discovery with engine boundary doubles."""
|
|
|
|
|
from policy_harness import ROOT, body, run
|
|
|
|
|
base = ROOT/'addons/core/Scripts/Game/ERR/00_Core'
|
|
|
|
|
map_source = base/'ERR_DiscoveryMap.c'
|
|
|
|
|
rules = '\n'.join(body(map_source, s) for s in ('static int DisplayKnowledge(', 'static int Coordinate(')).replace('Math.Round','std::round').replace('Math.Floor','std::floor')
|
|
|
|
|
update = body(map_source, 'protected void ERR_UpdateMarker(').replace('protected ', '')
|
|
|
|
|
discover = body(base/'ERR_Location.c', 'bool Discover(')
|
|
|
|
|
icon = body(map_source, 'void SetLocationIcon(')
|
|
|
|
|
for name in ('ERR_GameMode', 'SCR_MapMarkerManagerComponent', 'ERR_DiscoveryMapRules', 'ERR_LocationKind', 'SCR_EMapMarkerType', 'Replication', 'ERR_MissionRules'):
|
|
|
|
|
update = update.replace(name+'.', name+'::')
|
|
|
|
|
discover = discover.replace(name+'.', name+'::')
|
|
|
|
|
for typename in ('ERR_GameMode', 'SCR_MapMarkerManagerComponent'):
|
|
|
|
|
update = update.replace(typename+' ', typename+'* ')
|
|
|
|
|
discover = discover.replace('ERR_GameMode mode', 'ERR_GameMode* mode')
|
|
|
|
|
for name in ('mode', 'manager', 'oldManager', 'm_ERRMarker'):
|
|
|
|
|
update = update.replace(name+'.',name+'->')
|
|
|
|
|
discover = discover.replace('mode.', 'mode->')
|
|
|
|
|
update = update.replace('GetGame().','GetGame()->').replace('null','nullptr')
|
|
|
|
|
mission = body(base/'ERR_MissionRules.c', 'static int Discovery(')
|
|
|
|
|
run(r'''
|
|
|
|
|
#include <cassert>
|
|
|
|
|
#include <cmath>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <memory>
|
|
|
|
|
struct string:std::string{using std::string::string;string(std::string s):std::string(s){}bool IsEmpty(){return empty();}};
|
|
|
|
|
namespace ERR_LocationKind {enum Kind{PRISON,RADIO,EXTRACTION,OUTPOST,DEPOT,MORTAR,HOSPITAL};}
|
|
|
|
|
namespace SCR_EMapMarkerType {constexpr int PLACED_CUSTOM=0;}
|
|
|
|
|
struct Game{bool controller=true;bool GetPlayerController(){return controller;}}game;
|
|
|
|
|
Game* GetGame(){return &game;}
|
|
|
|
|
struct Replication{static inline bool server=true;static bool IsServer(){return server;}static void BumpMe(){}};
|
|
|
|
|
struct ERR_GameMode{bool enabled=false;int events=0;static ERR_GameMode* Get();bool ShowAllSites(){return enabled;}void LocationDiscovered(void*,int,int){events++;}}mode;
|
|
|
|
|
ERR_GameMode* ERR_GameMode::Get(){return &mode;}
|
|
|
|
|
struct ERR_MissionRules {'''+mission+r'''};
|
|
|
|
|
struct ERR_DiscoveryMapRules {'''+rules+r'''};
|
|
|
|
|
struct ERR_DiscoveryMarker{
|
|
|
|
|
string label,m_Icon;int x=0,refreshes=0;bool removed=false;
|
|
|
|
|
static string Icon(int kind,string){return kind==ERR_LocationKind::RADIO?"radio":"supplies";}
|
|
|
|
|
void ApplyIcon(){}void SetType(int){}void SetMarkerConfigID(int){}
|
|
|
|
|
void SetCustomText(string v){label=v;}void RefreshPresentation(){refreshes++;}
|
|
|
|
|
void SetDiscoveryPosition(float p,int knowledge){x=ERR_DiscoveryMapRules::Coordinate(p,knowledge);}
|
|
|
|
|
void OnDelete(){removed=true;}
|
|
|
|
|
'''+icon.replace('ERR_LocationKind kind','int kind')+r'''
|
|
|
|
|
};
|
|
|
|
|
struct SCR_MapMarkerManagerComponent{
|
|
|
|
|
static inline bool ready=true;int inserts=0,removes=0;
|
|
|
|
|
static SCR_MapMarkerManagerComponent* GetInstance();
|
|
|
|
|
bool GetMarkerConfig(){return ready;}
|
|
|
|
|
void ERR_InsertDiscoveryMarker(ERR_DiscoveryMarker*){inserts++;}
|
|
|
|
|
void ERR_RemoveDiscoveryMarker(ERR_DiscoveryMarker* marker){removes++;delete marker;}
|
|
|
|
|
}manager;
|
|
|
|
|
SCR_MapMarkerManagerComponent* SCR_MapMarkerManagerComponent::GetInstance(){return &manager;}
|
|
|
|
|
struct Location{
|
|
|
|
|
ERR_DiscoveryMarker* m_ERRMarker=nullptr;int m_ERRShown=-1,m_Knowledge=0;string m_ERRShownLabel;
|
|
|
|
|
bool m_Prepared=true;int kind=ERR_LocationKind::RADIO;
|
|
|
|
|
int Knowledge(){return m_Knowledge;}bool Prepared(){return m_Prepared;}int Kind(){return kind;}
|
|
|
|
|
string Label(){return "Secret radio station";}string Id(){return "secret-radio-id";}float Position(){return 6123.25f;}
|
|
|
|
|
'''+update+'\n'+discover+r'''
|
|
|
|
|
~Location(){delete m_ERRMarker;}
|
|
|
|
|
};
|
|
|
|
|
int main(){
|
|
|
|
|
Location site;site.ERR_UpdateMarker();assert(!site.m_ERRMarker&&site.m_Knowledge==0);
|
|
|
|
|
mode.enabled=true;site.ERR_UpdateMarker();assert(site.m_ERRMarker);
|
|
|
|
|
assert(site.m_ERRMarker->label=="Unknown site"&&site.m_ERRMarker->m_Icon=="mark-question"&&site.m_ERRMarker->x==6123);
|
|
|
|
|
assert(site.m_Knowledge==0&&mode.events==0); // Visibility never grants discovery or objective progress.
|
|
|
|
|
auto* first=site.m_ERRMarker;site.ERR_UpdateMarker();assert(site.m_ERRMarker==first&&manager.inserts==1);
|
|
|
|
|
mode.enabled=false;site.ERR_UpdateMarker();assert(!site.m_ERRMarker&&manager.removes==1);
|
|
|
|
|
mode.enabled=true;site.ERR_UpdateMarker();assert(site.m_ERRMarker&&manager.inserts==2);
|
|
|
|
|
assert(site.Discover(99,0)); // An actual clue identifies even when normal exact chance is zero.
|
|
|
|
|
site.ERR_UpdateMarker();assert(site.Knowledge()==2&&mode.events==1);
|
|
|
|
|
assert(site.m_ERRMarker->label=="Secret radio station"&&site.m_ERRMarker->m_Icon=="radio");
|
|
|
|
|
mode.enabled=false;site.ERR_UpdateMarker();assert(site.m_ERRMarker&&site.m_ERRMarker->x==6123);
|
|
|
|
|
assert(!site.Discover(0,100)&&mode.events==1);
|
|
|
|
|
Location rough;assert(rough.Discover(99,0)&&rough.Knowledge()==1);rough.ERR_UpdateMarker();
|
|
|
|
|
assert(rough.m_ERRMarker->label=="Unknown location (500 m area)"&&rough.m_ERRMarker->x==6250);
|
|
|
|
|
mode.enabled=true;rough.ERR_UpdateMarker();assert(rough.Knowledge()==1&&rough.m_ERRMarker->x==6123&&rough.m_ERRMarker->m_Icon=="mark-question");
|
|
|
|
|
mode.enabled=false;rough.ERR_UpdateMarker();assert(rough.m_ERRMarker->x==6250);
|
|
|
|
|
mode.enabled=true;assert(rough.Discover(99,0)&&rough.Knowledge()==2);
|
|
|
|
|
Location pending;pending.m_Prepared=false;pending.ERR_UpdateMarker();assert(!pending.m_ERRMarker&&!pending.Discover(0,100));
|
|
|
|
|
pending.m_Prepared=true;pending.ERR_UpdateMarker();assert(pending.m_ERRMarker);
|
|
|
|
|
pending.m_Prepared=false;pending.ERR_UpdateMarker();assert(!pending.m_ERRMarker);
|
|
|
|
|
Location prison;prison.kind=ERR_LocationKind::PRISON;prison.ERR_UpdateMarker();assert(!prison.m_ERRMarker);
|
|
|
|
|
Location late;manager.ready=false;late.ERR_UpdateMarker();assert(!late.m_ERRMarker);
|
|
|
|
|
manager.ready=true;late.ERR_UpdateMarker();assert(late.m_ERRMarker&&late.m_ERRMarker->m_Icon=="mark-question");
|
|
|
|
|
Replication::server=false;assert(!late.Discover(0,100)&&late.Knowledge()==0);
|
|
|
|
|
for(int kind=ERR_LocationKind::RADIO;kind<=ERR_LocationKind::HOSPITAL;kind++){
|
|
|
|
|
Location other;other.kind=kind;other.ERR_UpdateMarker();assert(other.m_ERRMarker&&other.m_ERRMarker->label=="Unknown site"&&other.m_ERRMarker->m_Icon=="mark-question");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
''')
|
|
|
|
|
# Persisted authority and runtime presentation wiring (including late-join replication).
|
|
|
|
|
settings=base/'ERR_Settings.c'
|
|
|
|
|
assert '"showAllSites"' in body(settings,'static array<string> Keys(')
|
|
|
|
|
assert 'if (key == "showAllSites") return 0;' in body(settings,'static int AddedDefault(')
|
|
|
|
|
assert 'showAllSites' not in body(settings,'static bool Randomizable(')
|
|
|
|
|
mode_source=(base/'ERR_GameMode.c').read_text()
|
|
|
|
|
assert '[RplProp()] protected bool m_ShowAllSites;' in mode_source
|
|
|
|
|
assert 'PublishSiteVisibility();' in body(base/'ERR_GameMode.c','protected override void EOnInit(')
|
|
|
|
|
publish=body(base/'ERR_GameMode.c','void PublishSiteVisibility(')
|
|
|
|
|
assert '!Replication.IsServer()' in publish and 'Replication.BumpMe()' in publish
|
|
|
|
|
admin=body(base/'ERR_AdminService.c','void Execute(')
|
|
|
|
|
assert admin.index('!authorized') < admin.index('mode.PublishSiteVisibility()')
|
|
|
|
|
assert admin.index('SettingCommand(mode.Settings(), key, parts, replies);') < admin.index('mode.PublishSiteVisibility()')
|
|
|
|
|
click=body(base/'ERR_AdminMenu.c','protected void OnButton(')
|
|
|
|
|
assert click.index('!m_Ready') < click.index('"intel sites set "')
|
|
|
|
|
print('PASS: hidden/anonymous/rough/identified markers, toggle transitions, prepared sites, no identity leakage, intel discovery and replicated authority wiring')
|