From 21ea50ca1ee2ef4e2e4e8228f9051fde23feb525 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 28 Mar 2023 17:02:18 +0300 Subject: [PATCH 1/9] Check obstacle image for existance in schema --- config/schemas/obstacle.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/config/schemas/obstacle.json b/config/schemas/obstacle.json index 08e7a2e8c..66b204cc9 100644 --- a/config/schemas/obstacle.json +++ b/config/schemas/obstacle.json @@ -32,7 +32,11 @@ }, "animation": { "type": "string", - "description": "Image resource" + "description": "Image resource", + "anyOf" : [ + { "format" : "defFile" }, + { "format" : "imageFile" } + ] }, "unknown": { "type": "number", From ae242be180ebeaaac97485745843077d78ab2a44 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 28 Mar 2023 17:03:47 +0300 Subject: [PATCH 2/9] Fix indexing of wog experience ranks --- Mods/vcmi/config/vcmi/chinese.json | 22 +++++++++++----------- Mods/vcmi/config/vcmi/english.json | 22 +++++++++++----------- Mods/vcmi/config/vcmi/german.json | 22 +++++++++++----------- Mods/vcmi/config/vcmi/russian.json | 22 +++++++++++----------- Mods/vcmi/config/vcmi/spanish.json | 22 +++++++++++----------- Mods/vcmi/config/vcmi/ukrainian.json | 22 +++++++++++----------- 6 files changed, 66 insertions(+), 66 deletions(-) diff --git a/Mods/vcmi/config/vcmi/chinese.json b/Mods/vcmi/config/vcmi/chinese.json index 3135bd2c8..97944de27 100644 --- a/Mods/vcmi/config/vcmi/chinese.json +++ b/Mods/vcmi/config/vcmi/chinese.json @@ -118,17 +118,17 @@ // few strings from WoG used by vcmi "vcmi.stackExperience.description" : "» 经 验 获 得 明 细 «\n\n生物类型 ................... : %s\n经验等级 ................. : %s (%i)\n经验点数 ............... : %i\n下一个等级所需经验 .. : %i\n每次战斗最大获得经验 ... : %i%% (%i)\n获得经验的生物数量 .... : %i\n最大招募数量\n不会丢失经验升级 .... : %i\n经验倍数 ........... : %.2f\n升级倍数 .............. : %.2f\n10级后经验值 ........ : %i\n最大招募数量下\n 升级到10级所需经验数量: %i", - "vcmi.stackExperience.rank.1" : "新兵 1级", - "vcmi.stackExperience.rank.2" : "列兵 2级", - "vcmi.stackExperience.rank.3" : "下士 3级", - "vcmi.stackExperience.rank.4" : "中士 4级", - "vcmi.stackExperience.rank.5" : "上士 5级", - "vcmi.stackExperience.rank.6" : "少尉 6级", - "vcmi.stackExperience.rank.7" : "中尉 7级", - "vcmi.stackExperience.rank.8" : "上尉 8级", - "vcmi.stackExperience.rank.9" : "少校 9级", - "vcmi.stackExperience.rank.10" : "中校 10级", - "vcmi.stackExperience.rank.11" : "上校 11级", + "vcmi.stackExperience.rank.0" : "新兵 1级", + "vcmi.stackExperience.rank.1" : "列兵 2级", + "vcmi.stackExperience.rank.2" : "下士 3级", + "vcmi.stackExperience.rank.3" : "中士 4级", + "vcmi.stackExperience.rank.4" : "上士 5级", + "vcmi.stackExperience.rank.5" : "少尉 6级", + "vcmi.stackExperience.rank.6" : "中尉 7级", + "vcmi.stackExperience.rank.7" : "上尉 8级", + "vcmi.stackExperience.rank.8" : "少校 9级", + "vcmi.stackExperience.rank.9" : "中校 10级", + "vcmi.stackExperience.rank.10" : "上校 11级", "core.bonus.ADDITIONAL_ATTACK.name": "双击", "core.bonus.ADDITIONAL_ATTACK.description": "可以攻击两次", diff --git a/Mods/vcmi/config/vcmi/english.json b/Mods/vcmi/config/vcmi/english.json index 68b0c81ee..be1276f7d 100644 --- a/Mods/vcmi/config/vcmi/english.json +++ b/Mods/vcmi/config/vcmi/english.json @@ -143,17 +143,17 @@ // few strings from WoG used by vcmi "vcmi.stackExperience.description" : "» S t a c k E x p e r i e n c e D e t a i l s «\n\nCreature Type ................... : %s\nExperience Rank ................. : %s (%i)\nExperience Points ............... : %i\nExperience Points to Next Rank .. : %i\nMaximum Experience per Battle ... : %i%% (%i)\nNumber of Creatures in stack .... : %i\nMaximum New Recruits\n without losing current Rank .... : %i\nExperience Multiplier ........... : %.2f\nUpgrade Multiplier .............. : %.2f\nExperience after Rank 10 ........ : %i\nMaximum New Recruits to remain at\n Rank 10 if at Maximum Experience : %i", - "vcmi.stackExperience.rank.1" : "Basic", - "vcmi.stackExperience.rank.2" : "Novice", - "vcmi.stackExperience.rank.3" : "Trained", - "vcmi.stackExperience.rank.4" : "Skilled", - "vcmi.stackExperience.rank.5" : "Proven", - "vcmi.stackExperience.rank.6" : "Veteran", - "vcmi.stackExperience.rank.7" : "Adept", - "vcmi.stackExperience.rank.8" : "Expert", - "vcmi.stackExperience.rank.9" : "Elite", - "vcmi.stackExperience.rank.10" : "Master", - "vcmi.stackExperience.rank.11" : "Ace", + "vcmi.stackExperience.rank.0" : "Basic", + "vcmi.stackExperience.rank.1" : "Novice", + "vcmi.stackExperience.rank.2" : "Trained", + "vcmi.stackExperience.rank.3" : "Skilled", + "vcmi.stackExperience.rank.4" : "Proven", + "vcmi.stackExperience.rank.5" : "Veteran", + "vcmi.stackExperience.rank.6" : "Adept", + "vcmi.stackExperience.rank.7" : "Expert", + "vcmi.stackExperience.rank.8" : "Elite", + "vcmi.stackExperience.rank.9" : "Master", + "vcmi.stackExperience.rank.10" : "Ace", "core.bonus.ADDITIONAL_ATTACK.name": "Double Strike", "core.bonus.ADDITIONAL_ATTACK.description": "Attacks twice", diff --git a/Mods/vcmi/config/vcmi/german.json b/Mods/vcmi/config/vcmi/german.json index 9c53ac960..f1d02efcf 100644 --- a/Mods/vcmi/config/vcmi/german.json +++ b/Mods/vcmi/config/vcmi/german.json @@ -128,17 +128,17 @@ // few strings from WoG used by vcmi "vcmi.stackExperience.description" : "» D e t a i l s z u r S t a p e l e r f a h r u n g «\n\nKreatur-Typ ................... : %s\nErfahrungsrang ................. : %s (%i)\nErfahrungspunkte ............... : %i\nErfahrungspunkte für den nächsten Rang .. : %i\nMaximale Erfahrung pro Kampf ... : %i%% (%i)\nAnzahl der Kreaturen im Stapel .... : %i\nMaximale Anzahl neuer Rekruten\n ohne Verlust von aktuellem Rang .... : %i\nErfahrungs-Multiplikator ........... : %.2f\nUpgrade-Multiplikator .............. : %.2f\nErfahrung nach Rang 10 ........ : %i\nMaximale Anzahl der neuen Rekruten, die bei\n Rang 10 bei maximaler Erfahrung übrig sind : %i", - "vcmi.stackExperience.rank.1" : "Grundlagen", - "vcmi.stackExperience.rank.2" : "Neuling", - "vcmi.stackExperience.rank.3" : "Ausgebildet", - "vcmi.stackExperience.rank.4" : "Kompetent", - "vcmi.stackExperience.rank.5" : "Bewährt", - "vcmi.stackExperience.rank.6" : "Veteran", - "vcmi.stackExperience.rank.7" : "Gekonnt", - "vcmi.stackExperience.rank.8" : "Experte", - "vcmi.stackExperience.rank.9" : "Elite", - "vcmi.stackExperience.rank.10" : "Meister", - "vcmi.stackExperience.rank.11" : "Ass", + "vcmi.stackExperience.rank.0" : "Grundlagen", + "vcmi.stackExperience.rank.1" : "Neuling", + "vcmi.stackExperience.rank.2" : "Ausgebildet", + "vcmi.stackExperience.rank.3" : "Kompetent", + "vcmi.stackExperience.rank.4" : "Bewährt", + "vcmi.stackExperience.rank.5" : "Veteran", + "vcmi.stackExperience.rank.6" : "Gekonnt", + "vcmi.stackExperience.rank.7" : "Experte", + "vcmi.stackExperience.rank.8" : "Elite", + "vcmi.stackExperience.rank.9" : "Meister", + "vcmi.stackExperience.rank.10" : "Ass", "core.bonus.ADDITIONAL_ATTACK.name": "Doppelschlag", "core.bonus.ADDITIONAL_ATTACK.description": "Greift zweimal an", diff --git a/Mods/vcmi/config/vcmi/russian.json b/Mods/vcmi/config/vcmi/russian.json index c6bd0cae7..92b5a8f6b 100644 --- a/Mods/vcmi/config/vcmi/russian.json +++ b/Mods/vcmi/config/vcmi/russian.json @@ -145,17 +145,17 @@ // few strings from WoG used by vcmi "vcmi.stackExperience.description" : "» О п ы т с у щ е с т в «\n\nТип существа ................... : %s\nРанг опыта ................. : %s (%i)\nОчки опыта ............... : %i\nДо следующего .. : %i\nМаксимум за битву ... : %i%% (%i)\nЧисло в отряде .... : %i\nМаксимум новичков\n без потери ранга .... : %i\nМножитель опыта ........... : %.2f\nМножитель улучшения .......... : %.2f\nОпыт после 10 ранга ........ : %i\nМаксимум новичков для сохранения\n ранга 10 при максимальном опыте : %i", - "vcmi.stackExperience.rank.1" : "Рекрут", - "vcmi.stackExperience.rank.2" : "Новичок", - "vcmi.stackExperience.rank.3" : "Тренирован", - "vcmi.stackExperience.rank.4" : "Знающий", - "vcmi.stackExperience.rank.5" : "Подтвержденный", - "vcmi.stackExperience.rank.6" : "Ветеран", - "vcmi.stackExperience.rank.7" : "Адепт", - "vcmi.stackExperience.rank.8" : "Эксперт", - "vcmi.stackExperience.rank.9" : "Элита", - "vcmi.stackExperience.rank.10" : "Мастер", - "vcmi.stackExperience.rank.11" : "Ас", + "vcmi.stackExperience.rank.0" : "Рекрут", + "vcmi.stackExperience.rank.1" : "Новичок", + "vcmi.stackExperience.rank.2" : "Тренирован", + "vcmi.stackExperience.rank.3" : "Знающий", + "vcmi.stackExperience.rank.4" : "Подтвержденный", + "vcmi.stackExperience.rank.5" : "Ветеран", + "vcmi.stackExperience.rank.6" : "Адепт", + "vcmi.stackExperience.rank.7" : "Эксперт", + "vcmi.stackExperience.rank.8" : "Элита", + "vcmi.stackExperience.rank.9" : "Мастер", + "vcmi.stackExperience.rank.10" : "Ас", "core.bonus.ADDITIONAL_ATTACK.name": "Двойной удар", "core.bonus.ADDITIONAL_ATTACK.description": "Бьет дважды", diff --git a/Mods/vcmi/config/vcmi/spanish.json b/Mods/vcmi/config/vcmi/spanish.json index 312a90254..429617329 100644 --- a/Mods/vcmi/config/vcmi/spanish.json +++ b/Mods/vcmi/config/vcmi/spanish.json @@ -131,17 +131,17 @@ // few strings from WoG used by vcmi "vcmi.stackExperience.description" : "» D e t a l l e s d e E x p e r i e n c i a d e l G r u p o «\n\nTipo de Criatura ................ : %s\nRango de Experiencia ............ : %s (%i)\nPuntos de Experiencia ............ : %i\nPuntos de Experiencia para el\nSiguiente Rango ............... : %i\nExperiencia Máxima por Batalla .. : %i%% (%i)\nNúmero de Criaturas en el grupo .. : %i\nMáximo de Nuevos Reclutas sin\nPerder el Rango Actual ......... : %i\nMultiplicador de Experiencia .... : %.2f\nMultiplicador de Actualización .. : %.2f\nExperiencia después del Rango 10 : %i\nMáximo de Nuevos Reclutas para\nMantener el Rango 10 si\nEstá en la Experiencia Máxima : %i", - "vcmi.stackExperience.rank.1" : "Básico", - "vcmi.stackExperience.rank.2" : "Novato", - "vcmi.stackExperience.rank.3" : "Entrenado", - "vcmi.stackExperience.rank.4" : "Hábil", - "vcmi.stackExperience.rank.5" : "Probado", - "vcmi.stackExperience.rank.6" : "Veterano", - "vcmi.stackExperience.rank.7" : "Experto", - "vcmi.stackExperience.rank.8" : "Experto Superior", - "vcmi.stackExperience.rank.9" : "Élite", - "vcmi.stackExperience.rank.10" : "Maestro", - "vcmi.stackExperience.rank.11" : "As", + "vcmi.stackExperience.rank.0" : "Básico", + "vcmi.stackExperience.rank.1" : "Novato", + "vcmi.stackExperience.rank.2" : "Entrenado", + "vcmi.stackExperience.rank.3" : "Hábil", + "vcmi.stackExperience.rank.4" : "Probado", + "vcmi.stackExperience.rank.5" : "Veterano", + "vcmi.stackExperience.rank.6" : "Experto", + "vcmi.stackExperience.rank.7" : "Experto Superior", + "vcmi.stackExperience.rank.8" : "Élite", + "vcmi.stackExperience.rank.9" : "Maestro", + "vcmi.stackExperience.rank.10" : "As", "core.bonus.ADDITIONAL_ATTACK.name": "Doble Ataque", "core.bonus.ADDITIONAL_ATTACK.description": "Ataca dos veces", diff --git a/Mods/vcmi/config/vcmi/ukrainian.json b/Mods/vcmi/config/vcmi/ukrainian.json index 758bb53b8..f1d3d00f8 100644 --- a/Mods/vcmi/config/vcmi/ukrainian.json +++ b/Mods/vcmi/config/vcmi/ukrainian.json @@ -295,15 +295,15 @@ "core.bonus.LIMITED_SHOOTING_RANGE.description" : "Не може стріляти по цілях на відстані більше ${val} гексів", "vcmi.stackExperience.description" : "» S t a c k E x p e r i e n c e D e t a i l s «\n\nCreature Type ................... : %s\nExperience Rank ................. : %s (%i)\nExperience Points ............... : %i\nExperience Points to Next Rank .. : %i\nMaximum Experience per Battle ... : %i%% (%i)\nNumber of Creatures in stack .... : %i\nMaximum New Recruits\n without losing current Rank .... : %i\nExperience Multiplier ........... : %.2f\nUpgrade Multiplier .............. : %.2f\nExperience after Rank 10 ........ : %i\nMaximum New Recruits to remain at\n Rank 10 if at Maximum Experience : %i", - "vcmi.stackExperience.rank.1" : "Початковий", - "vcmi.stackExperience.rank.2" : "Новачок", - "vcmi.stackExperience.rank.3" : "Підготовлений", - "vcmi.stackExperience.rank.4" : "Досвідчений", - "vcmi.stackExperience.rank.5" : "Випробуваний", - "vcmi.stackExperience.rank.6" : "Ветеран", - "vcmi.stackExperience.rank.7" : "Адепт", - "vcmi.stackExperience.rank.8" : "Експерт", - "vcmi.stackExperience.rank.9" : "Еліта", - "vcmi.stackExperience.rank.10" : "Майстер", - "vcmi.stackExperience.rank.11" : "Профі", + "vcmi.stackExperience.rank.0" : "Початковий", + "vcmi.stackExperience.rank.1" : "Новачок", + "vcmi.stackExperience.rank.2" : "Підготовлений", + "vcmi.stackExperience.rank.3" : "Досвідчений", + "vcmi.stackExperience.rank.4" : "Випробуваний", + "vcmi.stackExperience.rank.5" : "Ветеран", + "vcmi.stackExperience.rank.6" : "Адепт", + "vcmi.stackExperience.rank.7" : "Експерт", + "vcmi.stackExperience.rank.8" : "Еліта", + "vcmi.stackExperience.rank.9" : "Майстер", + "vcmi.stackExperience.rank.10" : "Профі", } From fd3f80e86017b7a6d8942d00bcd596c54a0e1ccc Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 28 Mar 2023 17:04:18 +0300 Subject: [PATCH 3/9] Fix game hang on invalid shooter animation config --- client/battle/BattleAnimationClasses.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/client/battle/BattleAnimationClasses.cpp b/client/battle/BattleAnimationClasses.cpp index 30f1eb2b7..96ffffbd4 100644 --- a/client/battle/BattleAnimationClasses.cpp +++ b/client/battle/BattleAnimationClasses.cpp @@ -756,7 +756,15 @@ void ShootingAnimation::createProjectile(const Point & from, const Point & dest) uint32_t ShootingAnimation::getAttackClimaxFrame() const { const CCreature *shooterInfo = getCreature(); - return shooterInfo->animation.attackClimaxFrame; + + uint32_t maxFrames = stackAnimation(attackingStack)->framesInGroup(getGroup()); + uint32_t climaxFrame = shooterInfo->animation.attackClimaxFrame; + uint32_t selectedFrame = vstd::clamp(shooterInfo->animation.attackClimaxFrame, 1, maxFrames); + + if (climaxFrame != selectedFrame) + logGlobal->warn("Shooter %s has ranged attack climax frame set to %d, but only %d available!", shooterInfo->getNamePluralTranslated(), climaxFrame, maxFrames); + + return selectedFrame - 1; // H3 counts frames from 1 } ECreatureAnimType ShootingAnimation::getUpwardsGroup() const From 47e774897d19fb09980c6fd5544d6ac5e24c2376 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 28 Mar 2023 17:36:46 +0300 Subject: [PATCH 4/9] Show simple message on left-clicking empty buildings --- client/windows/CCastleInterface.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/client/windows/CCastleInterface.cpp b/client/windows/CCastleInterface.cpp index 63030010a..332bc5544 100644 --- a/client/windows/CCastleInterface.cpp +++ b/client/windows/CCastleInterface.cpp @@ -727,6 +727,7 @@ void CCastleBuildings::buildingClicked(BuildingID building, BuildingSubID::EBuil switch(subID) { case BuildingSubID::NONE: + enterBuilding(building); break; case BuildingSubID::MYSTIC_POND: From 238de8a5d7fbeb71f7e2b9e0939b3bae2f33685d Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 28 Mar 2023 18:14:09 +0300 Subject: [PATCH 5/9] Properly disable combat panel during spell targeting --- client/battle/BattleActionsController.cpp | 5 +++++ client/battle/BattleWindow.cpp | 7 ++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/client/battle/BattleActionsController.cpp b/client/battle/BattleActionsController.cpp index 6d86edb31..b4566fc7f 100644 --- a/client/battle/BattleActionsController.cpp +++ b/client/battle/BattleActionsController.cpp @@ -119,7 +119,10 @@ BattleActionsController::BattleActionsController(BattleInterface & owner): void BattleActionsController::endCastingSpell() { if(heroSpellToCast) + { heroSpellToCast.reset(); + owner.windowObject->blockUI(false); + } if(owner.stacksController->getActiveStack()) possibleActions = getPossibleActionsForStack(owner.stacksController->getActiveStack()); //restore actions after they were cleared @@ -287,6 +290,8 @@ void BattleActionsController::castThisSpell(SpellID spellID) possibleActions.push_back (spellSelMode); //only this one action can be performed at the moment GH.fakeMouseMove();//update cursor } + + owner.windowObject->blockUI(true); } const CSpell * BattleActionsController::getHeroSpellToCast( ) const diff --git a/client/battle/BattleWindow.cpp b/client/battle/BattleWindow.cpp index f8270ec15..b9d308764 100644 --- a/client/battle/BattleWindow.cpp +++ b/client/battle/BattleWindow.cpp @@ -541,11 +541,8 @@ void BattleWindow::blockUI(bool on) w->block(on || owner.tacticsMode); if(auto w = widget("alternativeAction")) w->block(on || owner.tacticsMode); - - // block only if during enemy turn and auto-fight is off - // otherwise - crash on accessing non-exisiting active stack - if(auto w = widget("options")) - w->block(!owner.curInt->isAutoFightOn && !owner.stacksController->getActiveStack()); + if(auto w = widget("autofight")) + w->block(owner.actionsController->spellcastingModeActive()); auto btactEnd = widget("tacticEnd"); auto btactNext = widget("tacticNext"); From 9062d67f80c7d23d0462a420914c79fafd4e29a4 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 28 Mar 2023 18:56:44 +0300 Subject: [PATCH 6/9] Fixed volume of ambient sounds --- client/CMusicHandler.cpp | 55 ++++++++++++++++++++++++++++++---------- client/CMusicHandler.h | 3 +++ 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/client/CMusicHandler.cpp b/client/CMusicHandler.cpp index 4acc87d98..f15ad9c3f 100644 --- a/client/CMusicHandler.cpp +++ b/client/CMusicHandler.cpp @@ -142,11 +142,13 @@ Mix_Chunk *CSoundHandler::GetSoundChunk(std::string &sound, bool cache) int CSoundHandler::ambientDistToVolume(int distance) const { - if(distance >= ambientConfig["distances"].Vector().size()) + const auto & distancesVector = ambientConfig["distances"].Vector(); + + if(distance >= distancesVector.size()) return 0; - int volume = static_cast(ambientConfig["distances"].Vector()[distance].Integer()); - return volume * (int)ambientConfig["volume"].Integer() * getVolume() / 10000; + int volume = static_cast(distancesVector[distance].Integer()); + return volume * (int)ambientConfig["volume"].Integer() / 100; } void CSoundHandler::ambientStopSound(std::string soundId) @@ -211,7 +213,20 @@ void CSoundHandler::setVolume(ui32 percent) CAudioBase::setVolume(percent); if (initialized) + { setChannelVolume(-1, volume); + + for (auto const & channel : channelVolumes) + updateChannelVolume(channel.first); + } +} + +void CSoundHandler::updateChannelVolume(int channel) +{ + if (channelVolumes.count(channel)) + setChannelVolume(channel, getVolume() * channelVolumes[channel] / 100); + else + setChannelVolume(channel, getVolume()); } // Sets the sound volume, from 0 (mute) to 100 @@ -258,29 +273,40 @@ void CSoundHandler::ambientUpdateChannels(std::map soundsArg) std::vector stoppedSounds; for(auto & pair : ambientChannels) { - if(!vstd::contains(soundsArg, pair.first)) + const std::string & soundId = pair.first; + const int channel = pair.second; + + if(!vstd::contains(soundsArg, soundId)) { - ambientStopSound(pair.first); - stoppedSounds.push_back(pair.first); + ambientStopSound(soundId); + stoppedSounds.push_back(soundId); } else { - int volume = ambientDistToVolume(soundsArg[pair.first]); - CCS->soundh->setChannelVolume(pair.second, volume); + int volume = ambientDistToVolume(soundsArg[soundId]); + channelVolumes[channel] = volume; + updateChannelVolume(channel); } } for(auto soundId : stoppedSounds) + { + channelVolumes.erase(ambientChannels[soundId]); ambientChannels.erase(soundId); + } for(auto & pair : soundsArg) { - if(!vstd::contains(ambientChannels, pair.first)) - { - int channel = CCS->soundh->playSound(pair.first, -1); - int volume = ambientDistToVolume(pair.second); + const std::string & soundId = pair.first; + const int distance = pair.second; - CCS->soundh->setChannelVolume(channel, volume); - CCS->soundh->ambientChannels.insert(std::make_pair(pair.first, channel)); + if(!vstd::contains(ambientChannels, soundId)) + { + int channel = playSound(soundId, -1); + int volume = ambientDistToVolume(distance); + channelVolumes[channel] = volume; + + updateChannelVolume(channel); + ambientChannels[soundId] = channel; } } } @@ -293,6 +319,7 @@ void CSoundHandler::ambientStopAllChannels() { ambientStopSound(ch.first); } + channelVolumes.clear(); ambientChannels.clear(); } diff --git a/client/CMusicHandler.h b/client/CMusicHandler.h index 5d3319052..9c909c347 100644 --- a/client/CMusicHandler.h +++ b/client/CMusicHandler.h @@ -51,9 +51,12 @@ private: int ambientDistToVolume(int distance) const; void ambientStopSound(std::string soundId); + void updateChannelVolume(int channel); const JsonNode ambientConfig; + std::map ambientChannels; + std::map channelVolumes; public: CSoundHandler(); From 6d04c0b4db5d54519340f7394b3370e6bb8c22ed Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 28 Mar 2023 18:58:30 +0300 Subject: [PATCH 7/9] Fix affinities of Dungeon heroes --- config/heroClasses.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/heroClasses.json b/config/heroClasses.json index 103931da2..cf4f65d01 100644 --- a/config/heroClasses.json +++ b/config/heroClasses.json @@ -104,7 +104,7 @@ "index": 10, "faction" : "dungeon", "defaultTavern" : 5, - "affinity" : "might", + "affinity" : "magic", "commander" : "medusaQueen", "mapObject" : { "templates" : { "default" : { "animation" : "AH11_.def", "editorAnimation": "AH11_E.def" } } }, "animation": { "battle" : { "male" : "CH010.DEF", "female" : "CH11.DEF" } } @@ -114,7 +114,7 @@ "index": 11, "faction" : "dungeon", "defaultTavern" : 5, - "affinity" : "magic", + "affinity" : "might", "commander" : "medusaQueen", "mapObject" : { "templates" : { "default" : { "animation" : "AH10_.def", "editorAnimation": "AH10_E.def" } } }, "animation": { "battle" : { "male" : "CH010.DEF", "female" : "CH11.DEF" } } From be52d46981065275e2724b910510f0d15d39b631 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 28 Mar 2023 19:05:38 +0300 Subject: [PATCH 8/9] Fix Whirlpool sounds --- config/objects/generic.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/objects/generic.json b/config/objects/generic.json index 5ec2d8c49..9838ef0ba 100644 --- a/config/objects/generic.json +++ b/config/objects/generic.json @@ -215,7 +215,7 @@ "handler" : "whirlpool", "base" : { "sounds" : { - "ambient" : ["LOOPWHIRL"], + "ambient" : ["LOOPWHIR"], "visit" : ["DANGER"] } }, From 0c7dae09136209f8713f4b34b4882fbfc07d25f2 Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Tue, 28 Mar 2023 19:12:35 +0300 Subject: [PATCH 9/9] Allow formation change while in hero exchange query --- server/CQuery.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/server/CQuery.cpp b/server/CQuery.cpp index a9849ba4c..cdfd90527 100644 --- a/server/CQuery.cpp +++ b/server/CQuery.cpp @@ -380,6 +380,9 @@ bool CGarrisonDialogQuery::blocksPack(const CPack * pack) const if(auto upgrade = dynamic_ptr_cast(pack)) return !vstd::contains(ourIds, upgrade->id); + if(auto formation = dynamic_ptr_cast(pack)) + return !vstd::contains(ourIds, formation->hid); + return CDialogQuery::blocksPack(pack); }