Skip to content

Update HEMTT to 1.23, clear lint findings and fix the bugs they exposed - #445

Open
headswe wants to merge 42 commits into
devfrom
claude/project-thread-op72q3
Open

headswe wants to merge 42 commits into
devfrom
claude/project-thread-op72q3

Conversation

@headswe

@headswe headswe commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

Requested by Sebastian

Updates the build to HEMTT 1.23, works through every HEMTT finding addon by addon, and fixes the bugs that came up along the way. hemtt check passes with 3 style-only warnings (down from about 1,270 findings), and hemtt build passes.

Build and tooling

  • HEMTT 1.13 → 1.23: mainprefix = "x", VERSION/VERSION_STR split (fixes the VERSION_CONFIG errors), final newlines, include guards on every script_component.hpp
  • Rapify enabled for all 19 addons (10 had it turned off, so their configs were never validated): unquoted expressions wrapped in QUOTE(), the BI INIT_DISPLAY/INIT_CONTROL macros written out, module booleans as 1/0, and the addon.toml files removed
  • REQUIRED_VERSION raised to 2.18 (the code already uses select -1 and other newer commands)
  • .hemtt/launch.toml for hemtt launch (CBA_A3 and ACRE2, opens tmf_template.vr in Eden), plus tools/launch.ps1

Bug fixes

  • Admin menu: the ACRE2 radio assign tool never worked (it called the language function, and the radio function used an undefined _radio); the quick respawn log entry was never written; the teleport log entry errored; "print log to RPT" called a missing function; the utility modal shared the menu's IDD
  • Admin menu: follows CBA 3.19's rename of fnc_isDebugConsoleAllowed.sqf (fixes the "script not found" box at startup)
  • ORBAT editor: deleting an entry and switching bins didn't clear parent attributes (undefined _val); editing a group marker read undefined _fName/_entity; rhsdisposable typo; undefined value pushed into the ORBAT data
  • Chat: #loadout read "tmf_assigngear_ faction" (macro padding), so it never found the player's faction; the CMND macro ignored its argument
  • AI: the AI gear fallback was stored under a nil key
  • Spectator: the Eden "TMF Spectator Settings" menu item opened a removed attribute section and froze Eden, so it's removed; marker functions used the caller's _x instead of their own parameters; case default fixed
  • Other: endMission messaged a non-existent TAC1 function; the autotest RPT output skipped the first test; testGear read _weaponMags before defining it; 2 missing ; in AssignGear Cfg3DEN; a corrupt, unused square_ca.paa removed

Wave spawner

  • Spawning is spread over frames with a small cost budget, instead of creating the whole wave (objects, vehicles, units with full loadouts) in one frame. This fixes the lag spikes on big waves
  • Each vehicle spawns in the same frame as its whole crew, so aircraft spawned in the air are never left without a pilot
  • Groups keep their original leader; waypoints are applied once all units exist
  • The next-wave condition (time passed and % dead) is checked once a second instead of every frame
  • Wave handlers, the admin log entry and the next-wave timer run once the wave has fully spawned

UI

  • Respawn menu, spectator HUD and name tags keep 16:9 proportions on ultrawide screens (unchanged on 16:9)
  • Safe start banner and dry-fire text boxes sized to their fonts (text was clipped at the top of the screen)
  • closeDialog <idd> misuse replaced with closeDisplay; admin map handlers use call instead of spawn
  • Autotest messages and CBA setting titles and tooltips rewritten to say what's wrong and how to fix it

Cleanup

  • Command and event-name casing, private locals, isNotEqualTo/isEqualTo [], configOf, objectParent, remoteExec instead of BIS_fnc_MP, joinString instead of string building in loops, deprecated BIS_fnc_inString and stacked event handlers replaced, unused config declarations removed

Also included from the BF-888S work

  • Use the ACE kill tracker debriefing include in the template description.ext
  • Remove TMF lobby slotting group names (CBA handles lobby group names now)

These were pushed to feature/add-bf888s after #444 was merged, so they never reached dev.

Testing

  • hemtt check and hemtt build pass
  • Launched in Eden with CBA and ACRE2. The admin menu radio and quick respawn tools, the ORBAT editor, the respawn menu, spectator and wave spawner still need an in-game pass

🤖 Generated with Claude Code

headswe and others added 30 commits October 31, 2026 15:06
- Set mainprefix = "x" so HEMTT accepts the x\tmf\addons\* pboprefixes
- Make VERSION a number (MAJOR.MINOR) and add VERSION_STR, fixing the
  L-C01M "macro's result could not be parsed" errors from VERSION_CONFIG
- Fix calls to functions that don't exist:
  - adminmenu: printLogToRPT -> messageLog_printAll (log-to-RPT setting was a no-op)
  - adminmenu: drop call to removed utilityClose
  - adminmenu: respawnGroupMarkerUpdate lives in the respawn component
  - common: testGroupsSlottingScreen called tmf_autotest_fnc_checkTMFVersion
  - chat: CMND macro ignored its argument
- Fix forEach/select precedence in briefing unitPage
- Fix params type array in randPosArea and "case default" in spectator keyhandler
- Add include guards to script_component.hpp (macro redefinition warnings)
- Use standard config class casing, list ai modules in CfgPatches units[]
- Use backslash include paths in modules
- Add missing final newlines (hemtt utils fnl)
- Ignore HEMTT/BI private keys, bump actions/checkout to v4

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
These belong to the ACRE BF-888S work on claude/project-thread-m9t6zv.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Matches the BI wiki casing for commands (HEMTT L-S04) and UI/object
event names (L-S02UE), including safeZoneX/Y/W/H in UI defines.
Case-only changes; Arma treats these case-insensitively.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- adminmenu: _isParadropped was only defined inside the PFH, breaking the teleport log entry
- assigngear testGear: sidearm check read _weaponMags before defining it
- assigngear initAIGear: fallback type code was stored under a nil key instead of "code"
- spectator drawMap: draw2D event passed undefined _campos; now passes camera position and map control

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Make loop and UI-script locals private (L-S16)
- Drop dead "_list = " assignments in front of params
- Use isEqualTypeAny, configOf, isEqualTo/isNotEqualTo [] and select
  instead of if/else assignment

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Bugs:
- ACRE2 radio modal ran the language assign function instead of the radio one
- ACRE2 radio assign used an undefined _radio, so no radio was ever added
- Quick respawn built a log entry but never called the logger

Cleanup:
- Replace BIS_fnc_MP with remoteExec
- Modal utilities get _display from ctrlParent instead of the caller's scope
- Private locals, isEqualTo/isNotEqualTo instead of count and !(),
  configOf, objectParent, joinString, macro argument padding

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Private locals in rearm, spawnWave, waveInit, rearmInit
- isEqualTo/isNotEqualTo [] instead of count comparisons
- Local marker commands for debug/error markers, one global sync at the end
- configOf, macro argument padding, != instead of !(==)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
spawnWave created every object, vehicle and unit (with full loadout) in
a single frame, freezing the machine on big waves. Spawning now runs in a
per-frame handler with a small cost budget per frame. Wave handlers, the
next-wave timer and the admin log run once the wave is fully spawned.

The next-wave condition (time + dead count) is now checked once a second
instead of every frame.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Aircraft spawned in the air were left without a pilot for a few frames.
Each vehicle step now also spawns its crew (from any group). Groups are
created with their first unit and get their original leader back before
waypoints are applied.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- isNotEqualTo instead of !(isEqualTo) and count comparisons
- Private locals in saveRole and replaceSidearmWeapon
- Drop push to an undefined _mags in the radio fit check
- Loadout attribute DLC logo no longer relies on a nil if-result
- #undef GETGEAR before redefining it in testGear
- Macro argument padding

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Print each test's own output to RPT; the old check used the accumulated
  output, so the first test was never printed
- Use QUOTE(ADDON) for the config lookup
- isNotEqualTo, configOf, private locals, macro padding

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Build unit/vehicle page text with arrays and joinString; vehicle cargo
  sections share one loop
- isNotEqualTo, isEqualTypeAny, configOf, pushBack, private locals
- Drop dead _list assignments and a stray _ before a comment

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
QEGVAR(assigngear, faction) had a space in the macro argument, so #loadout
read the variable "tmf_assigngear_ faction" and never found the player's
faction. Also removes padding from other macro arguments, uses objectParent
and isNotEqualTo.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
endMission broadcast messages to tac1_admin_fnc_messageAdmin, which no
longer exists. They now go to the admin menu log. The mission end uses
remoteExec instead of BIS_fnc_MP.

Also: isNotEqualTo/!= instead of !(), isEqualTo [] instead of count,
private locals, and drop unused external config classes.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Also puts the multi-line QUOTE() blocks in the ambient vehicle init and
wave spawner attribute on one line.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- respawn: replace BIS_fnc_MP with remoteExec for the wave server and
  local client calls
- Private locals, objectParent, configOf, isNotEqualTo []
- lints: allow ACRE_* globals in all caps (ACRE's own variables)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Private locals, isNotEqualTo []
- Build action text with joinString
- Use QGVAR(mapEvent) for the stacked map click handler id

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Bugs:
- Deleting an ORBAT entry compared against an undefined _val, so units
  and groups kept pointing at the deleted parent
- Switching the ORBAT bin never cleared the parent attributes (same _val)
- Editing a group's marker read undefined _fName and _entity
- Primary weapon launcher check used rhsdisposable instead of rhs_disposable
- Briefing parent scan pushed an undefined _added into the raw ORBAT data

Cleanup: configOf, select -1, isEqualTo [], isEqualTypeAny, countSide on
units, joinString, private locals. Allow the shared UI IDC arrays in caps.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Group/unit marker and cache functions used the caller's _x instead of
  their own _grp/_unit parameter
- Private locals, configOf, objectParent, isNotEqualTo, select -1,
  macro argument padding

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- BIS_fnc_inString -> case-insensitive `toLower a in toLower b`
- teleport: BIS_fnc_addStackedEventHandler -> MapSingleClick mission EH
- Raise REQUIRED_VERSION to 2.18 (negative select indexes and other
  modern commands are already in use)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
tools/launch.ps1 builds TMF and starts Arma 3 with CBA_A3, ACRE2 and the
fresh build. .hemtt/launch.toml lets `hemtt launch` do the same from the
workshop IDs.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
CBA 3.19 renamed fnc_isDebugConsoleAllowed.sqf to
fnc_isDebugConsoleAllowed.inc.sqf, so TMF's wrapper pointed at a missing
file and Arma showed "Script ... not found" on start.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The TMF Spectator Settings menu item still opened the TMF_Spectator_Settings
mission attribute section, which was removed when the settings moved to CBA
(#403). Opening a missing section closed Arma. It now opens the CBA addon
options, where the spectator settings live.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Matches d0e9880 on feature/add-bf888s so both branches merge cleanly.
Spectator settings are CBA settings (Addon Options > TMF > Spectator).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
That branch simplified the test (d6e2ea6); using the same file here keeps
the two branches merging cleanly.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
headswe and others added 10 commits November 1, 2026 19:10
Autotest results now say what is wrong and how to fix it (loadout names,
where to assign ACRE2 networks/languages, how to clear DLC notices, ...).
CBA setting titles and tooltips describe what each option does and what
the choices mean.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The modal reused the admin menu's IDD (56100), so findDisplay could return
the modal instead of the menu while both were open.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- New TMF_UI_W/TMF_UI_X canvas: full width up to 16:9, capped and
  centered on wider screens
- Respawn menu is laid out on that canvas instead of raw safeZoneW, so it
  no longer stretches on 21:9/32:9 (unchanged on 16:9)
- Spectator HUD and name tags keep their screen edge but cap their widths;
  tag centering offset follows the new tag width
- Remove an unused tag background control placed outside its group
- Admin respawn and Admin Eye map handlers use call instead of spawn
- Close displays with closeDisplay instead of closeDialog <idd> (closeDialog
  takes an exit code, not a display ID)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The file is truncated (HEMTT: failed to fill whole buffer while generating
texture headers) and nothing references it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- tags.hpp: remove a stray `};` left behind when the unused background
  control was deleted; it closed the controls class early and broke the
  config
- Respawn and spectator dialogs are packed unrapified, so the canvas
  expressions are written out as plain strings instead of QUOTE(TMF_UI_*)
  macros, and the now unused macros are removed

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Rapify was turned off for 10 addons, so HEMTT never parsed their configs
and broken syntax only showed up in game. Configs are now rapifiable:

- Unquoted expressions (x/y/w/h, sizeEx, defaultValue, ...) wrapped in
  QUOTE(), which matches how the engine read them (as strings)
- Unquoted class names and stringtable keys in arrays quoted
- BI INIT_DISPLAY/INIT_CONTROL macros written out with QUOTE
- Module booleans as 1/0
- Add two missing semicolons in assigngear Cfg3DEN
- Fix parent class name casing
- Quote the default font in the vendored defineCommon.inc
- Remove the addon.toml files that disabled rapify

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Guard macros that redefine identical BI/CBA defines with #ifndef
- Remove padding from macro arguments; put multi-line QUOTE() values on
  one line
- Remove 66 external class declarations that were never used
- Class name casing (ctrlToolbox, CfgScriptPaths, RscListBox)
- Add the missing .paa extension on the ORBAT menu icon
- List the spectator module in CfgPatches units[]

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The SAFESTART ACTIVE banner and the dry-fire X used a box measured in
safeZone fractions with a font measured in GUI grid units, so the text was
taller than its box and clipped at the top of the screen. Heights now use
the same grid unit as the font, and the X sits at 82.5% of the safe zone
instead of a fixed 0.825 offset that moved with the interface size.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@headswe headswe self-assigned this Nov 3, 2026
headswe and others added 2 commits November 3, 2026 21:33
ACEX was merged into ACE3, so include ACE's killtracker.inc when
available instead of the old acex_killTracker section. (From #431)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Drop the TMF lobby group name handler in favour of CBA's Role@Group
naming, and make the 3DEN test always check for CBA-style role
descriptions. (From #426)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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