If you guessed (I did) that the issue is a pathfinding failure, you win a kewpie doll!
I look in the engine.log for some clues to confirm my suspicions. The engine.log is quite large
rober@Rob10rto /cygdrive/r/Temp/Logs
$
ls -lh engine.log
-rwxrwxrwx 1 rober rober
906M Aug 29 05:28 engine.log
So by filtering and capturing to a junk file only the items of special interest (note: I have changed the logging ID #s in the latest EXEs, available in the next release(s))
rober@Rob10rto /cygdrive/r/Temp/Logs
$
egrep "ID 300[0-9]|ID 4000|attack_sequential" engine.log > junk
I have a much smaller file to analyze
rober@Rob10rto /cygdrive/r/Temp/Logs
$
ls -lh junk
-rw-r--r-- 1 rober rober
59M Aug 29 05:28 junk
One of the units in that 2nd/6th & 3rd/6th stack has trackid 238. Using the Cygwin/Linux egrep pattern matching utility, I look for 'MakeGoal' log entries for that trackid:
rober@Rob10rto /cygdrive/r/Temp/Logs
$
egrep "trackid 238" junk | egrep MakeGoal
2022-08-28 20:06:00 vnengine.exe: [DEBUG ID 4000] (control.cpp, line 1641, Control::MakeGoal()) in Control::MakeGoal(), turn 5, side 0, trackid 238, strackid 236, xai -1, yai -1, hexai -1,-1, aidir -1, airadius -1, aiactprob 100, aiorder 2
2022-08-28 20:06:58 vnengine.exe: [DEBUG ID 4000] (control.cpp, line 1641, Control::MakeGoal()) in Control::MakeGoal(), turn 6, side 0, trackid 238, strackid 236, xai -1, yai -1, hexai -1,-1, aidir -1, airadius -1, aiactprob 100, aiorder 2
...
2022-08-28 20:08:48 vnengine.exe: [DEBUG ID 4000] (control.cpp, line 1641, Control::MakeGoal()) in Control::MakeGoal(), turn 8, side 0, trackid 238, strackid 236, xai 77, yai 15, hexai 77,15, aidir -1, airadius -1, aiactprob 100, aiorder 13
2022-08-28 20:08:48 vnengine.exe: [DEBUG ID 4000] (control.cpp, line 1644, Control::MakeGoal()) in Control::MakeGoal(), setting goal, assigning order, turn 8, side 0, unit Parachute Platoon 55 A, hex 71,11, trackid 238, strackid 236, xai 77, yai 15, hexai 77,15, aidir -1, airadius -1, aiactprob 100, aiorder 13
2022-08-28 20:10:47 vnengine.exe: [DEBUG ID 4000] (control.cpp, line 1641, Control::MakeGoal()) in Control::MakeGoal(), turn 9, side 0, trackid 238, strackid 236, xai 77, yai 15, hexai 77,15, aidir -1, airadius -1, aiactprob 100, aiorder 13
2022-08-28 20:10:47 vnengine.exe: [DEBUG ID 4000] (control.cpp, line 1644, Control::MakeGoal()) in Control::MakeGoal(), setting goal, assigning order, turn 9, side 0, unit Parachute Platoon 55 A, hex 72,12, trackid 238, strackid 236, xai 77, yai 15, hexai 77,15, aidir -1, airadius -1, aiactprob 100, aiorder 13
...
2022-08-28 20:24:06 vnengine.exe: [DEBUG ID 4000] (control.cpp, line 1641, Control::MakeGoal()) in Control::MakeGoal(), turn 16, side 0, trackid 238, strackid 236, xai 85, yai 18, hexai 85,18, aidir -1, airadius -1, aiactprob 100, aiorder 13
2022-08-28 20:24:06 vnengine.exe: [DEBUG ID 4000] (control.cpp, line 1644, Control::MakeGoal()) in Control::MakeGoal(), setting goal, assigning order, turn 16, side 0, unit Parachute Platoon 55 A, hex 77,15, trackid 238, strackid 236, xai 85, yai 18, hexai 85,18, aidir -1, airadius -1, aiactprob 100, aiorder 13
2022-08-28 20:25:31 vnengine.exe: [DEBUG ID 4000] (control.cpp, line 1641, Control::MakeGoal()) in Control::MakeGoal(), turn 17, side 0, trackid 238, strackid 236, xai 85, yai 18, hexai 85,18, aidir -1, airadius -1, aiactprob 100, aiorder 13
2022-08-28 20:25:31 vnengine.exe: [DEBUG ID 4000] (control.cpp, line 1644, Control::MakeGoal()) in Control::MakeGoal(), setting goal, assigning order, turn 17, side 0, unit Parachute Platoon 55 A, hex 79,16, trackid 238, strackid 236, xai 85, yai 18, hexai 85,18, aidir -1, airadius -1, aiactprob 100, aiorder 13
...
2022-08-28 20:37:51 vnengine.exe: [DEBUG ID 4000] (control.cpp, line 1641, Control::MakeGoal()) in Control::MakeGoal(), turn 24, side 0, trackid 238, strackid 236, xai 93, yai 24, hexai 93,24, aidir -1, airadius -1, aiactprob 100, aiorder 13
2022-08-28 20:37:51 vnengine.exe: [DEBUG ID 4000] (control.cpp, line 1644, Control::MakeGoal()) in Control::MakeGoal(), setting goal, assigning order, turn 24, side 0, unit Parachute Platoon 55 A, hex 84,16, trackid 238, strackid 236, xai 93, yai 24, hexai 93,24, aidir -1, airadius -1, aiactprob 100, aiorder 13
2022-08-28 20:39:46 vnengine.exe: [DEBUG ID 4000] (control.cpp, line 1641, Control::MakeGoal()) in Control::MakeGoal(), turn 25, side 0, trackid 238, strackid 236, xai 93, yai 24, hexai 93,24, aidir -1, airadius -1, aiactprob 100, aiorder 13
2022-08-28 20:39:46 vnengine.exe: [DEBUG ID 4000] (control.cpp, line 1644, Control::MakeGoal()) in Control::MakeGoal(), setting goal, assigning order, turn 25, side 0, unit Parachute Platoon 55 A, hex 85,18, trackid 238, strackid 236, xai 93, yai 24, hexai 93,24, aidir -1, airadius -1, aiactprob 100, aiorder 13
...
2022-08-28 21:00:27 vnengine.exe: [DEBUG ID 4000] (control.cpp, line 1641, Control::MakeGoal()) in Control::MakeGoal(), turn 31, side 0, trackid 238, strackid 236, xai 93, yai 24, hexai 93,24, aidir -1, airadius -1, aiactprob 100, aiorder 13
2022-08-28 21:00:27 vnengine.exe: [DEBUG ID 4000] (control.cpp, line 1644, Control::MakeGoal()) in Control::MakeGoal(), setting goal, assigning order, turn 31, side 0, unit Parachute Platoon 55 A, hex 91,20, trackid 238, strackid 236, xai 93, yai 24, hexai 93,24, aidir -1, airadius -1, aiactprob 100, aiorder 13
2022-08-28 21:01:43 vnengine.exe: [DEBUG ID 4000] (control.cpp, line 1641, Control::MakeGoal()) in Control::MakeGoal(), turn 32, side 0, trackid 238, strackid 236, xai 93, yai 24, hexai 93,24, aidir -1, airadius -1, aiactprob 100, aiorder 13
2022-08-28 21:01:43 vnengine.exe: [DEBUG ID 4000] (control.cpp, line 1644, Control::MakeGoal()) in Control::MakeGoal(), setting goal, assigning order, turn 32, side 0, unit Parachute Platoon 55 A, hex 91,20, trackid 238, strackid 236, xai 93, yai 24, hexai 93,24, aidir -1, airadius -1, aiactprob 100, aiorder 13
...
2022-08-28 21:24:32 vnengine.exe: [DEBUG ID 4000] (control.cpp, line 1641, Control::MakeGoal()) in Control::MakeGoal(), turn 39, side 0, trackid 238, strackid 236, xai 93, yai 24, hexai 93,24, aidir -1, airadius -1, aiactprob 100, aiorder 13
2022-08-28 21:24:32 vnengine.exe: [DEBUG ID 4000] (control.cpp, line 1644, Control::MakeGoal()) in Control::MakeGoal(), setting goal, assigning order, turn 39, side 0, unit Parachute Platoon 55 A, hex 91,20, trackid 238, strackid 236, xai 93, yai 24, hexai 93,24, aidir -1, airadius -1, aiactprob 100, aiorder 13
2022-08-28 21:30:43 vnengine.exe: [DEBUG ID 4000] (control.cpp, line 1641, Control::MakeGoal()) in Control::MakeGoal(), turn 40, side 0, trackid 238, strackid 236, xai 93, yai 24, hexai 93,24, aidir -1, airadius -1, aiactprob 100, aiorder 13
2022-08-28 21:30:43 vnengine.exe: [DEBUG ID 4000] (control.cpp, line 1644, Control::MakeGoal()) in Control::MakeGoal(), setting goal, assigning order, turn 40, side 0, unit Parachute Platoon 55 A, hex 91,20, trackid 238, strackid 236, xai 93, yai 24, hexai 93,24, aidir -1, airadius -1, aiactprob 100, aiorder 13
A review of the OBJECTIVES[] (from the VN_550921_Rung_Sat.lua file init_constants()):
...
OBJECTIVES[24] = "77,15" -- 1-40[2/2] 21
...
OBJECTIVES[27] = "85,18" -- 1-40[2/2] 21
...
OBJECTIVES[31] = "93,24" -- 1-40[2/2] 21
...
And a review of the aiorder #s (from init.lua):
...
HALT = 2
...
ATTACK_STRONG = 13
...
On Turn 5, after landing, arriving on map, _2ND_PLT_238 is given the HALT aiorder 2, while it awaits it and rest of its company to undisrupt.
On Turn 8, _2ND_PLT_238 (& co.) now undisrupted, the unit receives its first attack order, ATTACK_STRONG, aiorder 13, with hexai 77,15 -- OBJECTIVES[24] -- as its target hex.
On Turn 16, with OBJECTIVES[24] by now taken, _2ND_PLT_238 receives the ATTACK_STRONG, aiorder 13, with hexai 85,18 -- OBJECTIVES[27] -- as its target.
On Turn 24, with OBJECTIVES[27] by now taken, _2ND_PLT_238 receives the ATTACK_STRONG, aiorder 13, with hexai 93,24 -- OBJECTIVES[31] -- as its target.
On Turn 31, _2ND_PLT_238 arrives at hex 91,20 ... where it remains stuck for the remainder of the scenario.
At Turn 40:

- CSVN_AAR_AI_AI_RungSat82.jpg (2.59 MiB) Viewed 3389 times
Note where hex 91,20 abuts a Minor River. That right there is the problem. The game engine path finding doesn't "see" across waterways very well, or at all. From the starting point hex 91,20, the pathfinding cannot determine, cannot find, a path across the Minor River to hex 93,24 (OBJECTIVES[31]).
Without devoting more time to single step through the game engine code execution (the programmer can do that; you can't), I am pretty darned sure this is the crux of the problem. Carefully inspecting the game engine.log as I have just done was not really necessary. Sometimes there is no other way than digging deep and deeper still to pinpoint the cause of failure. Maybe not this time.
This is the latest in a long line of SAI "gotchas", mysterious glitches, where the SAI doesn't do exactly what you would like it to do. Improving the game engine pathfinding is a long-term aim, but for now it is what it is. (Sometimes the issue is a deeper game engine bug, but that is outside the current discussion.)
What to do? attack_way_point() is the answer. Rather than fret about the E[ngine]AI and its shortcomings, we instead use the S[cripted]AI tools we have at hand to address these sorts of glitches.
The attack_sequential() function only encompasses attack_strong(), not attack_way_point(..., ATTACK_STRONG, ...).
Code: Select all
-- attack_sequential() -- attack the indicated hexes in sequence
function attack_sequential (trackids, hcs, attype, backtrack)
...
if at == ATTACK_WEAK then
attack_weak(ca, targethex)
elseif at == ATTACK_NORMAL then
attack_normal(ca, targethex)
elseif at == ATTACK_STRONG then
attack_strong(ca, targethex)
elseif at == ATTACK_BANZAI or
at == ATTACK_FANATICAL then
attack_banzai(ca, targethex)
else
return false
end
...
end
Again, what to do? I might add still more bells & whistles and capabilities and special cases
and complexity and additional input parameters ... but I prefer not to do that. The attack_sequential() function is already quite complex. We want using it to be fairly easy and straightforward. I don't want it to become bloated to the point of using it being rocket science. KISS it, and all that.
For _3RD_6TH_PARACHUTE_COY_55_A_236, there is a possible solution. Abandon use of attack_sequential() altogether:
Code: Select all
if obj24_threatened then
attack_nearest_to_hex(units, OBJECTIVES[24], NODIR, 1, 100, ATTACK_STRONG)
elseif obj27_threatened then
attack_way_point(units, {"84,17", OBJECTIVES[27]}, NODIR, 1, 100, ATTACK_STRONG)
elseif objective_owner(OBJECTIVES[31]) == BX_SIDE then
attack_way_point(units, {"92,19", OBJECTIVES[31]}, NODIR, 1, 100, ATTACK_STRONG)
elseif objective_owner(OBJECTIVES[33]) == BX_SIDE then
attack_strong(units, OBJECTIVES[33])
elseif objective_owner(OBJECTIVES[34]) == BX_SIDE then
attack_strong(units, OBJECTIVES[34])
else
defend_normal(units, OBJECTIVES[31])
end
In the earlier formulation above, note where attack_way_point() was used for attacks on both OBJECTIVES[27] and OBJECTIVES[31].
But that puts us back to square one. Bloated code, and unreadability (and code maintenance difficulty).
One possible fix would be
Code: Select all
if not attack_sequential(units, {OBJECTIVES[24], OBJECTIVES[27]}, ATTACK_STRONG, true) then
if objective_owner(OBJECTIVES[31]) == BX_SIDE then
attack_way_point(units, {"92,19", OBJECTIVES[31]}, NODIR, 1, 100, ATTACK_STRONG)
elseif not attack_sequential(units, {OBJECTIVES[33], OBJECTIVES[34]}, ATTACK_STRONG, true) then
defend_normal(units, "97,22")
end
end
that is, sandwich the attack_way_point() on OBJECTIVES[31] between the outer attack_sequential() calls to attack OBJECTIVES[24] & OBJECTIVES[27], and OBJECTIVES[33] & OBJECTIVES[34]. But I dunno. I have a bad feeling about that code, not sure it would be WAD.
This is the approach I have adopted:
Code: Select all
-- _3RD_6TH_PARACHUTE_COY_55_A_236 -- 3rd/6th Parachute Company 55 - A
do local units = _3RD_6TH_PARACHUTE_COY_55_A_236
_3RD_6TH_PARACHUTE_COY_55_A_236_READY = _3RD_6TH_PARACHUTE_COY_55_A_236_READY or ready(units)
if _3RD_6TH_PARACHUTE_COY_55_A_236_READY then
_2ND_6TH_PARACHUTE_COY_3RD_6TH_PARACHUTE_COY_ORDER = _2ND_6TH_PARACHUTE_COY_3RD_6TH_PARACHUTE_COY_ORDER or 1 -- random_pick({1,1,2})
if _2ND_6TH_PARACHUTE_COY_3RD_6TH_PARACHUTE_COY_ORDER == 1 then
attack_strong(units, OBJECTIVES[24])
if owned(OBJECTIVES[25], VNA_SIDE) then
if not attack_sequential(units, {OBJECTIVES[27], OBJECTIVES[31], OBJECTIVES[33], OBJECTIVES[34]}, ATTACK_STRONG, true) then
defend_normal(units, "97,22")
end
end
else
if not attack_sequential(units, {OBJECTIVES[24], OBJECTIVES[27], OBJECTIVES[31], OBJECTIVES[33], OBJECTIVES[34]}, ATTACK_STRONG, true) then
defend_normal(units, "97,22")
end
end
-- if stuck at the major river at 91,20, unable to proceed due to pathfinding failure...
if at(units, "91,20") and
(hexai(units[1]) == OBJECTIVES[31]) and
(aiorder(units[1]) == ATTACK_STRONG) then
attack_way_point(units, {"92,19", OBJECTIVES[31]}, NODIR, 1, 100, ATTACK_STRONG)
end
if loss_rate(units) >= VNA_LOSS_RATE_TRIGGER then
_3RD_6TH_PARACHUTE_COY_55_A_236_RETIRE_PT = _3RD_6TH_PARACHUTE_COY_55_A_236_RETIRE_PT or retire_point(units)
defend_weak(units, _3RD_6TH_PARACHUTE_COY_55_A_236_RETIRE_PT, NODIR, 1)
end
end
end
With this, I make use of the CSEE/SAI rule: later orders override earlier orders in the command sequence. After the preceding attack_sequential() calls, we next consider the OBJECTIVES[31] special case:
Code: Select all
-- if stuck at the major river at 91,20, unable to proceed due to pathfinding failure...
if at(units, "91,20") and
(hexai(units[1]) == OBJECTIVES[31]) and
(aiorder(units[1]) == ATTACK_STRONG) then
attack_way_point(units, {"92,19", OBJECTIVES[31]}, NODIR, 1, 100, ATTACK_STRONG)
end
We first test whether all units are at hex 91,20. We then test whether the units are under the standing order to ATTACK_STRONG OBJECTIVES[31]. This is precisely the situation where _2ND_PLT_238 & co. are stuck at the Minor River, unable to figure out how to proceed across the Minor River to the target destination. In this situation, we override the earlier order with the later order
Code: Select all
attack_way_point(units, {"92,19", OBJECTIVES[31]}, NODIR, 1, 100, ATTACK_STRONG)
Problem solved, I think. The proof is in the testing.
(Note: I apply this coding solution to orders for both _2ND_6TH_PARACHUTE_COY_55_A_232 and _3RD_6TH_PARACHUTE_COY_55_A_236.)