1
0
mirror of https://github.com/vcmi/vcmi.git synced 2026-05-22 09:55:17 +02:00

Fixes for crashes in 1.7.4 beta

- Fixed crash in MP between 1.7.3 and 1.7.4 on opening exchange window
- Fixed crash if creature with area attack and death blow attacks empty
space (Magog in WoG)
- Fixed crash on formatting of spell effect preview text
- Fixed crash if hero has invalid path (e.g. blocked by another hero)
and player attempts to end turn
- Try to fix crash on opening battle-only mode in some cases(?)
This commit is contained in:
Ivan Savenko
2026-05-17 22:32:31 +03:00
parent 9907128e1d
commit de7bfcaa8d
10 changed files with 32 additions and 28 deletions
+1 -1
View File
@@ -35,7 +35,7 @@ android {
minSdk = qtMinSdkVersion as Integer
targetSdk = qtTargetSdkVersion as Integer // ANDROID_TARGET_SDK_VERSION in the CMake project
versionCode 1754
versionCode 1757
versionName "1.7.4"
}
+1 -1
View File
@@ -261,6 +261,6 @@ void ApplyOnLobbyScreenNetPackVisitor::visitLobbyShowMessage(LobbyShowMessage &
void ApplyOnLobbyScreenNetPackVisitor::visitLobbySetBattleOnlyModeStartInfo(LobbySetBattleOnlyModeStartInfo & pack)
{
if(lobby->tabBattleOnlyMode)
if(lobby && lobby->tabBattleOnlyMode)
lobby->tabBattleOnlyMode->applyStartInfo(pack.startInfo);
}
+3 -5
View File
@@ -84,12 +84,10 @@ void PlayerLocalState::erasePath(const CGHeroInstance * h)
synchronizeState();
}
bool PlayerLocalState::verifyPath(const CGHeroInstance * h)
void PlayerLocalState::verifyPath(const CGHeroInstance * h)
{
if(!hasPath(h))
return false;
setPath(h, getPath(h).endPos());
return true;
if (hasPath(h))
setPath(h, getPath(h).endPos());
}
SpellID PlayerLocalState::getCurrentSpell() const
+1 -1
View File
@@ -84,7 +84,7 @@ public:
void removeLastNode(const CGHeroInstance * h);
void erasePath(const CGHeroInstance * h);
bool verifyPath(const CGHeroInstance * h);
void verifyPath(const CGHeroInstance * h);
/// Returns currently selected object
const CGHeroInstance * getCurrentHero() const;
@@ -307,11 +307,12 @@ void AdventureMapShortcuts::endTurn()
{
if(!GAME->interface()->localState->isHeroSleeping(hero) && hero->movementPointsRemaining() > 0)
{
GAME->interface()->localState->verifyPath(hero);
// Only show hero reminder if conditions are met:
// - There are still movement points
// - Hero doesn't have a path or there are no points for the first step on path
if(!GAME->interface()->localState->verifyPath(hero))
// - Hero doesn't have a path or there are enough points for the first step on path
if(!GAME->interface()->localState->hasPath(hero))
{
showMoveReminderDialog();
return;
+8 -9
View File
@@ -135,16 +135,15 @@ static std::string formatRetaliation(const DamageEstimation & estimation, bool m
}
static std::string prepareSpellEffectText(int gnrlTextID, const spells::effects::SpellEffectValue & value,
std::string_view spellName, std::string_view targetName)
const std::string & spellName, const std::string & targetName)
{
auto const & templateText = LIBRARY->generaltexth->allTexts[gnrlTextID];
std::string baseText;
if(!targetName.empty() && !spellName.empty())
baseText = boost::str(boost::format(templateText) % spellName % targetName);
else if(targetName.empty())
baseText = boost::str(boost::format(templateText) % spellName);
else
baseText = boost::str(boost::format(templateText) % targetName);
auto templateText = MetaString::createFromTextID( "core.genrltxt." + std::to_string(gnrlTextID));
if (!spellName.empty())
templateText.replaceRawString(spellName);
if (!targetName.empty())
templateText.replaceRawString(targetName);
std::string baseText = templateText.toString();
if(value.unitsDelta > 0)
{
+7 -4
View File
@@ -614,10 +614,13 @@ void BattleStacksController::stackAttacking( const StackAttackInfo & info )
if(info.deathBlow)
{
owner.addToAnimationStage(EAnimationEvents::BEFORE_HIT, [this, defender, info]() {
owner.appendBattleLog(info.attacker->formatGeneralMessage(365));
owner.effectsController->displayEffect(EBattleEffect::DEATH_BLOW, AudioPath::builtin("DEATHBLO"), defender->getPosition());
});
if (defender)
{
owner.addToAnimationStage(EAnimationEvents::BEFORE_HIT, [this, defender, info]() {
owner.appendBattleLog(info.attacker->formatGeneralMessage(365));
owner.effectsController->displayEffect(EBattleEffect::DEATH_BLOW, AudioPath::builtin("DEATHBLO"), defender->getPosition());
});
}
for(auto elem : info.secondaryDefender)
{
+2 -2
View File
@@ -97,7 +97,7 @@ public:
auto * result = std::get_if<CustomType>(&data_);
if (result)
return *result;
throw std::runtime_error("Invalid addInfo type access!");
throw std::runtime_error("Invalid addInfo type access! Stored type: " + std::to_string(data_.index()));
}
template<typename CustomType>
@@ -106,7 +106,7 @@ public:
auto * result = std::get_if<CustomType>(&data_);
if (result)
return *result;
throw std::runtime_error("Invalid addInfo type access!");
throw std::runtime_error("Invalid addInfo type access! Stored type: " + std::to_string(data_.index()));
}
template <class H>
+2 -1
View File
@@ -1402,7 +1402,8 @@ struct DLL_LINKAGE GarrisonDialog : public Query
h & objid;
h & hid;
h & removableUnits;
h & customTitle;
if (h.hasFeature(Handler::Version::CUSTOM_GARRISON_TITLE))
h & customTitle;
}
};
+3 -1
View File
@@ -62,9 +62,11 @@ enum class ESerializationVersion : int32_t
DISABLE_TACTICS, // disable tactics
REWARDABLE_EXTENSIONS_2, // movement points limiter for rewardables
BONUS_TRIGGER, // bonus that allows triggered effects in combat
CUSTOM_GARRISON_TITLE, // GarrisonDialog pack now has custom title parameter
RELEASE_170 = HOTA_MAP_STACK_COUNT,
CURRENT = BONUS_TRIGGER,
RELEASE_174 = CUSTOM_GARRISON_TITLE,
CURRENT = CUSTOM_GARRISON_TITLE,
};
static_assert(ESerializationVersion::MINIMAL <= ESerializationVersion::CURRENT, "Invalid serialization version definition!");