Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
429 commits
Select commit Hold shift + click to select a range
827f73a
GameGUI: fix chat-input slash-command past-end read
kylelutze May 24, 2026
1f1f761
TeamStep: clear selection via GameGUI hook instead of reading GUI state
kylelutze May 24, 2026
40cb914
MapMinigrad: replace 8 hand-unrolled UPDATE_MAX blocks with a directi…
kylelutze May 24, 2026
af49e61
Building::subscribeForFlagingStep: use linear distance for worker/war…
kylelutze May 24, 2026
47a0e42
GameGUIDrawUnitInfos: extract drawAbilityRow helper
kylelutze May 24, 2026
85ef15e
GameGUI::handleMenuClick: drop unit-selection debug hatch
kylelutze May 24, 2026
bf39d06
Engine: delete dead CPUStatisticsManager
kylelutze May 24, 2026
3714228
ChooseMapScreen::onAction: own InputStream via unique_ptr to plug exc…
kylelutze May 25, 2026
00b4196
BasePlayer::load: reject out-of-range teamNumber/number from external…
kylelutze May 25, 2026
4fd4a56
drawBuildingFailureReasons: fix swapped fruit/resource labels via ind…
kylelutze May 25, 2026
fd9ecde
GameMusicController: extract music state from GameGUI::musicStep to f…
kylelutze May 25, 2026
425554a
GameGUIInputMenuClickBuilding: extract interpretScrollBoxClick helper…
kylelutze May 26, 2026
0052ec4
magic-numbers: name SWIM_VARIANT_COUNT and team-slice constants
kylelutze May 26, 2026
44865b4
drawChoiceSprites: fix tutorial-hilight arrow Y using horizontal cent…
kylelutze May 27, 2026
c183f8e
drawChoice: anchor sprite grid and hit grid to one panel-top Y
kylelutze May 27, 2026
0249dd3
iterateSelection: guard stale selection.building before deref
kylelutze May 27, 2026
6d252ea
parseArgs: rename inner -dl loop counter to avoid shadowing argv index
kylelutze May 27, 2026
32a27d9
GameGUI: collapse three reverse-iterate message-wrap loops into one h…
kylelutze May 27, 2026
fe1633c
drawPanel: split nested mode dispatch into three helpers
kylelutze May 27, 2026
695ad78
GlobalContainer: convert 7 owning raw pointers to std::unique_ptr
kylelutze May 27, 2026
e25415a
Move per-viewer GUI shadow state off Building into BuildingGuiState
kylelutze May 28, 2026
c3946d9
Decompose Building::turretStep into testable helpers
kylelutze May 28, 2026
1b8ee84
Make GameGUI own gameMenuScreen via unique_ptr
kylelutze May 29, 2026
24a23e6
Fix typo: rename defualtGameSaveName to defaultGameSaveName
kylelutze May 29, 2026
65826ff
Remove AIToubib, an unreachable no-op stub AI
kylelutze May 30, 2026
11e52fd
Replace GameGUI selection union with std::variant
kylelutze May 30, 2026
a1de0b5
Decompose Building::subscribeToBringRessourcesStep
kylelutze May 30, 2026
a46c350
Unify AI roster onto a single table in AINames
kylelutze Jun 3, 2026
28fed2d
Add experimental AICortex AI scaffold
kylelutze Jun 3, 2026
fac080d
Add AI benchmark harness; ignore OrderAlterateAreaTest binary
kylelutze Jun 3, 2026
a4b8054
Implement AICortex: economy, combat, and building-upgrade layers
kylelutze Jun 4, 2026
65b95f1
AICortex: wheat-protection upkeep, resource-dump tool, flag cooldown
kylelutze Jun 5, 2026
7f01819
Fix multiplayer desync from local-only hard-pause hotkey
kylelutze Jun 5, 2026
46a6a2d
Fix leaked Unit* scratch buffer in Nicowar explorer-attack flag posit…
kylelutze Jun 5, 2026
290c431
AICortex: hold the offense push against minor harassment (thrash fix)
kylelutze Jun 5, 2026
db2eecd
Add --jobs flag to ai-benchmark.sh for parallel game execution
kylelutze Jun 5, 2026
d42cbeb
AICortex: closed-loop wheat economy + pre-combat panic defense
kylelutze Jun 5, 2026
dae6bb4
AICortex: never-halt / always-expand economy redesign
kylelutze Jun 5, 2026
82efa91
AICortex: env-gated diagnostic dumps for economy/attack tracing
kylelutze Jun 5, 2026
9c5c644
docs(AICortex): expand-vs-upgrade engine mechanics ground truth
kylelutze Jun 5, 2026
e77fdc6
AICortex: unified expand-vs-upgrade ladder + army-scaled hospitals
kylelutze Jun 5, 2026
c48c40f
Cortex: building-placement overhaul and per-type build cooldown
kylelutze Jun 6, 2026
4acba73
Cortex: tighten building placement and pool/panic timing
kylelutze Jun 6, 2026
7541f91
Cortex: run wheat-forbidden upkeep every cycle, plus wheat-harvestabi…
kylelutze Jun 6, 2026
92c8313
Cortex: set inn hauler ceiling from collectable restock demand
kylelutze Jun 6, 2026
4711d9b
Cortex: parallel worker-tuning, algae-gated and inn-decoupled build o…
kylelutze Jun 6, 2026
9c85580
Cortex: decompose decide()/translateAction() and move offense-hold in…
kylelutze Jun 7, 2026
930b894
Cortex: split oversized AI files into submodules (under 500 lines each)
kylelutze Jun 7, 2026
aa9160d
Make Cortex worker-surplus throttle level-aware
kylelutze Jun 7, 2026
7761417
Add Cortex ML swarm worker-cap pilot (integer inference net)
kylelutze Jun 7, 2026
76c4c5c
Convert Cortex policy from priority ladder to utility scoring
kylelutze Jun 7, 2026
45eba02
Add Cortex ML pilot Python tooling and ignore .tmp scratch dir
kylelutze Jun 7, 2026
9bbec68
Grade Cortex feed/second-swarm scores so a spent wheat catchment expands
kylelutze Jun 7, 2026
9baf513
Cap Cortex population to wheat capacity with a feeding governor + whe…
kylelutze Jun 8, 2026
b8479c3
GameGUI: erase pending GUI shadow when a building is destroyed
kylelutze Jun 9, 2026
96b402b
Delete dead Gradient.h/Gradient.cpp template pair
kylelutze Jun 9, 2026
625225f
Collapse LoadSaveScreen's two near-duplicate constructors into one
kylelutze Jun 9, 2026
d73310a
Factor parseArgs argv consumption into shared helpers
kylelutze Jun 9, 2026
13c2f4c
Let a starving Cortex colony relocate onto fresh wheat, and drop the …
kylelutze Jun 9, 2026
1116ef0
Collapse payload-free MultiplayerGameEvent boilerplate into macros
kylelutze Jun 9, 2026
75bca95
Scale Cortex hospital provisioning off standing-army size, uncapped, …
kylelutze Jun 9, 2026
70a29b8
Rename Map's local-team render caches to displayed* for port clarity
kylelutze Jun 10, 2026
91ac8e9
Cortex: two independent war flags + separate combat decision cadence
kylelutze Jun 11, 2026
acc69d5
Move wait-notice debounce counter from Game to GameGUI
kylelutze Jun 17, 2026
d6df44d
Remove dead write-only oldEnough[] cache from AICastor::enoughFreeWor…
kylelutze Jun 17, 2026
ac8f3f7
Cortex: offense wave pipeline + units-under-attack defense recall
kylelutze Jun 17, 2026
f1b6b39
Cortex: pin construction sites to LOW priority so they never out-recr…
kylelutze Jun 18, 2026
c93fe84
Cortex: drive swarm worker/warrior mix off a hauler-staffing target
kylelutze Jun 19, 2026
2e2d504
Cortex: ramp workers to a middle tier before committing the army
kylelutze Jun 20, 2026
17d2e38
Cortex: stop discounting inn builds when a swarm catchment is depleted
kylelutze Jun 20, 2026
b5ccaff
LAN menu: replace busy-wait handshake loops with timeout-aware bring-up
kylelutze Jun 20, 2026
a697e3b
Cortex: fix inn worker starvation and tighten inn placement to wheat
kylelutze Jun 22, 2026
7bc132c
Fix SGSL guiEnable/guiDisable flag dispatch routing flags to buildings
kylelutze Jun 23, 2026
0db3db4
Remove file-scope using namespace GAGCore from LogFileManager.h
kylelutze Jun 23, 2026
26fc778
Replace OrderCreate flagRadius -1 sentinel with std::optional
kylelutze Jun 23, 2026
5af99a0
Read OrderChangePriority priority as Sint32 to mirror writer
kylelutze Jun 24, 2026
f242561
Group Game's view/selection scratch into a ViewState struct
kylelutze Jun 25, 2026
f0335d0
Move per-client view/selection state off the shared Game object
kylelutze Jun 25, 2026
76c1186
Split GameGUI::processEvent into per-event-type helpers
kylelutze Jul 7, 2026
67994af
Name the flag option-list row counts shared by draw and click hit-test
kylelutze Jul 7, 2026
e95e78d
Deduplicate tab switching in InGameObjectivesScreen
kylelutze Jul 7, 2026
b6a053b
Replace firstPlacementX/Y sentinel pair with std::optional in GameGUI…
kylelutze Jul 7, 2026
20ec062
Deduplicate MODE_ADD/MODE_DEL zone-painting loops in handleZonePlacement
kylelutze Jul 7, 2026
7357f6c
Factor duplicated building-site-or-flag type lookup into BuildingsTypes
kylelutze Jul 7, 2026
f659cde
Use Building::LAST_SHOOT_STEP_NEVER instead of open-coded 0xFFFFFFFF …
kylelutze Jul 7, 2026
342a96d
Replace MapEdit firstPlacementX/Y sentinel pair with std::optional
kylelutze Jul 7, 2026
50e877e
Deduplicate MODE_ADD/MODE_DEL zone-brush loops in map editor handleBr…
kylelutze Jul 7, 2026
e74fd23
Cortex: add per-inn worker-allocation diagnostic trace
kylelutze Jul 7, 2026
0d15a38
CampaignMenuScreen: guard mission lookup against empty list selection
kylelutze Jul 7, 2026
1ed3483
Write checksum sidecar integers in little-endian byte order
kylelutze Jul 7, 2026
a4aafd3
Detect and reject checksum sidecar write failures
kylelutze Jul 7, 2026
10b0085
Propagate initGame failure in Engine::initMultiplayer instead of NULL…
kylelutze Jul 7, 2026
4e4e459
Cortex: bypass opening ladder for second swarm when catchment is fiel…
kylelutze Jul 7, 2026
25f02be
Cortex devlog: record the three failed rescue-site escalation A/Bs
kylelutze Jul 7, 2026
22e7af2
Single-source the misc-order payload lengths
kylelutze Jul 7, 2026
b2f9f9f
Split AINumbi.cpp into four translation units under 400 lines each
kylelutze Jul 7, 2026
c9f9d7a
Cortex: centralize decide() feasibility gates; expansion by ranking, …
kylelutze Jul 8, 2026
1294737
Cortex: add CortexTuning env-file params seam and knob-search driver
kylelutze Jul 11, 2026
05b497b
Cortex: combat envelope (attack range + forward base, multi-defense, …
kylelutze Jul 12, 2026
6b78d69
Cortex: forward-base candidates require an immediate construction site
kylelutze Jul 12, 2026
cae850e
Cortex: waive the attack-range gate on first contact
kylelutze Jul 12, 2026
6e1e29c
AIEcho: fix enemy_building_iterator post-increment returning an unini…
kylelutze Jul 13, 2026
c1797f5
Nicowar: zero-initialize all NicowarStrategy members in-class
kylelutze Jul 13, 2026
76ebd3e
Fix signed-shift UB when building player/team bitmasks
kylelutze Jul 13, 2026
2cf3d0b
MapQueryTest: update to renamed displayedTeam Map API
kylelutze Jul 13, 2026
0a9a956
Fix particle crossfade centering the blend-in frame with the wrong sp…
kylelutze Jul 13, 2026
d36382e
Fix out-of-bounds gradient read making Nicowar farming non-deterministic
kylelutze Jul 13, 2026
3544e69
Add DET_INIT build knob for uninitialized-read diagnostics
kylelutze Jul 13, 2026
2b641f7
Remove 891 unused includes from src/
kylelutze Jul 14, 2026
d3435f9
gui: store resolved typeNum in ghost buildings instead of re-resolvin…
kylelutze Jul 15, 2026
ca61511
test: regenerate cpp-refactor.replay at a 90000-tick cap
kylelutze Jul 15, 2026
1616226
BitArray: name the bits-per-byte constant, document bit ordering
kylelutze Jul 15, 2026
c6be66f
Fix off-by-one in the brush tool hit grid and map editor click routing
kylelutze Jul 15, 2026
7b857df
Route map editor button events through the click's own coordinates
kylelutze Jul 16, 2026
ac7f0c9
Make the GUI toolkit's point-in-rect predicate half-open
kylelutze Jul 16, 2026
ef6a79c
Cortex: sweep orphaned war flags, gate the defense-deficit army release
kylelutze Jul 16, 2026
5740f2a
Cortex: amphibious offense staging — swim-aware classifier, landing-z…
kylelutze Jul 17, 2026
57f8c14
Fix interpreter leak on map-script recompile
kylelutze Jul 17, 2026
ef85954
GameHints: make size_t->int narrowing explicit, const-qualify accessors
kylelutze Jul 17, 2026
12f608c
Remove dead getComputerHostName() from GlobalContainer
kylelutze Jul 17, 2026
6b2d9e2
Fix UB in MapScript when map file carries an unknown mode byte
kylelutze Jul 17, 2026
74e2e3d
Reject corrupt winning-condition data instead of crashing later
kylelutze Jul 17, 2026
c6c71dd
Fix SGSL hilight name table pointing "forbidden zone on panel" at the…
kylelutze Jul 17, 2026
9ea5d65
Fix BrushTool::setFigure asserting the old figure instead of the new …
kylelutze Jul 17, 2026
38bf23f
Initialize CampaignMapEntry lock/completion state in the name+file co…
kylelutze Jul 17, 2026
ba20ae6
Default-initialize version-gated fields in campaign load paths
kylelutze Jul 17, 2026
5993b37
Fix placeBuildingAt future-worker lookup to use getFinishedTypeNum
kylelutze Jul 17, 2026
3a44a47
Clarify BitArray serialize/deserialize units (bits vs bytes)
kylelutze Jul 17, 2026
91092e0
Reset ally-team numbers before repopulating in custom game setup
kylelutze Jul 17, 2026
72c4548
Serialize Bullet::ticksInitial so reloaded bullets keep their ballist…
kylelutze Jul 17, 2026
9cb1bdc
Propagate AICastor load failure instead of asserting in a constructor
kylelutze Jul 17, 2026
b40df42
Store brush torus-wrap offsets once at apply time instead of re-deriv…
kylelutze Jul 17, 2026
4eee2a2
Handle flag and market tokens in SGSL wait-condition variables
kylelutze Jul 17, 2026
b9f85b6
Fix AICastor footprint visibility scan sampling only one column
kylelutze Jul 17, 2026
7a61c29
Remove leaked forbidden zone when a building dies awaiting upgrade room
kylelutze Jul 17, 2026
3ec617d
Widen BasePlayer::playerID serialization from Uint16 to Uint32
kylelutze Jul 17, 2026
34e6255
Widen the replay inter-order step counter from Uint16 to Uint32
kylelutze Jul 17, 2026
e2f4da9
Regenerate all replay baselines for the version-87 format and Castor …
kylelutze Jul 17, 2026
7a3d5e7
Validate BasePlayer deserialization against corrupt and hostile streams
kylelutze Jul 18, 2026
1d0cc02
Symmetrize the BaseTeam colorPAD wire byte on save
kylelutze Jul 18, 2026
27c1f30
Guard Campaign::removeMap against out-of-range indices
kylelutze Jul 18, 2026
82c13b8
Make Campaign::getMap bounds-checked
kylelutze Jul 18, 2026
227f931
Avoid deprecated enum-enum arithmetic in the invalid-player-type diag…
kylelutze Jul 18, 2026
9ad374e
Rename campaign editor widget constant ISLOCKED to ISUNLOCKED
kylelutze Jul 18, 2026
bd8e964
Name the screen quit sentinel and separate CampaignMainMenu return co…
kylelutze Jul 18, 2026
85b8bc6
Rename CampaignMenuScreen's exit button member to exitButton
kylelutze Jul 18, 2026
81add34
Cache campaign descriptions in the campaign selector screen
kylelutze Jul 18, 2026
e2584b4
Make CampaignSelectorScreen::getCampaignName const
kylelutze Jul 18, 2026
cdcf766
Fix size_t underflow when deleting the last file in ChooseMapScreen
kylelutze Jul 18, 2026
033f825
Validate units sprite frame count before drawing credits decoration
kylelutze Jul 18, 2026
601f6ad
Use a stack InputLineStream when loading the credits text
kylelutze Jul 18, 2026
2537263
SConstruct: forward TMPDIR into the build ENV
kylelutze Jul 18, 2026
0af11dd
Make LoadSaveScreen name-extractor callbacks safe on stray filenames
kylelutze Jul 18, 2026
e212128
Engine: own net and checksumSidecar via unique_ptr
kylelutze Jul 18, 2026
95e74aa
Commit to replay state only after the replay file parses
kylelutze Jul 18, 2026
836e602
Clean up replay state when the replayed map fails to load
kylelutze Jul 18, 2026
febf57d
Remove dead crash-handler translation unit Fatal.cpp
kylelutze Jul 18, 2026
eb62bb2
Delete dead Game::setMapHeader with guaranteed null-deref
kylelutze Jul 18, 2026
229e480
Move replay writer finalization from Game's destructor to Engine
kylelutze Jul 18, 2026
167261a
Fix readLeaveSection(i) misuse in GameHeader and MapHeader load loops
kylelutze Jul 18, 2026
2396326
Guard GameObjectives::removeObjective against out-of-range indices
kylelutze Jul 18, 2026
b43c7ef
Give every GameObjectives accessor a real bounds guard
kylelutze Jul 18, 2026
0f8d7be
Clamp GameObjectives script numbers to the Uint8 wire domain
kylelutze Jul 18, 2026
8599b1e
Derive checksum sidecar team/player counts from the live game
kylelutze Jul 18, 2026
f482652
Edit the prestige winning condition in place instead of resetting the…
kylelutze Jul 18, 2026
37f1ccb
Guard the ally-team widget lookup against a failed match
kylelutze Jul 18, 2026
4f13a60
Map malformed ally team numbers to a defined widget index
kylelutze Jul 18, 2026
b12d0f4
Model the custom-game human color explicitly instead of a 0 sentinel
kylelutze Jul 18, 2026
1fe2c53
Clamp GameHints script numbers to the Uint8 wire domain
kylelutze Jul 18, 2026
1d0f336
Close the game-router connection on every multiplayer-game exit
kylelutze Jul 18, 2026
17fa40a
Fix undefined read at the tail of a voice transmission in the mixer
kylelutze Jul 18, 2026
ff40193
Make Defence overlay reflect turret strength, not just footprint
kylelutze Jul 18, 2026
6b9e7df
Fix null-pointer crash in SGSL summonFlag on building-limit exhaustion
kylelutze Jul 18, 2026
d6b5179
Guard ConfigVector::load against a missing config file
kylelutze Jul 18, 2026
cf5c34d
Fix private-message echo to handle multi-recipient masks safely
kylelutze Jul 18, 2026
ab41995
Fix scroll-wheel modifier misrouting in flushScrollWheelOrders
kylelutze Jul 18, 2026
d8e69de
Fix swapped hilight arrows for warrior/explorer top-bar counters
kylelutze Jul 18, 2026
4247607
Fix dead gate that always showed building failure-reason rows
kylelutze Jul 18, 2026
929647f
Fix vertical centering of choice-panel building icons
kylelutze Jul 18, 2026
9bffb5f
Fix crash when highlighting a tool over a panel that doesn't own it
kylelutze Jul 18, 2026
9e0e24b
Fix latent negative-shift UB in right-panel view-button hit-test
kylelutze Jul 18, 2026
69af4f5
Fix silent DoNothing binding for unknown keyboard action names
kylelutze Jul 18, 2026
0bca886
Make test/ build-artifact ignores robust to new harnesses
kylelutze Aug 29, 2026
ccc71fd
Cortex: generalize amphibious CROSS phase into staged campaigns (forw…
kylelutze Aug 29, 2026
da8e1fe
Fix portability/robustness bugs surfaced by non-macOS and headless bu…
kylelutze Aug 29, 2026
d3875b6
Split MapEditAction.cpp into per-domain action handlers
kylelutze Aug 29, 2026
0f8bb77
Factor duplicated logic out of the MapEdit action handlers
kylelutze Aug 29, 2026
aa193ae
Include BuildingType.h directly in the building action handler
kylelutze Aug 29, 2026
a65580c
Add FileManager::exists() and use it in Engine::haveMap
kylelutze Aug 29, 2026
d90cf36
Clean up EngineInit: dedupe map-load error box, drop noise comments
kylelutze Aug 29, 2026
44bf429
Stack-allocate load/dump streams, fold dump blocks into a helper
kylelutze Aug 29, 2026
31497a4
Group EngineRun main-loop state into MainLoopState; tidy comments
kylelutze Aug 29, 2026
24ad8cd
Hoist modal-overlay loop into OverlayScreen::executeModal
kylelutze Aug 29, 2026
1522418
Factor starvation travel range into maxTravelDistance helper
kylelutze Aug 29, 2026
dae1900
Re-post SDL_QUIT from modal loops so one Cmd+Q quits the game
kylelutze Aug 29, 2026
ff81b7c
Silence Apple's OpenGL deprecation warnings and tidy MapEdit.h includes
kylelutze Aug 29, 2026
3f18c90
Trim comments and clarify helper names
kylelutze Aug 29, 2026
034eb77
Own YOG command lists with unique_ptr
kylelutze Aug 29, 2026
85f2818
Share YOG login/register connection screen via a common base
kylelutze Aug 29, 2026
179da93
Clarify YOG connection screen names
kylelutze Aug 29, 2026
383475c
Introduce YOGPlayerID alias for YOG player IDs
kylelutze Aug 29, 2026
3042334
Introduce YOGPlayerID alias for YOG player IDs
kylelutze Aug 29, 2026
38ec8f6
Merge branch 'feat/ai-trainer-support' of https://github.com/Globulat…
kylelutze Aug 29, 2026
f41cdd3
Restore SDL types in MultiplayerGameEvent.h
kylelutze Aug 29, 2026
f129efd
Group the building-type table by role instead of PartA/PartB
kylelutze Aug 29, 2026
66e054c
Fix Uint8 overflow in the guard-area least-explored direction scan
kylelutze Aug 30, 2026
ba6e1cf
Document that test/ has its own SConstruct, and unstale the version test
kylelutze Aug 30, 2026
8bdcbcb
Enforce hp <= hpMax at every Building hp writer
kylelutze Aug 30, 2026
f06e375
Factor the cross-connect neighbour test out of drawMapBuilding
kylelutze Aug 30, 2026
2679d6e
Normalize net/message whitespace and make message names self-documenting
kylelutze Aug 30, 2026
0c64c8a
AIEcho: remove the dead Conditions API demo doc
kylelutze Aug 30, 2026
ecff353
Add BuildingsTypes::getLastLevel and drop its three copies
kylelutze Aug 30, 2026
431b2e1
Name the upgrade-preview locals instead of commenting them
kylelutze Aug 30, 2026
0d625a5
Rename the bat* draw locals to rect*
kylelutze Aug 30, 2026
ac133e3
AIEcho: simplify Entities predicates and hoist the shared load call
kylelutze Aug 31, 2026
47ed78b
fix missing includes
Giszmo Aug 31, 2026
2b7eb76
Select epoxy/wgl.h on all Windows toolchains, not just MSVC
kylelutze Sep 2, 2026
9c5080e
Merge remote-tracking branch 'origin/master' into feat/ai-trainer-sup…
kylelutze Sep 3, 2026
ee0fa3b
Build the server-mode libgag inside test/, and run every harness in CI
kylelutze Sep 3, 2026
abaf87a
Restore the GPU-mode dummy surface release lost in the master merge
kylelutze Sep 3, 2026
e50e445
Merge remote-tracking branch 'origin/master' into feat/ai-trainer-sup…
kylelutze Sep 4, 2026
81c1286
Merge remote-tracking branch 'origin/master' into feat/ai-trainer-sup…
kylelutze Sep 4, 2026
ddaa2f1
Remove 90 unused includes from src/ and script the cleanup pipeline
kylelutze Sep 4, 2026
29b5f10
Team.h: trim comments, name startPosSet sources, rename call-list hel…
kylelutze Sep 4, 2026
e0028c1
Fix CI builds on Ubuntu 22.04, 24.04 and MinGW
kylelutze Sep 4, 2026
5072ca1
Fix MinGW SGSL build and Linux test include path
kylelutze Sep 4, 2026
ebf7ba2
Build with gnu++20 instead of strict c++20
kylelutze Sep 4, 2026
9c9849e
MapMinigrad: rename far member, it collides with a Windows macro
kylelutze Sep 4, 2026
9055f2e
MapMinigrad: rename far member declaration to match its uses
kylelutze Sep 4, 2026
0586f78
SConstruct: link through a response file on Windows
kylelutze Sep 4, 2026
922cb4f
EndGameScreen: name button ids and build stat buttons in a loop
kylelutze Sep 4, 2026
223d988
AICastor: trim header comments and drop dead members
kylelutze Sep 4, 2026
1823a2f
Trim CLAUDE.md and finish the #pragma once migration
kylelutze Sep 4, 2026
5f26708
GUITextArea: split layout and input handling into their own files
kylelutze Sep 4, 2026
9b6ee17
TextArea: give each key in onSDLKeyDown its own method
kylelutze Sep 4, 2026
4c5e9ba
TextArea: fold the three wrap sites in layout into one helper
kylelutze Sep 4, 2026
f6b8693
SGSL: split the 2500-line SGSL.cpp into a src/sgsl/ module
kylelutze Sep 4, 2026
4e670c9
Unit::load: compute trigHungryCarying the way the constructor does
kylelutze Sep 4, 2026
b103c2a
Save Map::exploredArea in saved games (format version 88)
kylelutze Sep 4, 2026
59c48a3
Remove LogFileManager
kylelutze Sep 5, 2026
b6140f1
Remove unreachable window-resize and expose event branches
kylelutze Sep 5, 2026
fea05a5
Echo::load: free the per-order read buffer
kylelutze Sep 5, 2026
2e318cd
Delete stale FIXMEs, commented-out code, and dead rect helpers
kylelutze Sep 5, 2026
ca4cd75
Factor the hand-rolled observer lists into ListenerList<T>
kylelutze Sep 5, 2026
a9e3ca9
Share the script-number clamp between GameHints and GameObjectives
kylelutze Sep 5, 2026
c4f9e24
Rename YOGClientMapDownloader::getPercentUploaded to getPercentDownlo…
kylelutze Sep 5, 2026
a3a7cde
Drop commented-out replayReader checksum call in EngineRun
kylelutze Sep 5, 2026
6bcbb5b
Share one KeyActionTable between GameGUI and MapEdit key actions
kylelutze Sep 5, 2026
edaa02c
Remove the duplicate-functions analysis report
kylelutze Sep 5, 2026
ccb6063
Merge remote-tracking branch 'origin/master' into feat/ai-trainer-sup…
kylelutze Sep 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 4 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ jobs:
run: |
scons -j$(nproc)
./TestsRunner
for harness in ./*Harness ./*Test; do
echo "== $harness"
"$harness"
done

windows:
name: windows (mingw-w64)
Expand Down
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ options_cache.py
libgag.a
libusl.a
src/glob2
testResults.xml
.sconf_temp
.sconsign.dblite
*.o
Expand All @@ -12,3 +13,9 @@ src/glob2
__pycache__/
build/
vcpkg_installed/
.DS_Store
compile_commands.json
.cache/
Glob2.app/
Glob2-*.dmg
/.tmp
117 changes: 45 additions & 72 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,108 +1,81 @@
# glob2 (Legacy C++ Codebase)
# glob2 (C++ Codebase)

This is the original Globulation 2 C++ codebase. It is legacy code and is not under active development.
The Globulation 2 C++ codebase. Actively maintained.

## Build Commands
## Build

```bash
cd glob2

# Build (requires SCons, Python 3)
scons -j16
scons -j16 # default: -g, no -O
scons release=1 -j16 # optimized; use for any headless/replay work
scons server=1 # YOG server only (no GUI/sound)
scons -c # clean
scons --build=/tmp/out # out-of-source
scons mingw=1 # native Windows (MSYS2/mingw-w64)
scons mingwcross=1 # cross-compile for Windows from Linux
scons BINDIR=/path/bin INSTALLDIR=/path/share
```

# Install (may need root)
scons install
Options are cached in `options_cache.py`, so `release=1` and `server=1` stick until you pass `release=0` / `server=0`.

# Clean
scons -c
**Server build gotcha.** Always build the server with `scons server=1`, never a bare `scons build/src/glob2-server`. The flag defines `YOG_SERVER_ONLY` and switches to the stripped `libgag_server.a`. Without it the objects are compiled with GUI code but linked against the stripped library, producing dozens of misleading undefined-symbol errors.

# Build options
scons release=1 # Optimized release build
scons server=1 # Build YOG server only (no GUI/sound)
scons --build=/tmp/out # Out-of-source build
scons mingw=1 # Native Windows build (MSYS2/mingw-w64)
scons mingwcross=1 # Cross-compile for Windows from Linux
**Use `release=1` for headless runs.** The default build is roughly 10× slower under `--nox` / `-test-games-nox`. Drop back to the default only when you need a debugger, sanitizers, or fast incremental rebuilds.

# Custom paths
scons BINDIR=/path/bin INSTALLDIR=/path/share
```
**`DET_INIT` — hunting uninitialized-read nondeterminism.** Valgrind/MSan don't work on modern macOS. Instead build twice, `DET_INIT=zero scons` and `DET_INIT=pattern scons`, and hammer one seed serially per build (add `MallocPreScribble=1 MallocScribble=1` to scribble the heap). If each build is internally stable but the two disagree, an uninitialized stack read is confirmed; if a scribbled build is still unstable run-to-run, the cause is not uninitialized memory. The env var is invisible to scons's dependency tracking, so rebuild affected objects when toggling.

**Dependencies:** SDL2, SDL2_net, SDL2_ttf, SDL2_image, libvorbis, libogg, speex, OpenGL, GLU, libepoxy, Boost (date_time; system is header-only from 1.69 on and only linked when present), zlib, fribidi, pcre. Optional: portaudio (voice chat). See `vcpkg.json` for the full list.
**Dependencies:** SDL2, SDL2_net, SDL2_ttf, SDL2_image, libvorbis, libogg, speex, OpenGL, GLU, libepoxy, Boost date_time, zlib, fribidi, pcre. Optional: portaudio. See `vcpkg.json`.

## Running Tests
## Tests

Tests have their own `test/SConstruct` and are **not** built by the top-level `scons`:
Tests live in `test/` with their own `test/SConstruct` and are **not** built by the top-level `scons`:

```bash
cd test
scons -j16
./TestsRunner
./WinningConditionsHarness
```

## Build System Internals
Binaries are written in-tree. A top-level `scons` reports "up to date" without touching them, so a stale binary keeps passing against changed assertions. Rebuild from `test/` before trusting a run.

SCons-based. `SConstruct` is the main build script with platform detection (Linux, Darwin, Windows/MinGW). Library checks are done via custom configure functions in `scons/`. Build options are cached in `options_cache.py`.

## Architecture
See [`test/README.md`](test/README.md) for the Map subclass pattern used to unit-test Map predicates without pulling in `globalContainer`, `Team`, or the full simulation.

### Engine Loop (40ms tick)
## Headless Runs and Replays

The engine is **synchronous** — no multithreading in the core. Every 40ms, `Engine::run()` calls `.step()` on the class hierarchy. See `doc/sourceCodeUnderstanding.txt` for the full explanation.
See [docs/headless-replays.md](docs/headless-replays.md).

```
Engine::run() loop:
gui.step() → handle input
net.pushOrder(gui.getOrder()) → send local player order to network
net.pushOrder(ai.getOrder()) → send AI orders
net.step() → exchange orders over network
gui.executeOrder(...) → execute all received orders
gui.drawAll() → render
sleep() → maintain 40ms frame
```bash
./glob2 -test-games-nox # random AI-vs-AI games, loops forever
./glob2 --nox <game-file> <steps> <runs> # single game from a .game file
```

### Class Hierarchy
Replays go to `~/.glob2/replays/last_game.replay` unless `GLOB2_REPLAY_PATH` is set. The lockstep engine is the regression test: identical replays mean identical behavior. See [`../docs/replay-verification.md`](../docs/replay-verification.md).

```
Engine
├─ NetGame (network abstraction, order transmission via UDP)
└─ GameGUI (rendering, input)
└─ Game (game state)
├─ Map (terrain, resources)
├─ Team[32] (a "colony" — has color, units, buildings)
│ ├─ Unit[1024]
│ └─ Building[1024]
├─ Player[32] (human interface — keyboard+mouse or AI)
└─ Session (serializable state: BasePlayer[32], BaseTeam[32])
```
## Architecture

The engine is synchronous, one 40ms tick at a time, and every client computes identical state from the same stream of `Order`s. `doc/sourceCodeUnderstanding.txt` has the full walkthrough. Two things to hold onto:

- **Team vs Player.** A Team is a colony (color, units, buildings). A Player is a controller, human or AI. Several players may control one team; only teams can be allied.
- **Determinism.** Use `Utilities::syncRand()`, never `rand()`. Avoid `std::set`; iteration order is not portable.

**Team vs Player:** A Team is a logical colony (color, units, buildings). A Player is a controller (human or AI). Multiple players can control one team. Only teams can be allied.
AI implementations live under `src/ai/`: Castor, Cortex, Echo, Nicowar, Numbi, Warrush, all behind `AIImplementation`.

### Deterministic Networking
## Conventions

All clients compute identical game state. Only Orders (player actions) are transmitted. This requires:
- **Use `Utilities::syncRand()`** instead of `rand()` — all machines must get the same random numbers
- **Avoid `std::set`** — it is non-deterministic across platforms
- Orders are buffered in per-player FIFO queues (256 slots) to handle latency
**Filenames:** PascalCase (`Game.cpp`, `GameRenderUnits.cpp`). Do not introduce snake_case C++ filenames. On macOS a case-only rename needs `git mv -f Foo.cpp foo_tmp.cpp && git mv -f foo_tmp.cpp Foo.cpp`; a direct rename may silently no-op.

### Key Source Directories
**Header guards:** `#pragma once`.

- **`src/`** — Main game (382 files): engine, game logic, AI, networking, GUI screens, YOG online system
- **`libgag/`** — Graphics/GUI toolkit library (widget system, sprites, file I/O, rendering)
- **`libusl/`** — USL scripting language for maps/campaigns
- **`libwee/`** — Utility library
- **`data/`** — Runtime assets (graphics, fonts, music, GUI resources)
- **`maps/`** — Game maps
- **`campaigns/`** — Campaign definitions
- **`doc/`** — Architecture documentation
**Unused includes:** run `tools/remove-unused-includes.py` after `scons compile_commands.json`. Never hand-guess or run `clang-tidy --fix` blindly. Afterwards rebuild both `scons` and `scons server=1` and verify with Workflow 1 in the replay-verification doc.

### AI System
**Comments:** match the surrounding terse style. The *why* of a change goes in the commit message. Add a comment only when the code can't carry the reasoning itself.

Multiple AI implementations in `src/`: AICastor, AIEcho, AINicowar, AINumbi, AIToubib, AIWarrush — all inherit from `AI` base class.
**Never document the past.** How code used to look, why it changed, or where something "used to live" belongs in the commit message only. When you remove something, remove it completely: no tombstone comments, no "moved to X" pointers. Describe only what the code does now. The same applies to replies: don't recount the history of a change unless asked.

### Orders System
## Logging

All player actions are serialized as `Order` objects (see `src/Order.h`). `NullOrder` means "player did nothing this tick" — distinct from "we haven't heard from this player yet." Orders carry complete action data (team, position, type, unit counts).
There is no logging facility; diagnostics go to `std::cerr`. Do not propose adding a logging library; nothing consumes the data.

### YOG (Online Gaming)
## Pathfinding: chamfer pass cap

Server/client architecture for online play. `YOGServer` handles matchmaking, chat channels, ratings, map database. LAN play is peer-to-peer. Build server-only binary with `scons server=1`.
In `src/map/gradient/MapGradientGlobal.cpp` the chamfer distance transform's convergence-pass cap is bounded by the Uint8 value range (256), not by the Borgefors 1-pass result. Borgefors holds only on an obstacle-free grid; with obstacles each bend in the propagation path costs about K/2 passes, and real 128×128 maps needed well over 8. The cap is a tripwire for monotonicity violations, not a throttle. Do not derive a tighter bound from grid geometry.
31 changes: 29 additions & 2 deletions SConstruct
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ def configure(env, server_only):
if isDarwinPlatform:
print("Using Apple's OpenGL framework")
env.Append(FRAMEWORKS=["OpenGL", "CoreFoundation"])
# Silence Apple's hundreds of OpenGL deprecation warnings.
env.Append(CPPDEFINES=["GL_SILENCE_DEPRECATION"])
elif conf.CheckLib("GL") and conf.CheckCXXHeader("GL/gl.h"):
gl_libraries.append("GL")
elif conf.CheckLib("GL") and conf.CheckCXXHeader("OpenGL/gl.h"):
Expand Down Expand Up @@ -243,11 +245,22 @@ def main():
default='build',
help='build directory')
env = Environment()
# SCons scrubs the shell environment for build commands; without TMPDIR,
# tools like ar fall back to /tmp, which sandboxed environments may block.
if 'TMPDIR' in os.environ:
env['ENV']['TMPDIR'] = os.environ['TMPDIR']
env["VERSION"] = "0.9.5.0"
establish_options(env)

# Emit compile_commands.json for clangd / IDE LSPs.
env.Tool('compilation_db')
env.CompilationDatabase()

if env['mingw'] or env['mingwcross']:
Tool('mingw')(env)
if env['mingw'] or isWindowsPlatform:
# Windows caps command lines at 32K; pass the link arguments via @response-file
env['LINKCOM'] = '${TEMPFILE("$LINK -o $TARGET $LINKFLAGS $__RPATH $SOURCES $_LIBDIRFLAGS $_LIBFLAGS", "$LINKCOMSTR")}'

if env['mingwcross']:
env.Platform('cygwin')
Expand Down Expand Up @@ -291,8 +304,22 @@ def main():

env.Append(CPPPATH=['#libgag/include', '#'])
env.Append(CPPPATH=['#libusl/src', '#'])
env.Append(CPPPATH=['#src'])
env.Append(CXXFLAGS=' -Wall -fPIC')
env.Append(CPPPATH=['#src', '#src/yog', '#src/ai', '#src/building',
'#src/game/entities',
'#src/gui',
'#src/map', '#src/map/edit', '#src/map/generator',
'#src/map/gradient', '#src/map/io', '#src/map/pathfind',
'#src/net', '#src/net/irc', '#src/net/message',
'#src/sgsl',
'#src/team',
'#src/unit'])
env.Append(CXXFLAGS=' -std=gnu++20 -Wall -fPIC')
# Uninitialized-read diagnostics: DET_INIT=zero|pattern forces deterministic
# stack initialization (see CLAUDE.md). Env var, not a cached scons option.
_detinit = os.environ.get('DET_INIT')
if _detinit:
env.Append(CXXFLAGS=' -ftrivial-auto-var-init=' + _detinit)
env.Append(CCFLAGS=' -ftrivial-auto-var-init=' + _detinit)
env.Append(LINKFLAGS=' -Wall')
env.Append(LIBS=['SDL2_net'])
if not server_only:
Expand Down
6 changes: 0 additions & 6 deletions darwin/SConscript

This file was deleted.

Loading
Loading