Skip to content

Reimpl/AICState development - #262

Draft
gynt wants to merge 25 commits into
mainfrom
reimpl/AICState-leftover
Draft

gynt wants to merge 25 commits into
mainfrom
reimpl/AICState-leftover

Conversation

@gynt

@gynt gynt commented Oct 14, 2026

Copy link
Copy Markdown
Contributor

No description provided.

@gynt
gynt changed the base branch from main to reimpl/AICState-100 October 14, 2026 07:50
@gynt
gynt marked this pull request as draft October 14, 2026 08:03
@gynt
gynt force-pushed the reimpl/AICState-100 branch from 959b9a9 to a8f7dae Compare October 14, 2026 08:15
@gynt
gynt force-pushed the reimpl/AICState-leftover branch from bd0ce24 to 8251a29 Compare October 15, 2026 22:08
gynt and others added 21 commits October 16, 2026 02:56
The header declares the parameter as int; the PlayerID typedef the
definitions used is not visible there and broke the build.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JP48NBCkB9vy6M7zLArtgo
aiBuyAndSellGoods only differs in its tail-jump targets; with the
sellExcessGoods and buyRequiredGoods resolvers enabled it matches 100%.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JP48NBCkB9vy6M7zLArtgo
…nabled

computeAttackPossibilities, playNervous2BikFromPlayer and buyRequiredGoods
were recorded before the global data resolvers were switched on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JP48NBCkB9vy6M7zLArtgo
@gynt
gynt force-pushed the reimpl/AICState-100 branch from 08895be to 21ede33 Compare October 18, 2026 21:23
Base automatically changed from reimpl/AICState-100 to main October 18, 2026 21:57
…layerData

Merging main brought the regenerated headers, and four AICState sources no
longer compiled against them. Main does not notice because its
cmake/openshc-sources.txt is empty, so nothing under src/OpenSHC is built
there.

MapAndTimeState lost `aiTribeMoveDestinationXYPairArray1`, which was never a
field: its address 0x11809a4 is &unitMoveDestinationXYPairs[-1][0], the base
MSVC constant-folds for an access the original writes as [playerID - 1]. The
same folding is visible at 0x117f0d4 == &signpostEntryData[-1], referenced
only by computeEnemyKeepApproachTile, which spells playerID - 1 out three
times. commandFourTribesToMove, giveMoveCommandToAttackTribes and
moveAttackTribesToLocations all indexed the phantom as [playerID * 5] on a
Point8IntXY[5][8], abusing the wrong type's 64-byte row stride to land on
playerID * 320; they now read unitMoveDestinationXYPairs[playerID - 1], which
is the same arithmetic and what the original source said. All three stay at
100.0/100.0.

updateAIPlayerState took `&...attackedByPlayerArrayUnk` and indexed
[playerID * 8], which stopped being an lvalue once the header started
declaring that field as int[10][8] - the layout its own fixme predicted.
playerID * 8 ints from the base is [playerID][0], so the fixme is resolved
rather than worked around.

reccmp, reimplemented data and all 193 AICState resolvers enabled: BUILD_OK,
avg 97.70 over 193.

No match percentages moved. diff_triage.py says why: of the 21 functions below
100, seven are alloc-only (raw far below norm - aiRecruitUnits 0.473/0.889,
countSiegeEngineUnits 0.538/1.000, sellExcessGoods 0.624/0.970,
decideOnTribeAttackLocation, recruitHarrassingSiegeEngines, updateAIStrengthState,
setTribe0x11ToAggressiveAndAttackIfConditionMet), where the tool's own advice is
to stop editing the source. countSiegeEngineUnits is the clearest case: every
instruction, offset and order already matches and the only difference is that
the original holds the unit pointer in edx with ecx as scratch while we hold it
in ecx with edx as scratch. A reference-variable form and a while-loop form both
reproduced it exactly, and /GL on five of the worst files changed nothing.

Tried and rejected on the source-reachable ones: inlining aicIndex in
addUnitToSmallestBehaviourTypeTribe, whose frame is one 4-byte local larger than
the original's, cost 0.6230 -> 0.3934, and moving smallestSize into the only
branch that uses it was neutral; collapsing teamIsWeakRelativeToEnemy's seven
`return FALSE` into a computed threshold with one comparison - it has one ret
site too many - cost 0.9577 -> 0.5354, so the original really does repeat the
returns. The remaining leads are the two FRAME functions
(addUnitToSmallestBehaviourTypeTribe one local over, renderDebugDataAiInfo 8
bytes under at 0x3f8 against 0x400) and the four RET ones.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013Fzi11pcBU1Y7Y4oanrZQL

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant