Repository navigation
D2LoD Vanilla+0.0.7-R101
Pre-release
Release Notes — Vanilla+ working rounds R98 → R101
Four rounds, one storyline: issue #26 (no_panel_shift) goes from
"perspective toggle dies in D3D" to "fixed, field-proven, and toggleable
in-game." All four rounds carry the 0.0.7 build line — no new ini keys
anywhere, existing d2vp.ini files stay valid as-is.
| Round | Self-ID | Date | One-liner |
|---|---|---|---|
| R98 | Vanilla+0.0.7-R98 |
2026-11-03 | D3D perspective-toggle death: root cause fixed |
| R99 | Vanilla+0.0.7-R99 |
2026-11-03 | Upstream sync (Ghidra 1864–1877 library rounds) |
| R100 | Vanilla+0.0.7-R100 |
2026-11-04 | Unit-sprite pan regression from the R99 merge — fixed |
| R101 | Vanilla+0.0.7-R101 |
2026-11-04 | no_panel_shift toggle added to the Vanilla+ Options panel |
Skip straight to R101 if you are upgrading from anything older — it
contains everything above.
Vanilla+0.0.7-R98 — D3D perspective-toggle death: root cause fixed
Issue #26 round 7. The R97 instrumentation guard fired on its first field
pass, and the log it produced was the smoking gun the probe rows were built
to catch:
d3d: subtile promote out-of-range idx=4097 max=1536 ... healed to uncached [R97]
VEH: fatal exception 0xC0000005 / AV READ at FF600060
What was actually wrong
The D3D flat-wall builder (RENDERER_D3D_BuildWallTileVerticesNoPerspective)
walks its subtile array by byte offset, and the decompiler had typed that
iterator uint8_t — every sibling iterator in the tree is a full-width
int. Accumulating 0x14 per record, it wraps at 256: from the 13th subtile
on, the loop reads the real array shifted +4 bytes. The fake records
explain both artifacts precisely — idx=4097 = 0x1001 is a DT1 wFormat
word mistaken for a cache index (the same word that halted line=200 in R96),
and FF600060 is a wall subtile's {nOffsetY=-160, nOffsetX=+96} pair
mistaken for a pixel pointer. Latent since the original decompilation; it
only ever fired on the first flat-wall frame after a perspective 1 → 0 flip,
which is why D3D sessions that never toggled lived.
Fixed
- The byte-offset iterator is now
int— real records at any subtile count.
This also kills the silent wrong-record class the wrap could produce
(wrong-textured quads that never crashed). - The R97 promote guards stay verbatim as defense in depth.
- New confirmation probe: tiles with > 12 subtiles (the exact wrap
population) logd3d: flat wall subtiles=<n> [R98], first 8 per session.
Verification
SMOKE §L item 48: in D3D, toggle Perspective both directions — no death, no
healed to uncached marks; a few flat wall subtiles= marks are the
expected confirmation data. Then finish the #26 D3D matrix (items 41–45).
Vanilla+0.0.7-R99 — upstream sync (Ghidra 1864–1877 library rounds)
The periodic upstream alignment, done as one merge round: upstream
088c4ee3..94ec239d (one-TU globals made static, 48 functions re-filed into
their source files, msvc8 evidence at 6,478 functions / 20.66% of bytes).
209 files changed, +12,860 / −13,350 — net 490 lines out of the tree.
Highlights relevant to Vanilla+:
- Retail bodies landed for the unit-sprite draw path (
DRAW_WORLD_Unit_1,
GFX_DrawUnitSelectionShape, …) among the Ghidra 1864–1877 library rounds.
⚠️ Known follow-up: these retail bodies re-armed the vanilla ±quarter
sprite pan in the perspective branch, which the R95no_panel_shift
neutralizer didn't cover — fixed in R100 (see below). R99 builds
should not be used withno_panel_shift=1. - Sound-table gates re-pinned to upstream 1870 spellings; the sound-init hwnd
fix superseded by upstream's 1870BOOLparameter; texture-cache init
branches realigned verbatim. - The merge was redone cleanly after a first pass broke the
ui.cppbuild;
the shipped merge (18838a8b) compiles and all gates are green.
Vanilla+0.0.7-R100 — unit-sprite pan regression fixed (issue #26 round 8)
Field report: "clean build successful. no_panel_shift is still missing. with
it set to 0 shifts normally, when set to 1, player, npc, campfire get pushed
into wrong locations."
Decode
Exactly the three unit classes — players, monsters, objects — riding the
path the R99 merge re-armed. The R95 feature covered every terrain pass
(floor/wall/roof/shadow, weather, automap) with the
PANELSHIFT_BorderForWorld neutralizer, but the pre-1864 unit copies had no
border handling at all (they rode the view rect, already fixed). The new
retail bodies compute sprite screen-x the vanilla way in the perspective
branch: AdjustPerspectivePosition + a hand-applied ±quarter pan keyed on
the real window border. So with no_panel_shift=1 the world stayed at the
border-0 camera while units — and everything anchored to them — panned one
quarter sideways. no_panel_shift=0 was never affected (there the sprite pan
matches the world pan).
Fixed
All 14 unit-anchored world-render consumers now read the border through
PANELSHIFT_BorderForWorld:
Gfx.cpp×7 — unit sprites, state overlays, shadows, colored/selection
shapes,DRAW_WORLD_Unit_1GfxUtil.cpp×1 — unit COF directionText.cpp×2 — monster/object hover textShowItems.cpp×1 — ground-item label anchor (label culling keeps the
real border, per charter)ui.cpp×3 — mercenary HP bar, player name plates, unit/warp tooltip anchor
UI/interaction consumers (panel click rects, hit tests, mouse warps) keep the
real border by charter; no_panel_shift=0 behavior is byte-identical to
before. 5 new gates pin every call-site count — suite 377/377.
Verification
SMOKE items 41a/41b. Owner-confirmed on the field build:
"no_panel_shift is working as intended now."
Vanilla+0.0.7-R101 — the Options-panel toggle (issue #26 round 9)
Field ask: "Great job, no_panel_shift is working as intended now. Let's add
the toggle to the Vanilla+ Options panel."
What's new
Esc → Options → Vanilla+ Options grows a seventh row — No Panel World
Shift — wired exactly like the existing rows: one entry in the row table
riding the same ini read/write bridge. Nothing else needed touching: the
write bridge already flushes the PANELSHIFT gate cache, so the flip applies
the same frame — the world stays put the moment you flip On, and slides
again the moment you flip Off. No ini edit needed, ever; your existing
[features] no_panel_shift key is read and shown as-is.
Layout
Seven rows overflowed the R67 page geometry (row 7 would have overlapped
Previous Menu by 6 px), so the Previous Menu row moved down one pitch
(0x124 → 0x144): same spacing, still inside the panel box, and
hit-test/hover/draw all move in step via the shared row-geometry helper.
As documented on the ini template since the feature shipped: the feature is
wide-layout only (1280x720 / 1344x700). At 640x480 / 800x600 the row
flips the key but the vanilla slide is kept by design. no_panel_shift=0
behavior unchanged everywhere. Gates 380/380 (3 new).
Verification
SMOKE item 2 now includes the panel round trip: toggle On → open the
character screen at 1280x720 → world stays put (units included); toggle Off →
world slides again.
Full Changelog: R98...R101