Adds a PlayerDataLoaded event, fired after classdat.tsv loads and before each
class's own data folder is read, plus player.addClassDataFromTsv(path), which
feeds the existing LoadClassDatFromFile. This matches the MonsterDataLoaded /
monsters.addMonsterDataFromTsv pattern. Several mods can each add classes
without overriding the shared classdat.tsv; the existing class limit still
applies.
No handler means no change: class data loads exactly as before.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The updated Amiga SDL2 fork builds an sdl2.library wrapper by default.
We link SDL2 statically so we do not need it, and it fails to link with
LTO enabled.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Start target search from wide bounds (rotations=4, distance=25) instead of 0
so the first candidate is always accepted and the closest target wins,
in FindRangedTarget/FindMeleeTarget/CheckPlayerNearby/FindTrigger.
With vcpkg on Windows, every executable and DLL gets a post-link step
that runs `vcpkg z-applocal` to copy its DLL dependencies next to it.
All the test binaries share the build directory, so dozens of these
steps ran alongside the links, and the build occasionally failed with
"The process cannot access the file because it is being used by another
process."
Turn off the per-target step for the test binaries and deploy their DLLs
in a single step once they are all linked.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The PCX specification requires the number of bytes per scanline to be
even. PCX screenshots of an odd width were written without padding,
and `PcxToClx` ignored the header's bytes-per-line value and assumed a
padding byte for odd widths. The screen width can be odd, e.g. 683 with
integer scaling on a 1366x768 display.
`PcxToClx` now:
* Decodes scanlines using the bytes-per-line value from the header, so
both padded and unpadded files (e.g. older DevilutionX screenshots)
are read correctly.
* Validates the input (truncated data, runs crossing a scanline, image
format, frame count) and returns an error message, which is logged,
instead of reading out of bounds. Previously, the palette separator
was only checked by an assertion.
* Reads the palette from the end of the file, as per the specification.
The screenshot writer now:
* Pads scanlines to an even length.
* No longer reads one byte past the end of each line.
* Compiles with SDL3, where the surface palette is obtained with
`SDL_GetSurfacePalette`.
* Returns an error for a surface without a palette (the default for
indexed surfaces in SDL3), and no longer reads past the end of a
palette with fewer than 256 colors.
The PCX files from DIABDAT.MPQ, HELLFIRE.MPQ, and the DevilutionX assets
are all padded correctly and load the same as before.
`surface_to_pcx` is now an object library so that it can be tested in
builds with PNG screenshots.
Ported from https://github.com/diasurgical/clx-conversion-tools/commit/4d4debd
Co-Authored-By: Claude Opus 5.5 <[email protected]>
`gtest_discover_tests` ran each test executable right after linking it
to list its tests. On Windows, the vcpkg toolchain also copies a test's
DLLs next to it after linking, into the same build directory for every
test. With many tests linking in parallel, a test could be running
while another's copy step tried to replace a DLL it had loaded, which
failed the build with "The process cannot access the file because it is
being used by another process."
With `DISCOVERY_MODE PRE_TEST`, the tests are listed when `ctest` runs
instead, after the build has finished.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Add FixedPoint::divideWithoutWidening for cases where the caller can
already show the wide intermediate isn't needed, and use it in
AnimationInfo::setNewAnimation to avoid a 64-bit division that the
original int32_t arithmetic never required.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Replaces ParseFixed6/parseFixed6/readFixed6/readDecimal's raw-int
plumbing with the new FixedPoint type, then propagates strongly-typed
fixed-point fields through everywhere that consumed them: player
_pHitPoints/_pMana (and their base/max variants), ClassAttributes'
percentage/multiplier fields, Item::_iPLHP/_iPLMana, and
Monster::hitPoints/maxHitPoints. Eliminates manual <<6/>>6 bit-shifting
at nearly every call site in favor of fromInt/fromRaw/whole() and the
new fixed-point arithmetic operators, while preserving raw() only at
genuine serialization/network wire-format boundaries.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
Introduces a strongly-typed wrapper for the 10.6 fixed-point values used
throughout the engine (e.g. hit points, mana), with Fixed10_6 (int16_t
storage) and Fixed26_6 (int32_t storage) aliases.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
In CLX, only transparent runs can continue on the next line.
`Cl2ToClx` joined the opaque pixels that end a line with the opaque
pixels that begin the next line into a single run, and the renderer
then drew the second part past the end of the first line instead of
at the beginning of the next one.
CL2 itself has no such runs. Among the player sprites of DIABDAT.MPQ,
the converter produced them in 991 of 78,016 frames (2,236 pixels),
mostly in spell casting animations that reach both edges of the frame.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
While a mouse button or controller action is held, the last action is
re-sent every game tick. This affects walking, melee attacks on targets
out of reach and operating objects the player isn't next to. If no path
to the target exists, each repeat runs two or three worst-case path
searches for the same result, which noticeably reduces FPS.
Add WalkabilityGeneration, bumped whenever tile solidity, objects or
the tiles occupied by monsters and players change. RepeatPlayerAction
remembers the last request that needed walking and skips an identical
one while the start tile, destination, generation and player life
states are unchanged. A request that finds a path moves the player, so
this only skips requests that failed or are still pending.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Added option to show summoned monster (Golem) party portrait
Fixed crash when loading .trn files for monsters with missing animations
(Golem is missing standing animation)
When calculating width of mana bars, if another player has a maximum amount of mana of zero (like a Barbarian) would cause a division by zero, crashing the rendering client. Fixed by not rendering the blue portion of the mana bar if the max mana is zero.
Not applying players palette transform, stored in a .trn file. Fixed by applying the trn to the stored portrait sprite, if available.
Created several values in the player classes sprites.tsv to store the offsets of the sprites rendered in the portrait. The new values are:
- **partyOffsetTownX** : X Offset for the portrait when the player is in town
- **partyOffsetTownY** : Y Offset for the portrait when the player is in town
- **partyOffsetDungeonX** : X Offset for the portrait when the player is in dungeon
- **partyOffsetDungeonY** : Y Offset for the portrait when the player is in dungeon
- **partyOffsetDeadX** : X Offset for the portrait when the player is dead
- **partyOffsetDeadY** : Y Offset for the portrait when the player is dead
This new values are documented in the assets/txtdata/classes/README.md file, with also the rest of the possible values for the sprites.tsv files