Files
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

108 lines
7.3 KiB
Python

"""Run production fleet selection and bench policy; native seat entry is separate."""
from policy_harness import ROOT, body, run
base = ROOT/'addons/core/Scripts/Game/ERR/00_Core'
selector = body(base/'ERR_CasualtyLoadingGameMode.c', 'Vehicle CasualtyLoadingAircraftFor(')
selector = (selector.replace('Vehicle ', 'Actor* ').replace('array<Vehicle> aircrafts = {}', 'std::vector<Actor*> aircrafts')
.replace('foreach (Actor* aircraft : aircrafts)', 'for (Actor* aircraft : aircrafts)')
.replace('Actor* nearest, available;', 'Actor* nearest=nullptr; Actor* available=nullptr;')
.replace('float.MAX', 'std::numeric_limits<float>::max()')
.replace('BaseCompartmentManagerComponent manager = BaseCompartmentManagerComponent.Cast(aircraft.FindComponent(BaseCompartmentManagerComponent));', 'Manager* manager = aircraft->manager;')
.replace('array<BaseCompartmentSlot> seats = {}', 'std::vector<Seat*> seats')
.replace('foreach (BaseCompartmentSlot seat : seats)', 'for (Seat* seat : seats)')
.replace('vector.Distance', 'Distance').replace('null', 'nullptr'))
selector=selector.replace('nullptrptr','nullptr')
for name in ('caller','casualty','aircraft','manager','seat'):
selector=selector.replace(name+'.',name+'->')
selector=selector.replace('ERR_Actors.', 'ERR_Actors::').replace('ERR_CasualtyLoadingRules.', 'ERR_CasualtyLoadingRules::')
ranges=body(base/'ERR_CasualtyLoadingService.c', 'static bool Ranges(')
run(r'''
#include <cassert>
#include <cmath>
#include <limits>
#include <vector>
struct Actor;using IEntity=Actor*;
struct Seat {Actor* reserved=nullptr;bool transport=true,occupied=false,accessible=true,locked=false;
bool GetOccupant(){return occupied;} bool IsCompartmentAccessible(){return accessible;}
bool IsGetInLockedFor(Actor*){return locked;} bool IsReserved(){return reserved;}
bool IsReservedBy(Actor* actor){return actor&&reserved==actor;}
};
struct Manager {std::vector<Seat*> seats;void GetCompartments(std::vector<Seat*>& result){result=seats;}};
struct Actor {float position=0;bool alive=true,ready=true;Manager* manager=nullptr;float GetOrigin(){return position;}};
float Distance(float a,float b){return std::abs(a-b);}
namespace ERR_Actors {bool Alive(Actor* a){return a&&a->alive;}}
namespace ERR_CasualtyLoadingRules {
''' + ranges + r'''
bool AircraftReady(Actor* a){return a&&a->ready;}
bool TransportBench(Seat* s,Actor*){return s&&s->transport;}
}
struct Mode {
std::vector<Actor*> fleet;
void CasualtyLoadingAircrafts(std::vector<Actor*>& aircrafts){aircrafts=fleet;}
''' + selector + r'''
};
int main(){
Actor caller,casualty,first,second;Seat firstSeat,secondSeat;Manager firstManager,secondManager;
firstManager.seats={nullptr,&firstSeat};secondManager.seats={&secondSeat};
first.manager=&firstManager;second.manager=&secondManager;first.position=4;second.position=9;
Mode mode;mode.fleet={&first,&second};
assert(mode.CasualtyLoadingAircraftFor(&caller,&casualty)==&first);
firstSeat.occupied=true;assert(mode.CasualtyLoadingAircraftFor(&caller,&casualty)==&second);firstSeat.occupied=false;
firstSeat.locked=true;assert(mode.CasualtyLoadingAircraftFor(&caller,&casualty)==&second);firstSeat.locked=false;
firstSeat.accessible=false;assert(mode.CasualtyLoadingAircraftFor(&caller,&casualty)==&second);firstSeat.accessible=true;
firstSeat.transport=false;assert(mode.CasualtyLoadingAircraftFor(&caller,&casualty)==&second);firstSeat.transport=true;
first.ready=false;assert(mode.CasualtyLoadingAircraftFor(&caller,&casualty)==&second);first.ready=true;
// The pending patient's own reserved aircraft remains stable even when nearer
// free seats exist; someone else's reservation never offers a seat.
secondSeat.reserved=&casualty;assert(mode.CasualtyLoadingAircraftFor(&caller,&casualty)==&second);
secondSeat.reserved=&caller;assert(mode.CasualtyLoadingAircraftFor(&caller,&casualty)==&first);
firstSeat.occupied=true;assert(mode.CasualtyLoadingAircraftFor(&caller,&casualty)==&first); // nearest denial fallback
secondSeat.reserved=nullptr;assert(mode.CasualtyLoadingAircraftFor(&caller,&casualty)==&second);
caller.position=-4;assert(mode.CasualtyLoadingAircraftFor(&caller,&casualty)==&first); // independently enforce rescuer range
caller.position=0;second.position=13;assert(mode.CasualtyLoadingAircraftFor(&caller,&casualty)==&first);
second.position=9;first.alive=false;assert(mode.CasualtyLoadingAircraftFor(&caller,&casualty)==&second);
second.alive=false;assert(!mode.CasualtyLoadingAircraftFor(&caller,&casualty));
assert(!mode.CasualtyLoadingAircraftFor(nullptr,&casualty));assert(!mode.CasualtyLoadingAircraftFor(&caller,nullptr));
mode.fleet.clear();assert(!mode.CasualtyLoadingAircraftFor(&caller,&casualty));
}
''')
bench=body(base/'ERR_CasualtyLoadingService.c','static bool TransportBenchPrefab(')
gear=body(base/'ERR_CasualtyGroundSupport.c','static int LandingGearKind(')
run(r'''
#include <cassert>
#include <string>
struct string : std::string {
using std::string::string;
bool EndsWith(const char* value) const {std::string suffix(value);return size()>=suffix.size()&&compare(size()-suffix.size(),suffix.size(),suffix)==0;}
bool Contains(const char* value) const {return find(value)!=npos;}
};
''' + bench + gear + r'''
int main(){
assert(TransportBenchPrefab("{id}Prefabs/Vehicles/Helicopters/Mi8MT/VehParts/Seats/VehPart_MI8_seats_cargo.et"));
assert(TransportBenchPrefab("{id}Prefabs/Vehicles/Helicopters/UH1H/VehParts/Seats/VehPart_UH1H_seats_cargo.et"));
assert(TransportBenchPrefab("{id}Prefabs/Vehicles/Helicopters/UH1H/VehParts/Seats/VehPart_UH1H_seats_gunners.et"));
assert(TransportBenchPrefab("{id}Prefabs/Vehicles/Helicopters/UH1H/VehParts/Seats/VehPart_UH1H_seats_cargo_openDoor.et"));
assert(!TransportBenchPrefab("{id}Prefabs/Vehicles/Helicopters/UH1H/VehParts/Seats/VehPart_UH1H_seats_gunners_dummy.et"));
assert(!TransportBenchPrefab("{id}Prefabs/Vehicles/Helicopters/UH1H/VehParts/Seats/VehPart_UH1H_seats_base.et"));
assert(!TransportBenchPrefab("{id}Prefabs/Vehicles/Helicopters/UH1H/VehParts/WeapSystems/UH1H_M60D_gunner_left.et"));
assert(!TransportBenchPrefab("{id}Prefabs/ERR/RescueHelicopterWest.et"));
assert(!TransportBenchPrefab(""));
assert(!TransportBenchPrefab("{id}Prefabs/Other/VehPart_UH1H_seats_cargo.et"));
assert(LandingGearKind("{id}Prefabs/ERR/RescueHelicopter.et")==1);
assert(LandingGearKind("{id}Prefabs/ERR/RescueHelicopterFIA.et")==1);
assert(LandingGearKind("{id}Prefabs/ERR/RescueHelicopterAFRF.et")==1);
assert(LandingGearKind("{id}Prefabs/ERR/RescueHelicopterWest.et")==2);
assert(LandingGearKind("{id}Prefabs/ERR/RescueHelicopterION.et")==2);
assert(LandingGearKind("{id}Prefabs/ERR/RescueEscortWest.et")==0);
assert(LandingGearKind("{id}Prefabs/Vehicles/Helicopters/UH1H/UH1H.et")==2);
assert(LandingGearKind("{id}Prefabs/Vehicles/Helicopters/Mi8MT/Mi8MT.et")==1);
assert(LandingGearKind("unknown")==0);
}
''')
owner=(base/'ERR_CasualtyLoadingOwner.c').read_text()
service=(base/'ERR_CasualtyLoadingService.c').read_text()
assert 'mode.CasualtyLoadingTransport(vehicle)' in owner
assert 'NearbyAircraft(mode, caller, actor, vehicle)' in owner
assert service.count('NearbyAircraft(m_Mode, ticket.Caller, ticket.Casualty, ticket.Aircraft)')==2
assert service.count('m_Mode.CasualtyLoadingTransport(ticket.Aircraft)')==2
print('PASS: actual nearest usable registered-fleet selection, patient reservation priority, independent ranges, audited benches/skids and captured-aircraft handshake guards')