Repository navigation
Combined 3: hire floors + spot check (#385), Zul'Farrak boss steps (#391), walk-super without eval, boss rows own their boss, pull_size lint (#398) - #401
Merged
Conversation
…by its units, agent_only unit waits; Zul'Farrak exports without a cut A boss's hold may leave instance_data out: plan-export writes the run leader's hold done by its units (entry 0, param 0, flags 0, the boss entry first, so a boss a script turns hostile later counts while still friendly). wait_for.agent_only names why a unit wait needs no row: plan-export leaves it out with a warning quoting the reason instead of cutting the plan. Validate takes the units hold as the loader does. A boss.first under a hold is warned as no kill order. zulfarrak.json: the bly leg's three unit waits are agent_only, Bly's gossip is option 0, the boss has a units hold on the leg's spot (1884 1212 9, r25, 300 s); Murta, Oro and Raven join kill_first; the gahzrilla leg's Gahz'rilla wait is agent_only (the leg stays optional: its gong needs a row kind the module does not have). The whole plan now exports without --skip-legs bly.
…l writes an optional leg; Zul'Farrak's End Door wait is for active_alt A via_item use_object (the item used ON the object) exports as TortoiseBots' use_on row: entry = the object, x,y,z = its near point, item = requires_item, after the move to its stand; Validate applies the loader's use_on rule. Options.WithOptional (--with-optional) writes a named optional leg into the rows with a warning that its item is the operator's to give to the lead bot before .bot run start (a GM .additem); a name that is no optional leg is refused. zulfarrak.json: the weegli_door wait for the End Door is for active_alt (state 2): Weegli's blast opens it with the alternative state (zulfarrak.cpp:423), and the module run r8 paused twice at a state-1 wait on an open door.
…Gahz'rilla dies at once, an invisible corpse at the pit); README: the gahzrilla export is TortoiseBots' opt-in file
…n Zul'Farrak's Bly gossip Bly's crew is killed by the pyramid event's troll waves in some runs; the run leader then paused at the gossip and held 300 s on a dead hold. The flag lets the module count a dead NPC as done.
…Solid 11836, Icicle 11131)
…s the east pool ring from within 50 yd (no navmesh hops of its own)
…hold, Gahz'rilla leg)
The hire spot judged the portal ground from a guessed z (a GM teleport, climb or landing leaves session.StatusInfo.ZUnknown until the server sends a position), so a guess could pass the drop check. AgentPosition now returns whether z is the server's own; the step waits up to 10 s for it near the portal and refuses with "hire: commander height unknown near the portal" when it never arrives. Far from the portal an unknown height is not judged.
Sergeant Bly's gossip row counts a dead NPC as done, but the units hold after it needed a unit seen hostile: a Bly killed by the pyramid waves leaves the crew friendly for good (zulfarrak.cpp npc_sergeant_blyAI turns them only from his own postGossipStep 3), so nobody turns hostile and the hold waited 300 s. hold.skip_if_dead_of_gossip on a boss's units hold: plan-export writes flag 16384 (kPlanFlagDeadGossipOk) and the plan check wants the boss's gossip step with dead_is_done. The run leader ends such a hold when no unit of it is hostile; at once when all lie dead.
…nFlagResetToGossip The dead-gossip hold flag moves from 16384 to 32768 (plan-export constant, plan check, README, zulfarrak.json note, tests). kPlanFlagDeadGossipOk = 32768 on the TortoiseBots side is not written yet.
…oor (#266) The hire spot compares the navmesh floor under the commander with the navmesh floor under the portal point instead of the guessed height against the trigger centre, so a trigger a few yards above the ground no longer refuses a commander standing on it, and the 10 s height wait is gone. A kept binding that already holds the wanted party is not checked: a resume hires nothing new there. The plan's tank_min_hp is set at the band's middle level; the preflight scales it to the hired tank's own level with the 2026-10 test runs' per-level health curve, rounded down to 50.
… the script resets it hold.reset_to_gossip (a boss's units hold only, never with skip_if_dead_of_gossip; the leg's last event-start step must be the boss's gossip) exports as flag 16384, kPlanFlagResetToGossip on the TortoiseBots side (#1455). skip_if_dead_of_gossip stays 32768. Validation, plan-parse tests, the arena row pin and the export row test cover both flags; README and the arena note say which row takes which.
The cut hop is the exporter's own walk. A hop whose cut points would come within LeaveClearYd (15 yd) of a leg's leave spawn is left uncut, with a warning, so the run leader hops it itself as it did before --approach-hops: Zul'Farrak's island Shadowhunter 81610 otherwise stood 9 yd from the cut path to the velratha leg's pull group 4. README says so.
…t its via vertices
… assumes tier gear
LegNumber and PlanLeg treated optional and skip_export legs as absent even when --with-optional or --with-legs exported them, so firstLeaveConflict checked a cut hop against the wrong plan leg's leave list. The export now builds one LegMap (plan leg index -> row leg number) from the legs it writes, by name, with ExportedLegs, and passes it to LegNumber, PlanLeg and firstLeaveConflict. Rows.LegMap matches a rows set's legs to the plan by name for the callers that hold rows. The default export is unchanged.
A mob no row owns reads 0 from the owned map, which is also the route's first row index: the first row could pick a stranger. TestPullSizeTargetIgnoresUnownedMobAtRouteStart pins both sides.
Matches worldspawn.AggroRadius (0 for detection under a yard, like NO_AGGRO). pull_size keeps its own explicit mapping: its 0 means the export predates the column, read as 20 yd. TestNoDetectionRangeNeverWakes mirrors the worldspawn row.
The Bly gossip option lets the export reach Bly and Ukorz, so the count covers more of the run. Two Sandfury Guardian passes on Ukorz's leg (19.5/21.6 yd, later rows' own packs) and Ukorz's own 0.1 yd final approach (no row: his boss row names only Ruuzlu in first, and the loader refuses 7267 there); the Courtyard via removed two. Fixes the comment that claimed the old baseline saw the whole run.
pullMobs uses the route lint's filter (hostileMob, shared with RouteIntoLaterPacks, not a copy): no NPC flags, no ignored or friendly faction (35 is friendly to all, as in Check), no critters. Rows gated to the other team are not pulled by this run: routePoint carries the plan's team gate off the export flags and PullSizes skips those rows (no pull number consumed). No pinned count moves: the fixtures' counted rows are all hostile and ungated. TestPullSizeIgnoresFriendlySpawnsAndOtherTeamRows pins the friendly neighbour and the gate; TestPullSizeTargetIgnoresUnownedMobAtRouteStart pins the owned presence check.
Over-ceiling rows are warnings for a person; only -pull-size-strict opts into the ceiling. No-target rows and load errors still fail -strict. checkFile takes the ignore factions and the pull-size-strict flag, and the N warning(s) summary line is back. Tests: the committed uldaman plan passes -strict on its 58 over-ceiling warnings (its no-target row still fails it), and a synthetic over-ceiling row pins the strict matrix.
Pull 14 (the row over the G13/G16 terrace, export step 29) estimates 27 bodies; the neighbours 13, 16, 17 estimate the same set, 15 and 18 break away at 31. RingYd 10 drops pull 14 to 22 (red, then restored).
…lk is floor-checked The settle walk for a guessed height over two floors tried a 3 yd step east first, and a step that left the 15 yd portal radius passed the hire as allowed without the portal-ground floor check. The walk now picks only targets inside the radius, the one nearest the portal first, and a settled height is judged on its floor wherever the walk ended.
The route check gave a boss row ownership of its First entries only. A final approach that walked up to its own boss (Zul'Farrak Ukorz 7267 at 0.1 yd) was reported as an unowned pass. A boss row now owns boss.entry and boss.phase_entries too; the export carries neither. Re-pinned the 16 hand-written plans with the old count in each comment: boss rows own their boss. 277 findings dropped, none added (168 lines changed only their owner text, to the boss row).
- The cmd line is split into argv by a strict word parser: plain words and
double-quoted words only. $, backticks, backslashes, ; & | < > ( ), other
quotes, globs, ~, # and a second line refuse the file (exit 2, nothing runs).
The walk runs as nice -n 10 "${ARGS[@]}"; there is no bash -c re-parse.
- A missing or non-numeric exit-status file is exit 70, logged "status
unknown", and stops like a crash (no restart).
- Tests: cases 16-18 (injected operators refused with nothing run; status
unknown with a missing and a malformed file; walk-28 shaped argv matches the
literal list and the old eval parse). make_cmd writes double-quoted words.
The pull lint dropped every npc_flags spawn and every faction-35 spawn, so the -awakened and -scripted entries (Uldaman's Stone Keepers, scripted gossip NPCs) never joined a pull. A pull row that owned only such a spawn reported "no target" instead of its body count. PullFilter now carries the check's awakened and scripted sets. A spawn of those entries bypasses the npc_flags, faction 35, friendly and ignore exclusions; the critter rule still applies. hostileMob is unchanged for the route lint. Test: four awakened Stone Keepers at one stand with ceiling 3 count 4 bodies, and the same for a scripted spawn with npc_flags.
… batch/ta-combined-3
…batch/ta-combined-3 # Conflicts: # tools/dungeongen/route_aggro_test.go
…tch/ta-combined-3 # Conflicts: # tools/dungeongen/route_aggro.go
… re-pin route counts after the boss-ownership merge
This was referenced Nov 2, 2026
…tAtBly) went with the Zul'Farrak boss steps (staticcheck U1000)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #266
Fixes #243
Replaces #385, #391, #398. Combines the branches named below into one dev PR (one CI run).
Hire floors + spot check (#385)
tank_min_hp, scaled to the hired tank's level. Under the floor: a preflight warning, and a refusal under strict preflight.team.Zul'Farrak boss steps (#391, parts A and B of #243)
reset_to_gossip(flag 16384) andskip_if_dead_of_gossip(flag 32768). A gossip may setdead_is_done. A cut hop keeps off the plan's leave spawns.zulfarrakis 66 with Zul'Farrak boss steps: Zel'jeb, Farraki Arena, Gahz'rilla tactics, Bly (with the dead-NPC and arena-reset hold flags) #391 (re-measured below).farraki_arenaorblylegs to a server without TortoiseBots PR #1477 (fix/units-hold-reset). Without it the holds hang.walk-super without eval
From 3162c31: the cmd file is parsed by a strict word parser (plain and double-quoted words only). Anything else (
$, backticks,;,&,|, redirects, globs,~,#, a second line) refuses the file with exit 2 and nothing runs. The walk runs asnice -n 10 "${ARGS[@]}". A missing or non-numeric exit-status file is exit 70, "status unknown", and stops like a crash.Boss rows own their boss (from ab4fd16)
A boss row now owns
boss.entryandboss.phase_entriesin the route check, so a final approach that walks up to its own boss is no finding. The 16 hand-written route pins are re-measured on this merged tree (zulfarrak 66 -> 56, the others as in ab4fd16 with the new base). The merge also fixed a compile break:routeBossByExportLegtakes the built rows'LegMap, sinceplanexport.LegNumbernow takes a map (#391).pull_size lint (#398, part A of the camp-pull spec)
internal/aggroest: port of TortoiseBots' pull estimate (pack, live mobs within aggro reach of the walk and stand, 20 yd call-for-help ring, 2 hops, 12 yd height band).max_bodiesper pull group, with plan-widepull_ceilingfallback; exported in the pull row'sitemcolumn.dungeongen -checkpull_sizefindings. World or estimate load errors fail the check, with or without-strict.Known limits
feat/aggro-walk-ring.-raceflake (make test -race is flaky on dev: data races in internal/dungeon driver_test fakeGame and internal/dashboard TestSavesAreBounded #386) may recur; a re-run is the only fix here.Verification
vm-test taon the merged tree (02e91d5): PASS (rc=0), 1411 files.