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

56 lines
5.0 KiB
Python

from pathlib import Path
r=Path('/home/jakub/devel/escapistsrereintroduced')
o=Path('/tmp/erri-mine-zones-tests-0558')
s=(r/'tests/test_engineer_mine.py').read_text()
s=s.replace("'ERR_GameMode','ERR_HQUnit'", "'SCR_AIGroupUtilityComponent','ERR_GameMode','ERR_HQUnit'")
s=s.replace("'m_Mode','m_Unit'", "'groupUtility','m_Mode','m_Unit'")
old='struct SCR_AIGroup {bool slave=false;int players=0;Faction* faction=nullptr;bool IsSlave(){return slave;}int GetPlayerCount(bool){return players;}Faction* GetFaction(){return faction;}};'
new='''// Native group movement envelope boundary, not navigation/pathfinding.
struct AIWaypoint {virtual ~AIWaypoint()=default;};
struct SCR_DefendWaypoint:AIWaypoint {vector origin;float radius=30;vector GetOrigin(){return origin;}float GetCompletionRadius(){return radius;}static SCR_DefendWaypoint* Cast(AIWaypoint* p){return dynamic_cast<SCR_DefendWaypoint*>(p);}};
struct SCR_AIGroupUtilityComponent;
struct SCR_AIGroup {bool slave=false;int players=0;Faction* faction=nullptr;SCR_AIGroupUtilityComponent* utility=nullptr;AIWaypoint* waypoint=nullptr;vector center;
bool IsSlave(){return slave;}int GetPlayerCount(bool){return players;}Faction* GetFaction(){return faction;}SCR_AIGroupUtilityComponent* GetGroupUtilityComponent(){return utility;}AIWaypoint* GetCurrentWaypoint(){return waypoint;}vector GetCenterOfMass(){return center;}};
struct SCR_AIGroupUtilityComponent {SCR_AIGroup* m_Owner=nullptr;float m_fMaxAutonomousDistance=100;
// Matches installed SCR_AIGroupUtilityComponent.IsPositionAllowed semantics.
bool IsPositionAllowed(vector pos){auto wp=m_Owner->GetCurrentWaypoint();auto defendWp=SCR_DefendWaypoint::Cast(wp);if(defendWp)return vector::Distance(defendWp->GetOrigin(),pos)<defendWp->GetCompletionRadius();return vector::Distance(m_Owner->GetCenterOfMass(),pos)<m_fMaxAutonomousDistance;}
};'''
assert old in s;s=s.replace(old,new)
s=s.replace('SCR_AIGroup group;SCR_AIUtilityComponent utility;', 'SCR_AIGroup group;SCR_AIGroupUtilityComponent groupUtility;SCR_AIUtilityComponent utility;')
s=s.replace('group.faction=&faction;actor.group=', 'group.faction=&faction;group.utility=&groupUtility;groupUtility.m_Owner=&group;actor.group=')
needle='int main(){\n'
extra='''int main(){
// Current native defend radius is strict and three dimensional: the broad
// 25..60 m mission band does not authorize bypassing the group's own envelope.
for(int fault=0;fault<4;fault++){Fixture f;SCR_DefendWaypoint defend;f.group.waypoint=&defend;vector point={30,0,0};
if(fault==0)f.group.utility=nullptr;
if(fault==2)point={25,17,0};
if(fault==3){f.group.waypoint=nullptr;f.groupUtility.m_fMaxAutonomousDistance=30;}
assert(!f.controller.Begin(&f.mode,&f.unit,&f.task,point,1000));
assert(f.controller.Finished()&&f.attempted.empty()&&!f.utility.additions&&!f.inventory.calls&&!f.trigger.calls&&!f.mode.mineIntel.candidates);
}
for(int boundary=0;boundary<3;boundary++){Fixture f;SCR_DefendWaypoint defend;f.group.waypoint=&defend;vector point={29.999f,0,0};
if(boundary==1)point={25,16,0};
if(boundary==2){f.group.waypoint=nullptr;f.group.center={1,0,0};f.groupUtility.m_fMaxAutonomousDistance=30;point={30,0,0};}
assert(f.controller.Begin(&f.mode,&f.unit,&f.task,point,1000));assert(f.attempted.Count()==1&&f.utility.additions==1);
}
// Revalidate the current utility and its current waypoint at every phase.
// Cancellation completes only our exact action and never resumes after a late
// inventory acknowledgement or a later enlargement of the movement envelope.
for(int phase=0;phase<4;phase++)for(int replacement=0;replacement<3;replacement++){Fixture f;
if(phase==3)f.Withdraw();else if(phase==2)f.Prepare();else{f.Begin();if(phase==1){f.actor.position={30,0,0};f.controller.Tick(2000);}}
auto own=f.controller.m_Action;SCR_AIBehaviorBase foreign;f.utility.actions.Insert(&foreign);
auto callback=f.inventory.callback;int calls=f.inventory.calls,additions=f.utility.additions,moves=f.mine.moves;
SCR_DefendWaypoint defend;defend.radius=29;SCR_AIGroupUtilityComponent newUtility;newUtility.m_Owner=&f.group;newUtility.m_fMaxAutonomousDistance=29;
if(replacement==0)f.group.waypoint=&defend;else if(replacement==1)f.group.utility=&newUtility;else f.group.utility=nullptr;
f.controller.Tick(13000);
assert(f.controller.Finished()&&own->completed==1&&!foreign.completed&&f.attempted.Count()==1);
assert(f.inventory.calls==calls&&f.utility.additions==additions&&f.mine.moves==moves&&!f.trigger.calls&&!f.mode.mineIntel.seals);
f.group.utility=&f.groupUtility;f.group.waypoint=nullptr;f.Drop();if(callback)callback->OnComplete();f.actor.position={0,0,0};f.controller.Tick(14000);
assert(f.controller.Finished()&&own->completed==1&&!foreign.completed&&f.inventory.calls==calls&&f.utility.additions==additions&&f.mine.moves==moves&&!f.trigger.calls);
}
'''
assert needle in s;s=s.replace(needle,extra,1)
s=s.replace('PASS: actual engineer mine preparation/deadline,', 'PASS: actual engineer native group-envelope admission and phase cancellation, preparation/deadline,')
(o/'tests/test_engineer_mine.py').write_text(s)