Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
93 lines
5.1 KiB
Python
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')
|