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

51 lines
2.9 KiB
Diff

--- a/addons/core/Scripts/Game/ERR/10_AI/ERR_HQNetwork.c
+++ b/addons/core/Scripts/Game/ERR/10_AI/ERR_HQNetwork.c
@@ -85,12 +85,12 @@
int target = Cursor + 1;
if (Sending)
{
- if (now < Due)
- return 0;
// A transmission takes two seconds. The sender must keep its physical
// radio throughout that interval, including the final manpack-to-HQ leg.
if (Cursor >= 0 && !Nodes[Cursor].Valid(!Downlink && Cursor == Nodes.Count() - 1))
return Fail(journal, "transmitting carrier lost radio during transmission");
+ if (now < Due)
+ return 0;
if (target < Nodes.Count())
{
if (!Nodes[target].Valid(Downlink && target == 0))
--- a/tests/hq_network_regression.py
+++ b/tests/hq_network_regression.py
@@ -89,6 +89,30 @@
assert(down->Advance(2000,&journal)==0);assert(down->Advance(4000,&journal)==0);assert(down->Advance(6000,&journal)==1);
assert(!down->Originated&&down->OriginDue==-1);for(int j=beforeDown;j<journal.events.Count();j++)assert(journal.events[j].find("CALL")!=0);
auto captured=network.Route(&c[2],true);captured->Advance(0,&journal);c[0].captured=true;assert(captured->Advance(2000,&journal)==-1);c[0].captured=false;
+ // The sender must stay valid on EVERY observed tick of the two-second hop,
+ // not only at completion. Recovery before Due cannot revive an interrupted hop.
+ for(bool downlink:{false,true})for(int reason=0;reason<3;reason++){
+ auto interrupted=network.Route(downlink?&c[1]:&c[0],downlink);ERR_HQJournal log;
+ assert(interrupted->Advance(0,&log)==0);
+ float sendingAt=3000;
+ if(downlink)sendingAt=2000;
+ assert(interrupted->Advance(sendingAt,&log)==0&&interrupted->Sending);
+ if(reason==0)c[0].alive=false;
+ if(reason==1)c[0].captured=true;
+ if(reason==2)c[0].radio=0;
+ assert(interrupted->Advance(sendingAt+1000,&log)==-1);
+ assert(interrupted->Failed&&log.events.back().find("LOST ")==0);
+ int terminalEvents=log.events.Count();
+ c[0].alive=true;c[0].captured=false;c[0].radio=2;
+ assert(interrupted->Advance(sendingAt+2000,&log)==-1&&log.events.Count()==terminalEvents);
+ }
+ // Healthy intermediate polling does not transmit early or duplicate log entries.
+ auto waiting=network.Route(&c[0]);ERR_HQJournal waitingLog;
+ assert(waiting->Advance(0,&waitingLog)==0&&waiting->Advance(3000,&waitingLog)==0);
+ int transmittingEvents=waitingLog.events.Count();
+ assert(waiting->Advance(4000,&waitingLog)==0&&waiting->Sending);
+ assert(waitingLog.events.Count()==transmittingEvents);
+ assert(waiting->Advance(5000,&waitingLog)==1&&waitingLog.events.Count()==transmittingEvents+1);
auto timeout=network.Route(&c[2]);timeout->Advance(0,&journal);assert(timeout->Advance(30001,&journal)==-1);
Network disconnected;disconnected.Add(&c[1],&group,1,1);disconnected.Build();assert(!disconnected.Route(&c[1]));
Network boundary;c[1].pos=V(501);boundary.Add(&c[0],&group,1,2);boundary.Add(&c[1],&group,2,1);boundary.Build();assert(!boundary.Route(&c[1]));