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