Fix convoy coordination, AI combat and spectator recovery
This commit is contained in:
@@ -128,3 +128,61 @@ supply_state=body(battery,'ERR_MortarSupplyState SupplyState(')
|
||||
assert supply_state.index('m_Transfer.Poll(now)') < supply_state.index('if (!SupplyAuthorized(now))')
|
||||
assert shoot.count('super.EOnTaskSimulate(')==1 and 'battery.SupplyGunner()' not in shoot
|
||||
print('PASS: actual startup/generation/ownership/timeout/callback policies and native-counter wait; integration preserves one-shot allocation and pending-crew cancellation')
|
||||
|
||||
# Execute the production post-shot node, including the superclass completion
|
||||
# callback. A fast repeater must not start a ninth aim while HQ is still waiting
|
||||
# to observe native completion; pending ammunition and duplicate ticks stay safe.
|
||||
from types import SimpleNamespace
|
||||
section=(r/'ERR_MortarFiring.c').read_text().split('modded class SCR_AIStaticArtilleryBehavior_ShootingLogic',1)[1]
|
||||
cycle=body(SimpleNamespace(read_text=lambda:section),'override ENodeResult EOnTaskSimulate(')
|
||||
cycle=cycle.replace('override ', '').replace('AIAgent owner','void* owner')
|
||||
cycle=cycle.replace('ERR_MortarBattery battery;', 'ERR_MortarBattery* battery=nullptr;').replace('SCR_AIStaticArtilleryBehavior behavior;', 'SCR_AIStaticArtilleryBehavior* behavior=nullptr;')
|
||||
cycle=cycle.replace('SCR_AIStaticArtilleryBehavior.Cast(m_Utility.GetExecutedAction())','m_Utility->GetExecutedAction()')
|
||||
cycle=cycle.replace('ERR_MortarSystem system = ERR_MortarSystem.Get();','ERR_MortarSystem* system = &systemInstance;')
|
||||
for name in ['battery','behavior','system']:cycle=cycle.replace(name+'.',name+'->')
|
||||
for name in ['ERR_MortarSupplyRules','ERR_MortarSalvo','ERR_MortarSupplyState','ENodeResult']:cycle=cycle.replace(name+'.',name+'::')
|
||||
cycle=cycle.replace('GetGame().GetWorld().GetWorldTime()', '1000.f').replace('super.EOnTaskSimulate(owner, dt)', 'Base::EOnTaskSimulate(owner, dt)')
|
||||
gate=body(readiness,'static int CycleGate(')
|
||||
run('''#include <cassert>
|
||||
enum class ENodeResult {FAIL,RUNNING,SUCCESS};
|
||||
enum ERR_MortarSupplyState {FAILED=-1,PENDING,READY};
|
||||
struct ERR_MortarSalvo {static constexpr int ROUNDS=8;};
|
||||
struct ERR_MortarSupplyRules {'''+gate+'''};
|
||||
struct ERR_MortarBattery {
|
||||
bool CommandOpen=true;int OrderShots=0,checks=0;ERR_MortarSupplyState supply=ERR_MortarSupplyState::READY;
|
||||
ERR_MortarSupplyState SupplyState(float){checks++;return supply;}
|
||||
};
|
||||
struct SCR_AIStaticArtilleryBehavior {
|
||||
ERR_MortarBattery* battery=nullptr;int count=0,completions=0;
|
||||
int GetShotCount(){return count;}ERR_MortarBattery* ERR_GetMortarBattery(){return battery;}
|
||||
};
|
||||
struct Utility {SCR_AIStaticArtilleryBehavior* behavior;auto GetExecutedAction(){return behavior;}};
|
||||
struct ERR_MortarSystem {int refusals=0;void Withhold(ERR_MortarBattery*,int){refusals++;}int SupplyFailure(ERR_MortarBattery*,float){return 0;}} systemInstance;
|
||||
struct Base {
|
||||
Utility* m_Utility=nullptr;int calls=0;bool aiming=false;static constexpr int PORT_AIMING_NEEDED=1;
|
||||
ENodeResult EOnTaskSimulate(void*,float){calls++;auto b=m_Utility->behavior;if(++b->count==8)b->completions++;return ENodeResult::SUCCESS;}
|
||||
void SetVariableOut(int,bool value){aiming=value;}
|
||||
};
|
||||
struct Node:Base {'''+cycle+'''};
|
||||
int main(){
|
||||
ERR_MortarBattery battery;SCR_AIStaticArtilleryBehavior behavior;behavior.battery=&battery;Utility utility{&behavior};Node n;n.m_Utility=&utility;
|
||||
assert(n.EOnTaskSimulate(nullptr,0)==ENodeResult::RUNNING&&n.calls==0);
|
||||
battery.OrderShots=1;battery.supply=ERR_MortarSupplyState::PENDING;
|
||||
assert(n.EOnTaskSimulate(nullptr,0)==ENodeResult::RUNNING&&n.calls==0);
|
||||
battery.supply=ERR_MortarSupplyState::READY;
|
||||
for(int shot=1;shot<=8;shot++){
|
||||
battery.OrderShots=shot;n.aiming=false;
|
||||
if(shot==8)battery.supply=ERR_MortarSupplyState::FAILED; // final shot needs no ninth shell
|
||||
auto result=n.EOnTaskSimulate(nullptr,0);
|
||||
assert(n.calls==shot&&behavior.count==shot);
|
||||
assert(result==(shot<8?ENodeResult::SUCCESS:ENodeResult::RUNNING));
|
||||
assert(n.aiming==(shot<8));
|
||||
}
|
||||
assert(behavior.completions==1&&systemInstance.refusals==0);
|
||||
for(int tick=0;tick<100;tick++)assert(n.EOnTaskSimulate(nullptr,0)==ENodeResult::RUNNING);
|
||||
assert(n.calls==8&&behavior.completions==1); // no duplicate count or ninth aim
|
||||
battery.CommandOpen=false;assert(n.EOnTaskSimulate(nullptr,0)==ENodeResult::FAIL);
|
||||
behavior.battery=nullptr;assert(n.EOnTaskSimulate(nullptr,0)==ENodeResult::SUCCESS); // unrelated native artillery unchanged
|
||||
}
|
||||
''')
|
||||
print('PASS: rapid mortar cycle counts eight physical rounds once and waits for native completion without a ninth aim or shell')
|
||||
|
||||
Reference in New Issue
Block a user