When the clicked building has no upgrade chain (e.g. vanilla Rampart's
Mystic Pond), buildingClicked() passes the same BuildingID as both the
buildingToTest and buildingTarget arguments down to enterFountain().
The `upgrades != BuildingID::NONE` check then always passed, appending
the building's own description to itself.
Skip the extra append when `upgrades` points to the same building we're
already describing. When a mod actually upgrades Mystic Pond into a
separate building, the two IDs differ and the intended behavior of
showing both descriptions is preserved.
Fixes#7142
Fix two issues with the battleLogMessage feature:
1. Translation not working: string registration now happens in
CSpellHandler::loadFromJson (before translations are loaded)
instead of in Timed::serializeJsonUnitEffect (which runs in
afterLoadFinalization, after translations are already loaded).
The effect now only generates the text ID without registering.
2. Singular/plural support: battleLogMessage is now an object with
"singular" and "plural" fields for grammatically correct messages
based on stack size.
Example: { "singular": "The %s is petrified.",
"plural": "The %s are petrified." }
Values starting with @ reference an existing text ID instead of
registering a new string. Core spells now use @core.genrltxt.XXX
to reuse the original H3 translations directly.
Timed spell effects (core:timed) now support an optional
"battleLogMessage" field displayed in the battle log when the effect
is applied. The text should include a %s placeholder for the affected
creature's name.
The field contains the English text directly (same pattern as spell
name/description). A text ID for translation export is auto-generated
at load time as: spell.<scope>.<identifier>.<effectName>.battleLogMessage
String registration happens in the effect itself during deserialization
(Timed::serializeJsonUnitEffect), using spell scope, identifier, and
effect name passed down through the Effects loading chain.
This replaces the previously hardcoded battle log messages for stone
gaze, paralyze, poison, disease, and bind, which are now converted
from the old effects format to the new battleEffects format with
configurable messages. The age ability retains its hardcoded message
because it computes health loss at runtime.
Resolves: https://github.com/vcmi-mods/horn-of-the-abyss/issues/551
waitForServerShutdown() was blocking on serverRunner->wait() while
holding interfaceMutex, preventing the GUI thread from processing
events or rendering frames. This caused the highscore name entry
screen to freeze after winning a game.
Release interfaceMutex during the blocking wait using makeUnlockGuard,
matching the existing pattern in endNetwork().
Also fix [&] lambda capture in the highscore input callback to [this]
to avoid a dangling reference to a stack variable (cursorPosition).
Fixes cases where game would try to access file on real filesystem for
VCMI campaigns files that are actually located inside .zip archive.
Made search for other usages of last_write_time access, don't see any
other similar cases left