Files
EscapistsReintroduced/tests/test_rescue_factions.py
T
jakub 6a667d8deb Capture current mission, AI, map and administration development
Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
2026-10-13 22:52:53 +02:00

93 lines
5.1 KiB
Python

"""Execute actual rescue asset/crew selection; native capacity remains a separate check."""
from policy_harness import ROOT, body, run
import re
source = ROOT / 'addons/core/Scripts/Game/ERR/10_AI/ERR_RescueAssets.c'
s = '\n'.join(body(source, signature) for signature in (
'static bool Western(', 'static int TransportCount(', 'static int TransportSeats(',
'static ResourceName Aircraft(', 'static ResourceName Pilot(', 'static ResourceName Crew('))
s = s.replace('ResourceName', 'std::string').replace('string faction', 'std::string faction')
s = s.replace('ERR_GameMode mode', 'ERR_GameMode* mode')
s = s.replace('ERR_FactionChoice choice', 'ERR_FactionChoice* choice')
s = s.replace('Resource group', 'Resource* group').replace('IEntitySource source', 'IEntitySource* source')
s = s.replace('array<std::string>', 'Array<std::string>')
s = s.replace('mode.PlayerFaction().GetFactionKey()', 'mode->PlayerFaction()->GetFactionKey()')
s = s.replace('mode.FactionSelection().Choice(', 'mode->FactionSelection()->Choice(')
s = s.replace('group.GetResource().ToEntitySource()', 'group->GetResource()->ToEntitySource()')
for name in ('mode', 'choice', 'group', 'source'):
s = re.sub(r'\b' + name + r'\.', name + '->', s)
s = s.replace('pilot.IsEmpty()', 'pilot.empty()').replace('Resource.Load(', 'Resource::Load(')
run(r'''
#include <algorithm>
#include <cassert>
#include <map>
#include <string>
#include <vector>
template<class T> struct Array : std::vector<T> {
using std::vector<T>::vector;
bool IsEmpty(){return this->empty();}
};
struct Faction {std::string key;std::string GetFactionKey(){return key;}};
struct ERR_FactionChoice {std::string Key, Group;};
struct Selection {
ERR_FactionChoice* choice=nullptr;
ERR_FactionChoice* Choice(std::string role){assert(role=="escapists");return choice;}
};
struct ERR_GameMode {
Faction* faction=nullptr;Selection* selection=nullptr;
Faction* PlayerFaction(){return faction;}Selection* FactionSelection(){return selection;}
};
struct IEntitySource {
Array<std::string> members;bool available=true;
bool Get(std::string property,Array<std::string>& out){assert(property=="m_aUnitPrefabSlots");out=members;return available;}
};
struct Resource {
bool valid=true;IEntitySource* source=nullptr;
static inline std::map<std::string,Resource*> resources;
static Resource* Load(std::string name){return resources[name];}
bool IsValid(){return valid;}Resource* GetResource(){return this;}
IEntitySource* ToEntitySource(){return source;}
};
struct Assets {
''' + s + r'''
};
int main(){
for (std::string key : {"US","USSR","FIA","RHS_USAF","RHS_AFRF","RHS_ION"}) {
int count=Assets::TransportCount(key),capacity=Assets::TransportSeats(key);
assert(count*capacity>=12);
if(key=="US"||key=="RHS_USAF"||key=="RHS_ION")assert(count==2&&capacity==8);
else assert(count==1&&capacity>=12);
assert(!Assets::Aircraft(key,false).empty()&&!Assets::Aircraft(key,true).empty());
}
assert(Assets::Aircraft("US",false).find("RescueHelicopterWest.et")!=std::string::npos);
assert(Assets::Aircraft("US",true).find("RescueEscortWest.et")!=std::string::npos);
assert(Assets::Aircraft("RHS_USAF",false)==Assets::Aircraft("US",false));
assert(Assets::Aircraft("USSR",false).find("RescueHelicopter.et")!=std::string::npos);
assert(Assets::Aircraft("FIA",false).find("RescueHelicopterFIA.et")!=std::string::npos);
assert(Assets::Aircraft("RHS_AFRF",false).find("RescueHelicopterAFRF.et")!=std::string::npos);
assert(Assets::Aircraft("RHS_ION",false).find("RescueHelicopterION.et")!=std::string::npos);
assert(Assets::Aircraft("RHS_ION",true).find("RescueEscortION.et")!=std::string::npos);
Selection selection;Faction faction{"US"};ERR_GameMode mode{&faction,&selection};
for (std::string key : {"US","USSR","RHS_USAF","RHS_AFRF"}) {
faction.key=key;assert(!Assets::Pilot(key).empty());assert(Assets::Crew(&mode)==Assets::Pilot(key));
}
assert(Assets::Pilot("FIA").empty()&&Assets::Pilot("RHS_ION").empty());
ERR_FactionChoice choice{"FIA","selected-group"};selection.choice=&choice;
IEntitySource source{{"faction-specific-first-member","second-member"}};Resource group{true,&source};
Resource::resources[choice.Group]=&group;
for(std::string key : {"FIA","RHS_ION","custom-friendly"}){
faction.key=key;choice.Key=key;assert(Assets::Crew(&mode)=="faction-specific-first-member");
}
choice.Key="USSR";assert(Assets::Crew(&mode).empty()); // A mismatched role never falls back to Soviet pilots.
choice.Key=faction.key;group.valid=false;assert(Assets::Crew(&mode).empty());group.valid=true;
source.available=false;assert(Assets::Crew(&mode).empty());source.available=true;
source.members.clear();assert(Assets::Crew(&mode).empty());
group.source=nullptr;assert(Assets::Crew(&mode).empty());
Resource::resources.clear();assert(Assets::Crew(&mode).empty());
selection.choice=nullptr;assert(Assets::Crew(&mode).empty());
mode.selection=nullptr;assert(Assets::Crew(&mode).empty());
mode.faction=nullptr;assert(Assets::Crew(&mode).empty());assert(Assets::Crew(nullptr).empty());
}
''')
print('PASS: faction aircraft profiles provide 12+ cargo capacity; FIA/ION crew comes only from the selected faction')