diff --git a/ChangeLog.md b/ChangeLog.md index bf895d923..7c7a93454 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,3 +1,13 @@ +# 1.5.4 -> 1.5.5 + +* Fixed crash when advancing to the next scenario in campaigns when the hero not transferring has a combination artefact that can be transferred to the next scenario. +* Fixed game not updating information such as hero path and current music on new day +* Changed default battle queue hotkey from Q to Z to match HD Mod / HotA +* Changed default hotkey for finishing battle with quick combat from E to Z to match HD Mod / HotA +* Creature casting now uses both F and G keyboard hotkeys +* Shift+left click now directly opens the hero window when two heroes are in town +* Fixed handling of alternative actions for creatures that have more than two potential actions, such as move, shoot, and cast spells. + # 1.5.3 -> 1.5.4 ### Stability diff --git a/Mods/vcmi/config/vcmi/portuguese.json b/Mods/vcmi/config/vcmi/portuguese.json index 4405870fc..0e5391e17 100644 --- a/Mods/vcmi/config/vcmi/portuguese.json +++ b/Mods/vcmi/config/vcmi/portuguese.json @@ -33,7 +33,7 @@ "vcmi.heroOverview.startingArmy" : "Unidades Iniciais", "vcmi.heroOverview.warMachine" : "Máquinas de Guerra", - "vcmi.heroOverview.secondarySkills" : "Habilidades Secundárias", + "vcmi.heroOverview.secondarySkills" : "Habilid. Secundárias", "vcmi.heroOverview.spells" : "Feitiços", "vcmi.radialWheel.mergeSameUnit" : "Mesclar criaturas iguais", @@ -259,7 +259,7 @@ "vcmi.battleWindow.damageRetaliation.damage" : "(%DAMAGE).", "vcmi.battleWindow.damageRetaliation.damageKills" : "(%DAMAGE, %KILLS).", - "vcmi.battleWindow.killed" : "Eliminados", + "vcmi.battleWindow.killed" : "Mortos", "vcmi.battleWindow.accurateShot.resultDescription.0" : "%d %s morreram por tiros precisos!", "vcmi.battleWindow.accurateShot.resultDescription.1" : "%d %s morreu com um tiro preciso!", "vcmi.battleWindow.accurateShot.resultDescription.2" : "%d %s morreram por tiros precisos!", @@ -612,7 +612,7 @@ "core.bonus.SPELL_LIKE_ATTACK.description" : "Ataques com ${subtype.spell}", "core.bonus.SPELL_RESISTANCE_AURA.name" : "Aura de Resistência a Feitiços", "core.bonus.SPELL_RESISTANCE_AURA.description" : "Pilhas próximas ganham ${val}% de resistência a magia", - "core.bonus.SUMMON_GUARDIANS.name" : "Invocar Guardiões", + "core.bonus.SUMMON_GUARDIANS.name" : "Invocar Guardas", "core.bonus.SUMMON_GUARDIANS.description" : "No início da batalha, invoca ${subtype.creature} (${val}%)", "core.bonus.SYNERGY_TARGET.name" : "Alvo Sinergizável", "core.bonus.SYNERGY_TARGET.description" : "Esta criatura é vulnerável ao efeito de sinergia", diff --git a/client/adventureMap/AdventureMapInterface.cpp b/client/adventureMap/AdventureMapInterface.cpp index 43f005199..2a4dbe0be 100644 --- a/client/adventureMap/AdventureMapInterface.cpp +++ b/client/adventureMap/AdventureMapInterface.cpp @@ -444,7 +444,7 @@ void AdventureMapInterface::onPlayerTurnStarted(PlayerColor playerID) LOCPLINT->localState->setSelection(LOCPLINT->localState->getWanderingHero(0)); } - centerOnObject(LOCPLINT->localState->getCurrentArmy()); + onSelectionChanged(LOCPLINT->localState->getCurrentArmy()); //show new day animation and sound on infobar, except for 1st day of the game if (LOCPLINT->cb->getDate(Date::DAY) != 1) diff --git a/client/battle/BattleActionsController.cpp b/client/battle/BattleActionsController.cpp index 0228334ec..a4fe689a1 100644 --- a/client/battle/BattleActionsController.cpp +++ b/client/battle/BattleActionsController.cpp @@ -985,26 +985,27 @@ void BattleActionsController::activateStack() std::list actionsToSelect; if(!possibleActions.empty()) { - switch(possibleActions.front().get()) + auto primaryAction = possibleActions.front().get(); + + if(primaryAction == PossiblePlayerBattleAction::SHOOT || primaryAction == PossiblePlayerBattleAction::AIMED_SPELL_CREATURE + || primaryAction == PossiblePlayerBattleAction::ANY_LOCATION || primaryAction == PossiblePlayerBattleAction::ATTACK_AND_RETURN) { - case PossiblePlayerBattleAction::SHOOT: - actionsToSelect.push_back(possibleActions.front()); - actionsToSelect.push_back(PossiblePlayerBattleAction::ATTACK); - break; - - case PossiblePlayerBattleAction::ATTACK_AND_RETURN: - actionsToSelect.push_back(possibleActions.front()); - actionsToSelect.push_back(PossiblePlayerBattleAction::WALK_AND_ATTACK); - break; - - case PossiblePlayerBattleAction::AIMED_SPELL_CREATURE: - actionsToSelect.push_back(possibleActions.front()); - actionsToSelect.push_back(PossiblePlayerBattleAction::ATTACK); - break; - case PossiblePlayerBattleAction::ANY_LOCATION: - actionsToSelect.push_back(possibleActions.front()); - actionsToSelect.push_back(PossiblePlayerBattleAction::ATTACK); - break; + actionsToSelect.push_back(possibleActions.front()); + + auto shootActionPredicate = [](const PossiblePlayerBattleAction& action) + { + return action.get() == PossiblePlayerBattleAction::SHOOT; + }; + bool hasShootSecondaryAction = std::any_of(possibleActions.begin() + 1, possibleActions.end(), shootActionPredicate); + + if(hasShootSecondaryAction) //casters may have shooting capabilities, for example storm elementals + actionsToSelect.emplace_back(PossiblePlayerBattleAction::SHOOT); + + /* TODO: maybe it would also make sense to check spellcast as non-top priority action ("NO_SPELLCAST_BY_DEFAULT" bonus)? + * it would require going beyond this "if" block for melee casters + * F button helps, but some mod creatures may have that bonus and more than 1 castable spell */ + + actionsToSelect.emplace_back(PossiblePlayerBattleAction::ATTACK); //always allow melee attack as last option } } owner.windowObject->setAlternativeActions(actionsToSelect); @@ -1071,3 +1072,8 @@ void BattleActionsController::pushFrontPossibleAction(PossiblePlayerBattleAction { possibleActions.insert(possibleActions.begin(), action); } + +void BattleActionsController::resetCurrentStackPossibleActions() +{ + possibleActions = getPossibleActionsForStack(owner.stacksController->getActiveStack()); +} diff --git a/client/battle/BattleActionsController.h b/client/battle/BattleActionsController.h index 5b46b0bcb..409f3172a 100644 --- a/client/battle/BattleActionsController.h +++ b/client/battle/BattleActionsController.h @@ -122,4 +122,7 @@ public: /// inserts possible action in the beginning in order to prioritize it void pushFrontPossibleAction(PossiblePlayerBattleAction); + + /// resets possible actions to original state + void resetCurrentStackPossibleActions(); }; diff --git a/client/battle/BattleWindow.cpp b/client/battle/BattleWindow.cpp index c1a21e044..ecbc2af2f 100644 --- a/client/battle/BattleWindow.cpp +++ b/client/battle/BattleWindow.cpp @@ -47,7 +47,7 @@ BattleWindow::BattleWindow(BattleInterface & owner): owner(owner), - defaultAction(PossiblePlayerBattleAction::INVALID) + lastAlternativeAction(PossiblePlayerBattleAction::INVALID) { OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE; pos.w = 800; @@ -567,14 +567,18 @@ void BattleWindow::showAlternativeActionIcon(PossiblePlayerBattleAction action) void BattleWindow::setAlternativeActions(const std::list & actions) { + assert(actions.size() != 1); + alternativeActions = actions; - defaultAction = PossiblePlayerBattleAction::INVALID; + lastAlternativeAction = PossiblePlayerBattleAction::INVALID; + if(alternativeActions.size() > 1) - defaultAction = alternativeActions.back(); - if(!alternativeActions.empty()) + { + lastAlternativeAction = alternativeActions.back(); showAlternativeActionIcon(alternativeActions.front()); + } else - showAlternativeActionIcon(defaultAction); + showAlternativeActionIcon(PossiblePlayerBattleAction::INVALID); } void BattleWindow::bAutofightf() @@ -669,23 +673,18 @@ void BattleWindow::bSwitchActionf() { if(alternativeActions.empty()) return; - - if(alternativeActions.front() == defaultAction) - { - alternativeActions.push_back(alternativeActions.front()); - alternativeActions.pop_front(); - } - + auto actions = owner.actionsController->getPossibleActions(); - if(!actions.empty() && actions.front() == alternativeActions.front()) + + if(!actions.empty() && actions.front() != lastAlternativeAction) { owner.actionsController->removePossibleAction(alternativeActions.front()); - showAlternativeActionIcon(defaultAction); + showAlternativeActionIcon(*std::next(alternativeActions.begin())); } else { - owner.actionsController->pushFrontPossibleAction(alternativeActions.front()); - showAlternativeActionIcon(alternativeActions.front()); + owner.actionsController->resetCurrentStackPossibleActions(); + showAlternativeActionIcon(owner.actionsController->getPossibleActions().front()); } alternativeActions.push_back(alternativeActions.front()); diff --git a/client/battle/BattleWindow.h b/client/battle/BattleWindow.h index 5369cca9d..8b6b4f30d 100644 --- a/client/battle/BattleWindow.h +++ b/client/battle/BattleWindow.h @@ -65,7 +65,7 @@ class BattleWindow : public InterfaceObjectConfigurable /// management of alternative actions std::list alternativeActions; - PossiblePlayerBattleAction defaultAction; + PossiblePlayerBattleAction lastAlternativeAction; void showAlternativeActionIcon(PossiblePlayerBattleAction); /// flip battle queue visibility to opposite diff --git a/client/windows/CCastleInterface.cpp b/client/windows/CCastleInterface.cpp index 3b805687f..f5997dde5 100644 --- a/client/windows/CCastleInterface.cpp +++ b/client/windows/CCastleInterface.cpp @@ -430,7 +430,7 @@ void CHeroGSlot::clickPressed(const Point & cursorPosition) { setHighlight(false); - if(other->hero) + if(other->hero && !GH.isKeyboardShiftDown()) LOCPLINT->showHeroExchange(hero->id, other->hero->id); else LOCPLINT->openHeroWindow(hero); diff --git a/config/schemas/objectType.json b/config/schemas/objectType.json index 272e5d266..b470bc1cc 100644 --- a/config/schemas/objectType.json +++ b/config/schemas/objectType.json @@ -40,6 +40,12 @@ "$ref" : "objectTemplate.json" } }, + + "battleground" : { + "description" : "Battleground that will be used for combats in this object. Overrides terrain this object was placed on", + "type" : "string" + }, + "sounds" : { "type" : "object", "additionalProperties" : false, diff --git a/config/shortcutsConfig.json b/config/shortcutsConfig.json index 4359730be..ebf1463fb 100644 --- a/config/shortcutsConfig.json +++ b/config/shortcutsConfig.json @@ -55,7 +55,7 @@ "adventureZoomOut": "Keypad -", "adventureZoomReset": "Backspace", "battleAutocombat": "A", - "battleAutocombatEnd": "E", + "battleAutocombatEnd": "Q", "battleCastSpell": "C", "battleConsoleDown": "Down", "battleConsoleUp": "Up", @@ -68,8 +68,8 @@ "battleTacticsEnd": [ "Return", "Keypad Enter"], "battleTacticsNext": "Space", "battleToggleHeroesStats": [], - "battleToggleQueue": "Q", - "battleUseCreatureSpell": "F", + "battleToggleQueue": "Z", + "battleUseCreatureSpell": ["F", "G"], "battleWait": "W", "exchangeArmySwap": "F10", "exchangeArmyToLeft": [], diff --git a/debian/changelog b/debian/changelog index e2c64b577..5998a8c0a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -4,6 +4,12 @@ vcmi (1.6.0) jammy; urgency=medium -- Ivan Savenko Fri, 30 Aug 2024 12:00:00 +0200 +vcmi (1.5.5) jammy; urgency=medium + + * New upstream release + + -- Ivan Savenko Wed, 17 Jul 2024 12:00:00 +0200 + vcmi (1.5.4) jammy; urgency=medium * New upstream release diff --git a/docs/Readme.md b/docs/Readme.md index 2344f8a09..8ceb7a55d 100644 --- a/docs/Readme.md +++ b/docs/Readme.md @@ -1,7 +1,7 @@ [![VCMI](https://github.com/vcmi/vcmi/actions/workflows/github.yml/badge.svg?branch=develop&event=push)](https://github.com/vcmi/vcmi/actions/workflows/github.yml?query=branch%3Adevelop+event%3Apush) [![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/1.5.0/total)](https://github.com/vcmi/vcmi/releases/tag/1.5.0) -[![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/1.5.3/total)](https://github.com/vcmi/vcmi/releases/tag/1.5.3) [![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/1.5.4/total)](https://github.com/vcmi/vcmi/releases/tag/1.5.4) +[![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/1.5.5/total)](https://github.com/vcmi/vcmi/releases/tag/1.5.5) [![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/total)](https://github.com/vcmi/vcmi/releases) # VCMI Project diff --git a/docs/modders/Map_Object_Format.md b/docs/modders/Map_Object_Format.md index b2f5cd01a..887af1965 100644 --- a/docs/modders/Map_Object_Format.md +++ b/docs/modders/Map_Object_Format.md @@ -60,6 +60,9 @@ Full object consists from 3 parts: // How valuable this object is to AI "aiValue" : 1000, + // Battleground that will be used for combats in this object. Overrides terrain this object was placed on + "battleground" : "cursed_ground", + // Sounds assigned to this object "sounds" : { // Ambient sounds that plays when current hero is near this object diff --git a/launcher/eu.vcmi.VCMI.metainfo.xml b/launcher/eu.vcmi.VCMI.metainfo.xml index 16aaace12..4ab10bb28 100644 --- a/launcher/eu.vcmi.VCMI.metainfo.xml +++ b/launcher/eu.vcmi.VCMI.metainfo.xml @@ -91,6 +91,7 @@ vcmilauncher.desktop + diff --git a/launcher/translation/chinese.ts b/launcher/translation/chinese.ts index 2b245d6cd..26518f982 100644 --- a/launcher/translation/chinese.ts +++ b/launcher/translation/chinese.ts @@ -465,11 +465,11 @@ Downloading %1. %p% (%v MB out of %m MB) finished - + 正在下载 %1. %p% (%v MB 共 %m MB) 已完成 Downloading %s%. %p% (%v MB out of %m MB) finished - 下载进度 %s%. %p% (%v MB 共 %m MB) 已完成 + 正在下载 %s%. %p% (%v MB 共 %m MB) 已完成 @@ -738,12 +738,12 @@ Install successfully downloaded? Show Tutorial again - + 重新显示教程 Reset - + 重置 @@ -1275,7 +1275,7 @@ Offline installer consists of two parts, .exe and .bin. Make sure you download b File cannot opened - + 打开文件失败 @@ -1324,23 +1324,24 @@ Please select directory with installed Heroes III data. You've provided GOG Galaxy installer! This file doesn't contain the game. Please download the offline backup game installer! - + 您提供的是GOG Galaxy安装器!这个文件不包含游戏内容,请下载离线游戏安装器! Stream error while extracting files! error reason: - + 提取文件时遭遇文件流错误! +错误原因: Not a supported Inno Setup installer! - + 这不是一个支持的Inno Setup安装器! Extracting error! - + 提取错误! diff --git a/launcher/translation/portuguese.ts b/launcher/translation/portuguese.ts index ce306c2e8..364c674e7 100644 --- a/launcher/translation/portuguese.ts +++ b/launcher/translation/portuguese.ts @@ -461,7 +461,7 @@ Downloading %1. %p% (%v MB out of %m MB) finished - + Baixando %1. %p% (%v MB de %m MB) concluído Downloading %s%. %p% (%v MB out of %m MB) finished @@ -733,12 +733,12 @@ Instalar o download realizado com sucesso? Show Tutorial again - + Mostrar o Tutorial novamente Reset - + Redefinir @@ -940,7 +940,7 @@ Modo de tela cheia exclusivo - o jogo cobrirá toda a sua tela e usará a resolu Autosave - Salvar automaticamente + Salvamento automático @@ -1268,7 +1268,7 @@ O instalador offline consiste em duas partes, .exe e .bin. Certifique-se de baix File cannot opened - + O arquivo não pode ser aberto @@ -1317,23 +1317,24 @@ Por favor, selecione o diretório com os dados do Heroes III instalados. You've provided GOG Galaxy installer! This file doesn't contain the game. Please download the offline backup game installer! - + Você forneceu o instalador do GOG Galaxy! Este arquivo não contém o jogo. Por favor, faça o download do instalador offline de backup do jogo! Stream error while extracting files! error reason: - + Erro de fluxo ao extrair arquivos! +Motivo do erro: Not a supported Inno Setup installer! - + Instalador do Inno Setup não suportado! Extracting error! - + Erro ao extrair! diff --git a/lib/battle/PossiblePlayerBattleAction.h b/lib/battle/PossiblePlayerBattleAction.h index 401c18d00..402980ded 100644 --- a/lib/battle/PossiblePlayerBattleAction.h +++ b/lib/battle/PossiblePlayerBattleAction.h @@ -74,6 +74,11 @@ public: { return action == other.action && spellToCast == other.spellToCast; } + + bool operator != (const PossiblePlayerBattleAction & other) const + { + return action != other.action || spellToCast != other.spellToCast; + } }; VCMI_LIB_NAMESPACE_END diff --git a/lib/gameState/CGameStateCampaign.cpp b/lib/gameState/CGameStateCampaign.cpp index c496db471..409272626 100644 --- a/lib/gameState/CGameStateCampaign.cpp +++ b/lib/gameState/CGameStateCampaign.cpp @@ -120,6 +120,11 @@ void CGameStateCampaign::trimCrossoverHeroesParameters(const CampaignTravel & tr if(!info) return false; + // FIXME: double-check how H3 handles case of transferring components of a combined artifact if entire combined artifact is not transferrable + // For example, what happens if hero has assembled Angelic Alliance, AA is not marked is transferrable, but Sandals can be transferred? Should artifact be disassembled? + if (info->locked) + return false; + // TODO: why would there be nullptr artifacts? const CArtifactInstance *art = info->artifact; if(!art) diff --git a/mapeditor/translation/portuguese.ts b/mapeditor/translation/portuguese.ts index 5bc267e5a..e6ca56dd1 100644 --- a/mapeditor/translation/portuguese.ts +++ b/mapeditor/translation/portuguese.ts @@ -6,17 +6,17 @@ Army settings - Configurações do Exército + Configurações do exército Wide formation - Formação Aberta + Formação aberta Tight formation - Formação Compacta + Formação compacta @@ -29,7 +29,7 @@ Timed events - Eventos Temporizados + Eventos temporizados @@ -44,7 +44,7 @@ New event - Novo Evento + Novo evento @@ -57,12 +57,12 @@ Map name - Nome do Mapa + Nome do mapa Map description - Descrição do Mapa + Descrição do mapa @@ -88,7 +88,7 @@ Hero skills - Habilidades do Herói + Habilidades do herói @@ -172,7 +172,7 @@ Defeat message - Mensagem de Derrota + Mensagem de derrota