Синхронизация с upstream до e2aeaecf: исправления AccessKit на Windows, прокрутки трекпада на Linux и анимации моделей в меню.
MoonWell: расчёт рассеяния, вторичного освещения и AO перенесён в половинное разрешение с восстановлением по глубине. В контрольной сцене RTX 5070 суммарное время постобработки снизилось с 6,41 до 3,47 мс. При выключенном расширении изображение совпадает с исходным. Добавлен анализатор диагностических логов GPU.
Исправлена подготовка тестов интерфейса и обработка отсутствующих кинороликов в сокращённой установке. Уточнены причины существующих отклонений русского пакета и HD-атласа.
Проверки: 46 тестов графического модуля и сравнения дневных/ночных кадров пройдены; полный цикл scripts/gates.sh пройден: fmt, Clippy workspace и player, reference, тесты с установкой и без неё, документация, каталог сообщений, проверка GPU-проходов и запуск движка с данными и без. Проверки отсутствующих аддонов и четырёх кинороликов явно пропущены. Живой вход/выход на сервер не выполнялся.
Upstream 0.3.0. The ruRU pack now takes upstream's locale path
(Locale::from_language_country picks the column and the auth tag); our
own part is the Data/ruRU mount, the name GetLocale answers and the UI's
Russian name charsets. A language pack folder mounts without the base
set that upstream now requires. moonwell-gfx shadows and per-pixel
points move onto the per-vertex lit colour of upstream #2899; the
retained static pass passes its own normal.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Its far samples took their depth off the coarse pyramid levels but their
colour off the full screen, so a supersampled frame's colour fetches missed
the cache. A half-size colour pyramid beside the depth one now gives each
far sample its colour at its depth's level.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Three channels: near (the speaker's own faction within /say's 25 yards,
heard from where the speaker stands), group/raid and guild (any
distance). Voice never rides the world socket: clients send 20 ms Opus
frames over UDP to moonwell-voice-relay, which forwards each one only
to whoever may hear it, from the state the core feeds it (faction,
map, instance, position, group, guild), so no client can claim a place
or a group of its own. The core vouches for a client with a signed
ticket (`.mwvoice`).
- crates/moonwell-voice: the ticket and feed formats (byte-checked
against the core's own C++ output), the client-relay wire, routing,
the relay binary; with `client`, the microphone and voice output on
their own cpal streams, Opus through the vendored libopus (no cmake),
per-speaker playout queues and the UDP session.
- crates/moonwell/src/voice.rs: the game side: push-to-talk (Mouse4 by
default) or voice activation, near speakers placed by distance and
side, Lua MoonWell_Voice*, settings in moonwell-voice.toml, and the
MoonWellVoice addon (voice.lua): the ticket, /voice and its settings
window (devices by id with their Windows names, activation, key,
threshold and meter, talk channel, channels heard, volumes, echo test).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The lit air is eased toward a ceiling of 0.35 in luma (the faint dusk glow is as it was) and
laid over the frame as a screen, as are the sun shafts, so a bright pixel brightens little and
none clips; its forward lobe is gentler (g 0.5), and the bloom raises the stock glow less
(x(1 + 0.8 s), was 1.5). Checked at five places through seven hours.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The post pass takes from the dark and middle tones (eased off toward the bright, so a torch's
pool, a window or the moon keep theirs): post.shadow_depth at any hour, post.night_darkness
far further with the sun down, cooler and a little greyer. The lit air keeps 15% for the moon
(was 35%). The Forever preset sets both.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Light in the air through the sun's shadow cascades (rays through canopies, the air glowing
toward a low sun), secondary lighting off the screen, FXAA and a contrast-adaptive sharpen in
the post pass, bloom from the stock FFXGlow, dense far grass through ClutterConfig (the core
re-meshes on a fade change), wind waves on water without current (city canals included), and
a "WoW Forever look" button in the options window. Everything off still draws the stock image.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1.12 gives no quest id for a log row and no world position. benilla-ui
opens two reads (quest_log_row_quest, player_place) and the MoonWell
launcher adds MoonWell_GetQuestLogQuestID and MoonWell_GetPlayerPlace to
each in-game VM, for MoonWell UI's quest map. A dev build also adds
MoonWell_DevInteract(entry) for scripted runs.
Built and checked on Windows (release, and the player build without dev);
clippy clean for benilla-ui and moonwell; quest_log tests pass.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Since upstream b4d0987a startup recurses deeper than Windows' 1 MiB
default and MoonWell.exe overflowed its stack before the glue screen.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Applies upstream c5fc904f..b4d0987a (34 commits): live loot, auction,
mail and trade getters; packet-ordered signals; world click records;
transport props. docs/MAP.md and DEVIATIONS.md regenerated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Project Reforged's helms (patch-G) key their root bone in Stand: a
constant translation of (-0.09, 0, -0.18) that seats the helm on the HD
head. benilla drew every resting item at its bind pose, as no stock item
keys its bones, so these helms floated above and in front of the head.
An item whose loader-idle clip poses a bone now gets a pose and a player
like a flexing bow, its palette rows F x model[b] x ibp[b]: the reference
animates every attached M2 (0x714260). Stock items, keyless, are
unchanged.
Verified with creature-sun-front captures of MoonWell.exe at 1600x900
on the install's Data (Reforged A + G), the fixture's display set to
Stormwind guards (5446 female, 1984 male, Helm_Plate_AllianceUprez_B_01):
the helm sat above the head before and sits on it after; display 1862
(stock Helm_Plate_B_01Stormwind) is unchanged. benilla-app's equipment
tests 26/26. The fixture's display override was a working-tree change
only. Built on Windows.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A restarted process cannot log in: the launcher's login ticket is spent.
The saved choice now just closes the client, and the confirmation (patch-F)
tells the player to start it again through the launcher.
Verified: builds and lints clean (release).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Publishing Project Reforged's patch-A.mpq (1.7 GB) failed four times at
a random part (27, 85, 5, 24), and each failure aborted the upload and
restarted the file from part 1. A part is now sent up to six times with
a doubling pause (4 s to 64 s) before the upload fails, and the failure
names the store's error instead of dropping it.
Verified: builds and lints clean; the release publish is running with it.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Upstream's #2424 holds 1.12.1's device gate on UI textures: a side
that is not a power of two, or is 1024 or more, leaves the solid 8x8
green (0x4484ae-0x4484d0). MoonWell UI (patch-F) draws Forever UI and
its login screens from atlas sheets of 1024² (74) and 2048² (2), all
power-of-two, so after the upstream sync its frames, previews and
glue art turned green.
Core seam (benilla-formats, a few lines): raise_ui_texture_side(side),
set once by the entry point, lifts makes_device_texture's upper bound
(at least 1024); the power-of-two and 8-minimum rules stay. The MoonWell
launcher raises it to 4096, as VanillaHelpers raises the client's limit.
Verified with MoonWell.exe captures at 1600x900 on the release package's
Data: the style chooser's previews and the create screen's vignettes,
banners and bronze frames draw again (green before); the Forever style
in game (a --test-style forever patch-F) draws its frames, bars and
minimap. benilla-formats 549/549 and benilla-assets' green-gate test
pass. Built on Windows.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
66 upstream commits since d3b5df3f, applied with the explicit base.
Conflicts: docs/MAP.md and docs/DEVIATIONS.md taken from upstream and
regenerated (scripts/genmap.sh); Cargo.lock taken from upstream and
refreshed for MoonWell's crates; crates/benilla-ui/tests/vm_parity.golden
taken from upstream, its `sweep cos` answer keyed cos@linux-x86_64, as
this fork lists cos among the per-platform cases.
Verified: MoonWell (release) builds; benilla-formats 549/549,
vm_parity, moonwell-gfx 46/46 (the shader anchors hold).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The tests that read the install assert the stock 1.12.1 data, so a
player's texture pack (Project Reforged's patch-A, -G, -T...) or an
interface mod (patch-F) in the same Data folder failed them. With
$BENILLA_STOCK_CHAIN set, Chain::open mounts a Data directory's base
set, patch.MPQ, patch-2.MPQ and speech2.MPQ, and leaves out every other
patch-?.MPQ; the language pack's folder is not filtered.
scripts/unit-tests.sh, the gates' test runner, exports it.
Verified: a chain test (stock mode keeps patch and patch-2, drops
patch-A.mpq and patch-F.MPQ; without it all mount); benilla-formats'
547 tests pass on the install with Reforged's A and G under
BENILLA_STOCK_CHAIN=1, where three character tests failed before. The
other crates' install tests were not run here. Built on Windows.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
1.12 composites a character's body skin (base skin, face, hair,
underwear, worn armour) into a 256² atlas, and benilla copied each
overlay texel for texel into its 256²-space tile, so a pack's larger
textures landed misplaced or were cut. Project Reforged's patch-T (and
patch-U) ship skins and TextureComponents at 2x (4x) and say so with
VanillaHelpers' convention, VanillaHelpers\ResizeCharacterSkin.txt
holding 2 or 4.
CharSections reads that file at load. At scale 1 the composite is
unchanged. At 2 or 4 the atlas is 512² / 1024²: the base skin and every
overlay are resampled to their scaled tile when their size differs (a
pack texture at its scale fits as is, a stock one is enlarged), blended
at level 0, and the mip pyramid is built by 2x2 averages. A Deviation:
comment names the reference's 256².
Verified: a unit test (a stock 128x64 overlay fills its doubled g1 tile
and nothing else, 10 levels down to 1x1); the character tests pass on
the stock data (33/33; on the install with Reforged's patch-A, three of
them fail with or without this change, as they assert stock data);
benilla-extract charatlas for a human female naked and in plate (display
1184): 256² with patch-A alone, 512² with patch-A + patch-T, the layout
the same and the T one visibly sharper; glue-charcreate captures at
2560x1440 with A and with A + T, the T face sharper. The captures needed
upstream's e4bff386 in the working tree only. Built on Windows.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The install's HD archives (Project Reforged's character set: A
characters and NPCs, G gear, L female body, T and U high-resolution
character and gear textures) are mounted or left out of the chain. The
chain opens once, so a change restarts the client.
Core seam (benilla-formats, ~30 lines): leave_out_archives(names) set
by the entry point before anything opens the chain; Chain::open_client
and open_localized skip those archives of the install's Data folder by
name, in any case. The language pack's folder is not filtered.
The launcher (crates/moonwell/src/models.rs) reads the choice from
benilla-config/moonwell-models.toml (characters = "sd" | "hd", HD when
absent; $MOONWELL_MODELS overrides it for a run) and adds
MoonWell_GetCharacterModels / MoonWell_SetCharacterModels to every glue
and in-game VM; a different choice is saved and the client starts again
with its arguments. The interface for it lives in MoonWell UI (patch-F).
Verified: a chain test (a left-out archive does not mount, the rest keep
their order); glue-charcreate captures of MoonWell.exe at 2560x1440 on a
Data with Reforged's A, G and T, SD and HD showing the stock and the HD
human female; an in-game capture answers MoonWell_GetCharacterModels().
The restart itself was not run (captures save no state). Built on
Windows: release dev build and player build.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The FPS journal writes gpu-passes.log (every top-level GPU pass) and cpu-phases.csv (wall,
process and main-thread CPU per main schedule) beside fps-journal.csv, with a session marker
per recording. On Windows the phase clocks count thread cycles (QueryThreadCycleTime /
QueryProcessCycleTime at a TSC rate calibrated against Instant), since tick-sized process
times cannot split a frame. A crate on top labels recordings through FpsJournalTags; each tag
lands in all three files when recording starts and whenever it changes, and
scripts/journal-report.py summarises a recording per session and tag state side by side.
moonwell-gfx tags recordings with its settings (mwgfx) and gets cheaper at renderScale 2:
- the ambient occlusion reads a linear depth pyramid (ao_depth.wgsl, after McGuire's SAO),
far samples off coarse levels: 2.2-2.4 ms -> ~1.1 ms at 12 MP, image unchanged (max 9/255);
- the water's scene copy is skipped while no view sees a liquid;
- shadow casters take their own visibility class, so the world camera stops listing them.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Add the graphify knowledge graph of crates/ and the CLAUDE.md rules for using it. Only the graph, report, viz and manifest are tracked; caches and scratch files are ignored.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Import 48 upstream commits since 9a5f2a56 and retain the ruRU localization: Cyrillic names
keep the twelve-letter cap in upstream's reworked name check, the roster keeps its Unicode
name match beside upstream's new tests, and the spell cost cells take upstream's keyed
GlobalStrings templates, which supersede ours. The workspace stays at 0.3.0 (upstream went
back to 0.2.0 until its 0.3.0 ships); cos stays a per-platform VM parity case. Workspace
tests pass on Windows.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A graphics crate on top of benilla, added through `run_with` in the MoonWell launcher, with
small seams in the core: atmospheric fog, sun shadows (static, terrain and entity casters),
a post pass (SSAO, sun shafts, grading), wind in trees and grass, stylised water after
benilla-watershader (planar mirrors for two heights, SSR, shore foam, character wakes, river
current), light from fires and lamps with per-pixel point lights, halos and torch shadows,
and an in-game options window (/mwgfx, the game menu) with a defaults button. Everything is
off by default and then draws the stock image.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Import 25 commits through 9a5f2a56, retain Russian localization and agreement distribution. Windows locked player build, formatting and offline stock glue compatibility checks pass. Full suites not rerun. Production release requested by maintainer.
Import 32 upstream commits through a5cb73a8 and include original EULA/TOS in client packages. Windows player build, targeted packaging tests, clippy and offline stock agreement scrolling checks pass. Original data remain outside Git. Full workspace suites not rerun.
Accept Cyrillic confirmation case-insensitively in the ruRU glue layer. Offline stock GlueXML reproduction and focused verification passed; full suites not rerun per user instruction. Production release authorized.
Integrate 182 upstream commits through b2473e60 while retaining MoonWell packaging, branding and the community ruRU pack.
Upstream replaces the C Lua/mlua host with benilla-lua/benilla-mlua and the native glue screens with stock GlueXML. The update also includes the new locale/DBC/name rules, cache and interaction handling, rendering, quest log and chat behavior, including the latest quest completion and timed-quest failure fixes. Fork adaptations use the new APIs: stock Wow.ini locales remain intact, while the ruRU overlay reads column zero and retains its ruRU authentication tag and Lua identity. Russian names keep their twelve-letter policy and Unicode roster matching; fonts, spell costs, race/class labels and translated options retain real-pack regression coverage.
Windows regression fixes keep the locale-default test valid under instrumented window overrides and the shader assertion independent of checkout line endings. The original C Lua 5.1 host, rebuilt from c0630f3d in an isolated directory, reproduces the complete Windows cos-sweep answer byte for byte; cos now uses platform-specific goldens.
Validation on Windows: scripts/gates.sh passed all automatic gates, including real-data and no-install workspace tests, reference tables, documentation, message catalog, render-pass lint, player clippy/tests and engine boots with and without data. MoonWell player clippy also passed with -D warnings. The committed tree exactly matches the full green stamp; five vendored Kira files retain the tested checkout's line endings, with normalized contents unchanged. All three actual ruRU pack regressions passed in both builds. Fifteen test archives were restored read-only from the published client and SHA-256 checked.
Each real-data/player rung skipped 31 tests because the optional addon corpus is absent (24 general, 7 Quiver). Live smoke was not run: no declared probe account; no player-account login or character creation was performed. Linux/macOS changes were not locally built.
Integrate six upstream commits through c0630f3d (2026-10-11), preserving MoonWell branding, launcher integration and ruRU localization.
The update fixes OnUpdate ordering by strata/level/link order, bare Lua errors passed to the error handler, case-insensitive addon file lookup and UNIT_FACTION on faction-template changes. It also adds an optional Bevy dynamic-linking feature and lets test gates report all failing crates.
Merge conflicts retain localized spell costs, race/class display names, Cyrillic character-name input and the twelve-letter creation limit. UI error handling and update traversal follow upstream. docs/MAP.md was regenerated and has no delta.
Validation: full scripts/gates.sh passed on the exact source tree (1884 s) on Windows with the real 1.12.1 MPQ/DBC data and ruRU pack, including workspace tests with and without install data, player tests without dev, and engine boot checks. The 31 optional addon corpus tests are unavailable on this checkout. No live account login was attempted because no probe identity is configured. The optional dynamic-linking feature is retained but not enabled by the default gates.
Spell resource costs, UnitRace/UnitClass and the character-name field were still using English-only paths after enabling ruRU. Costs now fill the selected GlobalStrings templates, the player record and live unit feeds use ChrRaces/ChrClasses display names while retaining file tokens, and typed/pasted Unicode letters reach the UTF-8 create packet. CharacterCreateNameEdit now initializes its reference limit of 12 letters; a 12-letter Cyrillic name retains all 24 UTF-8 bytes. Roster selection also matches the server's recased Cyrillic name.
Reference: 1.12 PaperDollFrame_SetLevel reads UnitRace/UnitClass; ruRU GlobalStrings supplies MANA_COST/RAGE_COST/ENERGY_COST and their PER_TIME forms; the selected ChrRaces/ChrClasses DBCs supply display names. vmangos normalizePlayerName decodes UTF-8 and recases letters: https://github.com/vmangos/core/blob/development/src/game/ObjectMgr.cpp#L60.
Original symptoms reproduced by instruments with real client data: 30 Mana, Human/Warrior in CharacterLevelText, and Cyrillic keyboard text rejected. The same instruments check Russian and adjacent English text, Human/Warrior and Tauren/Druid, Unicode typing/paste/backspace and the 12-letter cap. The create packet and normalized roster spelling have separate checks.
Validation: the original three symptoms reproduced, then the same three instruments passed with real ruRU and adjacent enUS data. Full land gates passed on the final source tree (816 s): fmt, workspace clippy, workspace tests with data and without an install, doc links, render-pass lint, player tests without dev, and engine boot with/without data. Only the 31 absent addon-corpus tests skipped on each real-data test rung. The strengthened create-packet check verifies the actual reset field, its 12-letter cap and unmodified UTF-8. Built on Windows. No live character creation or player-account login (no declared probe account).
Bring the fork from its already integrated upstream c2fc3cf3 snapshot to 710eb8f531. The new upstream commit changes only development/play build profiles: dev ThinLTO is disabled and dependencies use one codegen unit. Production release and ship profiles are unchanged; MoonWell integration and Russian localization are retained.
Source: upstream commit 710eb8f5, PR samwhosung/benilla#857. The patch is applied unchanged. MAP was regenerated and has no delta.
Validation on Windows: formatting and locked workspace metadata pass. All automated land gates passed on the final tree (4100 seconds): clippy, workspace tests with and without installed data, documentation and render-pass checks, player-build tests and both engine boot checks. The only skipped tests are 31 optional vanilla-addon/Quiver corpus tests, because that corpus is unavailable. Parsed TOML confirms that all profiles match upstream and that release/ship profiles and workspace dependencies are unchanged. Russian roster labels, character creation names, deletion text and locale-aware NPC-cache tests passed against the real archives. No declared probe account is available for a live game login. Upstream performance figures were measured on macOS and are not claimed for Windows.
Russian character selection displays literal numbered placeholders, and character creation uses English race/class names even when its descriptions are translated. Resolve display names from the selected ChrRaces/ChrClasses DBCs and use the existing numbered-argument formatter for roster rows and deletion prompts.
Creature caches were always written and accepted as enUS. Write the selected client locale into the header and reject caches from another language, allowing the server to answer fresh NPC-name queries.
Reference: the supplied ruRU pack has CHARACTER_SELECT_INFO ordered as class then level, and its DBC name slots contain the Russian labels. The deployed server has 9,755 Russian NPC names; existing local caches contain 101 English-only NPC records. The reported quest giver is Guard Thomas (261), starting quest 37; its Russian name exists in the deployed database.
Validation: ten targeted Windows checks passed against the supplied archives with data required and no skips. All automated land gates passed: formatting, clippy, tests with and without installed data, player-build tests, documentation and enforcers. The 31 optional addon-corpus tests skip because the vanilla addon/Quiver corpus is unavailable. Tests cover real ruRU roster rows including ghosts, Human/Warrior and Tauren/Druid creation headers, changing class-button labels, deletion text without deleting, English fallback, and cache rejection across enUS/ruRU. Windows only. No unattended game login was performed because this checkout has no declared probe account.
The client selects an installed Data/ruRU pack for assets, DBCs, Lua GetLocale, Cyrillic fonts and realmd locale. WOW_LOCALE supports auto, enUS and ruRU. Localize MoonWell options, menu, bindings and script log; preserve English reference loading and fallback. The deployment tool stages and validates the supplied ruRU archives without changing the install.
Rebased on main 97a92194, which integrates approved GitHub upstream c2fc3cf3. No conflicts were required for localization.
Windows validation on the exact final tree: scripts/gates.sh ALL GATES GREEN (2671 seconds), workspace tests with and without reference data, player build tests and engine boot checks. Russian FrameXML, captions, settings/search, Cyrillic font glyphs and locale challenge tests are included. 31 tests skipped only because the addon corpus is absent. No declared account for a live login; other platforms were not built. Game assets remain outside Git.
Update the fork to the approved upstream/main snapshot c2fc3cf3, including UI scale, load/reload lifecycle and visibility fixes. Preserve MoonWell integration and live-player seating during ReloadUI. MAP was regenerated.
Windows validation: all scripts/gates.sh gates green (2963 seconds), with and without vanilla data, player build tests and engine boot checks. 31 tests skipped only for the absent addon corpus. No declared account for live login; other platforms were not built.
Integrate the MoonWell launcher and deployment tooling on the local upstream baseline d0d1b5de. Correct the shipped icon path, regenerate the code map, and make source/Lua gates portable to Windows. Classify launcher startup icon access as input plumbing.
Verified on Windows: scripts/gates.sh ALL GATES GREEN; MoonWell release build without dev; 12 deployment tests; deployment and packaging script syntax. Stock MPQ chain excludes the custom patch-3. Thirty-one addon tests skip per data-enabled rung because the corpus is absent. Native macOS/Linux and live login smoke were not run; no declared test account is available.
With Click to Move on, benilla walked only to things you interact with. In 1.12.1 a right-click on the ground walks to the point (`0x5e0378` → `0x6102b0`, 0.5 yd short, speed-scaled, no leash, held in a deck's frame). A right-click on the sky with an empty cursor walks along the ray (`0x492dca` → `0x610100`), pitching while swimming. An attack on an enemy out of melee walks to where it stood (`0x60c22b` → `0x60fcc0`, mode 10): the stop is about 1.9 yd because the arm names the player's own guid, the radii are unscaled, and the 80 yd leash says ERR_AUTOFOLLOW_TOO_FAR. Inside melee the player turns to face it.
Deviations, each written where it lives: the melee point keeps the enemy's height, does not snap to the reference's fixed arrival heading, and rides the deck it was armed on.
Tests: the router, the steering, the gates, the leash and the deck frames.
Fixes#758
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Mathih13 <15229325+Mathih13@users.noreply.github.com>
Co-Authored-By: Sam <samuv.eth@gmail.com>
In 1.12.1 the `SMSG_LOOT_RESPONSE` handler selects a looted unit before it opens the window (`0x5ebc35` → `0x48f3a0`, SetSelection at `0x48f3be`). benilla opened the window without selecting it. So a Tab pressed during a Click-to-Move walk to a corpse left the Tab target selected when the loot opened.
The handler now admits the response and arms the latch, then selects a unit through the one SetSelection path, then opens the window. A refusal, a chest or an item selects nothing. SetSelection's re-swing now uses StartAttack's target gate (alive, then CanAttack, `0x5ecc16`), so switching to a body mid-swing never swings at it.
Tests: the handler's select, dedup, refusals, teardown order and swing stop, a hostile body looted mid-swing, and the stock TargetFrame naming the looted body.
Fixes#763
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>