Skip to content

D2LoD Vanilla+0.0.7-R101

Pre-release
Pre-release

Choose a tag to compare

@VTSTech VTSTech released this 03 Nov 21:25
· 50 commits to main since this release
769bcac
image image image

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) log d3d: 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 R95 no_panel_shift
    neutralizer didn't cover — fixed in R100 (see below). R99 builds
    should not be used with no_panel_shift=1.
  • Sound-table gates re-pinned to upstream 1870 spellings; the sound-init hwnd
    fix superseded by upstream's 1870 BOOL parameter; texture-cache init
    branches realigned verbatim.
  • The merge was redone cleanly after a first pass broke the ui.cpp build;
    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_1
  • GfxUtil.cpp ×1 — unit COF direction
  • Text.cpp ×2 — monster/object hover text
  • ShowItems.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