mirror of
https://github.com/vcmi/vcmi.git
synced 2025-06-15 00:05:02 +02:00
Merge remote-tracking branch 'origin/beta' into random_prison_distributor
This commit is contained in:
12
.github/workflows/github.yml
vendored
12
.github/workflows/github.yml
vendored
@ -116,7 +116,7 @@ jobs:
|
||||
pack_type: RelWithDebInfo
|
||||
extension: exe
|
||||
preset: windows-msvc-release-ccache
|
||||
- platform: mingw-ubuntu
|
||||
- platform: mingw
|
||||
os: ubuntu-22.04
|
||||
test: 0
|
||||
pack: 1
|
||||
@ -126,6 +126,16 @@ jobs:
|
||||
cmake_args: -G Ninja
|
||||
preset: windows-mingw-conan-linux
|
||||
conan_profile: mingw64-linux.jinja
|
||||
- platform: mingw-32
|
||||
os: ubuntu-22.04
|
||||
test: 0
|
||||
pack: 1
|
||||
pack_type: Release
|
||||
extension: exe
|
||||
cpack_args: -D CPACK_NSIS_EXECUTABLE=`which makensis`
|
||||
cmake_args: -G Ninja
|
||||
preset: windows-mingw-conan-linux
|
||||
conan_profile: mingw32-linux.jinja
|
||||
- platform: android-32
|
||||
os: ubuntu-22.04
|
||||
extension: apk
|
||||
|
@ -427,33 +427,36 @@ bool BattleEvaluator::attemptCastingSpell(const CStack * activeStack)
|
||||
|
||||
state->nextTurn(unit->unitId());
|
||||
|
||||
PotentialTargets pt(unit, damageCache, state);
|
||||
PotentialTargets potentialTargets(unit, damageCache, state);
|
||||
|
||||
if(!pt.possibleAttacks.empty())
|
||||
if(!potentialTargets.possibleAttacks.empty())
|
||||
{
|
||||
AttackPossibility ap = pt.bestAction();
|
||||
AttackPossibility attackPossibility = potentialTargets.bestAction();
|
||||
|
||||
auto swb = state->getForUpdate(unit->unitId());
|
||||
*swb = *ap.attackerState;
|
||||
auto stackWithBonuses = state->getForUpdate(unit->unitId());
|
||||
*stackWithBonuses = *attackPossibility.attackerState;
|
||||
|
||||
if(ap.defenderDamageReduce > 0)
|
||||
swb->removeUnitBonus(Bonus::UntilAttack);
|
||||
if(ap.attackerDamageReduce > 0)
|
||||
swb->removeUnitBonus(Bonus::UntilBeingAttacked);
|
||||
|
||||
for(auto affected : ap.affectedUnits)
|
||||
if(attackPossibility.defenderDamageReduce > 0)
|
||||
{
|
||||
swb = state->getForUpdate(affected->unitId());
|
||||
*swb = *affected;
|
||||
stackWithBonuses->removeUnitBonus(Bonus::UntilAttack);
|
||||
stackWithBonuses->removeUnitBonus(Bonus::UntilOwnAttack);
|
||||
}
|
||||
if(attackPossibility.attackerDamageReduce > 0)
|
||||
stackWithBonuses->removeUnitBonus(Bonus::UntilBeingAttacked);
|
||||
|
||||
if(ap.defenderDamageReduce > 0)
|
||||
swb->removeUnitBonus(Bonus::UntilBeingAttacked);
|
||||
if(ap.attackerDamageReduce > 0 && ap.attack.defender->unitId() == affected->unitId())
|
||||
swb->removeUnitBonus(Bonus::UntilAttack);
|
||||
for(auto affected : attackPossibility.affectedUnits)
|
||||
{
|
||||
stackWithBonuses = state->getForUpdate(affected->unitId());
|
||||
*stackWithBonuses = *affected;
|
||||
|
||||
if(attackPossibility.defenderDamageReduce > 0)
|
||||
stackWithBonuses->removeUnitBonus(Bonus::UntilBeingAttacked);
|
||||
if(attackPossibility.attackerDamageReduce > 0 && attackPossibility.attack.defender->unitId() == affected->unitId())
|
||||
stackWithBonuses->removeUnitBonus(Bonus::UntilAttack);
|
||||
}
|
||||
}
|
||||
|
||||
auto bav = pt.bestActionValue();
|
||||
auto bav = potentialTargets.bestActionValue();
|
||||
|
||||
//best action is from effective owner`s point if view, we need to convert to our point if view
|
||||
if(state->battleGetOwner(unit) != playerID)
|
||||
|
@ -17,4 +17,5 @@ RC={{ target_host }}-windres
|
||||
{% macro generate_conf(target_host) -%}
|
||||
tools.build:compiler_executables = {"c": "{{ target_host }}-gcc", "cpp": "{{ target_host }}-g++"}
|
||||
tools.build:sysroot = /usr/{{ target_host }}
|
||||
tools.build:defines = ["WINVER=0x0601", "_WIN32_WINNT=0x0601"]
|
||||
{%- endmacro -%}
|
16
CI/mingw-32/before_install.sh
Normal file
16
CI/mingw-32/before_install.sh
Normal file
@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
sudo apt-get update
|
||||
sudo apt-get install ninja-build mingw-w64 nsis
|
||||
sudo update-alternatives --set i686-w64-mingw32-g++ /usr/bin/i686-w64-mingw32-g++-posix
|
||||
|
||||
# Workaround for getting new MinGW headers on Ubuntu 22.04.
|
||||
# Remove it once MinGW headers version in repository will be 10.0 at least
|
||||
curl -O -L http://mirrors.kernel.org/ubuntu/pool/universe/m/mingw-w64/mingw-w64-common_10.0.0-3_all.deb \
|
||||
&& sudo dpkg -i mingw-w64-common_10.0.0-3_all.deb;
|
||||
curl -O -L http://mirrors.kernel.org/ubuntu/pool/universe/m/mingw-w64/mingw-w64-i686-dev_10.0.0-3_all.deb \
|
||||
&& sudo dpkg -i mingw-w64-i686-dev_10.0.0-3_all.deb;
|
||||
|
||||
mkdir ~/.conan ; cd ~/.conan
|
||||
curl -L "https://github.com/vcmi/vcmi-deps-windows-conan/releases/download/1.1/vcmi-deps-windows-conan-w32.tgz" \
|
||||
| tar -xzf -
|
@ -12,5 +12,5 @@ curl -O -L http://mirrors.kernel.org/ubuntu/pool/universe/m/mingw-w64/mingw-w64-
|
||||
&& sudo dpkg -i mingw-w64-x86-64-dev_10.0.0-3_all.deb;
|
||||
|
||||
mkdir ~/.conan ; cd ~/.conan
|
||||
curl -L "https://github.com/vcmi/vcmi-deps-windows-conan/releases/download/1.0/vcmi-deps-windows-conan-w64.tgz" \
|
||||
curl -L "https://github.com/vcmi/vcmi-deps-windows-conan/releases/download/1.1/vcmi-deps-windows-conan-w64.tgz" \
|
||||
| tar -xzf -
|
@ -255,7 +255,10 @@ endif()
|
||||
|
||||
if(MINGW OR MSVC)
|
||||
# Windows Vista or newer for FuzzyLite 6 to compile
|
||||
add_definitions(-D_WIN32_WINNT=0x0600)
|
||||
# Except for conan which already has this definition in its preset
|
||||
if(NOT USING_CONAN)
|
||||
add_definitions(-D_WIN32_WINNT=0x0600)
|
||||
endif()
|
||||
|
||||
#delete lib prefix for dlls (libvcmi -> vcmi)
|
||||
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
||||
|
25
ChangeLog.md
25
ChangeLog.md
@ -1,3 +1,28 @@
|
||||
# 1.4.0 -> 1.4.1
|
||||
|
||||
### General
|
||||
* Fixed position for interaction with starting heroes
|
||||
* Fixed smooth map scrolling when running at high framerate
|
||||
* Fixed calculation of Fire Shield damage when caster has artifacts that increase its damage
|
||||
* Fixed untranslated message when visiting signs with random text
|
||||
* Fixed slider scrolling to maximum value when clicking on "scroll right" button
|
||||
* Fixed events and seer huts not activating in some cases
|
||||
* Fixed bug leading to Artifact Merchant selling Grails in loaded saved games
|
||||
* Fixed placement of objects in random maps near the top border of the map
|
||||
* Creatures under Slayer spell will no longer deal additional damage to creatures not affected by Slayer
|
||||
* Description of a mod in Launcher will no longer be converted to lower-case
|
||||
* Game will no longer fail to generate random map when AI-only players option is set to non-zero value
|
||||
* Added option to mute audio when VCMI window is not active
|
||||
* Added option to disable smooth map scrolling
|
||||
* Reverted ban on U-turns in pathfinder
|
||||
|
||||
### Stability
|
||||
* Fixed crash on using mods made for VCMI 1.3
|
||||
* Fixed crash on generating random map with large number of monoliths
|
||||
* Fixed crash on losing mission-critical hero in battle
|
||||
* Fixed crash on generating growth detalization in some localizations
|
||||
* Fixed crash on loading of some user-made maps
|
||||
|
||||
# 1.3.2 -> 1.4.0
|
||||
|
||||
### General
|
||||
|
@ -36,14 +36,27 @@
|
||||
"vcmi.heroOverview.spells" : "魔法",
|
||||
|
||||
"vcmi.radialWheel.mergeSameUnit" : "合并相同生物",
|
||||
"vcmi.radialWheel.showUnitInformation" : "显示生物信息",
|
||||
"vcmi.radialWheel.fillSingleUnit" : "单个生物填充空格",
|
||||
"vcmi.radialWheel.splitSingleUnit" : "分割单个生物",
|
||||
"vcmi.radialWheel.splitUnitEqually" : "平均分配生物",
|
||||
"vcmi.radialWheel.moveUnit" : "将生物移动到部队",
|
||||
"vcmi.radialWheel.splitUnit" : "分割生物到其他空位",
|
||||
|
||||
"vcmi.radialWheel.heroGetArmy" : "移动生物",
|
||||
"vcmi.radialWheel.heroSwapArmy" : "交换生物",
|
||||
"vcmi.radialWheel.heroExchange" : "开启英雄交换",
|
||||
"vcmi.radialWheel.heroGetArtifacts" : "移动宝物",
|
||||
"vcmi.radialWheel.heroSwapArtifacts" : "交换宝物",
|
||||
"vcmi.radialWheel.heroDismiss" : "解雇英雄",
|
||||
|
||||
"vcmi.radialWheel.moveTop" : "移到顶端",
|
||||
"vcmi.radialWheel.moveUp" : "上移",
|
||||
"vcmi.radialWheel.moveDown" : "下移",
|
||||
"vcmi.radialWheel.moveBottom" : "移到底端",
|
||||
|
||||
"vcmi.mainMenu.serverConnecting" : "连接中...",
|
||||
"vcmi.mainMenu.serverAddressEnter" : "使用地址:",
|
||||
"vcmi.mainMenu.serverConnectionFailed" : "连接失败",
|
||||
"vcmi.mainMenu.serverClosing" : "关闭中...",
|
||||
"vcmi.mainMenu.hostTCP" : "创建TCP/IP游戏",
|
||||
"vcmi.mainMenu.joinTCP" : "加入TCP/IP游戏",
|
||||
@ -51,11 +64,18 @@
|
||||
|
||||
"vcmi.lobby.filename" : "文件名",
|
||||
"vcmi.lobby.creationDate" : "创建时间",
|
||||
"vcmi.lobby.scenarioName" : "场景名称",
|
||||
"vcmi.lobby.mapPreview" : "地图预览",
|
||||
"vcmi.lobby.noPreview" : "无地上部分",
|
||||
"vcmi.lobby.noUnderground" : "无地下部分",
|
||||
|
||||
"vcmi.server.errors.existingProcess" : "一个VCMI进程已经在运行,启动新进程前请结束它。",
|
||||
"vcmi.server.errors.modsToEnable" : "{需要启用的mod列表}",
|
||||
"vcmi.server.errors.modsToDisable" : "{需要禁用的mod列表}",
|
||||
"vcmi.server.confirmReconnect" : "您想要重连上一个会话么?",
|
||||
"vcmi.server.errors.modNoDependency" : "读取mod包 {'%s'}失败!\n 需要的mod {'%s'} 没有安装或无效!\n",
|
||||
"vcmi.server.errors.modConflict" : "读取的mod包 {'%s'}无法运行!\n 与另一个mod {'%s'}冲突!\n",
|
||||
"vcmi.server.errors.unknownEntity" : "加载保存失败! 在保存的游戏中发现未知实体'%s'! 保存可能与当前安装的mod版本不兼容!",
|
||||
|
||||
"vcmi.settingsMainWindow.generalTab.hover" : "常规",
|
||||
"vcmi.settingsMainWindow.generalTab.help" : "切换到“常规”选项卡 - 设置游戏客户端呈现",
|
||||
@ -92,6 +112,10 @@
|
||||
"vcmi.systemOptions.hapticFeedbackButton.help" : "{触觉反馈}\n\n切换触摸输入的触觉反馈。",
|
||||
"vcmi.systemOptions.enableUiEnhancementsButton.hover" : "界面增强",
|
||||
"vcmi.systemOptions.enableUiEnhancementsButton.help" : "{界面增强}\n\n显示所有界面增强内容,如大背包和魔法书等。",
|
||||
"vcmi.systemOptions.enableLargeSpellbookButton.hover" : "增大魔法书界面",
|
||||
"vcmi.systemOptions.enableLargeSpellbookButton.help" : "{增大魔法书界面}\n\n可以在魔法书单页中显示更多的魔法,从而获得更好的视觉效果。",
|
||||
"vcmi.systemOptions.audioMuteFocus.hover" : "切换窗口时静音",
|
||||
"vcmi.systemOptions.audioMuteFocus.help" : "{切换窗口时静音}\n\n快速切换窗口时将静音,在工作时,切换游戏窗口不会有声音。",
|
||||
|
||||
"vcmi.adventureOptions.infoBarPick.hover" : "在信息面板显示消息",
|
||||
"vcmi.adventureOptions.infoBarPick.help" : "{在信息面板显示消息}\n\n来自访问地图物件的信息将显示在信息面板,而不是弹出窗口。",
|
||||
@ -107,6 +131,8 @@
|
||||
"vcmi.adventureOptions.infoBarCreatureManagement.help" : "{信息面板生物管理}\n\n允许在信息面板中重新排列生物,而不是在默认组件之间循环。",
|
||||
"vcmi.adventureOptions.leftButtonDrag.hover" : "左键拖动地图",
|
||||
"vcmi.adventureOptions.leftButtonDrag.help" : "{左键拖动地图}\n\n启用后,按住左键移动鼠标将拖动冒险地图视图。",
|
||||
"vcmi.adventureOptions.smoothDragging.hover" : "平滑地图拖动",
|
||||
"vcmi.adventureOptions.smoothDragging.help" : "{平滑地图拖动}\n\n启用后,地图拖动会产生柔和的羽化效果。",
|
||||
"vcmi.adventureOptions.mapScrollSpeed1.hover": "",
|
||||
"vcmi.adventureOptions.mapScrollSpeed5.hover": "",
|
||||
"vcmi.adventureOptions.mapScrollSpeed6.hover": "",
|
||||
@ -139,6 +165,9 @@
|
||||
"vcmi.battleOptions.enableAutocombatSpells.help": "{魔法}\n\n快速战斗时不会使用魔法。",
|
||||
"vcmi.battleOptions.skipBattleIntroMusic.hover": "跳过战斗开始音乐",
|
||||
"vcmi.battleOptions.skipBattleIntroMusic.help": "{跳过战斗开始音乐}\n\n战斗开始音乐播放期间,你也能够进行操作。",
|
||||
|
||||
"vcmi.adventureMap.revisitObject.hover" : "重新访问",
|
||||
"vcmi.adventureMap.revisitObject.help" : "{重新访问}\n\n让当前英雄重新访问地图建筑或城镇。",
|
||||
|
||||
"vcmi.battleWindow.pressKeyToSkipIntro" : "按下任意键立即开始战斗",
|
||||
"vcmi.battleWindow.damageEstimation.melee" : "近战攻击 %CREATURE (%DAMAGE).",
|
||||
@ -153,6 +182,15 @@
|
||||
"vcmi.battleWindow.damageEstimation.kills.1" : "%d 将被消灭",
|
||||
|
||||
"vcmi.battleResultsWindow.applyResultsLabel" : "接受战斗结果",
|
||||
|
||||
"vcmi.tutorialWindow.title" : "触摸屏介绍",
|
||||
"vcmi.tutorialWindow.decription.RightClick" : "触摸并按住要右键单击的元素。 触摸可用区域以关闭。",
|
||||
"vcmi.tutorialWindow.decription.MapPanning" : "用一根手指触摸并拖动来移动地图。",
|
||||
"vcmi.tutorialWindow.decription.MapZooming" : "用两根手指捏合可更改地图缩放比例。",
|
||||
"vcmi.tutorialWindow.decription.RadialWheel" : "滑动可打开径向轮以执行各种操作,例如生物/英雄管理和城镇排序。",
|
||||
"vcmi.tutorialWindow.decription.BattleDirection" : "要从特定方向攻击,请向要进行攻击的方向滑动。",
|
||||
"vcmi.tutorialWindow.decription.BattleDirectionAbort" : "如果手指距离足够远,可以取消攻击方向手势。",
|
||||
"vcmi.tutorialWindow.decription.AbortSpell" : "触摸并按住可取消魔法。",
|
||||
|
||||
"vcmi.otherOptions.availableCreaturesAsDwellingLabel.hover" : "显示可招募生物",
|
||||
"vcmi.otherOptions.availableCreaturesAsDwellingLabel.help" : "{显示可招募生物}\n\n在城镇摘要(城镇屏幕的左下角)中显示可招募的生物数量,而不是增长。",
|
||||
@ -202,14 +240,68 @@
|
||||
"vcmi.randomMapTab.widgets.teamAlignmentsLabel" : "同盟关系",
|
||||
"vcmi.randomMapTab.widgets.roadTypesLabel" : "道路类型",
|
||||
|
||||
"vcmi.optionsTab.chessFieldBase.hover" : "额外计时器",
|
||||
"vcmi.optionsTab.chessFieldTurn.hover" : "转动计时器",
|
||||
"vcmi.optionsTab.turnOptions.hover" : "回合选项",
|
||||
"vcmi.optionsTab.turnOptions.help" : "选择回合计时器并同步回合选项",
|
||||
"vcmi.optionsTab.selectPreset" : "预设",
|
||||
|
||||
"vcmi.optionsTab.chessFieldBase.hover" : "基本计时器",
|
||||
"vcmi.optionsTab.chessFieldTurn.hover" : "回合计时器",
|
||||
"vcmi.optionsTab.chessFieldBattle.hover" : "战斗计时器",
|
||||
"vcmi.optionsTab.chessFieldUnit.hover" : "堆栈计时器",
|
||||
"vcmi.optionsTab.chessFieldBase.help" : "当{转动计时器}达到零时开始倒计时。 它仅在游戏开始时设置一次。 当计时器达到零时,玩家的回合结束。",
|
||||
"vcmi.optionsTab.chessFieldTurn.help" : "当玩家在冒险地图上开始回合时开始倒计时。 它在每回合开始时重置为其初始值。 任何未使用的回合时间将被添加到{额外计时器}(如果正在使用)中。",
|
||||
"vcmi.optionsTab.chessFieldBattle.help" : "战斗期间当 {堆栈计时器} 达到0时进行倒计时。 每次战斗开始时都会重置为初始值。 如果计时器达到零,当前活动的堆栈将进行防御。",
|
||||
"vcmi.optionsTab.chessFieldUnit.help" : "当玩家在战斗中为当前堆栈选择一个动作时开始倒计时。 堆栈操作完成后,它会重置为其初始值。",
|
||||
"vcmi.optionsTab.chessFieldUnit.hover" : "单位计时器",
|
||||
"vcmi.optionsTab.chessFieldBase.help" : "当 {回合计时器} 达到 0 时使用。在游戏开始时设置一次。达到 0 时,结束当前回合。任何正在进行的战斗都会以失败告终。",
|
||||
"vcmi.optionsTab.chessFieldTurnAccumulate.help" : "在战斗外或{战斗计时器}耗尽时使用。 每回合重置。 剩余部分在回合结束时添加至 {基本计时器}。",
|
||||
"vcmi.optionsTab.chessFieldTurnDiscard.help" : "在战斗外或{战斗计时器}耗尽时使用。 每回合重置。 任何未花费的时间都会丢失。",
|
||||
"vcmi.optionsTab.chessFieldBattle.help" : "在与 AI 的战斗中使用,或者在 {单位计时器} 耗尽时用于 pvp 战斗。在每次战斗开始时重置。",
|
||||
"vcmi.optionsTab.chessFieldUnitAccumulate.help" : "在 PVP 战斗中选择单位动作时使用。 在单位回合结束时将剩余物添加到{战斗计时器}。",
|
||||
"vcmi.optionsTab.chessFieldUnitDiscard.help" : "在 PVP 战斗中选择单位动作时使用。 在每个单位回合开始时重置。 任何未花费的时间都会丢失。",
|
||||
|
||||
"vcmi.optionsTab.accumulate" : "累积",
|
||||
|
||||
"vcmi.optionsTab.simturnsTitle" : "同时进行回合",
|
||||
"vcmi.optionsTab.simturnsMin.hover" : "最少回合",
|
||||
"vcmi.optionsTab.simturnsMax.hover" : "最多回合",
|
||||
"vcmi.optionsTab.simturnsAI.hover" : "(测试中) AI回合同时行动",
|
||||
"vcmi.optionsTab.simturnsMin.help" : "同时游戏进行的最少指定天数。在此期间玩家之间的联系将被阻止",
|
||||
"vcmi.optionsTab.simturnsMax.help" : "同时游戏指定的最多天数或直到与其他玩家联系",
|
||||
"vcmi.optionsTab.simturnsAI.help" : "{AI回合同时行动}\n实验选项。启用同时回合后,允许 AI 玩家与人类玩家同时行动。",
|
||||
|
||||
"vcmi.optionsTab.turnTime.select" : "回合计时器预设",
|
||||
"vcmi.optionsTab.turnTime.unlimited" : "无限时",
|
||||
"vcmi.optionsTab.turnTime.classic.1" : "经典计时器: 1 分钟",
|
||||
"vcmi.optionsTab.turnTime.classic.2" : "经典计时器: 2 分钟",
|
||||
"vcmi.optionsTab.turnTime.classic.5" : "经典计时器: 5 分钟",
|
||||
"vcmi.optionsTab.turnTime.classic.10" : "经典计时器: 10 分钟",
|
||||
"vcmi.optionsTab.turnTime.classic.20" : "经典计时器: 20 分钟",
|
||||
"vcmi.optionsTab.turnTime.classic.30" : "经典计时器: 30 分钟",
|
||||
"vcmi.optionsTab.turnTime.chess.20" : "国际象棋计时器: 20:00 + 10:00 + 02:00 + 00:00",
|
||||
"vcmi.optionsTab.turnTime.chess.16" : "国际象棋计时器: 16:00 + 08:00 + 01:30 + 00:00",
|
||||
"vcmi.optionsTab.turnTime.chess.8" : "国际象棋计时器: 08:00 + 04:00 + 01:00 + 00:00",
|
||||
"vcmi.optionsTab.turnTime.chess.4" : "国际象棋计时器: 04:00 + 02:00 + 00:30 + 00:00",
|
||||
"vcmi.optionsTab.turnTime.chess.2" : "国际象棋计时器: 02:00 + 01:00 + 00:15 + 00:00",
|
||||
"vcmi.optionsTab.turnTime.chess.1" : "国际象棋计时器: 01:00 + 01:00 + 00:00 + 00:00",
|
||||
|
||||
"vcmi.optionsTab.simturns.select" : "同时进行回合预设",
|
||||
"vcmi.optionsTab.simturns.none" : "不同时进行回合",
|
||||
"vcmi.optionsTab.simturns.tillContactMax" : "同时进行: 可进行联系",
|
||||
"vcmi.optionsTab.simturns.tillContact1" : "同时进行: 1 周, 联系时中断",
|
||||
"vcmi.optionsTab.simturns.tillContact2" : "同时进行: 2 周, 联系时中断",
|
||||
"vcmi.optionsTab.simturns.tillContact4" : "同时进行: 1 月, 联系时中断",
|
||||
"vcmi.optionsTab.simturns.blocked1" : "同时进行: 1 周, 屏蔽联系",
|
||||
"vcmi.optionsTab.simturns.blocked2" : "同时进行: 2 周, 屏蔽联系",
|
||||
"vcmi.optionsTab.simturns.blocked4" : "同时进行: 1 月, 屏蔽联系",
|
||||
|
||||
// Translation note: translate strings below using form that is correct for "0 days", "1 day" and "2 days" in your language
|
||||
// Using this information, VCMI will automatically select correct plural form for every possible amount
|
||||
"vcmi.optionsTab.simturns.days.0" : " %d 天",
|
||||
"vcmi.optionsTab.simturns.days.1" : " %d 天",
|
||||
"vcmi.optionsTab.simturns.days.2" : " %d 天",
|
||||
"vcmi.optionsTab.simturns.weeks.0" : " %d 周",
|
||||
"vcmi.optionsTab.simturns.weeks.1" : " %d 周",
|
||||
"vcmi.optionsTab.simturns.weeks.2" : " %d 周",
|
||||
"vcmi.optionsTab.simturns.months.0" : " %d 月",
|
||||
"vcmi.optionsTab.simturns.months.1" : " %d 月",
|
||||
"vcmi.optionsTab.simturns.months.2" : " %d 月",
|
||||
|
||||
|
||||
// Custom victory conditions for H3 campaigns and HotA maps
|
||||
"vcmi.map.victoryCondition.daysPassed.toOthers" : "敌人依然存活至今,你失败了!",
|
||||
@ -275,7 +367,7 @@
|
||||
"core.bonus.ENEMY_DEFENCE_REDUCTION.name": "忽略防御 (${val}%)",
|
||||
"core.bonus.ENEMY_DEFENCE_REDUCTION.description": "当攻击时,目标生物${val}%的防御力将被无视。",
|
||||
"core.bonus.FIRE_IMMUNITY.name": "火系免疫",
|
||||
"core.bonus.FIRE_IMMUNITY.description": "免疫所有火系魔法",
|
||||
"core.bonus.FIRE_IMMUNITY.description": "免疫所有火系魔法。",
|
||||
"core.bonus.FIRE_SHIELD.name": "烈火神盾 (${val}%)",
|
||||
"core.bonus.FIRE_SHIELD.description": "反弹部分受到的近战伤害",
|
||||
"core.bonus.FIRST_STRIKE.name": "抢先反击",
|
||||
|
@ -29,16 +29,34 @@
|
||||
"vcmi.capitalColors.5" : "Fialový",
|
||||
"vcmi.capitalColors.6" : "Tyrkysový",
|
||||
"vcmi.capitalColors.7" : "Růžový",
|
||||
|
||||
"vcmi.heroOverview.startingArmy" : "Počáteční jednotky",
|
||||
"vcmi.heroOverview.warMachine" : "Bojové stroje",
|
||||
"vcmi.heroOverview.secondarySkills" : "Druhotné schopnosti",
|
||||
"vcmi.heroOverview.spells" : "Kouzla",
|
||||
|
||||
"vcmi.radialWheel.mergeSameUnit" : "Sloučit stejné jednotky",
|
||||
"vcmi.radialWheel.fillSingleUnit" : "Vyplnit jednou jednotkou",
|
||||
"vcmi.radialWheel.splitSingleUnit" : "Rozdělit jedinou jednotku",
|
||||
"vcmi.radialWheel.splitUnitEqually" : "Rovnoměrně rozdělit jednotky",
|
||||
"vcmi.radialWheel.splitUnitEqually" : "Rozdělit jednotky rovnoměrně",
|
||||
"vcmi.radialWheel.moveUnit" : "Přesunout jednotky do jiného oddílu",
|
||||
"vcmi.radialWheel.splitUnit" : "Rozdělit jednotku do jiné pozice",
|
||||
|
||||
"vcmi.radialWheel.heroGetArmy" : "Získat armádu jiného hrdiny",
|
||||
"vcmi.radialWheel.heroSwapArmy" : "Vyměnit armádu s jiným hrdinou",
|
||||
"vcmi.radialWheel.heroExchange" : "Otevřít výměnu hrdinů",
|
||||
"vcmi.radialWheel.heroGetArtifacts" : "Získat artefakty od jiního hrdiny",
|
||||
"vcmi.radialWheel.heroSwapArtifacts" : "Vyměnit artefakty s jiným hrdinou",
|
||||
"vcmi.radialWheel.heroDismiss" : "Propustit hrdinu",
|
||||
|
||||
"vcmi.radialWheel.moveTop" : "Move to top",
|
||||
"vcmi.radialWheel.moveUp" : "Move up",
|
||||
"vcmi.radialWheel.moveDown" : "Move down",
|
||||
"vcmi.radialWheel.moveBottom" : "Move to bottom",
|
||||
|
||||
"vcmi.mainMenu.serverConnecting" : "Připojování...",
|
||||
"vcmi.mainMenu.serverAddressEnter" : "Zadejte adresu:",
|
||||
"vcmi.mainMenu.serverConnectionFailed" : "Připojování selhalo",
|
||||
"vcmi.mainMenu.serverClosing" : "Zavírání...",
|
||||
"vcmi.mainMenu.hostTCP" : "Pořádat hru TCP/IP",
|
||||
"vcmi.mainMenu.joinTCP" : "Připojit se do hry TCP/IP",
|
||||
@ -46,10 +64,18 @@
|
||||
|
||||
"vcmi.lobby.filepath" : "Název souboru",
|
||||
"vcmi.lobby.creationDate" : "Datum vytvoření",
|
||||
"vcmi.lobby.scenarioName" : "Název scénáře",
|
||||
"vcmi.lobby.mapPreview" : "Náhled mapy",
|
||||
"vcmi.lobby.noPreview" : "bez náhledu",
|
||||
"vcmi.lobby.noUnderground" : "bez podzemí",
|
||||
|
||||
"vcmi.server.errors.existingProcess" : "Již běží jiný server VCMI. Prosím, ukončete ho před startem nové hry.",
|
||||
"vcmi.server.errors.modsToEnable" : "{Následující modifikace jsou nutné pro načtení hry}",
|
||||
"vcmi.server.errors.modsToDisable" : "{Následující modifikace musí být zakázány}",
|
||||
"vcmi.server.confirmReconnect" : "Chcete se připojit k poslední relaci?",
|
||||
"vcmi.server.errors.modNoDependency" : "Nelze načíst modifikaci {'%s'}!\n Závisí na modifikaci {'%s'}, která není aktivní!\n",
|
||||
"vcmi.server.errors.modConflict" : "Nelze načíst modifikaci {'%s'}!\n Je v kolizi s aktivní modifikací {'%s'}!\n",
|
||||
"vcmi.server.errors.unknownEntity" : "Nelze načíst uloženou pozici! Neznámá entita '%s' nalezena v uložené pozici! Uložná pozice nemusí být kompatibilní s aktuálními verzemi modifikací!",
|
||||
|
||||
"vcmi.settingsMainWindow.generalTab.hover" : "Obecné",
|
||||
"vcmi.settingsMainWindow.generalTab.help" : "Přepne na kartu obecných nastavení, která obsahuje nastavení související s obecným chováním klienta hry",
|
||||
@ -84,6 +110,10 @@
|
||||
"vcmi.systemOptions.framerateButton.help" : "{Zobrazit FPS}\n\nPřepne viditelnost počitadla snímků za sekundu v rohu obrazovky hry",
|
||||
"vcmi.systemOptions.hapticFeedbackButton.hover" : "Vibrace",
|
||||
"vcmi.systemOptions.hapticFeedbackButton.help" : "{Vibrace}\n\nPřepnout stav vibrací při dotykovém ovládání",
|
||||
"vcmi.systemOptions.enableUiEnhancementsButton.hover" : "Vylepšení rozhraní",
|
||||
"vcmi.systemOptions.enableUiEnhancementsButton.help" : "{Vylepšení rozhraní}\n\nZapne různá vylepšení rozhraní, jako je tlačítko batohu atd. Zakažte pro zážitek klasické hry.",
|
||||
"vcmi.systemOptions.enableLargeSpellbookButton.hover" : "Velká kniha kouzel",
|
||||
"vcmi.systemOptions.enableLargeSpellbookButton.help" : "{Velká kniha kouzel}\n\nPovolí větší knihu kouzel, do které se jich více vleze na jednu stranu. Animace změny stránek s tímto nastavením nefunguje.",
|
||||
|
||||
"vcmi.adventureOptions.infoBarPick.hover" : "Zobrazit zprávy v panelu informací",
|
||||
"vcmi.adventureOptions.infoBarPick.help" : "{Zobrazit zprávy v panelu informací}\n\nKdyž bude možné, herní zprávy z návštěv míst na mapě budou zobrazeny v panelu informací místo ve zvláštním okně.",
|
||||
@ -97,8 +127,8 @@
|
||||
"vcmi.adventureOptions.borderScroll.help" : "{Posouvání okraji}\n\nPosouvat mapu světa, když je kurzor na okraji obrazovky. Může být zakázáno držením klávesy CTRL.",
|
||||
"vcmi.adventureOptions.infoBarCreatureManagement.hover" : "Info Panel Creature Management", //TODO
|
||||
"vcmi.adventureOptions.infoBarCreatureManagement.help" : "{Info Panel Creature Management}\n\nAllows rearranging creatures in info panel instead of cycling between default components",
|
||||
"vcmi.adventureOptions.leftButtonDrag.hover" : "Left Click Drag Map",
|
||||
"vcmi.adventureOptions.leftButtonDrag.help" : "{Left Click Drag Map}\n\nWhen enabled, moving mouse with left button pressed will drag adventure map view",
|
||||
"vcmi.adventureOptions.leftButtonDrag.hover" : "Posouvání mapy levým kliknutím",
|
||||
"vcmi.adventureOptions.leftButtonDrag.help" : "{Posouvání mapy levým kliknutím}\n\nPosouvání mapy tažením myši se stisknutým levým tlačítkem",
|
||||
"vcmi.adventureOptions.mapScrollSpeed1.hover": "",
|
||||
"vcmi.adventureOptions.mapScrollSpeed5.hover": "",
|
||||
"vcmi.adventureOptions.mapScrollSpeed6.hover": "",
|
||||
@ -129,6 +159,8 @@
|
||||
"vcmi.battleOptions.showStickyHeroInfoWindows.help": "{Zobrazit okno statistik hrdinů}\n\nTrvale zapne okno statistiky hrdinů, které ukazuje hlavní schopnosti a magickou energii.",
|
||||
"vcmi.battleOptions.skipBattleIntroMusic.hover": "Přeskočit úvodní hudbu",
|
||||
"vcmi.battleOptions.skipBattleIntroMusic.help": "{Přeskočit úvodní hudbu}\n\nPovolí akce při úvodní hudbě přehrávané při začátku každé bitvy.",
|
||||
"vcmi.adventureMap.revisitObject.hover" : "Znovu navštívit místo",
|
||||
"vcmi.adventureMap.revisitObject.help" : "{Znovu navštívit místo}\n\nPokud se hrdina nachází na nějakém místě mapy, může jej znovu navštívit.",
|
||||
|
||||
"vcmi.battleWindow.pressKeyToSkipIntro" : "Stiskněte jakoukoliv klávesu pro okamžité zahájení bitvy",
|
||||
"vcmi.battleWindow.damageEstimation.melee" : "Zaútočit na %CREATURE (%DAMAGE).",
|
||||
@ -144,6 +176,15 @@
|
||||
|
||||
"vcmi.battleResultsWindow.applyResultsLabel" : "Použít výsledek bitvy",
|
||||
|
||||
"vcmi.tutorialWindow.title" : "Úvod ovládání dotykem",
|
||||
"vcmi.tutorialWindow.decription.RightClick" : "Klepněte a držte prvek, na který byste chtěli použít pravé tlačítko myši. Klepněte na volnou oblast pro zavření.",
|
||||
"vcmi.tutorialWindow.decription.MapPanning" : "Klepněte a držte jedním prstem pro posouvání mapy.",
|
||||
"vcmi.tutorialWindow.decription.MapZooming" : "Přibližte dva prsty k sobě pro přiblížení mapy.",
|
||||
"vcmi.tutorialWindow.decription.RadialWheel" : "Přejetí otevře kruhovou nabídku pro různé akce, třeba správa hrdiny/bojovnínků a příkazy měst.",
|
||||
"vcmi.tutorialWindow.decription.BattleDirection" : "Pro útok ze speifického úhlu, přejeďte směrem, ze kterého má být útok vykonán.",
|
||||
"vcmi.tutorialWindow.decription.BattleDirectionAbort" : "Gesto útoku pod úhlem může být zrušeno, pokud, pokud je prst dostatečně daleko.",
|
||||
"vcmi.tutorialWindow.decription.AbortSpell" : "Klepněte a držte pro zrušení kouzla.",
|
||||
|
||||
"vcmi.otherOptions.availableCreaturesAsDwellingLabel.hover" : "Zobrazit dostupné jednotky",
|
||||
"vcmi.otherOptions.availableCreaturesAsDwellingLabel.help" : "{Zobrazit dostupné jednotky}\n\nZobrazit počet jednotek dostupných ke koupení místo jejich týdenního přírůstku v přehledu města. (levý spodní okraj obrazovky města).",
|
||||
"vcmi.otherOptions.creatureGrowthAsDwellingLabel.hover" : "Zobrazit týdenní přírůstek jednotek",
|
||||
@ -152,18 +193,18 @@
|
||||
"vcmi.otherOptions.compactTownCreatureInfo.help": "{Kompaktní informace o jednotkách}\n\nZobrazit menší informace o jednotkách města v jeho přehledu (levý spodní okraj obrazovky města).",
|
||||
|
||||
"vcmi.townHall.missingBase" : "Základní budova %s musí být postavena jako první",
|
||||
"vcmi.townHall.noCreaturesToRecruit" : "Žádné jednotky k vycvičení!", //TODO
|
||||
"vcmi.townHall.greetingManaVortex" : "As you near the %s your body is filled with new energy. You have doubled your normal spell points.",
|
||||
"vcmi.townHall.greetingKnowledge" : "You study the glyphs on the %s and gain insight into the workings of various magics (+1 Knowledge).",
|
||||
"vcmi.townHall.noCreaturesToRecruit" : "Žádné jednotky k vycvičení!",
|
||||
"vcmi.townHall.greetingManaVortex" : "Při pobytu u místa %s se vaše tělo naplnilo novou energií. Máte dvojnásobné množství maximální magické energie.",
|
||||
"vcmi.townHall.greetingKnowledge" : "Studujete glyfy na the %s a porozumíte fungování různých magií (+1 Znalosti).",
|
||||
"vcmi.townHall.greetingSpellPower" : "%s vás učí nové cesty zaměření vaší magické síly (+1 Síla kouzel).",
|
||||
"vcmi.townHall.greetingExperience" : "Návštěva %s vás naučila spoustu nových dovedností (+1000 zkušeností).",
|
||||
"vcmi.townHall.greetingAttack" : "Čas strávený poblíž místa zvaného %s allows you to learn more effective combat skills (+1 Attack Skill).",
|
||||
"vcmi.townHall.greetingDefence" : "Spending time in the %s, the experienced warriors therein teach you additional defensive skills (+1 Defense).",
|
||||
"vcmi.townHall.hasNotProduced" : "%s zatím nic nevyrobil.",
|
||||
"vcmi.townHall.hasProduced" : "%s vyrobil %d %s tento týden.",
|
||||
"vcmi.townHall.greetingAttack" : "Čas strávený poblíž místa zvaného %s vám dovolil se naučit efektivnější bojové dovednosti (+1 Útočná síla).",
|
||||
"vcmi.townHall.greetingDefence" : "Trávíte čas na místě zvaném %s, zkušení bojovníci vás u toho naučili nové metody obrany (+1 Obranná síla).",
|
||||
"vcmi.townHall.hasNotProduced" : "%s - zatím nic nevyrobeno.",
|
||||
"vcmi.townHall.hasProduced" : "%s - vyrobeno %d %s tento týden.",
|
||||
"vcmi.townHall.greetingCustomBonus" : "%s vám dává +%d %s%s",
|
||||
"vcmi.townHall.greetingCustomUntil" : " do další bitvy.",
|
||||
"vcmi.townHall.greetingInTownMagicWell" : "%s obnovil na maximum vaši magickou energii.",
|
||||
"vcmi.townHall.greetingInTownMagicWell" : "%s - obnoveno na maximum vaši magickou energii.",
|
||||
|
||||
"vcmi.logicalExpressions.anyOf" : "Něco z následujících:",
|
||||
"vcmi.logicalExpressions.allOf" : "Všechny následující:",
|
||||
@ -174,17 +215,17 @@
|
||||
"vcmi.heroWindow.openBackpack.hover" : "Open artifact backpack window",
|
||||
"vcmi.heroWindow.openBackpack.help" : "Opens window that allows easier artifact backpack management",
|
||||
|
||||
"vcmi.commanderWindow.artifactMessage" : "Do you want to return this artifact to the hero?",
|
||||
"vcmi.commanderWindow.artifactMessage" : "Chcete navrátit tento artefakt hrdinovi?",
|
||||
|
||||
"vcmi.creatureWindow.showBonuses.hover" : "Switch to bonuses view",
|
||||
"vcmi.creatureWindow.showBonuses.hover" : "Přepnout na zobrazení bonusů",
|
||||
"vcmi.creatureWindow.showBonuses.help" : "Display all active bonuses of the commander",
|
||||
"vcmi.creatureWindow.showSkills.hover" : "Switch to skills view",
|
||||
"vcmi.creatureWindow.showSkills.hover" : "Přepnout na zobrazení schoostí",
|
||||
"vcmi.creatureWindow.showSkills.help" : "Display all learned skills of the commander",
|
||||
"vcmi.creatureWindow.returnArtifact.hover" : "Vrátit artefakt",
|
||||
"vcmi.creatureWindow.returnArtifact.help" : "Klikněte na toto tlačítko pro navrácení artefaktů do hrdinova batohu",
|
||||
|
||||
"vcmi.questLog.hideComplete.hover" : "Hide complete quests",
|
||||
"vcmi.questLog.hideComplete.help" : "Hide all completed quests",
|
||||
"vcmi.questLog.hideComplete.hover" : "Skrýt dokončené úkoly",
|
||||
"vcmi.questLog.hideComplete.help" : "Skrýt všechny dokončené úkoly",
|
||||
|
||||
"vcmi.randomMapTab.widgets.randomTemplate" : "(Random)",
|
||||
"vcmi.randomMapTab.widgets.templateLabel" : "Šablona",
|
||||
@ -192,9 +233,67 @@
|
||||
"vcmi.randomMapTab.widgets.teamAlignmentsLabel" : "Team Alignments",
|
||||
"vcmi.randomMapTab.widgets.roadTypesLabel" : "Druhy cest",
|
||||
|
||||
"vcmi.optionsTab.widgets.labelTimer" : "Časovač",
|
||||
"vcmi.optionsTab.widgets.timerModeSwitch.classic" : "Klasický časovač",
|
||||
"vcmi.optionsTab.widgets.timerModeSwitch.chess" : "Šachový časovač",
|
||||
"vcmi.optionsTab.turnOptions.hover" : "Možnosti tahu",
|
||||
"vcmi.optionsTab.turnOptions.help" : "Vyberte odpočítávadlo tahů a nastavení souběžných tahů",
|
||||
"vcmi.optionsTab.selectPreset" : "Preset",
|
||||
|
||||
"vcmi.optionsTab.chessFieldBase.hover" : "Base timer",
|
||||
"vcmi.optionsTab.chessFieldTurn.hover" : "Turn timer",
|
||||
"vcmi.optionsTab.chessFieldBattle.hover" : "Battle timer",
|
||||
"vcmi.optionsTab.chessFieldUnit.hover" : "Unit timer",
|
||||
"vcmi.optionsTab.chessFieldBase.help" : "Used when {Turn Timer} reaches 0. Set once at game start. On reaching zero, ends current turn. Any ongoing combat with end with a loss.",
|
||||
"vcmi.optionsTab.chessFieldTurnAccumulate.help" : "Used out of combat or when {Battle Timer} runs out. Reset each turn. Leftover added to {Base Timer} at turn's end.",
|
||||
"vcmi.optionsTab.chessFieldTurnDiscard.help" : "Used out of combat or when {Battle Timer} runs out. Reset each turn. Any unspent time is lost",
|
||||
"vcmi.optionsTab.chessFieldBattle.help" : "Used in battles with AI or in pvp combat when {Unit Timer} runs out. Reset at start of each combat.",
|
||||
"vcmi.optionsTab.chessFieldUnitAccumulate.help" : "Used when selecting unit action in pvp combat. Leftover added to {Battle Timer} at end of unit turn.",
|
||||
"vcmi.optionsTab.chessFieldUnitDiscard.help" : "Used when selecting unit action in pvp combat. Reset at start of each unit's turn. Any unspent time is lost",
|
||||
|
||||
"vcmi.optionsTab.accumulate" : "Accumulate",
|
||||
|
||||
"vcmi.optionsTab.simturnsTitle" : "Souběžné tahy",
|
||||
"vcmi.optionsTab.simturnsMin.hover" : "At least for",
|
||||
"vcmi.optionsTab.simturnsMax.hover" : "At most for",
|
||||
"vcmi.optionsTab.simturnsAI.hover" : "(Experimental) Simultaneous AI Turns",
|
||||
"vcmi.optionsTab.simturnsMin.help" : "Play simultaneously for specified number of days. Contacts between players during this period are blocked",
|
||||
"vcmi.optionsTab.simturnsMax.help" : "Play simultaneously for specified number of days or until contact with another player",
|
||||
"vcmi.optionsTab.simturnsAI.help" : "{Simultaneous AI Turns}\nExperimental option. Allows AI players to act at the same time as human player when simultaneous turns are enabled.",
|
||||
|
||||
"vcmi.optionsTab.turnTime.select" : "Select turn timer preset",
|
||||
"vcmi.optionsTab.turnTime.unlimited" : "Unlimited turn time",
|
||||
"vcmi.optionsTab.turnTime.classic.1" : "Classic timer: 1 minute",
|
||||
"vcmi.optionsTab.turnTime.classic.2" : "Classic timer: 2 minutes",
|
||||
"vcmi.optionsTab.turnTime.classic.5" : "Classic timer: 5 minutes",
|
||||
"vcmi.optionsTab.turnTime.classic.10" : "Classic timer: 10 minutes",
|
||||
"vcmi.optionsTab.turnTime.classic.20" : "Classic timer: 20 minutes",
|
||||
"vcmi.optionsTab.turnTime.classic.30" : "Classic timer: 30 minutes",
|
||||
"vcmi.optionsTab.turnTime.chess.20" : "Chess: 20:00 + 10:00 + 02:00 + 00:00",
|
||||
"vcmi.optionsTab.turnTime.chess.16" : "Chess: 16:00 + 08:00 + 01:30 + 00:00",
|
||||
"vcmi.optionsTab.turnTime.chess.8" : "Chess: 08:00 + 04:00 + 01:00 + 00:00",
|
||||
"vcmi.optionsTab.turnTime.chess.4" : "Chess: 04:00 + 02:00 + 00:30 + 00:00",
|
||||
"vcmi.optionsTab.turnTime.chess.2" : "Chess: 02:00 + 01:00 + 00:15 + 00:00",
|
||||
"vcmi.optionsTab.turnTime.chess.1" : "Chess: 01:00 + 01:00 + 00:00 + 00:00",
|
||||
|
||||
"vcmi.optionsTab.simturns.select" : "Select simultaneous turns preset",
|
||||
"vcmi.optionsTab.simturns.none" : "No simultaneous turns",
|
||||
"vcmi.optionsTab.simturns.tillContactMax" : "Simturns: Until contact",
|
||||
"vcmi.optionsTab.simturns.tillContact1" : "Simturns: 1 week, break on contact",
|
||||
"vcmi.optionsTab.simturns.tillContact2" : "Simturns: 2 weeks, break on contact",
|
||||
"vcmi.optionsTab.simturns.tillContact4" : "Simturns: 1 month, break on contact",
|
||||
"vcmi.optionsTab.simturns.blocked1" : "Simturns: 1 week, contacts blocked",
|
||||
"vcmi.optionsTab.simturns.blocked2" : "Simturns: 2 weeks, contacts blocked",
|
||||
"vcmi.optionsTab.simturns.blocked4" : "Simturns: 1 month, contacts blocked",
|
||||
|
||||
// Translation note: translate strings below using form that is correct for "0 days", "1 day" and "2 days" in your language
|
||||
// Using this information, VCMI will automatically select correct plural form for every possible amount
|
||||
"vcmi.optionsTab.simturns.days.0" : " %d dní",
|
||||
"vcmi.optionsTab.simturns.days.1" : " %d den",
|
||||
"vcmi.optionsTab.simturns.days.2" : " %d dny",
|
||||
"vcmi.optionsTab.simturns.weeks.0" : " %d týdnů",
|
||||
"vcmi.optionsTab.simturns.weeks.1" : " %d týden",
|
||||
"vcmi.optionsTab.simturns.weeks.2" : " %d týdny",
|
||||
"vcmi.optionsTab.simturns.months.0" : " %d měsíců",
|
||||
"vcmi.optionsTab.simturns.months.1" : " %d měsíc",
|
||||
"vcmi.optionsTab.simturns.months.2" : " %d měsíce",
|
||||
|
||||
// Custom victory conditions for H3 campaigns and HotA maps
|
||||
"vcmi.map.victoryCondition.daysPassed.toOthers" : "Nepřítel zvládl přežít do této chvíle. Vítězství je jeho!",
|
||||
@ -203,162 +302,162 @@
|
||||
"vcmi.map.victoryCondition.eliminateMonsters.toSelf" : "Gratulace! Porazili jste všechny nepřátele zamořující tuto zemi a můžete si nárokovat vítězství!",
|
||||
"vcmi.map.victoryCondition.collectArtifacts.message" : "Získejte tři artefakty",
|
||||
"vcmi.map.victoryCondition.angelicAlliance.toSelf" : "Gratulace! Všichni vaši nepřítelé byli poraženi a máte Andělskou alianci! Vítězství je vaše!",
|
||||
"vcmi.map.victoryCondition.angelicAlliance.message" : "Porazte všechny nepřátele a vyrobte Andělskou alianci",
|
||||
"vcmi.map.victoryCondition.angelicAlliance.message" : "Porazte všechny nepřátele a utužte Andělskou alianci",
|
||||
|
||||
// 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.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.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", //TODO
|
||||
"vcmi.stackExperience.rank.0" : "Začátečník",
|
||||
"vcmi.stackExperience.rank.1" : "Učeň",
|
||||
"vcmi.stackExperience.rank.2" : "Trénovaný",
|
||||
"vcmi.stackExperience.rank.3" : "Zručný",
|
||||
"vcmi.stackExperience.rank.4" : "Prověřený",
|
||||
"vcmi.stackExperience.rank.5" : "Veterán",
|
||||
"vcmi.stackExperience.rank.6" : "Adept",
|
||||
"vcmi.stackExperience.rank.7" : "Expert",
|
||||
"vcmi.stackExperience.rank.8" : "Elite",
|
||||
"vcmi.stackExperience.rank.8" : "Elitní",
|
||||
"vcmi.stackExperience.rank.9" : "Master",
|
||||
"vcmi.stackExperience.rank.10" : "Ace",
|
||||
"vcmi.stackExperience.rank.10" : "Eso",
|
||||
|
||||
"core.bonus.ADDITIONAL_ATTACK.name": "Dvojitý úder",
|
||||
"core.bonus.ADDITIONAL_ATTACK.description": "Útočí dvakrát",
|
||||
"core.bonus.ADDITIONAL_RETALIATION.name": "Additional retaliations",
|
||||
"core.bonus.ADDITIONAL_RETALIATION.description": "May retaliate ${val} extra times",
|
||||
"core.bonus.ADDITIONAL_RETALIATION.name": "Další odveta",
|
||||
"core.bonus.ADDITIONAL_RETALIATION.description": "Může zaútočit zpět navíc ${val}x",
|
||||
"core.bonus.AIR_IMMUNITY.name": "Vzdušná odolnost",
|
||||
"core.bonus.AIR_IMMUNITY.description": "Immune to all spells from the school of Air magic",
|
||||
"core.bonus.AIR_IMMUNITY.description": "Imunní všem kouzlům školy vzdušné magie",
|
||||
"core.bonus.ATTACKS_ALL_ADJACENT.name": "Útok okolo",
|
||||
"core.bonus.ATTACKS_ALL_ADJACENT.description": "Útočí na všechny sousední jednotky",
|
||||
"core.bonus.BLOCKS_RETALIATION.name": "No retaliation",
|
||||
"core.bonus.BLOCKS_RETALIATION.description": "Enemy cannot retaliate",
|
||||
"core.bonus.BLOCKS_RANGED_RETALIATION.name": "No ranged retaliation",
|
||||
"core.bonus.BLOCKS_RANGED_RETALIATION.description": "Enemy cannot retaliate by using a ranged attack",
|
||||
"core.bonus.BLOCKS_RETALIATION.name": "Žádná odplata",
|
||||
"core.bonus.BLOCKS_RETALIATION.description": "Nepřítel nemůže zaútočit zpět",
|
||||
"core.bonus.BLOCKS_RANGED_RETALIATION.name": "Žádná odplata na dálku",
|
||||
"core.bonus.BLOCKS_RANGED_RETALIATION.description": "Nepřítel nemůže zaútočit zpět útokem na dálku",
|
||||
"core.bonus.CATAPULT.name": "Katapult",
|
||||
"core.bonus.CATAPULT.description": "Attacks siege walls",
|
||||
"core.bonus.CHANGES_SPELL_COST_FOR_ALLY.name": "Reduce Casting Cost (${val})",
|
||||
"core.bonus.CHANGES_SPELL_COST_FOR_ALLY.description": "Reduces the spellcasting cost for the hero by ${val}",
|
||||
"core.bonus.CHANGES_SPELL_COST_FOR_ENEMY.name": "Magic Damper (${val})",
|
||||
"core.bonus.CHANGES_SPELL_COST_FOR_ENEMY.description": "Increases spellcasting cost of enemy spells by ${val}",
|
||||
"core.bonus.CHARGE_IMMUNITY.name": "Immune to Charge",
|
||||
"core.bonus.CATAPULT.description": "Útočí na ochranné hradby",
|
||||
"core.bonus.CHANGES_SPELL_COST_FOR_ALLY.name": "Snížit cenu kouzel (${val})",
|
||||
"core.bonus.CHANGES_SPELL_COST_FOR_ALLY.description": "Snižuje cenu energie hrdiny o ${val}",
|
||||
"core.bonus.CHANGES_SPELL_COST_FOR_ENEMY.name": "Tlumič magie (${val})",
|
||||
"core.bonus.CHANGES_SPELL_COST_FOR_ENEMY.description": "Zvyšuje cenu energie kouzlení nepřítele o ${val}",
|
||||
"core.bonus.CHARGE_IMMUNITY.name": "Immune to Charge", // TODO
|
||||
"core.bonus.CHARGE_IMMUNITY.description": "Immune to Cavalier's and Champion's Charge",
|
||||
"core.bonus.DARKNESS.name": "Darkness cover",
|
||||
"core.bonus.DARKNESS.description": "Creates a shroud of darkness with a ${val} radius",
|
||||
"core.bonus.DEATH_STARE.name": "Death Stare (${val}%)",
|
||||
"core.bonus.DEATH_STARE.description": "Has a ${val}% chance to kill a single creature",
|
||||
"core.bonus.DEFENSIVE_STANCE.name": "Defense Bonus",
|
||||
"core.bonus.DEFENSIVE_STANCE.description": "+${val} Defense when defending",
|
||||
"core.bonus.DESTRUCTION.name": "Destruction",
|
||||
"core.bonus.DESTRUCTION.description": "Has ${val}% chance to kill extra units after attack",
|
||||
"core.bonus.DOUBLE_DAMAGE_CHANCE.name": "Death Blow",
|
||||
"core.bonus.DOUBLE_DAMAGE_CHANCE.description": "Has a ${val}% chance of dealing double base damage when attacking",
|
||||
"core.bonus.DARKNESS.name": "Závoj temnoty",
|
||||
"core.bonus.DARKNESS.description": "Vytvoří clonu temnoty v oblasti ${val} polí",
|
||||
"core.bonus.DEATH_STARE.name": "Smrtící pohled (${val}%)",
|
||||
"core.bonus.DEATH_STARE.description": "Má ${val}% šanci zabít jednu creature",
|
||||
"core.bonus.DEFENSIVE_STANCE.name": "Obranný bonus",
|
||||
"core.bonus.DEFENSIVE_STANCE.description": "+${val} obranné síly při obraně",
|
||||
"core.bonus.DESTRUCTION.name": "Zničení",
|
||||
"core.bonus.DESTRUCTION.description": "Má ${val}% šanci zabít další jednotky po útoku",
|
||||
"core.bonus.DOUBLE_DAMAGE_CHANCE.name": "Smrtící rána",
|
||||
"core.bonus.DOUBLE_DAMAGE_CHANCE.description": "Má ${val}% šanci na udělení dvojnásobného základního poškození při útoku",
|
||||
"core.bonus.DRAGON_NATURE.name": "Drak",
|
||||
"core.bonus.DRAGON_NATURE.description": "Creature has a Dragon Nature",
|
||||
"core.bonus.DRAGON_NATURE.description": "Jednotka má povahu draka",
|
||||
"core.bonus.EARTH_IMMUNITY.name": "Zemní odolnost",
|
||||
"core.bonus.EARTH_IMMUNITY.description": "Immune to all spells from the school of Earth magic",
|
||||
"core.bonus.ENCHANTER.name": "Enchanter",
|
||||
"core.bonus.ENCHANTER.description": "Can cast mass ${subtype.spell} every turn",
|
||||
"core.bonus.ENCHANTED.name": "Enchanted",
|
||||
"core.bonus.ENCHANTED.description": "Affected by permanent ${subtype.spell}",
|
||||
"core.bonus.ENEMY_DEFENCE_REDUCTION.name": "Ignore Defense (${val}%)",
|
||||
"core.bonus.ENEMY_DEFENCE_REDUCTION.description": "When attacking, ${val}% of the defender's defense is ignored",
|
||||
"core.bonus.EARTH_IMMUNITY.description": "Imunní všem kouzlům školy zemské magie",
|
||||
"core.bonus.ENCHANTER.name": "Zaklínač",
|
||||
"core.bonus.ENCHANTER.description": "Může masově seslat ${subtype.spell} každý tah",
|
||||
"core.bonus.ENCHANTED.name": "Očarovaný",
|
||||
"core.bonus.ENCHANTED.description": "Trvale ovlivněm kouzlem ${subtype.spell}",
|
||||
"core.bonus.ENEMY_DEFENCE_REDUCTION.name": "Nevšímá si ${val} % bodů obrany",
|
||||
"core.bonus.ENEMY_DEFENCE_REDUCTION.description": "Pří útoku nebude brát v potaz ${val}% bodů obrany obránce",
|
||||
"core.bonus.FIRE_IMMUNITY.name": "Ohnivá odolnost",
|
||||
"core.bonus.FIRE_IMMUNITY.description": "Immune to all spells from the school of Fire magic",
|
||||
"core.bonus.FIRE_IMMUNITY.description": "Imunní všem kouzlům školy ohnivé magie",
|
||||
"core.bonus.FIRE_SHIELD.name": "Ohnivý štít (${val}%)",
|
||||
"core.bonus.FIRE_SHIELD.description": "Reflects part of melee damage",
|
||||
"core.bonus.FIRST_STRIKE.name": "First Strike",
|
||||
"core.bonus.FIRST_STRIKE.description": "This creature retaliates before being attacked",
|
||||
"core.bonus.FEAR.name": "Fear",
|
||||
"core.bonus.FEAR.description": "Causes Fear on an enemy stack",
|
||||
"core.bonus.FIRE_SHIELD.description": "Odrazí část zranení útoku zblízka",
|
||||
"core.bonus.FIRST_STRIKE.name": "První úder",
|
||||
"core.bonus.FIRST_STRIKE.description": "Tato jednotka útočí zpět ještě než je na ni zaútočeno",
|
||||
"core.bonus.FEAR.name": "Strach",
|
||||
"core.bonus.FEAR.description": "Způsobí strach nepřátelskému oddílu",
|
||||
"core.bonus.FEARLESS.name": "Nebojácnost",
|
||||
"core.bonus.FEARLESS.description": "Odolnost proti strachu",
|
||||
"core.bonus.FLYING.name": "Letec",
|
||||
"core.bonus.FLYING.description": "Při pohybu létá (přes překážky)",
|
||||
"core.bonus.FREE_SHOOTING.name": "Blízké výstřely",
|
||||
"core.bonus.FREE_SHOOTING.description": "Může použít výstřely při útoku zblízka",
|
||||
"core.bonus.GARGOYLE.name": "Gargoyle",
|
||||
"core.bonus.GARGOYLE.description": "Cannot be raised or healed",
|
||||
"core.bonus.GENERAL_DAMAGE_REDUCTION.name": "Reduce Damage (${val}%)",
|
||||
"core.bonus.GENERAL_DAMAGE_REDUCTION.description": "Reduces physical damage from ranged or melee attacks",
|
||||
"core.bonus.GARGOYLE.name": "Chrlič",
|
||||
"core.bonus.GARGOYLE.description": "Cannot be raised or healed", // TODO
|
||||
"core.bonus.GENERAL_DAMAGE_REDUCTION.name": "Snižuje poškození (${val}%)",
|
||||
"core.bonus.GENERAL_DAMAGE_REDUCTION.description": "Snižuje poškození od útoků z dálky a blízka",
|
||||
"core.bonus.HATE.name": "Nesnáší ${subtype.creature}",
|
||||
"core.bonus.HATE.description": "Does ${val}% more damage to ${subtype.creature}",
|
||||
"core.bonus.HATE.description": "Dává o ${val} % větší zranění jednotce ${subtype.creature}",
|
||||
"core.bonus.HEALER.name": "Léčitel",
|
||||
"core.bonus.HEALER.description": "Léčí spojenecké jednotky",
|
||||
"core.bonus.HP_REGENERATION.name": "Regenerace",
|
||||
"core.bonus.HP_REGENERATION.description": "Každé kolo léčí ${val} životů",
|
||||
"core.bonus.JOUSTING.name": "Champion charge",
|
||||
"core.bonus.JOUSTING.description": "+${val}% damage for each hex travelled",
|
||||
"core.bonus.JOUSTING.name": "Nabití šampiona",
|
||||
"core.bonus.JOUSTING.description": "+${val}% poškození za každé projité pole",
|
||||
"core.bonus.KING.name": "Král",
|
||||
"core.bonus.KING.description": "Vulnerable to SLAYER level ${val} or higher",
|
||||
"core.bonus.LEVEL_SPELL_IMMUNITY.name": "Spell immunity 1-${val}",
|
||||
"core.bonus.LEVEL_SPELL_IMMUNITY.description": "Immune to spells of levels 1-${val}",
|
||||
"core.bonus.LIMITED_SHOOTING_RANGE.name" : "Limited shooting range",
|
||||
"core.bonus.LIMITED_SHOOTING_RANGE.description" : "Unable to target units farther than ${val} hexes",
|
||||
"core.bonus.KING.description": "Zranitelný zabijákovi úrovně ${val} a vyšší",
|
||||
"core.bonus.LEVEL_SPELL_IMMUNITY.name": "Odolnost kouzel 1-${val}",
|
||||
"core.bonus.LEVEL_SPELL_IMMUNITY.description": "Odolnost vůči kouzlům úrovní 1-${val}",
|
||||
"core.bonus.LIMITED_SHOOTING_RANGE.name" : "Omezený dosah střelby",
|
||||
"core.bonus.LIMITED_SHOOTING_RANGE.description" : "Nevystřelí na jednotky dále než ${val} polí",
|
||||
"core.bonus.LIFE_DRAIN.name": "Vysátí životů (${val}%)",
|
||||
"core.bonus.LIFE_DRAIN.description": "Vysaje ${val}% uděleného poškození",
|
||||
"core.bonus.MANA_CHANNELING.name": "Magic Channel ${val}%",
|
||||
"core.bonus.MANA_CHANNELING.description": "Gives your hero ${val}% of the mana spent by the enemy",
|
||||
"core.bonus.MANA_CHANNELING.name": "Magic Channel ${val}%", // TODO
|
||||
"core.bonus.MANA_CHANNELING.description": "Dá vašemu hrdinovi ${val} % many využité nepřítelem",
|
||||
"core.bonus.MANA_DRAIN.name": "Vysátí many",
|
||||
"core.bonus.MANA_DRAIN.description": "Každé kolo vysaje ${val} many",
|
||||
"core.bonus.MAGIC_MIRROR.name": "Kouzelné zrcadlo (${val}%)",
|
||||
"core.bonus.MAGIC_MIRROR.description": "Has a ${val}% chance to redirect an offensive spell to an enemy unit",
|
||||
"core.bonus.MAGIC_RESISTANCE.name": "Magic Resistance (${val}%)",
|
||||
"core.bonus.MAGIC_RESISTANCE.description": "Has a ${val}% chance to resist an enemy spell",
|
||||
"core.bonus.MIND_IMMUNITY.name": "Mind Spell Immunity",
|
||||
"core.bonus.MIND_IMMUNITY.description": "Immune to Mind-type spells",
|
||||
"core.bonus.NO_DISTANCE_PENALTY.name": "No distance penalty",
|
||||
"core.bonus.NO_DISTANCE_PENALTY.description": "Does full damage at any distance",
|
||||
"core.bonus.NO_MELEE_PENALTY.name": "No melee penalty",
|
||||
"core.bonus.NO_MELEE_PENALTY.description": "Creature has no Melee Penalty",
|
||||
"core.bonus.NO_MORALE.name": "Neutral Morale",
|
||||
"core.bonus.NO_MORALE.description": "Creature is immune to morale effects",
|
||||
"core.bonus.NO_WALL_PENALTY.name": "No wall penalty",
|
||||
"core.bonus.NO_WALL_PENALTY.description": "Full damage during siege",
|
||||
"core.bonus.NON_LIVING.name": "Non living",
|
||||
"core.bonus.NON_LIVING.description": "Immunity to many effects",
|
||||
"core.bonus.RANDOM_SPELLCASTER.name": "Random spellcaster",
|
||||
"core.bonus.RANDOM_SPELLCASTER.description": "Can cast random spell",
|
||||
"core.bonus.RANGED_RETALIATION.name": "Ranged retaliation",
|
||||
"core.bonus.RANGED_RETALIATION.description": "Can perform ranged counterattack",
|
||||
"core.bonus.RECEPTIVE.name": "Receptive",
|
||||
"core.bonus.RECEPTIVE.description": "No Immunity to Friendly Spells",
|
||||
"core.bonus.REBIRTH.name": "Rebirth (${val}%)",
|
||||
"core.bonus.REBIRTH.description": "${val}% of stack will rise after death",
|
||||
"core.bonus.RETURN_AFTER_STRIKE.name": "Attack and Return",
|
||||
"core.bonus.RETURN_AFTER_STRIKE.description": "Returns after melee attack",
|
||||
"core.bonus.SHOOTER.name": "Ranged",
|
||||
"core.bonus.SHOOTER.description": "Creature can shoot",
|
||||
"core.bonus.SHOOTS_ALL_ADJACENT.name": "Shoot all around",
|
||||
"core.bonus.SHOOTS_ALL_ADJACENT.description": "This creature's ranged attacks strike all targets in a small area",
|
||||
"core.bonus.SOUL_STEAL.name": "Soul Steal",
|
||||
"core.bonus.SOUL_STEAL.description": "Gains ${val} new creatures for each enemy killed",
|
||||
"core.bonus.SPELLCASTER.name": "Spellcaster",
|
||||
"core.bonus.SPELLCASTER.description": "Can cast ${subtype.spell}",
|
||||
"core.bonus.SPELL_AFTER_ATTACK.name": "Cast After Attack",
|
||||
"core.bonus.SPELL_AFTER_ATTACK.description": "Has a ${val}% chance to cast ${subtype.spell} after it attacks",
|
||||
"core.bonus.SPELL_BEFORE_ATTACK.name": "Cast Before Attack",
|
||||
"core.bonus.SPELL_BEFORE_ATTACK.description": "Has a ${val}% chance to cast ${subtype.spell} before it attacks",
|
||||
"core.bonus.SPELL_DAMAGE_REDUCTION.name": "Spell Resistance",
|
||||
"core.bonus.SPELL_DAMAGE_REDUCTION.description": "Damage from spells reduced by ${val}%.",
|
||||
"core.bonus.MAGIC_MIRROR.description": "Má ${val}% šanci odrazit útočné kouzlo na nepřátelskou jednotku",
|
||||
"core.bonus.MAGIC_RESISTANCE.name": "Magická odolnost (${val}%)",
|
||||
"core.bonus.MAGIC_RESISTANCE.description": "Má ${val}% šanci ustát nepřátelské kouzlo",
|
||||
"core.bonus.MIND_IMMUNITY.name": "Imunita kouzel mysli",
|
||||
"core.bonus.MIND_IMMUNITY.description": "Imunní vůči kouzlům cílícím na mysl",
|
||||
"core.bonus.NO_DISTANCE_PENALTY.name": "Bez penalizace vzdálenosti",
|
||||
"core.bonus.NO_DISTANCE_PENALTY.description": "Plné poškození na jakoukoliv vzdálenost",
|
||||
"core.bonus.NO_MELEE_PENALTY.name": "Bez penalizace útoku zblízka",
|
||||
"core.bonus.NO_MELEE_PENALTY.description": "Jednotka není penalizována za útok zblízka",
|
||||
"core.bonus.NO_MORALE.name": "Neutrální morálka",
|
||||
"core.bonus.NO_MORALE.description": "Jednotka je imunní vůči efektu morálky",
|
||||
"core.bonus.NO_WALL_PENALTY.name": "Bez penalizace hradbami",
|
||||
"core.bonus.NO_WALL_PENALTY.description": "Plné poškození při obléhání",
|
||||
"core.bonus.NON_LIVING.name": "Neživoucí",
|
||||
"core.bonus.NON_LIVING.description": "Imunní vůči mnohým efektům",
|
||||
"core.bonus.RANDOM_SPELLCASTER.name": "Náhodný kouzelník",
|
||||
"core.bonus.RANDOM_SPELLCASTER.description": "Může seslat náhodné kouzlo",
|
||||
"core.bonus.RANGED_RETALIATION.name": "Vzdálená msta",
|
||||
"core.bonus.RANGED_RETALIATION.description": "Může provést protiútok na dálku",
|
||||
"core.bonus.RECEPTIVE.name": "Přijímavý",
|
||||
"core.bonus.RECEPTIVE.description": "Není imunní vůči přátelským kouzlům",
|
||||
"core.bonus.REBIRTH.name": "Znovuzrození (${val}%)",
|
||||
"core.bonus.REBIRTH.description": "${val}% oddílu se po smrti znovu narodí",
|
||||
"core.bonus.RETURN_AFTER_STRIKE.name": "Útok a návrat",
|
||||
"core.bonus.RETURN_AFTER_STRIKE.description": "Navrátí se po útoku na blízko",
|
||||
"core.bonus.SHOOTER.name": "Střelec",
|
||||
"core.bonus.SHOOTER.description": "Jednotka může střílet",
|
||||
"core.bonus.SHOOTS_ALL_ADJACENT.name": "Střílí okolo",
|
||||
"core.bonus.SHOOTS_ALL_ADJACENT.description": "Vzdálené útoky této jednotky zasáhnou všechny cíle v malé oblasti",
|
||||
"core.bonus.SOUL_STEAL.name": "Zloděj duší",
|
||||
"core.bonus.SOUL_STEAL.description": "Získá ${val} nových jednotek za každého zabitého nepřítele",
|
||||
"core.bonus.SPELLCASTER.name": "Kouzelník",
|
||||
"core.bonus.SPELLCASTER.description": "Může seslat ${subtype.spell}",
|
||||
"core.bonus.SPELL_AFTER_ATTACK.name": "Kouzlení po útoku",
|
||||
"core.bonus.SPELL_AFTER_ATTACK.description": "Má ${val}% šanci seslat ${subtype.spell} po zaútočení",
|
||||
"core.bonus.SPELL_BEFORE_ATTACK.name": "Kouzlení před útokem",
|
||||
"core.bonus.SPELL_BEFORE_ATTACK.description": "Má ${val}% šanci seslat ${subtype.spell} před zaútočením",
|
||||
"core.bonus.SPELL_DAMAGE_REDUCTION.name": "Magická odolnost",
|
||||
"core.bonus.SPELL_DAMAGE_REDUCTION.description": "Zranění od kouzel sníženo o ${val}%.",
|
||||
"core.bonus.SPELL_IMMUNITY.name": "Odolnost vůči kouzlům",
|
||||
"core.bonus.SPELL_IMMUNITY.description": "Odolnost proti ${subtype.spell}",
|
||||
"core.bonus.SPELL_LIKE_ATTACK.name": "Spell-like attack",
|
||||
"core.bonus.SPELL_LIKE_ATTACK.description": "Attacks with ${subtype.spell}",
|
||||
"core.bonus.SPELL_RESISTANCE_AURA.name": "Aura of Resistance",
|
||||
"core.bonus.SPELL_RESISTANCE_AURA.description": "Nearby stacks get ${val}% magic resistance",
|
||||
"core.bonus.SUMMON_GUARDIANS.name": "Summon guardians",
|
||||
"core.bonus.SUMMON_GUARDIANS.description": "At the start of battle summons ${subtype.creature} (${val}%)",
|
||||
"core.bonus.SYNERGY_TARGET.name": "Synergizable",
|
||||
"core.bonus.SPELL_LIKE_ATTACK.name": "Útok kouzlem",
|
||||
"core.bonus.SPELL_LIKE_ATTACK.description": "Útočí kouzlem ${subtype.spell}",
|
||||
"core.bonus.SPELL_RESISTANCE_AURA.name": "Aura odolnosti",
|
||||
"core.bonus.SPELL_RESISTANCE_AURA.description": "Oddíly poblíž získají ${val}% magickou odolnost",
|
||||
"core.bonus.SUMMON_GUARDIANS.name": "Povolat strážce",
|
||||
"core.bonus.SUMMON_GUARDIANS.description": "Na začátku bitvy povolá ${subtype.creature} (${val}%)",
|
||||
"core.bonus.SYNERGY_TARGET.name": "Synergizable", // TODO
|
||||
"core.bonus.SYNERGY_TARGET.description": "This creature is vulnerable to synergy effect",
|
||||
"core.bonus.TWO_HEX_ATTACK_BREATH.name": "Breath",
|
||||
"core.bonus.TWO_HEX_ATTACK_BREATH.description": "Breath Attack (2-hex range)",
|
||||
"core.bonus.THREE_HEADED_ATTACK.name": "Three-headed attack",
|
||||
"core.bonus.THREE_HEADED_ATTACK.description": "Attacks three adjacent units",
|
||||
"core.bonus.TRANSMUTATION.name": "Transmutation",
|
||||
"core.bonus.TRANSMUTATION.description": "${val}% chance to transform attacked unit to a different type",
|
||||
"core.bonus.TWO_HEX_ATTACK_BREATH.name": "Dech",
|
||||
"core.bonus.TWO_HEX_ATTACK_BREATH.description": "Dechový útok (dosah do dvou polí)",
|
||||
"core.bonus.THREE_HEADED_ATTACK.name": "Tříhlavý útok",
|
||||
"core.bonus.THREE_HEADED_ATTACK.description": "Útočí na tři sousední jednotky",
|
||||
"core.bonus.TRANSMUTATION.name": "Transmutace",
|
||||
"core.bonus.TRANSMUTATION.description": "${val}% šance na přeměnu útočené jednotky na jiný druh",
|
||||
"core.bonus.UNDEAD.name": "Nemrtvý",
|
||||
"core.bonus.UNDEAD.description": "Jednotka je nemrtvá",
|
||||
"core.bonus.UNLIMITED_RETALIATIONS.name": "Unlimited retaliations",
|
||||
"core.bonus.UNLIMITED_RETALIATIONS.description": "Can retaliate against an unlimited number of attacks",
|
||||
"core.bonus.WATER_IMMUNITY.name": "Water immunity",
|
||||
"core.bonus.WATER_IMMUNITY.description": "Immune to all spells from the school of Water magic",
|
||||
"core.bonus.WIDE_BREATH.name": "Wide breath",
|
||||
"core.bonus.WIDE_BREATH.description": "Wide breath attack (multiple hexes)"
|
||||
"core.bonus.UNLIMITED_RETALIATIONS.name": "Neomezené odvety",
|
||||
"core.bonus.UNLIMITED_RETALIATIONS.description": "Může se mstít za neomezený počet útoků",
|
||||
"core.bonus.WATER_IMMUNITY.name": "Vodní odolnost",
|
||||
"core.bonus.WATER_IMMUNITY.description": "Imunní všem kouzlům školy vodní magie",
|
||||
"core.bonus.WIDE_BREATH.name": "Široký dech",
|
||||
"core.bonus.WIDE_BREATH.description": "Útočí širokým dechem (více polí)"
|
||||
}
|
||||
|
@ -54,6 +54,8 @@
|
||||
"vcmi.radialWheel.moveDown" : "Move down",
|
||||
"vcmi.radialWheel.moveBottom" : "Move to bottom",
|
||||
|
||||
"vcmi.spellBook.search" : "search...",
|
||||
|
||||
"vcmi.mainMenu.serverConnecting" : "Connecting...",
|
||||
"vcmi.mainMenu.serverAddressEnter" : "Enter address:",
|
||||
"vcmi.mainMenu.serverConnectionFailed" : "Failed to connect",
|
||||
@ -69,6 +71,7 @@
|
||||
"vcmi.lobby.noPreview" : "no preview",
|
||||
"vcmi.lobby.noUnderground" : "no underground",
|
||||
|
||||
"vcmi.client.errors.missingCampaigns" : "{Missing data files}\n\nCampaigns data files were not found! You may be using incomplete or corrupted Heroes 3 data files. Please reinstall game data.",
|
||||
"vcmi.server.errors.existingProcess" : "Another VCMI server process is running. Please terminate it before starting a new game.",
|
||||
"vcmi.server.errors.modsToEnable" : "{Following mods are required}",
|
||||
"vcmi.server.errors.modsToDisable" : "{Following mods must be disabled}",
|
||||
|
@ -54,6 +54,8 @@
|
||||
"vcmi.radialWheel.moveDown" : "Nach unten bewegen",
|
||||
"vcmi.radialWheel.moveBottom" : "Ganz nach unten bewegen",
|
||||
|
||||
"vcmi.spellBook.search" : "suchen...",
|
||||
|
||||
"vcmi.mainMenu.serverConnecting" : "Verbinde...",
|
||||
"vcmi.mainMenu.serverAddressEnter" : "Addresse eingeben:",
|
||||
"vcmi.mainMenu.serverConnectionFailed" : "Verbindung fehlgeschlagen",
|
||||
|
@ -69,6 +69,7 @@
|
||||
"vcmi.lobby.noPreview" : "огляд недоступний",
|
||||
"vcmi.lobby.noUnderground" : "немає підземелля",
|
||||
|
||||
"vcmi.client.errors.missingCampaigns" : "{Не вистачає файлів даних}\n\nФайли даних кампаній не знайдено! Можливо, ви використовуєте неповні або пошкоджені файли даних Heroes 3. Будь ласка, перевстановіть дані гри.",
|
||||
"vcmi.server.errors.existingProcess" : "Працює інший процес vcmiserver, будь ласка, спочатку завершіть його",
|
||||
"vcmi.server.errors.modsToEnable" : "{Потрібні модифікації для завантаження гри}",
|
||||
"vcmi.server.errors.modsToDisable" : "{Модифікації що мають бути вимкнені}",
|
||||
@ -114,6 +115,8 @@
|
||||
"vcmi.systemOptions.enableUiEnhancementsButton.help" : "{Розширення інтерфейсу}\n\nУвімкніть різні розширення інтерфейсу для покращення якості життя. Наприклад, більша книга заклинань, рюкзак тощо. Вимкнути, щоб отримати більш класичний досвід.",
|
||||
"vcmi.systemOptions.enableLargeSpellbookButton.hover" : "Велика книга заклять",
|
||||
"vcmi.systemOptions.enableLargeSpellbookButton.help" : "{Велика книга заклять}\n\nВмикає більшу книгу заклять, яка вміщує більше заклять на сторінці. Якщо цей параметр увімкнено, анімація зміни сторінок книги заклять не буде відображатися.",
|
||||
"vcmi.systemOptions.audioMuteFocus.hover" : "Тиша при втраті фокусу",
|
||||
"vcmi.systemOptions.audioMuteFocus.help" : "{Тиша при втраті фокусу}\n\nВимкнути звук коли вікно не у фокусі. Виняток становлять ігрові сповіщення та звук нового ходу.",
|
||||
|
||||
"vcmi.adventureOptions.infoBarPick.help" : "{Повідомлення у панелі статусу}\n\nЗа можливості, повідомлення про відвідування об'єктів карти пригод будуть відображені у панелі статусу замість окремого вікна",
|
||||
"vcmi.adventureOptions.infoBarPick.hover" : "Повідомлення у панелі статусу",
|
||||
@ -129,6 +132,8 @@
|
||||
"vcmi.adventureOptions.infoBarCreatureManagement.help" : "{Керування істотами у вікні статусу}\n\nДозволяє впорядковувати істот у вікні статусу замість циклічного перемикання між типовими компонентами",
|
||||
"vcmi.adventureOptions.leftButtonDrag.hover" : "Переміщення мапи лівою кнопкою",
|
||||
"vcmi.adventureOptions.leftButtonDrag.help" : "{Переміщення мапи лівою кнопкою}\n\nЯкщо увімкнено, переміщення миші з натиснутою лівою кнопкою буде перетягувати мапу пригод",
|
||||
"vcmi.adventureOptions.smoothDragging.hover" : "Плавне перетягування мапи",
|
||||
"vcmi.adventureOptions.smoothDragging.help" : "{Плавне перетягування мапи}\n\nЯкщо увімкнено, перетягування мапи має сучасний ефект завершення.",
|
||||
"vcmi.adventureOptions.mapScrollSpeed1.hover": "",
|
||||
"vcmi.adventureOptions.mapScrollSpeed5.hover": "",
|
||||
"vcmi.adventureOptions.mapScrollSpeed6.hover": "",
|
||||
|
@ -10,8 +10,8 @@ android {
|
||||
applicationId "is.xyz.vcmi"
|
||||
minSdk 19
|
||||
targetSdk 33
|
||||
versionCode 1410
|
||||
versionName "1.4.1"
|
||||
versionCode 1420
|
||||
versionName "1.4.2"
|
||||
setProperty("archivesBaseName", "vcmi")
|
||||
}
|
||||
|
||||
|
@ -156,14 +156,6 @@ public class NativeMethods
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings(Const.JNI_METHOD_SUPPRESS)
|
||||
public static String getFormattedDateTime()
|
||||
{
|
||||
String currentDate = new SimpleDateFormat((new SimpleDateFormat()).toLocalizedPattern(), Locale.getDefault()).format(new Date());
|
||||
|
||||
return currentDate;
|
||||
}
|
||||
|
||||
private static void internalProgressDisplay(final boolean show)
|
||||
{
|
||||
final Context ctx = SDL.getContext();
|
||||
|
71
android/vcmi-app/src/main/res/values-cs/strings.xml
Normal file
71
android/vcmi-app/src/main/res/values-cs/strings.xml
Normal file
@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="url_project_page" translatable="false">https://vcmi.eu</string>
|
||||
<string name="url_project_repo" translatable="false">https://github.com/vcmi/vcmi</string>
|
||||
<string name="url_launcher_repo" translatable="false">https://github.com/vcmi/vcmi-android</string>
|
||||
<string name="url_launcher_privacy" translatable="false">https://github.com/vcmi/vcmi/blob/master/docs/players/Privacy_Policy.md</string>
|
||||
|
||||
<string name="app_name">VCMI</string>
|
||||
<string name="server_name">Server VCMI</string>
|
||||
<string name="launcher_title">Spouštěč VCMI</string>
|
||||
<string name="launcher_btn_scale_title">Škálování herního rozlišení</string>
|
||||
<string name="launcher_btn_scale_subtitle_unknown">Současné: neznámé</string>
|
||||
<string name="launcher_btn_scale_subtitle">Současné: %1$d%%</string>
|
||||
<string name="launcher_btn_start_title">Spustit VCMI</string>
|
||||
<string name="launcher_btn_start_subtitle">Současná verze VCMI: %1$s</string>
|
||||
<string name="launcher_btn_mods_title">Modifikace</string>
|
||||
<string name="launcher_btn_mods_subtitle">Nainstalovat nové frakce, přeměty a bonusy</string>
|
||||
<string name="launcher_btn_language_title">Jazyk</string>
|
||||
<string name="launcher_btn_language_subtitle_unknown">Současný: neznámý</string>
|
||||
<string name="launcher_btn_language_subtitle">Současný: %1$s</string>
|
||||
<string name="launcher_btn_pointermode_title">Změnit režim ukazatele</string>
|
||||
<string name="launcher_btn_pointermode_subtitle">Současný: %1$s</string>
|
||||
<string name="launcher_btn_pointermulti_title">Násobitel rychlosti relativního ukazatele</string>
|
||||
<string name="launcher_btn_pointermulti_subtitle">Současný: %1$s</string>
|
||||
<string name="launcher_btn_sound_title">Hlasitost zvuků</string>
|
||||
<string name="launcher_btn_music_title">Hlasitost hudby</string>
|
||||
<string name="launcher_btn_adventure_ai">AI světa</string>
|
||||
<string name="launcher_btn_adventure_ai_title">Změnit AI světa</string>
|
||||
<string name="launcher_btn_import_title">Importovat data VCMI</string>
|
||||
<string name="launcher_btn_import_description">Zkopírovat soubury VCMI do vestavěného úložiště. Můžete importovat starou složku dat vcmi z vydání 0.99 nebo soubory HOMM3</string>
|
||||
<string name="launcher_btn_export_title">Exportovat data VCMI</string>
|
||||
<string name="launcher_btn_export_description">Udělat kopii dat VCMI před odinstalací nebo pro synchronizaci s desktopovou verzí. Též můžete přímo přistoupit k interním datům.</string>
|
||||
<string name="launcher_progress_copy">Kopírování %1$s</string>
|
||||
<string name="launcher_version">Současná verze spouštěče: %1$s</string>
|
||||
<string name="launcher_error_vcmi_data_root_failed">Nelze vytvořit datovou složku VCMI v %1$s.</string>
|
||||
<string name="launcher_error_h3_data_missing">Nelze najít datovou složku v \'%1$s\'. Vložte do ní své datové soubory HoMM3 nebo použijte tlačítko níže. Možná budete muset také restartovat aplikaci.</string>
|
||||
<string name="launcher_error_vcmi_data_internal_missing">Nelze najít nebo rozbalit data vcmi ze zdrojů aplikace. Zkuste přeinstalovat aplikaci.</string>
|
||||
<string name="launcher_error_vcmi_data_internal_update">Nelze aktualizovat data vcmi ze zdrojů aplikace. Zkuste přeinstalovat aplikaci.</string>
|
||||
<string name="launcher_error_permissions">Tato aplikace potřebuje oprávnění k zápisu pro použití obsahu na externím úložišti</string>
|
||||
<string name="launcher_error_permission_broken">Nelze správně vyřešit oprávnění</string>
|
||||
<string name="mods_item_author_template">od %1$s</string>
|
||||
<string name="misc_try_again">Zkusit znovu</string>
|
||||
<string name="launcher_section_init">Inicializae hry</string>
|
||||
<string name="launcher_section_settings">Nastavení</string>
|
||||
<string name="menu_mods_download_repo">Stáhnout data repozitáře</string>
|
||||
|
||||
<string name="misc_pointermode_normal">Normální</string>
|
||||
<string name="misc_pointermode_relative">Relativní</string>
|
||||
<string name="menu_launcher_about">O spouštěči</string>
|
||||
|
||||
<string name="mods_title">Nalezené modifikace</string>
|
||||
<string name="mods_failed_mod_loading">Nelze načíst modifikaci ve složce \'%1$s\'</string>
|
||||
<string name="mods_removal_title">Odebírání %1$s</string>
|
||||
<string name="mods_removal_confirmation">Jste si jisti odebráním %1$s?</string>
|
||||
|
||||
<string name="about_title">O aplikaci</string>
|
||||
<string name="about_version_app">Verze aplikace: %1$s</string>
|
||||
<string name="about_version_launcher">Verze spouštěče: %1$s</string>
|
||||
<string name="about_section_project">Projekt</string>
|
||||
<string name="about_section_legal">Právní záležitosti</string>
|
||||
<string name="about_links_main">Hlavní stránka: %1$s</string>
|
||||
<string name="about_links_repo">Repozitář projektu: %1$s</string>
|
||||
<string name="about_links_repo_launcher">Repozitář spouštěče: %1$s</string>
|
||||
<string name="about_btn_authors">Autoři</string>
|
||||
<string name="about_btn_privacy">Zásady ochrany osobních údajů: %1$s</string>
|
||||
<string name="about_error_opening_url">Nebylo možné otevřít webovou stránku (nenalezena patřičná aplikace)</string>
|
||||
|
||||
<string name="dialog_authors_vcmi">Autoři VCMI</string>
|
||||
<string name="dialog_authors_launcher">Autoři spouštěče</string>
|
||||
<string name="launcher_error_config_saving_failed">Nelze uložit konfigurační soubor VCMI; důvod: %1$s</string>
|
||||
</resources>
|
@ -55,12 +55,14 @@
|
||||
namespace po = boost::program_options;
|
||||
namespace po_style = boost::program_options::command_line_style;
|
||||
|
||||
static std::atomic<bool> quitRequestedDuringOpeningPlayback = false;
|
||||
static po::variables_map vm;
|
||||
|
||||
#ifndef VCMI_IOS
|
||||
void processCommand(const std::string &message);
|
||||
#endif
|
||||
void playIntro();
|
||||
[[noreturn]] static void quitApplication();
|
||||
static void mainLoop();
|
||||
|
||||
static CBasicLogConfigurator *logConfig;
|
||||
@ -257,10 +259,10 @@ int main(int argc, char * argv[])
|
||||
};
|
||||
|
||||
testFile("DATA/HELP.TXT", "VCMI requires Heroes III: Shadow of Death or Heroes III: Complete data files to run!");
|
||||
testFile("MODS/VCMI/MOD.JSON", "VCMI installation is corrupted! Built-in mod was not found!");
|
||||
testFile("DATA/PLAYERS.PAL", "Heroes III data files are missing or corruped! Please reinstall them.");
|
||||
testFile("SPRITES/DEFAULT.DEF", "Heroes III data files are missing or corruped! Please reinstall them.");
|
||||
testFile("DATA/TENTCOLR.TXT", "Heroes III: Restoration of Erathia (including HD Edition) data files are not supported!");
|
||||
testFile("MODS/VCMI/MOD.JSON", "VCMI installation is corrupted! Built-in mod was not found!");
|
||||
testFile("DATA/PLAYERS.PAL", "Heroes III data files (Data/H3Bitmap.lod) are incomplete or corruped! Please reinstall them.");
|
||||
testFile("SPRITES/DEFAULT.DEF", "Heroes III data files (Data/H3Sprite.lod) are incomplete or corruped! Please reinstall them.");
|
||||
|
||||
srand ( (unsigned int)time(nullptr) );
|
||||
|
||||
@ -313,7 +315,6 @@ int main(int argc, char * argv[])
|
||||
GH.screenHandler().clearScreen();
|
||||
}
|
||||
|
||||
|
||||
#ifndef VCMI_NO_THREADED_LOAD
|
||||
#ifdef VCMI_ANDROID // android loads the data quite slowly so we display native progressbar to prevent having only black screen for few seconds
|
||||
{
|
||||
@ -327,6 +328,9 @@ int main(int argc, char * argv[])
|
||||
#endif // ANDROID
|
||||
#endif // THREADED
|
||||
|
||||
if (quitRequestedDuringOpeningPlayback)
|
||||
quitApplication();
|
||||
|
||||
if(!settings["session"]["headless"].Bool())
|
||||
{
|
||||
pomtime.getDiff();
|
||||
@ -414,7 +418,7 @@ int main(int argc, char * argv[])
|
||||
else
|
||||
{
|
||||
while(true)
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(1000));
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(200));
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -451,7 +455,7 @@ static void mainLoop()
|
||||
}
|
||||
}
|
||||
|
||||
static void quitApplication()
|
||||
[[noreturn]] static void quitApplication()
|
||||
{
|
||||
if(!settings["session"]["headless"].Bool())
|
||||
{
|
||||
@ -487,7 +491,8 @@ static void quitApplication()
|
||||
vstd::clear_pointer(CSH);
|
||||
vstd::clear_pointer(VLC);
|
||||
|
||||
vstd::clear_pointer(console);// should be removed after everything else since used by logging
|
||||
// sometimes leads to a hang. TODO: investigate
|
||||
//vstd::clear_pointer(console);// should be removed after everything else since used by logging
|
||||
|
||||
if(!settings["session"]["headless"].Bool())
|
||||
GH.screenHandler().close();
|
||||
@ -501,14 +506,29 @@ static void quitApplication()
|
||||
|
||||
std::cout << "Ending...\n";
|
||||
|
||||
// this method is always called from event/network threads, which keep interface mutex locked
|
||||
// unlock it here to avoid assertion failure on GH destruction in exit()
|
||||
GH.interfaceMutex.unlock();
|
||||
exit(0);
|
||||
// Perform quick exit without executing static destructors and let OS cleanup anything that we did not
|
||||
// We generally don't care about them and this leads to numerous issues, e.g.
|
||||
// destruction of locked mutexes (fails an assertion), even in third-party libraries (as well as native libs on Android)
|
||||
// Android - std::quick_exit is available only starting from API level 21
|
||||
// Mingw, macOS and iOS - std::quick_exit is unavailable (at least in current version of CI)
|
||||
#if (defined(__ANDROID_API__) && __ANDROID_API__ < 21) || (defined(__MINGW32__)) || defined(VCMI_APPLE)
|
||||
::exit(0);
|
||||
#else
|
||||
std::quick_exit(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void handleQuit(bool ask)
|
||||
{
|
||||
// FIXME: avoids crash if player attempts to close game while opening is still playing
|
||||
// use cursor handler as indicator that loading is not done yet
|
||||
// proper solution would be to abort init thread (or wait for it to finish)
|
||||
if (!CCS->curh)
|
||||
{
|
||||
quitRequestedDuringOpeningPlayback = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if(ask)
|
||||
{
|
||||
CCS->curh->set(Cursor::Map::POINTER);
|
||||
|
@ -637,7 +637,7 @@ bool CVideoPlayer::playVideo(int x, int y, bool stopOnKey)
|
||||
|
||||
SDL_Rect rect = CSDL_Ext::toSDL(pos);
|
||||
|
||||
SDL_RenderClear(mainRenderer);
|
||||
SDL_RenderFillRect(mainRenderer, &rect);
|
||||
SDL_RenderCopy(mainRenderer, texture, nullptr, &rect);
|
||||
SDL_RenderPresent(mainRenderer);
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#include "lobby/OptionsTab.h"
|
||||
#include "lobby/RandomMapTab.h"
|
||||
#include "lobby/TurnOptionsTab.h"
|
||||
#include "lobby/SelectionTab.h"
|
||||
#include "lobby/CBonusSelection.h"
|
||||
|
||||
@ -47,7 +48,7 @@ void ApplyOnLobbyHandlerNetPackVisitor::visitLobbyClientConnected(LobbyClientCon
|
||||
|
||||
void ApplyOnLobbyHandlerNetPackVisitor::visitLobbyClientDisconnected(LobbyClientDisconnected & pack)
|
||||
{
|
||||
if(pack.clientId != pack.c->connectionID)
|
||||
if(pack.clientId != handler.c->connectionID)
|
||||
{
|
||||
result = false;
|
||||
return;
|
||||
@ -95,6 +96,9 @@ void ApplyOnLobbyScreenNetPackVisitor::visitLobbyGuiAction(LobbyGuiAction & pack
|
||||
case LobbyGuiAction::OPEN_RANDOM_MAP_OPTIONS:
|
||||
lobby->toggleTab(lobby->tabRand);
|
||||
break;
|
||||
case LobbyGuiAction::OPEN_TURN_OPTIONS:
|
||||
lobby->toggleTab(lobby->tabTurnOptions);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -239,6 +239,8 @@ void PlayerLocalState::swapWanderingHero(int pos1, int pos2)
|
||||
{
|
||||
assert(wanderingHeroes[pos1] && wanderingHeroes[pos2]);
|
||||
std::swap(wanderingHeroes[pos1], wanderingHeroes[pos2]);
|
||||
|
||||
adventureInt->onHeroOrderChanged();
|
||||
}
|
||||
|
||||
const std::vector<const CGTownInstance *> & PlayerLocalState::getOwnedTowns()
|
||||
|
@ -42,7 +42,7 @@ public:
|
||||
{
|
||||
//on which page we left spellbook
|
||||
int spellbookLastPageBattle = 0;
|
||||
int spellbokLastPageAdvmap = 0;
|
||||
int spellbookLastPageAdvmap = 0;
|
||||
int spellbookLastTabBattle = 4;
|
||||
int spellbookLastTabAdvmap = 4;
|
||||
|
||||
@ -50,7 +50,7 @@ public:
|
||||
void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & spellbookLastPageBattle;
|
||||
h & spellbokLastPageAdvmap;
|
||||
h & spellbookLastPageAdvmap;
|
||||
h & spellbookLastTabBattle;
|
||||
h & spellbookLastTabAdvmap;
|
||||
}
|
||||
|
@ -65,8 +65,8 @@ AdventureMapInterface::AdventureMapInterface():
|
||||
shortcuts->setState(EAdventureState::MAKING_TURN);
|
||||
widget->getMapView()->onViewMapActivated();
|
||||
|
||||
if(LOCPLINT->cb->getStartInfo()->turnTimerInfo.isEnabled() || LOCPLINT->cb->getStartInfo()->turnTimerInfo.isBattleEnabled())
|
||||
watches = std::make_shared<TurnTimerWidget>();
|
||||
if(LOCPLINT->cb->getStartInfo()->turnTimerInfo.turnTimer != 0)
|
||||
watches = std::make_shared<TurnTimerWidget>(Point(24, 24));
|
||||
|
||||
addUsedEvents(KEYBOARD | TIME);
|
||||
}
|
||||
@ -331,6 +331,11 @@ void AdventureMapInterface::onTownOrderChanged()
|
||||
widget->getTownList()->updateWidget();
|
||||
}
|
||||
|
||||
void AdventureMapInterface::onHeroOrderChanged()
|
||||
{
|
||||
widget->getHeroList()->updateWidget();
|
||||
}
|
||||
|
||||
void AdventureMapInterface::onMapTilesChanged(boost::optional<std::unordered_set<int3>> positions)
|
||||
{
|
||||
if (positions)
|
||||
|
@ -149,6 +149,9 @@ public:
|
||||
/// Called when town order changes
|
||||
void onTownOrderChanged();
|
||||
|
||||
/// Called when hero order changes
|
||||
void onHeroOrderChanged();
|
||||
|
||||
/// Called when map audio should be paused, e.g. on combat or town screen access
|
||||
void onAudioPaused();
|
||||
|
||||
|
@ -151,6 +151,9 @@ void CInGameConsole::keyPressed (EShortcut key)
|
||||
break;
|
||||
|
||||
case EShortcut::GAME_ACTIVATE_CONSOLE:
|
||||
if(GH.isKeyboardAltDown())
|
||||
return; //QoL for alt-tab operating system shortcut
|
||||
|
||||
if(!enteredText.empty())
|
||||
endEnteringText(false);
|
||||
else
|
||||
|
@ -218,8 +218,7 @@ CHeroList::CEmptyHeroItem::CEmptyHeroItem()
|
||||
|
||||
CHeroList::CHeroItem::CHeroItem(CHeroList *parent, const CGHeroInstance * Hero)
|
||||
: CListItem(parent),
|
||||
hero(Hero),
|
||||
parentList(parent)
|
||||
hero(Hero)
|
||||
{
|
||||
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
|
||||
movement = std::make_shared<CAnimImage>(AnimationPath::builtin("IMOBIL"), 0, 0, 0, 1);
|
||||
@ -285,19 +284,17 @@ void CHeroList::CHeroItem::gesture(bool on, const Point & initialPosition, const
|
||||
const CGHeroInstance * heroLower = (heroPos > heroes.size() - 2) ? nullptr : heroes[heroPos + 1];
|
||||
|
||||
std::vector<RadialMenuConfig> menuElements = {
|
||||
{ RadialMenuConfig::ITEM_ALT_NN, heroUpper != nullptr, "altUpTop", "vcmi.radialWheel.moveTop", [this, heroPos]()
|
||||
{ RadialMenuConfig::ITEM_ALT_NN, heroUpper != nullptr, "altUpTop", "vcmi.radialWheel.moveTop", [heroPos]()
|
||||
{
|
||||
for (int i = heroPos; i > 0; i--)
|
||||
LOCPLINT->localState->swapWanderingHero(i, i - 1);
|
||||
parentList->updateWidget();
|
||||
} },
|
||||
{ RadialMenuConfig::ITEM_ALT_NW, heroUpper != nullptr, "altUp", "vcmi.radialWheel.moveUp", [this, heroPos](){LOCPLINT->localState->swapWanderingHero(heroPos, heroPos - 1); parentList->updateWidget(); } },
|
||||
{ RadialMenuConfig::ITEM_ALT_SW, heroLower != nullptr, "altDown", "vcmi.radialWheel.moveDown", [this, heroPos](){ LOCPLINT->localState->swapWanderingHero(heroPos, heroPos + 1); parentList->updateWidget(); } },
|
||||
{ RadialMenuConfig::ITEM_ALT_SS, heroLower != nullptr, "altDownBottom", "vcmi.radialWheel.moveBottom", [this, heroPos, heroes]()
|
||||
{ RadialMenuConfig::ITEM_ALT_NW, heroUpper != nullptr, "altUp", "vcmi.radialWheel.moveUp", [heroPos](){LOCPLINT->localState->swapWanderingHero(heroPos, heroPos - 1); } },
|
||||
{ RadialMenuConfig::ITEM_ALT_SW, heroLower != nullptr, "altDown", "vcmi.radialWheel.moveDown", [heroPos](){ LOCPLINT->localState->swapWanderingHero(heroPos, heroPos + 1); } },
|
||||
{ RadialMenuConfig::ITEM_ALT_SS, heroLower != nullptr, "altDownBottom", "vcmi.radialWheel.moveBottom", [heroPos, heroes]()
|
||||
{
|
||||
for (int i = heroPos; i < heroes.size() - 1; i++)
|
||||
LOCPLINT->localState->swapWanderingHero(i, i + 1);
|
||||
parentList->updateWidget();
|
||||
} },
|
||||
};
|
||||
|
||||
@ -365,8 +362,7 @@ std::shared_ptr<CIntObject> CTownList::createItem(size_t index)
|
||||
}
|
||||
|
||||
CTownList::CTownItem::CTownItem(CTownList *parent, const CGTownInstance *Town):
|
||||
CListItem(parent),
|
||||
parentList(parent)
|
||||
CListItem(parent)
|
||||
{
|
||||
const std::vector<const CGTownInstance *> towns = LOCPLINT->localState->getOwnedTowns();
|
||||
townIndex = std::distance(towns.begin(), std::find(towns.begin(), towns.end(), Town));
|
||||
@ -430,15 +426,13 @@ void CTownList::CTownItem::gesture(bool on, const Point & initialPosition, const
|
||||
{
|
||||
for (int i = townIndex; i > 0; i--)
|
||||
LOCPLINT->localState->swapOwnedTowns(i, i - 1);
|
||||
parentList->updateWidget();
|
||||
} },
|
||||
{ RadialMenuConfig::ITEM_ALT_NW, townUpperPos > -1, "altUp", "vcmi.radialWheel.moveUp", [this, townUpperPos](){LOCPLINT->localState->swapOwnedTowns(townIndex, townUpperPos); parentList->updateWidget(); } },
|
||||
{ RadialMenuConfig::ITEM_ALT_SW, townLowerPos > -1, "altDown", "vcmi.radialWheel.moveDown", [this, townLowerPos](){ LOCPLINT->localState->swapOwnedTowns(townIndex, townLowerPos); parentList->updateWidget(); } },
|
||||
{ RadialMenuConfig::ITEM_ALT_NW, townUpperPos > -1, "altUp", "vcmi.radialWheel.moveUp", [this, townUpperPos](){LOCPLINT->localState->swapOwnedTowns(townIndex, townUpperPos); } },
|
||||
{ RadialMenuConfig::ITEM_ALT_SW, townLowerPos > -1, "altDown", "vcmi.radialWheel.moveDown", [this, townLowerPos](){ LOCPLINT->localState->swapOwnedTowns(townIndex, townLowerPos); } },
|
||||
{ RadialMenuConfig::ITEM_ALT_SS, townLowerPos > -1, "altDownBottom", "vcmi.radialWheel.moveBottom", [this, towns]()
|
||||
{
|
||||
for (int i = townIndex; i < towns.size() - 1; i++)
|
||||
LOCPLINT->localState->swapOwnedTowns(i, i + 1);
|
||||
parentList->updateWidget();
|
||||
} },
|
||||
};
|
||||
|
||||
|
@ -117,7 +117,6 @@ class CHeroList : public CList
|
||||
std::shared_ptr<CAnimImage> movement;
|
||||
std::shared_ptr<CAnimImage> mana;
|
||||
std::shared_ptr<CAnimImage> portrait;
|
||||
CHeroList *parentList;
|
||||
public:
|
||||
const CGHeroInstance * const hero;
|
||||
|
||||
@ -152,7 +151,6 @@ class CTownList : public CList
|
||||
class CTownItem : public CListItem
|
||||
{
|
||||
std::shared_ptr<CAnimImage> picture;
|
||||
CTownList *parentList;
|
||||
public:
|
||||
int townIndex;
|
||||
|
||||
|
@ -15,54 +15,86 @@
|
||||
#include "../CPlayerInterface.h"
|
||||
#include "../battle/BattleInterface.h"
|
||||
#include "../battle/BattleStacksController.h"
|
||||
|
||||
#include "../render/EFont.h"
|
||||
#include "../render/Graphics.h"
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../gui/TextAlignment.h"
|
||||
#include "../render/Graphics.h"
|
||||
#include "../widgets/Images.h"
|
||||
#include "../widgets/MiscWidgets.h"
|
||||
#include "../widgets/TextControls.h"
|
||||
|
||||
#include "../../CCallback.h"
|
||||
#include "../../lib/CStack.h"
|
||||
#include "../../lib/CPlayerState.h"
|
||||
#include "../../lib/filesystem/ResourcePath.h"
|
||||
#include "../../lib/CStack.h"
|
||||
#include "../../lib/StartInfo.h"
|
||||
|
||||
TurnTimerWidget::DrawRect::DrawRect(const Rect & r, const ColorRGBA & c):
|
||||
CIntObject(), rect(r), color(c)
|
||||
{
|
||||
}
|
||||
TurnTimerWidget::TurnTimerWidget(const Point & position)
|
||||
: TurnTimerWidget(position, PlayerColor::NEUTRAL)
|
||||
{}
|
||||
|
||||
void TurnTimerWidget::DrawRect::showAll(Canvas & to)
|
||||
TurnTimerWidget::TurnTimerWidget(const Point & position, PlayerColor player)
|
||||
: CIntObject(TIME)
|
||||
, lastSoundCheckSeconds(0)
|
||||
, isBattleMode(player.isValidPlayer())
|
||||
{
|
||||
to.drawColor(rect, color);
|
||||
|
||||
CIntObject::showAll(to);
|
||||
}
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
|
||||
|
||||
TurnTimerWidget::TurnTimerWidget():
|
||||
InterfaceObjectConfigurable(TIME),
|
||||
turnTime(0), lastTurnTime(0), cachedTurnTime(0), lastPlayer(PlayerColor::CANNOT_DETERMINE)
|
||||
{
|
||||
REGISTER_BUILDER("drawRect", &TurnTimerWidget::buildDrawRect);
|
||||
|
||||
pos += position;
|
||||
pos.w = 0;
|
||||
pos.h = 0;
|
||||
recActions &= ~DEACTIVATE;
|
||||
|
||||
const JsonNode config(JsonPath::builtin("config/widgets/turnTimer.json"));
|
||||
|
||||
build(config);
|
||||
|
||||
std::transform(variables["notificationTime"].Vector().begin(),
|
||||
variables["notificationTime"].Vector().end(),
|
||||
std::inserter(notifications, notifications.begin()),
|
||||
[](const JsonNode & node){ return node.Integer(); });
|
||||
}
|
||||
const auto & timers = LOCPLINT->cb->getStartInfo()->turnTimerInfo;
|
||||
|
||||
std::shared_ptr<TurnTimerWidget::DrawRect> TurnTimerWidget::buildDrawRect(const JsonNode & config) const
|
||||
{
|
||||
logGlobal->debug("Building widget TurnTimerWidget::DrawRect");
|
||||
auto rect = readRect(config["rect"]);
|
||||
auto color = readColor(config["color"]);
|
||||
return std::make_shared<TurnTimerWidget::DrawRect>(rect, color);
|
||||
backgroundTexture = std::make_shared<CFilledTexture>(ImagePath::builtin("DiBoxBck"), pos); // 1 px smaller on all sides
|
||||
|
||||
if (isBattleMode)
|
||||
backgroundBorder = std::make_shared<TransparentFilledRectangle>(pos, ColorRGBA(0, 0, 0, 128), Colors::BRIGHT_YELLOW);
|
||||
else
|
||||
backgroundBorder = std::make_shared<TransparentFilledRectangle>(pos, ColorRGBA(0, 0, 0, 128), Colors::BLACK);
|
||||
|
||||
if (isBattleMode)
|
||||
{
|
||||
pos.w = 76;
|
||||
|
||||
pos.h += 20;
|
||||
playerLabelsMain[player] = std::make_shared<CLabel>(pos.w / 2, pos.h - 10, FONT_BIG, ETextAlignment::CENTER, graphics->playerColors[player], "");
|
||||
|
||||
if (timers.battleTimer != 0)
|
||||
{
|
||||
pos.h += 20;
|
||||
playerLabelsBattle[player] = std::make_shared<CLabel>(pos.w / 2, pos.h - 10, FONT_BIG, ETextAlignment::CENTER, graphics->playerColors[player], "");
|
||||
}
|
||||
|
||||
if (!timers.accumulatingUnitTimer && timers.unitTimer != 0)
|
||||
{
|
||||
pos.h += 20;
|
||||
playerLabelsUnit[player] = std::make_shared<CLabel>(pos.w / 2, pos.h - 10, FONT_BIG, ETextAlignment::CENTER, graphics->playerColors[player], "");
|
||||
}
|
||||
|
||||
updateTextLabel(player, LOCPLINT->cb->getPlayerTurnTime(player));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!timers.accumulatingTurnTimer && timers.baseTimer != 0)
|
||||
pos.w = 120;
|
||||
else
|
||||
pos.w = 60;
|
||||
|
||||
for(PlayerColor player(0); player < PlayerColor::PLAYER_LIMIT; ++player)
|
||||
{
|
||||
if (LOCPLINT->cb->getStartInfo()->playerInfos.count(player) == 0)
|
||||
continue;
|
||||
|
||||
if (!LOCPLINT->cb->getStartInfo()->playerInfos.at(player).isControlledByHuman())
|
||||
continue;
|
||||
|
||||
pos.h += 20;
|
||||
playerLabelsMain[player] = std::make_shared<CLabel>(pos.w / 2, pos.h - 10, FONT_BIG, ETextAlignment::CENTER, graphics->playerColors[player], "");
|
||||
|
||||
updateTextLabel(player, LOCPLINT->cb->getPlayerTurnTime(player));
|
||||
}
|
||||
}
|
||||
|
||||
backgroundTexture->pos = Rect::createAround(pos, -1);
|
||||
backgroundBorder->pos = pos;
|
||||
}
|
||||
|
||||
void TurnTimerWidget::show(Canvas & to)
|
||||
@ -70,98 +102,95 @@ void TurnTimerWidget::show(Canvas & to)
|
||||
showAll(to);
|
||||
}
|
||||
|
||||
void TurnTimerWidget::setTime(PlayerColor player, int time)
|
||||
void TurnTimerWidget::updateNotifications(PlayerColor player, int timeMs)
|
||||
{
|
||||
int newTime = time / 1000;
|
||||
if(player == LOCPLINT->playerID
|
||||
&& newTime != turnTime
|
||||
&& notifications.count(newTime))
|
||||
{
|
||||
CCS->soundh->playSound(AudioPath::fromJson(variables["notificationSound"]));
|
||||
}
|
||||
if(player != LOCPLINT->playerID)
|
||||
return;
|
||||
|
||||
turnTime = newTime;
|
||||
int newTimeSeconds = timeMs / 1000;
|
||||
|
||||
if(auto w = widget<CLabel>("timer"))
|
||||
if (newTimeSeconds != lastSoundCheckSeconds && notificationThresholds.count(newTimeSeconds))
|
||||
CCS->soundh->playSound(AudioPath::builtin("WE5"));
|
||||
|
||||
lastSoundCheckSeconds = newTimeSeconds;
|
||||
}
|
||||
|
||||
static std::string msToString(int timeMs)
|
||||
{
|
||||
int timeSeconds = timeMs / 1000;
|
||||
std::ostringstream oss;
|
||||
oss << timeSeconds / 60 << ":" << std::setw(2) << std::setfill('0') << timeSeconds % 60;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
void TurnTimerWidget::updateTextLabel(PlayerColor player, const TurnTimerInfo & timer)
|
||||
{
|
||||
const auto & timerSettings = LOCPLINT->cb->getStartInfo()->turnTimerInfo;
|
||||
auto mainLabel = playerLabelsMain[player];
|
||||
|
||||
if (isBattleMode)
|
||||
{
|
||||
std::ostringstream oss;
|
||||
oss << turnTime / 60 << ":" << std::setw(2) << std::setfill('0') << turnTime % 60;
|
||||
w->setText(oss.str());
|
||||
|
||||
if(graphics && LOCPLINT && LOCPLINT->cb
|
||||
&& variables["textColorFromPlayerColor"].Bool()
|
||||
&& player.isValidPlayer())
|
||||
mainLabel->setText(msToString(timer.baseTimer + timer.turnTimer));
|
||||
|
||||
if (timerSettings.battleTimer != 0)
|
||||
{
|
||||
w->setColor(graphics->playerColors[player]);
|
||||
auto battleLabel = playerLabelsBattle[player];
|
||||
if (timer.battleTimer != 0)
|
||||
{
|
||||
if (timerSettings.accumulatingUnitTimer)
|
||||
battleLabel->setText("+" + msToString(timer.battleTimer + timer.unitTimer));
|
||||
else
|
||||
battleLabel->setText("+" + msToString(timer.battleTimer));
|
||||
}
|
||||
else
|
||||
battleLabel->setText("");
|
||||
}
|
||||
|
||||
if (!timerSettings.accumulatingUnitTimer && timerSettings.unitTimer != 0)
|
||||
{
|
||||
auto unitLabel = playerLabelsUnit[player];
|
||||
if (timer.unitTimer != 0)
|
||||
unitLabel->setText("+" + msToString(timer.unitTimer));
|
||||
else
|
||||
unitLabel->setText("");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!timerSettings.accumulatingTurnTimer && timerSettings.baseTimer != 0)
|
||||
mainLabel->setText(msToString(timer.baseTimer) + "+" + msToString(timer.turnTimer));
|
||||
else
|
||||
mainLabel->setText(msToString(timer.baseTimer + timer.turnTimer));
|
||||
}
|
||||
}
|
||||
|
||||
void TurnTimerWidget::updateTimer(PlayerColor player, uint32_t msPassed)
|
||||
{
|
||||
const auto & time = LOCPLINT->cb->getPlayerTurnTime(player);
|
||||
if(time.isActive)
|
||||
cachedTurnTime -= msPassed;
|
||||
|
||||
if(cachedTurnTime < 0)
|
||||
cachedTurnTime = 0; //do not go below zero
|
||||
|
||||
if(lastPlayer != player)
|
||||
{
|
||||
lastPlayer = player;
|
||||
lastTurnTime = 0;
|
||||
}
|
||||
|
||||
auto timeCheckAndUpdate = [&](int time)
|
||||
{
|
||||
if(time / 1000 != lastTurnTime / 1000)
|
||||
{
|
||||
//do not update timer on this tick
|
||||
lastTurnTime = time;
|
||||
cachedTurnTime = time;
|
||||
}
|
||||
else
|
||||
setTime(player, cachedTurnTime);
|
||||
};
|
||||
|
||||
auto * playerInfo = LOCPLINT->cb->getPlayer(player);
|
||||
if(player.isValidPlayer() || (playerInfo && playerInfo->isHuman()))
|
||||
{
|
||||
if(time.isBattle)
|
||||
timeCheckAndUpdate(time.baseTimer + time.turnTimer + time.battleTimer + time.unitTimer);
|
||||
else
|
||||
timeCheckAndUpdate(time.baseTimer + time.turnTimer);
|
||||
}
|
||||
else
|
||||
timeCheckAndUpdate(0);
|
||||
const auto & gamestateTimer = LOCPLINT->cb->getPlayerTurnTime(player);
|
||||
updateNotifications(player, gamestateTimer.valueMs());
|
||||
updateTextLabel(player, gamestateTimer);
|
||||
}
|
||||
|
||||
void TurnTimerWidget::tick(uint32_t msPassed)
|
||||
{
|
||||
if(!LOCPLINT || !LOCPLINT->cb)
|
||||
return;
|
||||
|
||||
if(LOCPLINT->battleInt)
|
||||
for(const auto & player : playerLabelsMain)
|
||||
{
|
||||
if(auto * stack = LOCPLINT->battleInt->stacksController->getActiveStack())
|
||||
updateTimer(stack->getOwner(), msPassed);
|
||||
else
|
||||
updateTimer(PlayerColor::NEUTRAL, msPassed);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(LOCPLINT->makingTurn)
|
||||
updateTimer(LOCPLINT->playerID, msPassed);
|
||||
else
|
||||
if (LOCPLINT->battleInt)
|
||||
{
|
||||
for(PlayerColor p(0); p < PlayerColor::PLAYER_LIMIT; ++p)
|
||||
{
|
||||
if(LOCPLINT->cb->isPlayerMakingTurn(p))
|
||||
{
|
||||
updateTimer(p, msPassed);
|
||||
break;
|
||||
}
|
||||
}
|
||||
const auto & battle = LOCPLINT->battleInt->getBattle();
|
||||
|
||||
bool isDefender = battle->sideToPlayer(BattleSide::DEFENDER) == player.first;
|
||||
bool isAttacker = battle->sideToPlayer(BattleSide::ATTACKER) == player.first;
|
||||
bool isMakingUnitTurn = battle->battleActiveUnit() && battle->battleActiveUnit()->unitOwner() == player.first;
|
||||
bool isEngagedInBattle = isDefender || isAttacker;
|
||||
|
||||
// Due to way our network message queue works during battle animation
|
||||
// client actually does not receives updates from server as to which timer is active when game has battle animations playing
|
||||
// so during battle skip updating timer unless game is waiting for player to select action
|
||||
if (isEngagedInBattle && !isMakingUnitTurn)
|
||||
continue;
|
||||
}
|
||||
|
||||
updateTimer(player.first, msPassed);
|
||||
}
|
||||
}
|
||||
|
@ -11,50 +11,43 @@
|
||||
#pragma once
|
||||
|
||||
#include "../gui/CIntObject.h"
|
||||
#include "../gui/InterfaceObjectConfigurable.h"
|
||||
#include "../render/Canvas.h"
|
||||
#include "../render/Colors.h"
|
||||
#include "../../lib/TurnTimerInfo.h"
|
||||
|
||||
class CAnimImage;
|
||||
class CLabel;
|
||||
class CFilledTexture;
|
||||
class TransparentFilledRectangle;
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
class PlayerColor;
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
class TurnTimerWidget : public InterfaceObjectConfigurable
|
||||
class TurnTimerWidget : public CIntObject
|
||||
{
|
||||
private:
|
||||
|
||||
class DrawRect : public CIntObject
|
||||
{
|
||||
const Rect rect;
|
||||
const ColorRGBA color;
|
||||
|
||||
public:
|
||||
DrawRect(const Rect &, const ColorRGBA &);
|
||||
void showAll(Canvas & to) override;
|
||||
};
|
||||
int lastSoundCheckSeconds;
|
||||
bool isBattleMode;
|
||||
|
||||
const std::set<int> notificationThresholds = {1, 2, 3, 4, 5, 10, 20, 30};
|
||||
|
||||
std::map<PlayerColor, std::shared_ptr<CLabel>> playerLabelsMain;
|
||||
std::map<PlayerColor, std::shared_ptr<CLabel>> playerLabelsBattle;
|
||||
std::map<PlayerColor, std::shared_ptr<CLabel>> playerLabelsUnit;
|
||||
std::shared_ptr<CFilledTexture> backgroundTexture;
|
||||
std::shared_ptr<TransparentFilledRectangle> backgroundBorder;
|
||||
|
||||
int turnTime;
|
||||
int lastTurnTime;
|
||||
int cachedTurnTime;
|
||||
PlayerColor lastPlayer;
|
||||
|
||||
std::set<int> notifications;
|
||||
|
||||
std::shared_ptr<DrawRect> buildDrawRect(const JsonNode & config) const;
|
||||
|
||||
void updateTimer(PlayerColor player, uint32_t msPassed);
|
||||
|
||||
public:
|
||||
|
||||
void show(Canvas & to) override;
|
||||
void tick(uint32_t msPassed) override;
|
||||
|
||||
void setTime(PlayerColor player, int time);
|
||||
void updateNotifications(PlayerColor player, int timeMs);
|
||||
void updateTextLabel(PlayerColor player, const TurnTimerInfo & timer);
|
||||
|
||||
TurnTimerWidget();
|
||||
public:
|
||||
/// Activates adventure map mode in which widget will display timer for all players
|
||||
TurnTimerWidget(const Point & position);
|
||||
|
||||
/// Activates battle mode in which timer displays only timer of specific player
|
||||
TurnTimerWidget(const Point & position, PlayerColor player);
|
||||
};
|
||||
|
@ -107,7 +107,8 @@ void BattleInterface::playIntroSoundAndUnlockInterface()
|
||||
{
|
||||
auto onIntroPlayed = [this]()
|
||||
{
|
||||
if(LOCPLINT->battleInt)
|
||||
// Make sure that battle have not ended while intro was playing AND that a different one has not started
|
||||
if(LOCPLINT->battleInt.get() == this)
|
||||
onIntroSoundPlayed();
|
||||
};
|
||||
|
||||
|
@ -691,6 +691,8 @@ void BattleStacksController::endAction(const BattleAction & action)
|
||||
|
||||
void BattleStacksController::startAction(const BattleAction & action)
|
||||
{
|
||||
// if timer run out and we did not act in time - deactivate current stack
|
||||
setActiveStack(nullptr);
|
||||
removeExpiredColorFilters();
|
||||
}
|
||||
|
||||
|
@ -31,6 +31,7 @@
|
||||
#include "../render/Canvas.h"
|
||||
#include "../render/IRenderHandler.h"
|
||||
#include "../adventureMap/CInGameConsole.h"
|
||||
#include "../adventureMap/TurnTimerWidget.h"
|
||||
|
||||
#include "../../CCallback.h"
|
||||
#include "../../lib/CGeneralTextHandler.h"
|
||||
@ -39,6 +40,7 @@
|
||||
#include "../../lib/CStack.h"
|
||||
#include "../../lib/CConfigHandler.h"
|
||||
#include "../../lib/filesystem/ResourcePath.h"
|
||||
#include "../../lib/StartInfo.h"
|
||||
#include "../windows/settings/SettingsMainWindow.h"
|
||||
|
||||
BattleWindow::BattleWindow(BattleInterface & owner):
|
||||
@ -83,6 +85,7 @@ BattleWindow::BattleWindow(BattleInterface & owner):
|
||||
|
||||
createQueue();
|
||||
createStickyHeroInfoWindows();
|
||||
createTimerInfoWindows();
|
||||
|
||||
if ( owner.tacticsMode )
|
||||
tacticPhaseStarted();
|
||||
@ -128,8 +131,8 @@ void BattleWindow::createStickyHeroInfoWindows()
|
||||
InfoAboutHero info;
|
||||
info.initFromHero(owner.defendingHeroInstance, InfoAboutHero::EInfoLevel::INBATTLE);
|
||||
Point position = (GH.screenDimensions().x >= 1000)
|
||||
? Point(pos.x + pos.w + 15, pos.y)
|
||||
: Point(pos.x + pos.w -79, pos.y + 135);
|
||||
? Point(pos.x + pos.w + 15, pos.y + 60)
|
||||
: Point(pos.x + pos.w -79, pos.y + 195);
|
||||
defenderHeroWindow = std::make_shared<HeroInfoBasicPanel>(info, &position);
|
||||
}
|
||||
if(owner.attackingHeroInstance)
|
||||
@ -137,8 +140,8 @@ void BattleWindow::createStickyHeroInfoWindows()
|
||||
InfoAboutHero info;
|
||||
info.initFromHero(owner.attackingHeroInstance, InfoAboutHero::EInfoLevel::INBATTLE);
|
||||
Point position = (GH.screenDimensions().x >= 1000)
|
||||
? Point(pos.x - 93, pos.y)
|
||||
: Point(pos.x + 1, pos.y + 135);
|
||||
? Point(pos.x - 93, pos.y + 60)
|
||||
: Point(pos.x + 1, pos.y + 195);
|
||||
attackerHeroWindow = std::make_shared<HeroInfoBasicPanel>(info, &position);
|
||||
}
|
||||
|
||||
@ -154,6 +157,33 @@ void BattleWindow::createStickyHeroInfoWindows()
|
||||
}
|
||||
}
|
||||
|
||||
void BattleWindow::createTimerInfoWindows()
|
||||
{
|
||||
OBJ_CONSTRUCTION_CAPTURING_ALL_NO_DISPOSE;
|
||||
|
||||
if(LOCPLINT->cb->getStartInfo()->turnTimerInfo.battleTimer != 0 || LOCPLINT->cb->getStartInfo()->turnTimerInfo.unitTimer != 0)
|
||||
{
|
||||
PlayerColor attacker = owner.getBattle()->sideToPlayer(BattleSide::ATTACKER);
|
||||
PlayerColor defender = owner.getBattle()->sideToPlayer(BattleSide::DEFENDER);
|
||||
|
||||
if (attacker.isValidPlayer())
|
||||
{
|
||||
if (GH.screenDimensions().x >= 1000)
|
||||
attackerTimerWidget = std::make_shared<TurnTimerWidget>(Point(-92, 1), attacker);
|
||||
else
|
||||
attackerTimerWidget = std::make_shared<TurnTimerWidget>(Point(1, 135), attacker);
|
||||
}
|
||||
|
||||
if (defender.isValidPlayer())
|
||||
{
|
||||
if (GH.screenDimensions().x >= 1000)
|
||||
defenderTimerWidget = std::make_shared<TurnTimerWidget>(Point(pos.w + 16, 1), defender);
|
||||
else
|
||||
defenderTimerWidget = std::make_shared<TurnTimerWidget>(Point(pos.w - 78, 135), defender);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BattleWindow::~BattleWindow()
|
||||
{
|
||||
CPlayerInterface::battleInt = nullptr;
|
||||
@ -557,6 +587,15 @@ void BattleWindow::bSpellf()
|
||||
LOCPLINT->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[683])
|
||||
% heroName % CGI->artifacts()->getByIndex(artID)->getNameTranslated()));
|
||||
}
|
||||
else if(blockingBonus->source == BonusSource::OBJECT_TYPE)
|
||||
{
|
||||
if(blockingBonus->sid.as<MapObjectID>() == Obj::GARRISON || blockingBonus->sid.as<MapObjectID>() == Obj::GARRISON2)
|
||||
LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[684]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
logGlobal->warn("Unexpected problem with readiness to cast spell");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,7 @@ class BattleInterface;
|
||||
class BattleConsole;
|
||||
class BattleRenderer;
|
||||
class StackQueue;
|
||||
class TurnTimerWidget;
|
||||
class HeroInfoBasicPanel;
|
||||
|
||||
/// GUI object that handles functionality of panel at the bottom of combat screen
|
||||
@ -36,6 +37,9 @@ class BattleWindow : public InterfaceObjectConfigurable
|
||||
std::shared_ptr<HeroInfoBasicPanel> attackerHeroWindow;
|
||||
std::shared_ptr<HeroInfoBasicPanel> defenderHeroWindow;
|
||||
|
||||
std::shared_ptr<TurnTimerWidget> attackerTimerWidget;
|
||||
std::shared_ptr<TurnTimerWidget> defenderTimerWidget;
|
||||
|
||||
/// button press handling functions
|
||||
void bOptionsf();
|
||||
void bSurrenderf();
|
||||
@ -65,6 +69,7 @@ class BattleWindow : public InterfaceObjectConfigurable
|
||||
|
||||
void toggleStickyHeroWindowsVisibility();
|
||||
void createStickyHeroInfoWindows();
|
||||
void createTimerInfoWindows();
|
||||
|
||||
std::shared_ptr<BattleConsole> buildBattleConsole(const JsonNode &) const;
|
||||
|
||||
|
@ -273,17 +273,15 @@ void CBonusSelection::createBonusesIcons()
|
||||
}
|
||||
|
||||
case CampaignBonusType::HERO:
|
||||
|
||||
desc.appendLocalString(EMetaText::GENERAL_TXT, 718);
|
||||
desc.replaceTextID(TextIdentifier("core", "genrltxt", "capColors", bonDescs[i].info1).get());
|
||||
if(bonDescs[i].info2 == 0xFFFF)
|
||||
{
|
||||
desc.replaceLocalString(EMetaText::GENERAL_TXT, 101);
|
||||
desc.appendLocalString(EMetaText::GENERAL_TXT, 720); // Start with random hero
|
||||
picNumber = -1;
|
||||
picName = "CBONN1A3.BMP";
|
||||
}
|
||||
else
|
||||
{
|
||||
desc.appendLocalString(EMetaText::GENERAL_TXT, 715); // Start with %s
|
||||
desc.replaceTextID(CGI->heroh->objects[bonDescs[i].info2]->getNameTextID());
|
||||
}
|
||||
break;
|
||||
|
@ -120,6 +120,8 @@ void CLobbyScreen::toggleTab(std::shared_ptr<CIntObject> tab)
|
||||
CSH->sendGuiAction(LobbyGuiAction::OPEN_SCENARIO_LIST);
|
||||
else if(tab == tabRand)
|
||||
CSH->sendGuiAction(LobbyGuiAction::OPEN_RANDOM_MAP_OPTIONS);
|
||||
else if(tab == tabTurnOptions)
|
||||
CSH->sendGuiAction(LobbyGuiAction::OPEN_TURN_OPTIONS);
|
||||
CSelectionBase::toggleTab(tab);
|
||||
}
|
||||
|
||||
|
@ -135,7 +135,7 @@ InfoCard::InfoCard()
|
||||
Rect descriptionRect(26, 149, 320, 115);
|
||||
mapDescription = std::make_shared<CTextBox>("", descriptionRect, 1);
|
||||
playerListBg = std::make_shared<CPicture>(ImagePath::builtin("CHATPLUG.bmp"), 16, 276);
|
||||
chat = std::make_shared<CChatBox>(Rect(26, 132, 340, 132));
|
||||
chat = std::make_shared<CChatBox>(Rect(18, 126, 335, 143));
|
||||
|
||||
if(SEL->screenType == ESelectionScreen::campaignList)
|
||||
{
|
||||
@ -332,9 +332,12 @@ CChatBox::CChatBox(const Rect & rect)
|
||||
setRedrawParent(true);
|
||||
|
||||
const int height = static_cast<int>(graphics->fonts[FONT_SMALL]->getLineHeight());
|
||||
inputBox = std::make_shared<CTextInput>(Rect(0, rect.h - height, rect.w, height), EFonts::FONT_SMALL, 0);
|
||||
Rect textInputArea(1, rect.h - height, rect.w - 1, height);
|
||||
Rect chatHistoryArea(3, 1, rect.w - 3, rect.h - height - 1);
|
||||
inputBackground = std::make_shared<TransparentFilledRectangle>(textInputArea, ColorRGBA(0,0,0,192));
|
||||
inputBox = std::make_shared<CTextInput>(textInputArea, EFonts::FONT_SMALL, 0);
|
||||
inputBox->removeUsedEvents(KEYBOARD);
|
||||
chatHistory = std::make_shared<CTextBox>("", Rect(0, 0, rect.w, rect.h - height), 1);
|
||||
chatHistory = std::make_shared<CTextBox>("", chatHistoryArea, 1);
|
||||
|
||||
chatHistory->label->color = Colors::GREEN;
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ class CChatBox;
|
||||
class CLabel;
|
||||
class CFlagBox;
|
||||
class CLabelGroup;
|
||||
class TransparentFilledRectangle;
|
||||
|
||||
class ISelectionScreenInfo
|
||||
{
|
||||
@ -122,6 +123,7 @@ class CChatBox : public CIntObject
|
||||
public:
|
||||
std::shared_ptr<CTextBox> chatHistory;
|
||||
std::shared_ptr<CTextInput> inputBox;
|
||||
std::shared_ptr<TransparentFilledRectangle> inputBackground;
|
||||
|
||||
CChatBox(const Rect & rect);
|
||||
|
||||
|
@ -503,7 +503,7 @@ void OptionsTab::SelectionWindow::recreate()
|
||||
int count = 0;
|
||||
for(auto & elem : allowedHeroes)
|
||||
{
|
||||
CHero * type = VLC->heroh->objects[elem];
|
||||
const CHero * type = elem.toHeroType();
|
||||
if(type->heroClass->faction == selectedFaction)
|
||||
{
|
||||
count++;
|
||||
|
@ -358,7 +358,11 @@ void RandomMapTab::setMapGenOptions(std::shared_ptr<CMapGenOptions> opts)
|
||||
}
|
||||
for(auto r : VLC->roadTypeHandler->objects)
|
||||
{
|
||||
if(auto w = widget<CToggleButton>(r->getJsonKey()))
|
||||
// Workaround for vcmi-extras bug
|
||||
std::string jsonKey = r->getJsonKey();
|
||||
std::string identifier = jsonKey.substr(jsonKey.find(':')+1);
|
||||
|
||||
if(auto w = widget<CToggleButton>(identifier))
|
||||
{
|
||||
w->setSelected(opts->isRoadEnabled(r->getId()));
|
||||
}
|
||||
|
@ -29,8 +29,7 @@
|
||||
#include "../../lib/CCreatureHandler.h"
|
||||
#include "../../lib/constants/EntityIdentifiers.h"
|
||||
#include "../../lib/TextOperations.h"
|
||||
|
||||
#include "vstd/DateUtils.h"
|
||||
#include "../../lib/Languages.h"
|
||||
|
||||
auto HighScoreCalculation::calculate()
|
||||
{
|
||||
@ -264,7 +263,7 @@ int CHighScoreInputScreen::addEntry(std::string text) {
|
||||
newNode["scenarioName"].String() = calc.calculate().cheater ? CGI->generaltexth->translate("core.genrltxt.260") : calc.parameters[0].scenarioName;
|
||||
newNode["days"].Integer() = calc.calculate().sumDays;
|
||||
newNode["points"].Integer() = calc.calculate().cheater ? 0 : calc.calculate().total;
|
||||
newNode["datetime"].String() = vstd::getFormattedDateTime(std::time(nullptr));
|
||||
newNode["datetime"].String() = TextOperations::getFormattedDateTimeLocal(std::time(nullptr));
|
||||
newNode["posFlag"].Bool() = true;
|
||||
|
||||
baseNode.push_back(newNode);
|
||||
|
@ -382,12 +382,29 @@ void CMainMenu::openCampaignLobby(std::shared_ptr<CampaignState> campaign)
|
||||
|
||||
void CMainMenu::openCampaignScreen(std::string name)
|
||||
{
|
||||
if(vstd::contains(CMainMenuConfig::get().getCampaigns().Struct(), name))
|
||||
auto const & config = CMainMenuConfig::get().getCampaigns();
|
||||
|
||||
if(!vstd::contains(config.Struct(), name))
|
||||
{
|
||||
GH.windows().createAndPushWindow<CCampaignScreen>(CMainMenuConfig::get().getCampaigns(), name);
|
||||
logGlobal->error("Unknown campaign set: %s", name);
|
||||
return;
|
||||
}
|
||||
logGlobal->error("Unknown campaign set: %s", name);
|
||||
|
||||
bool campaignsFound = true;
|
||||
for (auto const & entry : config[name]["items"].Vector())
|
||||
{
|
||||
ResourcePath resourceID(entry["file"].String(), EResType::CAMPAIGN);
|
||||
if (!CResourceHandler::get()->existsResource(resourceID))
|
||||
campaignsFound = false;
|
||||
}
|
||||
|
||||
if (!campaignsFound)
|
||||
{
|
||||
CInfoWindow::showInfoDialog(CGI->generaltexth->translate("vcmi.client.errors.missingCampaigns"), std::vector<std::shared_ptr<CComponent>>(), PlayerColor(1));
|
||||
return;
|
||||
}
|
||||
|
||||
GH.windows().createAndPushWindow<CCampaignScreen>(config, name);
|
||||
}
|
||||
|
||||
void CMainMenu::startTutorial()
|
||||
|
@ -139,7 +139,7 @@ void CCommanderArtPlace::clickPressed(const Point & cursorPosition)
|
||||
LOCPLINT->showYesNoDialog(CGI->generaltexth->translate("vcmi.commanderWindow.artifactMessage"), [this]() { returnArtToHeroCallback(); }, []() {});
|
||||
}
|
||||
|
||||
void CCommanderArtPlace::showPopupWindow(const Point & cursorPosition)
|
||||
void CCommanderArtPlace::showPopupWindow(const Point& cursorPosition)
|
||||
{
|
||||
if(ourArt && text.size())
|
||||
CArtPlace::showPopupWindow(cursorPosition);
|
||||
@ -180,16 +180,25 @@ bool CArtPlace::isSelected() const
|
||||
return selection->visible;
|
||||
}
|
||||
|
||||
void CHeroArtPlace::clickPressed(const Point & cursorPosition)
|
||||
void CArtPlace::clickPressed(const Point & cursorPosition)
|
||||
{
|
||||
if(leftClickCallback)
|
||||
leftClickCallback(*this);
|
||||
if(clickPressedCallback)
|
||||
clickPressedCallback(*this, cursorPosition);
|
||||
}
|
||||
|
||||
void CHeroArtPlace::showPopupWindow(const Point & cursorPosition)
|
||||
void CArtPlace::showPopupWindow(const Point & cursorPosition)
|
||||
{
|
||||
if(showPopupCallback)
|
||||
showPopupCallback(*this);
|
||||
showPopupCallback(*this, cursorPosition);
|
||||
}
|
||||
|
||||
void CArtPlace::gesture(bool on, const Point & initialPosition, const Point & finalPosition)
|
||||
{
|
||||
if(!on)
|
||||
return;
|
||||
|
||||
if(gestureCallback)
|
||||
gestureCallback(*this, initialPosition);
|
||||
}
|
||||
|
||||
void CArtPlace::showAll(Canvas & to)
|
||||
@ -216,6 +225,21 @@ void CArtPlace::setArtifact(const CArtifactInstance * art)
|
||||
}
|
||||
}
|
||||
|
||||
void CArtPlace::setClickPressedCallback(ClickFunctor callback)
|
||||
{
|
||||
clickPressedCallback = callback;
|
||||
}
|
||||
|
||||
void CArtPlace::setShowPopupCallback(ClickFunctor callback)
|
||||
{
|
||||
showPopupCallback = callback;
|
||||
}
|
||||
|
||||
void CArtPlace::setGestureCallback(ClickFunctor callback)
|
||||
{
|
||||
gestureCallback = callback;
|
||||
}
|
||||
|
||||
void CHeroArtPlace::addCombinedArtInfo(std::map<const CArtifact*, int> & arts)
|
||||
{
|
||||
for(const auto & combinedArt : arts)
|
||||
|
@ -32,14 +32,24 @@ public:
|
||||
class CArtPlace : public LRClickableAreaWTextComp
|
||||
{
|
||||
public:
|
||||
using ClickFunctor = std::function<void(CArtPlace&, const Point&)>;
|
||||
|
||||
ArtifactPosition slot;
|
||||
|
||||
CArtPlace(Point position, const CArtifactInstance * art = nullptr);
|
||||
const CArtifactInstance* getArt();
|
||||
const CArtifactInstance * getArt();
|
||||
void lockSlot(bool on);
|
||||
bool isLocked() const;
|
||||
void selectSlot(bool on);
|
||||
bool isSelected() const;
|
||||
void showAll(Canvas & to) override;
|
||||
void setArtifact(const CArtifactInstance * art);
|
||||
void setClickPressedCallback(ClickFunctor callback);
|
||||
void setShowPopupCallback(ClickFunctor callback);
|
||||
void setGestureCallback(ClickFunctor callback);
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
void showPopupWindow(const Point & cursorPosition) override;
|
||||
void gesture(bool on, const Point & initialPosition, const Point & finalPosition) override;
|
||||
|
||||
protected:
|
||||
std::shared_ptr<CAnimImage> image;
|
||||
@ -47,6 +57,9 @@ protected:
|
||||
int imageIndex;
|
||||
std::shared_ptr<CAnimImage> selection;
|
||||
bool locked;
|
||||
ClickFunctor clickPressedCallback;
|
||||
ClickFunctor showPopupCallback;
|
||||
ClickFunctor gestureCallback;
|
||||
|
||||
void setInternals(const CArtifactInstance * artInst);
|
||||
};
|
||||
@ -68,15 +81,7 @@ public:
|
||||
class CHeroArtPlace: public CArtPlace
|
||||
{
|
||||
public:
|
||||
using ClickFunctor = std::function<void(CHeroArtPlace&)>;
|
||||
|
||||
ArtifactPosition slot;
|
||||
ClickFunctor leftClickCallback;
|
||||
ClickFunctor showPopupCallback;
|
||||
|
||||
CHeroArtPlace(Point position, const CArtifactInstance * art = nullptr);
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
void showPopupWindow(const Point & cursorPosition) override;
|
||||
void addCombinedArtInfo(std::map<const CArtifact*, int> & arts);
|
||||
};
|
||||
|
||||
|
@ -23,8 +23,8 @@ CArtifactsOfHeroAltar::CArtifactsOfHeroAltar(const Point & position)
|
||||
: visibleArtSet(ArtBearer::ArtBearer::HERO)
|
||||
{
|
||||
init(
|
||||
std::bind(&CArtifactsOfHeroBase::leftClickArtPlace, this, _1),
|
||||
std::bind(&CArtifactsOfHeroBase::rightClickArtPlace, this, _1),
|
||||
std::bind(&CArtifactsOfHeroBase::clickPrassedArtPlace, this, _1, _2),
|
||||
std::bind(&CArtifactsOfHeroBase::showPopupArtPlace, this, _1, _2),
|
||||
position,
|
||||
std::bind(&CArtifactsOfHeroAltar::scrollBackpack, this, _1));
|
||||
pickedArtFromSlot = ArtifactPosition::PRE_FIRST;
|
||||
@ -69,7 +69,7 @@ void CArtifactsOfHeroAltar::scrollBackpack(int offset)
|
||||
redraw();
|
||||
}
|
||||
|
||||
void CArtifactsOfHeroAltar::pickUpArtifact(CHeroArtPlace & artPlace)
|
||||
void CArtifactsOfHeroAltar::pickUpArtifact(CArtPlace & artPlace)
|
||||
{
|
||||
if(const auto art = artPlace.getArt())
|
||||
{
|
||||
|
@ -26,7 +26,7 @@ public:
|
||||
void updateWornSlots() override;
|
||||
void updateBackpackSlots() override;
|
||||
void scrollBackpack(int offset) override;
|
||||
void pickUpArtifact(CHeroArtPlace & artPlace);
|
||||
void pickUpArtifact(CArtPlace & artPlace);
|
||||
void swapArtifacts(const ArtifactLocation & srcLoc, const ArtifactLocation & dstLoc);
|
||||
void pickedArtMoveToAltar(const ArtifactPosition & slot);
|
||||
void deleteFromVisible(const CArtifactInstance * artInst);
|
||||
|
@ -17,60 +17,28 @@
|
||||
#include "ObjectLists.h"
|
||||
|
||||
#include "../CPlayerInterface.h"
|
||||
#include "../../lib/ArtifactUtils.h"
|
||||
#include "../../lib/mapObjects/CGHeroInstance.h"
|
||||
#include "../../lib/networkPacks/ArtifactLocation.h"
|
||||
|
||||
#include "../../CCallback.h"
|
||||
|
||||
CArtifactsOfHeroBackpack::CArtifactsOfHeroBackpack(const Point & position)
|
||||
CArtifactsOfHeroBackpack::CArtifactsOfHeroBackpack(size_t slotsColumnsMax, size_t slotsRowsMax)
|
||||
: slotsColumnsMax(slotsColumnsMax)
|
||||
, slotsRowsMax(slotsRowsMax)
|
||||
{
|
||||
OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
|
||||
pos += position;
|
||||
setRedrawParent(true);
|
||||
}
|
||||
|
||||
CArtifactsOfHeroBackpack::CArtifactsOfHeroBackpack()
|
||||
: CArtifactsOfHeroBackpack(8, 8)
|
||||
{
|
||||
const auto backpackCap = VLC->settings()->getInteger(EGameSettings::HEROES_BACKPACK_CAP);
|
||||
auto visibleCapacityMax = HERO_BACKPACK_WINDOW_SLOT_ROWS * HERO_BACKPACK_WINDOW_SLOT_COLUMNS;
|
||||
auto visibleCapacityMax = slotsRowsMax * slotsColumnsMax;
|
||||
if(backpackCap >= 0)
|
||||
visibleCapacityMax = visibleCapacityMax > backpackCap ? backpackCap : visibleCapacityMax;
|
||||
|
||||
backpack.resize(visibleCapacityMax);
|
||||
size_t artPlaceIdx = 0;
|
||||
for(auto & artPlace : backpack)
|
||||
{
|
||||
const auto pos = Point(slotSizeWithMargin * (artPlaceIdx % HERO_BACKPACK_WINDOW_SLOT_COLUMNS),
|
||||
slotSizeWithMargin * (artPlaceIdx / HERO_BACKPACK_WINDOW_SLOT_COLUMNS));
|
||||
backpackSlotsBackgrounds.emplace_back(std::make_shared<CPicture>(ImagePath::builtin("heroWindow/artifactSlotEmpty"), pos));
|
||||
artPlace = std::make_shared<CHeroArtPlace>(pos);
|
||||
artPlace->setArtifact(nullptr);
|
||||
artPlace->leftClickCallback = std::bind(&CArtifactsOfHeroBase::leftClickArtPlace, this, _1);
|
||||
artPlace->showPopupCallback = std::bind(&CArtifactsOfHeroBase::rightClickArtPlace, this, _1);
|
||||
artPlaceIdx++;
|
||||
}
|
||||
|
||||
if(backpackCap < 0 || visibleCapacityMax < backpackCap)
|
||||
{
|
||||
auto onCreate = [](size_t index) -> std::shared_ptr<CIntObject>
|
||||
{
|
||||
return std::make_shared<CIntObject>();
|
||||
};
|
||||
CListBoxWithCallback::MovedPosCallback posMoved = [this](size_t pos) -> void
|
||||
{
|
||||
scrollBackpack(static_cast<int>(pos) * HERO_BACKPACK_WINDOW_SLOT_COLUMNS - backpackPos);
|
||||
};
|
||||
backpackListBox = std::make_shared<CListBoxWithCallback>(
|
||||
posMoved, onCreate, Point(0, 0), Point(0, 0), HERO_BACKPACK_WINDOW_SLOT_ROWS, 0, 0, 1,
|
||||
Rect(HERO_BACKPACK_WINDOW_SLOT_COLUMNS * slotSizeWithMargin + sliderPosOffsetX, 0, HERO_BACKPACK_WINDOW_SLOT_ROWS * slotSizeWithMargin - 2, 0));
|
||||
}
|
||||
|
||||
pos.w = visibleCapacityMax > HERO_BACKPACK_WINDOW_SLOT_COLUMNS ? HERO_BACKPACK_WINDOW_SLOT_COLUMNS : visibleCapacityMax;
|
||||
pos.w *= slotSizeWithMargin;
|
||||
if(backpackListBox)
|
||||
pos.w += sliderPosOffsetX + 16; // 16 is slider width. TODO: get it from CListBox directly;
|
||||
|
||||
pos.h = (visibleCapacityMax / HERO_BACKPACK_WINDOW_SLOT_COLUMNS);
|
||||
if(visibleCapacityMax % HERO_BACKPACK_WINDOW_SLOT_COLUMNS != 0)
|
||||
pos.h += 1;
|
||||
pos.h *= slotSizeWithMargin;
|
||||
initAOHbackpack(visibleCapacityMax, backpackCap < 0 || visibleCapacityMax < backpackCap);
|
||||
}
|
||||
|
||||
void CArtifactsOfHeroBackpack::swapArtifacts(const ArtifactLocation & srcLoc, const ArtifactLocation & dstLoc)
|
||||
@ -78,7 +46,7 @@ void CArtifactsOfHeroBackpack::swapArtifacts(const ArtifactLocation & srcLoc, co
|
||||
LOCPLINT->cb->swapArtifacts(srcLoc, dstLoc);
|
||||
}
|
||||
|
||||
void CArtifactsOfHeroBackpack::pickUpArtifact(CHeroArtPlace & artPlace)
|
||||
void CArtifactsOfHeroBackpack::pickUpArtifact(CArtPlace & artPlace)
|
||||
{
|
||||
LOCPLINT->cb->swapArtifacts(ArtifactLocation(curHero->id, artPlace.slot),
|
||||
ArtifactLocation(curHero->id, ArtifactPosition::TRANSITION_POS));
|
||||
@ -107,5 +75,145 @@ void CArtifactsOfHeroBackpack::updateBackpackSlots()
|
||||
|
||||
size_t CArtifactsOfHeroBackpack::getActiveSlotRowsNum()
|
||||
{
|
||||
return (curHero->artifactsInBackpack.size() + HERO_BACKPACK_WINDOW_SLOT_COLUMNS - 1) / HERO_BACKPACK_WINDOW_SLOT_COLUMNS;
|
||||
return (curHero->artifactsInBackpack.size() + slotsColumnsMax - 1) / slotsColumnsMax;
|
||||
}
|
||||
|
||||
size_t CArtifactsOfHeroBackpack::getSlotsNum()
|
||||
{
|
||||
return backpack.size();
|
||||
}
|
||||
|
||||
void CArtifactsOfHeroBackpack::initAOHbackpack(size_t slots, bool slider)
|
||||
{
|
||||
OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
|
||||
|
||||
backpack.resize(slots);
|
||||
size_t artPlaceIdx = 0;
|
||||
for(auto & artPlace : backpack)
|
||||
{
|
||||
const auto pos = Point(slotSizeWithMargin * (artPlaceIdx % slotsColumnsMax),
|
||||
slotSizeWithMargin * (artPlaceIdx / slotsColumnsMax));
|
||||
backpackSlotsBackgrounds.emplace_back(std::make_shared<CPicture>(ImagePath::builtin("heroWindow/artifactSlotEmpty"), pos));
|
||||
artPlace = std::make_shared<CHeroArtPlace>(pos);
|
||||
artPlace->setArtifact(nullptr);
|
||||
artPlace->setClickPressedCallback(std::bind(&CArtifactsOfHeroBase::clickPrassedArtPlace, this, _1, _2));
|
||||
artPlace->setShowPopupCallback(std::bind(&CArtifactsOfHeroBase::showPopupArtPlace, this, _1, _2));
|
||||
artPlaceIdx++;
|
||||
}
|
||||
|
||||
if(slider)
|
||||
{
|
||||
auto onCreate = [](size_t index) -> std::shared_ptr<CIntObject>
|
||||
{
|
||||
return std::make_shared<CIntObject>();
|
||||
};
|
||||
CListBoxWithCallback::MovedPosCallback posMoved = [this](size_t pos) -> void
|
||||
{
|
||||
scrollBackpack(static_cast<int>(pos) * slotsColumnsMax - backpackPos);
|
||||
};
|
||||
backpackListBox = std::make_shared<CListBoxWithCallback>(
|
||||
posMoved, onCreate, Point(0, 0), Point(0, 0), slotsRowsMax, 0, 0, 1,
|
||||
Rect(slotsColumnsMax * slotSizeWithMargin + sliderPosOffsetX, 0, slotsRowsMax * slotSizeWithMargin - 2, 0));
|
||||
}
|
||||
|
||||
pos.w = slots > slotsColumnsMax ? slotsColumnsMax : slots;
|
||||
pos.w *= slotSizeWithMargin;
|
||||
if(slider)
|
||||
pos.w += sliderPosOffsetX + 16; // 16 is slider width. TODO: get it from CListBox directly;
|
||||
pos.h = calcRows(slots) * slotSizeWithMargin;
|
||||
}
|
||||
|
||||
size_t CArtifactsOfHeroBackpack::calcRows(size_t slots)
|
||||
{
|
||||
size_t rows = 0;
|
||||
if(slotsColumnsMax != 0)
|
||||
{
|
||||
rows = slots / slotsColumnsMax;
|
||||
if(slots % slotsColumnsMax != 0)
|
||||
rows += 1;
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
CArtifactsOfHeroQuickBackpack::CArtifactsOfHeroQuickBackpack(const ArtifactPosition filterBySlot)
|
||||
: CArtifactsOfHeroBackpack(0, 0)
|
||||
{
|
||||
assert(filterBySlot != ArtifactPosition::FIRST_AVAILABLE);
|
||||
|
||||
if(!ArtifactUtils::isSlotEquipment(filterBySlot))
|
||||
return;
|
||||
|
||||
this->filterBySlot = filterBySlot;
|
||||
}
|
||||
|
||||
void CArtifactsOfHeroQuickBackpack::setHero(const CGHeroInstance * hero)
|
||||
{
|
||||
if(curHero == hero)
|
||||
return;
|
||||
|
||||
curHero = hero;
|
||||
if(curHero)
|
||||
{
|
||||
ArtifactID artInSlotId = ArtifactID::NONE;
|
||||
SpellID scrollInSlotSpellId = SpellID::NONE;
|
||||
if(auto artInSlot = curHero->getArt(filterBySlot))
|
||||
{
|
||||
artInSlotId = artInSlot->getTypeId();
|
||||
scrollInSlotSpellId = artInSlot->getScrollSpellID();
|
||||
}
|
||||
|
||||
std::map<const ArtifactID, const CArtifactInstance*> filteredArts;
|
||||
for(auto & slotInfo : curHero->artifactsInBackpack)
|
||||
if(slotInfo.artifact->getTypeId() != artInSlotId && !slotInfo.artifact->isScroll() &&
|
||||
slotInfo.artifact->artType->canBePutAt(curHero, filterBySlot, true))
|
||||
{
|
||||
filteredArts.insert(std::pair(slotInfo.artifact->getTypeId(), slotInfo.artifact));
|
||||
}
|
||||
|
||||
std::map<const SpellID, const CArtifactInstance*> filteredScrolls;
|
||||
if(filterBySlot == ArtifactPosition::MISC1 || filterBySlot == ArtifactPosition::MISC2 || filterBySlot == ArtifactPosition::MISC3 ||
|
||||
filterBySlot == ArtifactPosition::MISC4 || filterBySlot == ArtifactPosition::MISC5)
|
||||
{
|
||||
for(auto & slotInfo : curHero->artifactsInBackpack)
|
||||
{
|
||||
if(slotInfo.artifact->isScroll() && slotInfo.artifact->getScrollSpellID() != scrollInSlotSpellId)
|
||||
filteredScrolls.insert(std::pair(slotInfo.artifact->getScrollSpellID(), slotInfo.artifact));
|
||||
}
|
||||
}
|
||||
|
||||
backpack.clear();
|
||||
auto requiredSlots = filteredArts.size() + filteredScrolls.size();
|
||||
slotsColumnsMax = ceilf(sqrtf(requiredSlots));
|
||||
slotsRowsMax = calcRows(requiredSlots);
|
||||
initAOHbackpack(requiredSlots, false);
|
||||
auto artPlace = backpack.begin();
|
||||
for(auto & art : filteredArts)
|
||||
setSlotData(*artPlace++, curHero->getSlotByInstance(art.second), *curHero);
|
||||
for(auto & art : filteredScrolls)
|
||||
setSlotData(*artPlace++, curHero->getSlotByInstance(art.second), *curHero);
|
||||
}
|
||||
}
|
||||
|
||||
ArtifactPosition CArtifactsOfHeroQuickBackpack::getFilterSlot()
|
||||
{
|
||||
return filterBySlot;
|
||||
}
|
||||
|
||||
void CArtifactsOfHeroQuickBackpack::selectSlotAt(const Point & position)
|
||||
{
|
||||
for(auto & artPlace : backpack)
|
||||
artPlace->selectSlot(artPlace->pos.isInside(position));
|
||||
}
|
||||
|
||||
void CArtifactsOfHeroQuickBackpack::swapSelected()
|
||||
{
|
||||
ArtifactLocation backpackLoc(curHero->id, ArtifactPosition::PRE_FIRST);
|
||||
for(auto & artPlace : backpack)
|
||||
if(artPlace->isSelected())
|
||||
{
|
||||
backpackLoc.slot = artPlace->slot;
|
||||
break;
|
||||
}
|
||||
if(backpackLoc.slot != ArtifactPosition::PRE_FIRST && filterBySlot != ArtifactPosition::PRE_FIRST && curHero)
|
||||
swapArtifacts(backpackLoc, ArtifactLocation(curHero->id, filterBySlot));
|
||||
}
|
@ -22,18 +22,36 @@ class CListBoxWithCallback;
|
||||
class CArtifactsOfHeroBackpack : public CArtifactsOfHeroBase
|
||||
{
|
||||
public:
|
||||
CArtifactsOfHeroBackpack(const Point & position);
|
||||
CArtifactsOfHeroBackpack(size_t slotsColumnsMax, size_t slotsRowsMax);
|
||||
CArtifactsOfHeroBackpack();
|
||||
void swapArtifacts(const ArtifactLocation & srcLoc, const ArtifactLocation & dstLoc);
|
||||
void pickUpArtifact(CHeroArtPlace & artPlace);
|
||||
void pickUpArtifact(CArtPlace & artPlace);
|
||||
void scrollBackpack(int offset) override;
|
||||
void updateBackpackSlots() override;
|
||||
size_t getActiveSlotRowsNum();
|
||||
size_t getSlotsNum();
|
||||
|
||||
private:
|
||||
protected:
|
||||
std::shared_ptr<CListBoxWithCallback> backpackListBox;
|
||||
std::vector<std::shared_ptr<CPicture>> backpackSlotsBackgrounds;
|
||||
const size_t HERO_BACKPACK_WINDOW_SLOT_COLUMNS = 8;
|
||||
const size_t HERO_BACKPACK_WINDOW_SLOT_ROWS = 8;
|
||||
size_t slotsColumnsMax;
|
||||
size_t slotsRowsMax;
|
||||
const int slotSizeWithMargin = 46;
|
||||
const int sliderPosOffsetX = 10;
|
||||
const int sliderPosOffsetX = 5;
|
||||
|
||||
void initAOHbackpack(size_t slots, bool slider);
|
||||
size_t calcRows(size_t slots);
|
||||
};
|
||||
|
||||
class CArtifactsOfHeroQuickBackpack : public CArtifactsOfHeroBackpack
|
||||
{
|
||||
public:
|
||||
CArtifactsOfHeroQuickBackpack(const ArtifactPosition filterBySlot);
|
||||
void setHero(const CGHeroInstance * hero);
|
||||
ArtifactPosition getFilterSlot();
|
||||
void selectSlotAt(const Point & position);
|
||||
void swapSelected();
|
||||
|
||||
private:
|
||||
ArtifactPosition filterBySlot;
|
||||
};
|
||||
|
@ -56,8 +56,8 @@ void CArtifactsOfHeroBase::setPutBackPickedArtifactCallback(PutBackPickedArtCall
|
||||
}
|
||||
|
||||
void CArtifactsOfHeroBase::init(
|
||||
CHeroArtPlace::ClickFunctor lClickCallback,
|
||||
CHeroArtPlace::ClickFunctor showPopupCallback,
|
||||
CArtPlace::ClickFunctor lClickCallback,
|
||||
CArtPlace::ClickFunctor showPopupCallback,
|
||||
const Point & position,
|
||||
BpackScrollFunctor scrollCallback)
|
||||
{
|
||||
@ -78,14 +78,14 @@ void CArtifactsOfHeroBase::init(
|
||||
{
|
||||
artPlace.second->slot = artPlace.first;
|
||||
artPlace.second->setArtifact(nullptr);
|
||||
artPlace.second->leftClickCallback = lClickCallback;
|
||||
artPlace.second->showPopupCallback = showPopupCallback;
|
||||
artPlace.second->setClickPressedCallback(lClickCallback);
|
||||
artPlace.second->setShowPopupCallback(showPopupCallback);
|
||||
}
|
||||
for(auto artPlace : backpack)
|
||||
{
|
||||
artPlace->setArtifact(nullptr);
|
||||
artPlace->leftClickCallback = lClickCallback;
|
||||
artPlace->showPopupCallback = showPopupCallback;
|
||||
artPlace->setClickPressedCallback(lClickCallback);
|
||||
artPlace->setShowPopupCallback(showPopupCallback);
|
||||
}
|
||||
leftBackpackRoll = std::make_shared<CButton>(Point(379, 364), AnimationPath::builtin("hsbtns3.def"), CButton::tooltip(), [scrollCallback]() {scrollCallback(-1);}, EShortcut::MOVE_LEFT);
|
||||
rightBackpackRoll = std::make_shared<CButton>(Point(632, 364), AnimationPath::builtin("hsbtns5.def"), CButton::tooltip(), [scrollCallback]() {scrollCallback(+1);}, EShortcut::MOVE_RIGHT);
|
||||
@ -95,16 +95,22 @@ void CArtifactsOfHeroBase::init(
|
||||
setRedrawParent(true);
|
||||
}
|
||||
|
||||
void CArtifactsOfHeroBase::leftClickArtPlace(CHeroArtPlace & artPlace)
|
||||
void CArtifactsOfHeroBase::clickPrassedArtPlace(CArtPlace & artPlace, const Point & cursorPosition)
|
||||
{
|
||||
if(leftClickCallback)
|
||||
leftClickCallback(*this, artPlace);
|
||||
if(clickPressedCallback)
|
||||
clickPressedCallback(*this, artPlace, cursorPosition);
|
||||
}
|
||||
|
||||
void CArtifactsOfHeroBase::rightClickArtPlace(CHeroArtPlace & artPlace)
|
||||
void CArtifactsOfHeroBase::showPopupArtPlace(CArtPlace & artPlace, const Point & cursorPosition)
|
||||
{
|
||||
if(showPopupCallback)
|
||||
showPopupCallback(*this, artPlace);
|
||||
showPopupCallback(*this, artPlace, cursorPosition);
|
||||
}
|
||||
|
||||
void CArtifactsOfHeroBase::gestureArtPlace(CArtPlace & artPlace, const Point & cursorPosition)
|
||||
{
|
||||
if(gestureCallback)
|
||||
gestureCallback(*this, artPlace, cursorPosition);
|
||||
}
|
||||
|
||||
void CArtifactsOfHeroBase::setHero(const CGHeroInstance * hero)
|
||||
@ -241,6 +247,15 @@ const CArtifactInstance * CArtifactsOfHeroBase::getPickedArtifact()
|
||||
return curHero->getArt(ArtifactPosition::TRANSITION_POS);
|
||||
}
|
||||
|
||||
void CArtifactsOfHeroBase::addGestureCallback(CArtPlace::ClickFunctor callback)
|
||||
{
|
||||
for(auto & artPlace : artWorn)
|
||||
{
|
||||
artPlace.second->setGestureCallback(callback);
|
||||
artPlace.second->addUsedEvents(GESTURE);
|
||||
}
|
||||
}
|
||||
|
||||
void CArtifactsOfHeroBase::setSlotData(ArtPlacePtr artPlace, const ArtifactPosition & slot, const CArtifactSet & artSet)
|
||||
{
|
||||
// Spurious call from artifactMoved in attempt to update hidden backpack slot
|
||||
|
@ -21,17 +21,19 @@ protected:
|
||||
|
||||
public:
|
||||
using ArtPlaceMap = std::map<ArtifactPosition, ArtPlacePtr>;
|
||||
using ClickFunctor = std::function<void(CArtifactsOfHeroBase&, CHeroArtPlace&)>;
|
||||
using ClickFunctor = std::function<void(CArtifactsOfHeroBase&, CArtPlace&, const Point&)>;
|
||||
using PutBackPickedArtCallback = std::function<void()>;
|
||||
|
||||
ClickFunctor leftClickCallback;
|
||||
ClickFunctor clickPressedCallback;
|
||||
ClickFunctor showPopupCallback;
|
||||
ClickFunctor gestureCallback;
|
||||
|
||||
CArtifactsOfHeroBase();
|
||||
virtual void putBackPickedArtifact();
|
||||
virtual void setPutBackPickedArtifactCallback(PutBackPickedArtCallback callback);
|
||||
virtual void leftClickArtPlace(CHeroArtPlace & artPlace);
|
||||
virtual void rightClickArtPlace(CHeroArtPlace & artPlace);
|
||||
virtual void clickPrassedArtPlace(CArtPlace & artPlace, const Point & cursorPosition);
|
||||
virtual void showPopupArtPlace(CArtPlace & artPlace, const Point & cursorPosition);
|
||||
virtual void gestureArtPlace(CArtPlace & artPlace, const Point & cursorPosition);
|
||||
virtual void setHero(const CGHeroInstance * hero);
|
||||
virtual const CGHeroInstance * getHero() const;
|
||||
virtual void scrollBackpack(int offset);
|
||||
@ -42,6 +44,7 @@ public:
|
||||
virtual void updateBackpackSlots();
|
||||
virtual void updateSlot(const ArtifactPosition & slot);
|
||||
virtual const CArtifactInstance * getPickedArtifact();
|
||||
void addGestureCallback(CArtPlace::ClickFunctor callback);
|
||||
|
||||
protected:
|
||||
const CGHeroInstance * curHero;
|
||||
|
@ -30,14 +30,15 @@ CArtifactsOfHeroKingdom::CArtifactsOfHeroKingdom(ArtPlaceMap ArtWorn, std::vecto
|
||||
{
|
||||
artPlace.second->slot = artPlace.first;
|
||||
artPlace.second->setArtifact(nullptr);
|
||||
artPlace.second->leftClickCallback = std::bind(&CArtifactsOfHeroBase::leftClickArtPlace, this, _1);
|
||||
artPlace.second->showPopupCallback = std::bind(&CArtifactsOfHeroBase::rightClickArtPlace, this, _1);
|
||||
artPlace.second->setClickPressedCallback(std::bind(&CArtifactsOfHeroBase::clickPrassedArtPlace, this, _1, _2));
|
||||
artPlace.second->setShowPopupCallback(std::bind(&CArtifactsOfHeroBase::showPopupArtPlace, this, _1, _2));
|
||||
}
|
||||
addGestureCallback(std::bind(&CArtifactsOfHeroBase::gestureArtPlace, this, _1, _2));
|
||||
for(auto artPlace : backpack)
|
||||
{
|
||||
artPlace->setArtifact(nullptr);
|
||||
artPlace->leftClickCallback = std::bind(&CArtifactsOfHeroBase::leftClickArtPlace, this, _1);
|
||||
artPlace->showPopupCallback = std::bind(&CArtifactsOfHeroBase::rightClickArtPlace, this, _1);
|
||||
artPlace->setClickPressedCallback(std::bind(&CArtifactsOfHeroBase::clickPrassedArtPlace, this, _1, _2));
|
||||
artPlace->setShowPopupCallback(std::bind(&CArtifactsOfHeroBase::showPopupArtPlace, this, _1, _2));
|
||||
}
|
||||
leftBackpackRoll->addCallback(std::bind(&CArtifactsOfHeroBase::scrollBackpack, this, -1));
|
||||
rightBackpackRoll->addCallback(std::bind(&CArtifactsOfHeroBase::scrollBackpack, this, +1));
|
||||
@ -55,7 +56,7 @@ void CArtifactsOfHeroKingdom::swapArtifacts(const ArtifactLocation & srcLoc, con
|
||||
LOCPLINT->cb->swapArtifacts(srcLoc, dstLoc);
|
||||
}
|
||||
|
||||
void CArtifactsOfHeroKingdom::pickUpArtifact(CHeroArtPlace & artPlace)
|
||||
void CArtifactsOfHeroKingdom::pickUpArtifact(CArtPlace & artPlace)
|
||||
{
|
||||
LOCPLINT->cb->swapArtifacts(ArtifactLocation(curHero->id, artPlace.slot),
|
||||
ArtifactLocation(curHero->id, ArtifactPosition::TRANSITION_POS));
|
||||
|
@ -24,5 +24,5 @@ public:
|
||||
std::shared_ptr<CButton> leftScroll, std::shared_ptr<CButton> rightScroll);
|
||||
~CArtifactsOfHeroKingdom();
|
||||
void swapArtifacts(const ArtifactLocation & srcLoc, const ArtifactLocation & dstLoc);
|
||||
void pickUpArtifact(CHeroArtPlace & artPlace);
|
||||
void pickUpArtifact(CArtPlace & artPlace);
|
||||
};
|
@ -19,10 +19,11 @@
|
||||
CArtifactsOfHeroMain::CArtifactsOfHeroMain(const Point & position)
|
||||
{
|
||||
init(
|
||||
std::bind(&CArtifactsOfHeroBase::leftClickArtPlace, this, _1),
|
||||
std::bind(&CArtifactsOfHeroBase::rightClickArtPlace, this, _1),
|
||||
std::bind(&CArtifactsOfHeroBase::clickPrassedArtPlace, this, _1, _2),
|
||||
std::bind(&CArtifactsOfHeroBase::showPopupArtPlace, this, _1, _2),
|
||||
position,
|
||||
std::bind(&CArtifactsOfHeroBase::scrollBackpack, this, _1));
|
||||
addGestureCallback(std::bind(&CArtifactsOfHeroBase::gestureArtPlace, this, _1, _2));
|
||||
}
|
||||
|
||||
CArtifactsOfHeroMain::~CArtifactsOfHeroMain()
|
||||
@ -35,7 +36,7 @@ void CArtifactsOfHeroMain::swapArtifacts(const ArtifactLocation & srcLoc, const
|
||||
LOCPLINT->cb->swapArtifacts(srcLoc, dstLoc);
|
||||
}
|
||||
|
||||
void CArtifactsOfHeroMain::pickUpArtifact(CHeroArtPlace & artPlace)
|
||||
void CArtifactsOfHeroMain::pickUpArtifact(CArtPlace & artPlace)
|
||||
{
|
||||
LOCPLINT->cb->swapArtifacts(ArtifactLocation(curHero->id, artPlace.slot),
|
||||
ArtifactLocation(curHero->id, ArtifactPosition::TRANSITION_POS));
|
||||
|
@ -23,5 +23,5 @@ public:
|
||||
CArtifactsOfHeroMain(const Point & position);
|
||||
~CArtifactsOfHeroMain();
|
||||
void swapArtifacts(const ArtifactLocation & srcLoc, const ArtifactLocation & dstLoc);
|
||||
void pickUpArtifact(CHeroArtPlace & artPlace);
|
||||
void pickUpArtifact(CArtPlace & artPlace);
|
||||
};
|
||||
|
@ -15,8 +15,8 @@
|
||||
CArtifactsOfHeroMarket::CArtifactsOfHeroMarket(const Point & position)
|
||||
{
|
||||
init(
|
||||
std::bind(&CArtifactsOfHeroBase::leftClickArtPlace, this, _1),
|
||||
std::bind(&CArtifactsOfHeroBase::rightClickArtPlace, this, _1),
|
||||
std::bind(&CArtifactsOfHeroBase::clickPrassedArtPlace, this, _1, _2),
|
||||
std::bind(&CArtifactsOfHeroBase::showPopupArtPlace, this, _1, _2),
|
||||
position,
|
||||
std::bind(&CArtifactsOfHeroMarket::scrollBackpack, this, _1));
|
||||
};
|
||||
|
@ -14,7 +14,7 @@
|
||||
class CArtifactsOfHeroMarket : public CArtifactsOfHeroBase
|
||||
{
|
||||
public:
|
||||
std::function<void(CHeroArtPlace*)> selectArtCallback;
|
||||
std::function<void(CArtPlace*)> selectArtCallback;
|
||||
|
||||
CArtifactsOfHeroMarket(const Point & position);
|
||||
void scrollBackpack(int offset) override;
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "../windows/CHeroWindow.h"
|
||||
#include "../windows/CSpellWindow.h"
|
||||
#include "../windows/GUIClasses.h"
|
||||
#include "../windows/CHeroBackpackWindow.h"
|
||||
#include "../CPlayerInterface.h"
|
||||
#include "../CGameInfo.h"
|
||||
|
||||
@ -39,18 +40,19 @@ void CWindowWithArtifacts::addSet(CArtifactsOfHeroPtr artSet)
|
||||
|
||||
void CWindowWithArtifacts::addSetAndCallbacks(CArtifactsOfHeroPtr artSet)
|
||||
{
|
||||
CArtifactsOfHeroBase::PutBackPickedArtCallback artPutBackHandler = []() -> void
|
||||
CArtifactsOfHeroBase::PutBackPickedArtCallback artPutBackFunctor = []() -> void
|
||||
{
|
||||
CCS->curh->dragAndDropCursor(nullptr);
|
||||
};
|
||||
|
||||
addSet(artSet);
|
||||
std::visit([this, artPutBackHandler](auto artSetWeak)
|
||||
std::visit([this, artPutBackFunctor](auto artSetWeak)
|
||||
{
|
||||
auto artSet = artSetWeak.lock();
|
||||
artSet->leftClickCallback = std::bind(&CWindowWithArtifacts::leftClickArtPlaceHero, this, _1, _2);
|
||||
artSet->showPopupCallback = std::bind(&CWindowWithArtifacts::rightClickArtPlaceHero, this, _1, _2);
|
||||
artSet->setPutBackPickedArtifactCallback(artPutBackHandler);
|
||||
artSet->clickPressedCallback = std::bind(&CWindowWithArtifacts::clickPressedArtPlaceHero, this, _1, _2, _3);
|
||||
artSet->showPopupCallback = std::bind(&CWindowWithArtifacts::showPopupArtPlaceHero, this, _1, _2, _3);
|
||||
artSet->gestureCallback = std::bind(&CWindowWithArtifacts::gestureArtPlaceHero, this, _1, _2, _3);
|
||||
artSet->setPutBackPickedArtifactCallback(artPutBackFunctor);
|
||||
}, artSet);
|
||||
}
|
||||
|
||||
@ -77,7 +79,7 @@ const CArtifactInstance * CWindowWithArtifacts::getPickedArtifact()
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void CWindowWithArtifacts::leftClickArtPlaceHero(CArtifactsOfHeroBase & artsInst, CHeroArtPlace & artPlace)
|
||||
void CWindowWithArtifacts::clickPressedArtPlaceHero(CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition)
|
||||
{
|
||||
const auto artSetWeak = findAOHbyRef(artsInst);
|
||||
assert(artSetWeak.has_value());
|
||||
@ -85,7 +87,7 @@ void CWindowWithArtifacts::leftClickArtPlaceHero(CArtifactsOfHeroBase & artsInst
|
||||
if(artPlace.isLocked())
|
||||
return;
|
||||
|
||||
const auto checkSpecialArts = [](const CGHeroInstance * hero, CHeroArtPlace & artPlace) -> bool
|
||||
const auto checkSpecialArts = [](const CGHeroInstance * hero, CArtPlace & artPlace) -> bool
|
||||
{
|
||||
if(artPlace.getArt()->getTypeId() == ArtifactID::SPELLBOOK)
|
||||
{
|
||||
@ -206,10 +208,18 @@ void CWindowWithArtifacts::leftClickArtPlaceHero(CArtifactsOfHeroBase & artsInst
|
||||
}
|
||||
}
|
||||
}
|
||||
else if constexpr(std::is_same_v<decltype(artSetWeak), std::weak_ptr<CArtifactsOfHeroQuickBackpack>>)
|
||||
{
|
||||
const auto hero = artSetPtr->getHero();
|
||||
artSetPtr->swapArtifacts(ArtifactLocation(hero->id, artPlace.slot),
|
||||
ArtifactLocation(hero->id, artSetPtr->getFilterSlot()));
|
||||
if(closeCallback)
|
||||
closeCallback();
|
||||
}
|
||||
}, artSetWeak.value());
|
||||
}
|
||||
|
||||
void CWindowWithArtifacts::rightClickArtPlaceHero(CArtifactsOfHeroBase & artsInst, CHeroArtPlace & artPlace)
|
||||
void CWindowWithArtifacts::showPopupArtPlaceHero(CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition)
|
||||
{
|
||||
const auto artSetWeak = findAOHbyRef(artsInst);
|
||||
assert(artSetWeak.has_value());
|
||||
@ -218,7 +228,7 @@ void CWindowWithArtifacts::rightClickArtPlaceHero(CArtifactsOfHeroBase & artsIns
|
||||
return;
|
||||
|
||||
std::visit(
|
||||
[&artPlace](auto artSetWeak) -> void
|
||||
[&artPlace, &cursorPosition](auto artSetWeak) -> void
|
||||
{
|
||||
const auto artSetPtr = artSetWeak.lock();
|
||||
|
||||
@ -239,16 +249,40 @@ void CWindowWithArtifacts::rightClickArtPlaceHero(CArtifactsOfHeroBase & artsIns
|
||||
return;
|
||||
}
|
||||
if(artPlace.text.size())
|
||||
artPlace.LRClickableAreaWTextComp::showPopupWindow(GH.getCursorPosition());
|
||||
artPlace.LRClickableAreaWTextComp::showPopupWindow(cursorPosition);
|
||||
}
|
||||
}
|
||||
// Altar window, Market window right click handler
|
||||
else if constexpr(
|
||||
std::is_same_v<decltype(artSetWeak), std::weak_ptr<CArtifactsOfHeroAltar>> ||
|
||||
std::is_same_v<decltype(artSetWeak), std::weak_ptr<CArtifactsOfHeroMarket>>)
|
||||
std::is_same_v<decltype(artSetWeak), std::weak_ptr<CArtifactsOfHeroMarket>> ||
|
||||
std::is_same_v<decltype(artSetWeak), std::weak_ptr<CArtifactsOfHeroQuickBackpack>>)
|
||||
{
|
||||
if(artPlace.getArt() && artPlace.text.size())
|
||||
artPlace.LRClickableAreaWTextComp::showPopupWindow(GH.getCursorPosition());
|
||||
artPlace.LRClickableAreaWTextComp::showPopupWindow(cursorPosition);
|
||||
}
|
||||
}, artSetWeak.value());
|
||||
}
|
||||
|
||||
void CWindowWithArtifacts::gestureArtPlaceHero(CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition)
|
||||
{
|
||||
const auto artSetWeak = findAOHbyRef(artsInst);
|
||||
assert(artSetWeak.has_value());
|
||||
if(artPlace.isLocked())
|
||||
return;
|
||||
|
||||
std::visit(
|
||||
[&artPlace, cursorPosition](auto artSetWeak) -> void
|
||||
{
|
||||
const auto artSetPtr = artSetWeak.lock();
|
||||
if constexpr(
|
||||
std::is_same_v<decltype(artSetWeak), std::weak_ptr<CArtifactsOfHeroMain>> ||
|
||||
std::is_same_v<decltype(artSetWeak), std::weak_ptr<CArtifactsOfHeroKingdom>>)
|
||||
{
|
||||
GH.windows().createAndPushWindow<CHeroQuickBackpackWindow>(artSetPtr->getHero(), artPlace.slot);
|
||||
auto backpackWindow = GH.windows().topWindow<CHeroQuickBackpackWindow>();
|
||||
backpackWindow->moveTo(cursorPosition - Point(1, 1));
|
||||
backpackWindow->fitToScreen(15);
|
||||
}
|
||||
}, artSetWeak.value());
|
||||
}
|
||||
|
@ -24,7 +24,8 @@ public:
|
||||
std::weak_ptr<CArtifactsOfHeroAltar>,
|
||||
std::weak_ptr<CArtifactsOfHeroKingdom>,
|
||||
std::weak_ptr<CArtifactsOfHeroMain>,
|
||||
std::weak_ptr<CArtifactsOfHeroBackpack>>;
|
||||
std::weak_ptr<CArtifactsOfHeroBackpack>,
|
||||
std::weak_ptr<CArtifactsOfHeroQuickBackpack>>;
|
||||
using CloseCallback = std::function<void()>;
|
||||
|
||||
void addSet(CArtifactsOfHeroPtr artSet);
|
||||
@ -32,8 +33,9 @@ public:
|
||||
void addCloseCallback(CloseCallback callback);
|
||||
const CGHeroInstance * getHeroPickedArtifact();
|
||||
const CArtifactInstance * getPickedArtifact();
|
||||
void leftClickArtPlaceHero(CArtifactsOfHeroBase & artsInst, CHeroArtPlace & artPlace);
|
||||
void rightClickArtPlaceHero(CArtifactsOfHeroBase & artsInst, CHeroArtPlace & artPlace);
|
||||
void clickPressedArtPlaceHero(CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition);
|
||||
void showPopupArtPlaceHero(CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition);
|
||||
void gestureArtPlaceHero(CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition);
|
||||
|
||||
void artifactRemoved(const ArtifactLocation & artLoc) override;
|
||||
void artifactMoved(const ArtifactLocation & srcLoc, const ArtifactLocation & destLoc, bool withRedraw) override;
|
||||
|
@ -121,9 +121,10 @@ void LRClickableAreaWTextComp::showPopupWindow(const Point & cursorPosition)
|
||||
}
|
||||
|
||||
CHeroArea::CHeroArea(int x, int y, const CGHeroInstance * hero)
|
||||
: CIntObject(LCLICK | HOVER),
|
||||
: CIntObject(LCLICK | SHOW_POPUP | HOVER),
|
||||
hero(hero),
|
||||
clickFunctor(nullptr)
|
||||
clickFunctor(nullptr),
|
||||
clickRFunctor(nullptr)
|
||||
{
|
||||
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
|
||||
|
||||
@ -147,12 +148,23 @@ void CHeroArea::addClickCallback(ClickFunctor callback)
|
||||
clickFunctor = callback;
|
||||
}
|
||||
|
||||
void CHeroArea::addRClickCallback(ClickFunctor callback)
|
||||
{
|
||||
clickRFunctor = callback;
|
||||
}
|
||||
|
||||
void CHeroArea::clickPressed(const Point & cursorPosition)
|
||||
{
|
||||
if(clickFunctor)
|
||||
clickFunctor();
|
||||
}
|
||||
|
||||
void CHeroArea::showPopupWindow(const Point & cursorPosition)
|
||||
{
|
||||
if(clickRFunctor)
|
||||
clickRFunctor();
|
||||
}
|
||||
|
||||
void CHeroArea::hover(bool on)
|
||||
{
|
||||
if (on && hero)
|
||||
|
@ -190,12 +190,15 @@ public:
|
||||
|
||||
CHeroArea(int x, int y, const CGHeroInstance * hero);
|
||||
void addClickCallback(ClickFunctor callback);
|
||||
void addRClickCallback(ClickFunctor callback);
|
||||
void clickPressed(const Point & cursorPosition) override;
|
||||
void showPopupWindow(const Point & cursorPosition) override;
|
||||
void hover(bool on) override;
|
||||
private:
|
||||
const CGHeroInstance * hero;
|
||||
std::shared_ptr<CAnimImage> portrait;
|
||||
ClickFunctor clickFunctor;
|
||||
ClickFunctor clickRFunctor;
|
||||
ClickFunctor showPopupHandler;
|
||||
};
|
||||
|
||||
|
@ -375,7 +375,7 @@ void CTextBox::setText(const std::string & text)
|
||||
else if(slider)
|
||||
{
|
||||
// decrease width again if slider still used
|
||||
label->pos.w = pos.w - 32;
|
||||
label->pos.w = pos.w - 16;
|
||||
assert(label->pos.w > 0);
|
||||
label->setText(text);
|
||||
slider->setAmount(label->textSize.y);
|
||||
@ -383,12 +383,12 @@ void CTextBox::setText(const std::string & text)
|
||||
else if(label->textSize.y > label->pos.h)
|
||||
{
|
||||
// create slider and update widget
|
||||
label->pos.w = pos.w - 32;
|
||||
label->pos.w = pos.w - 16;
|
||||
assert(label->pos.w > 0);
|
||||
label->setText(text);
|
||||
|
||||
OBJECT_CONSTRUCTION_CUSTOM_CAPTURING(255 - DISPOSE);
|
||||
slider = std::make_shared<CSlider>(Point(pos.w - 32, 0), pos.h, std::bind(&CTextBox::sliderMoved, this, _1),
|
||||
slider = std::make_shared<CSlider>(Point(pos.w - 16, 0), pos.h, std::bind(&CTextBox::sliderMoved, this, _1),
|
||||
label->pos.h, label->textSize.y, 0, Orientation::VERTICAL, CSlider::EStyle(sliderStyle));
|
||||
slider->setScrollStep((int)graphics->fonts[label->font]->getLineHeight());
|
||||
slider->setPanningStep(1);
|
||||
|
@ -22,25 +22,19 @@
|
||||
CHeroBackpackWindow::CHeroBackpackWindow(const CGHeroInstance * hero)
|
||||
: CWindowObject((EOptions)0)
|
||||
{
|
||||
OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
|
||||
OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
|
||||
|
||||
stretchedBackground = std::make_shared<CFilledTexture>(ImagePath::builtin("DIBOXBCK"), Rect(0, 0, 410, 425));
|
||||
|
||||
arts = std::make_shared<CArtifactsOfHeroBackpack>(Point(windowMargin, windowMargin));
|
||||
arts->setHero(hero);
|
||||
stretchedBackground = std::make_shared<CFilledTexture>(ImagePath::builtin("DIBOXBCK"), Rect(0, 0, 0, 0));
|
||||
arts = std::make_shared<CArtifactsOfHeroBackpack>();
|
||||
arts->moveBy(Point(windowMargin, windowMargin));
|
||||
addSetAndCallbacks(arts);
|
||||
|
||||
arts->setHero(hero);
|
||||
addCloseCallback(std::bind(&CHeroBackpackWindow::close, this));
|
||||
|
||||
quitButton = std::make_shared<CButton>(Point(), AnimationPath::builtin("IOKAY32.def"), CButton::tooltip(""), [this]() { close(); }, EShortcut::GLOBAL_RETURN);
|
||||
|
||||
stretchedBackground->pos.w = arts->pos.w + 2 * windowMargin;
|
||||
stretchedBackground->pos.h = arts->pos.h + quitButton->pos.h + 3 * windowMargin;
|
||||
pos.w = stretchedBackground->pos.w;
|
||||
pos.h = stretchedBackground->pos.h;
|
||||
pos.w = stretchedBackground->pos.w = arts->pos.w + 2 * windowMargin;
|
||||
pos.h = stretchedBackground->pos.h = arts->pos.h + quitButton->pos.h + 3 * windowMargin;
|
||||
quitButton->moveTo(Point(pos.x + pos.w / 2 - quitButton->pos.w / 2, pos.y + arts->pos.h + 2 * windowMargin));
|
||||
center();
|
||||
|
||||
quitButton->moveBy(Point(GH.screenDimensions().x / 2 - quitButton->pos.w / 2 - quitButton->pos.x, arts->pos.h + 2 * windowMargin));
|
||||
}
|
||||
|
||||
void CHeroBackpackWindow::showAll(Canvas & to)
|
||||
@ -48,3 +42,46 @@ void CHeroBackpackWindow::showAll(Canvas & to)
|
||||
CIntObject::showAll(to);
|
||||
CMessage::drawBorder(PlayerColor(LOCPLINT->playerID), to.getInternalSurface(), pos.w+28, pos.h+29, pos.x-14, pos.y-15);
|
||||
}
|
||||
|
||||
CHeroQuickBackpackWindow::CHeroQuickBackpackWindow(const CGHeroInstance * hero, ArtifactPosition targetSlot)
|
||||
: CWindowObject((EOptions)0)
|
||||
{
|
||||
OBJECT_CONSTRUCTION_CAPTURING(255 - DISPOSE);
|
||||
|
||||
stretchedBackground = std::make_shared<CFilledTexture>(ImagePath::builtin("DIBOXBCK"), Rect(0, 0, 0, 0));
|
||||
arts = std::make_shared<CArtifactsOfHeroQuickBackpack>(targetSlot);
|
||||
arts->moveBy(Point(windowMargin, windowMargin));
|
||||
addSetAndCallbacks(static_cast<std::weak_ptr<CArtifactsOfHeroQuickBackpack>>(arts));
|
||||
arts->setHero(hero);
|
||||
addCloseCallback(std::bind(&CHeroQuickBackpackWindow::close, this));
|
||||
addUsedEvents(GESTURE);
|
||||
pos.w = stretchedBackground->pos.w = arts->pos.w + 2 * windowMargin;
|
||||
pos.h = stretchedBackground->pos.h = arts->pos.h + windowMargin;
|
||||
}
|
||||
|
||||
void CHeroQuickBackpackWindow::gesture(bool on, const Point & initialPosition, const Point & finalPosition)
|
||||
{
|
||||
if(on)
|
||||
return;
|
||||
|
||||
arts->swapSelected();
|
||||
close();
|
||||
}
|
||||
|
||||
void CHeroQuickBackpackWindow::gesturePanning(const Point & initialPosition, const Point & currentPosition, const Point & lastUpdateDistance)
|
||||
{
|
||||
arts->selectSlotAt(currentPosition);
|
||||
redraw();
|
||||
}
|
||||
|
||||
void CHeroQuickBackpackWindow::showAll(Canvas & to)
|
||||
{
|
||||
if(arts->getSlotsNum() == 0)
|
||||
{
|
||||
// Dirty solution for closing that window
|
||||
close();
|
||||
return;
|
||||
}
|
||||
CMessage::drawBorder(PlayerColor(LOCPLINT->playerID), to.getInternalSurface(), pos.w + 28, pos.h + 29, pos.x - 14, pos.y - 15);
|
||||
CIntObject::showAll(to);
|
||||
}
|
||||
|
@ -19,11 +19,26 @@ class CHeroBackpackWindow : public CWindowObject, public CWindowWithArtifacts
|
||||
public:
|
||||
CHeroBackpackWindow(const CGHeroInstance * hero);
|
||||
|
||||
private:
|
||||
protected:
|
||||
std::shared_ptr<CArtifactsOfHeroBackpack> arts;
|
||||
std::shared_ptr<CButton> quitButton;
|
||||
std::shared_ptr<CFilledTexture> stretchedBackground;
|
||||
const int windowMargin = 10;
|
||||
const int windowMargin = 5;
|
||||
|
||||
void showAll(Canvas & to) override;
|
||||
};
|
||||
|
||||
class CHeroQuickBackpackWindow : public CWindowObject, public CWindowWithArtifacts
|
||||
{
|
||||
public:
|
||||
CHeroQuickBackpackWindow(const CGHeroInstance * hero, ArtifactPosition targetSlot);
|
||||
void gesture(bool on, const Point & initialPosition, const Point & finalPosition) override;
|
||||
void gesturePanning(const Point & initialPosition, const Point & currentPosition, const Point & lastUpdateDistance) override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<CArtifactsOfHeroQuickBackpack> arts;
|
||||
std::shared_ptr<CFilledTexture> stretchedBackground;
|
||||
const int windowMargin = 5;
|
||||
|
||||
void showAll(Canvas & to) override;
|
||||
};
|
||||
|
@ -111,6 +111,5 @@ public:
|
||||
void createBackpackWindow();
|
||||
|
||||
//friends
|
||||
friend void CHeroArtPlace::clickPressed(const Point & cursorPosition);
|
||||
friend class CPlayerInterface;
|
||||
};
|
||||
|
@ -13,8 +13,6 @@
|
||||
|
||||
#include "../lobby/SelectionTab.h"
|
||||
|
||||
#include <vstd/DateUtils.h>
|
||||
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../gui/WindowHandler.h"
|
||||
#include "../widgets/CComponent.h"
|
||||
@ -29,6 +27,7 @@
|
||||
#include "../render/Graphics.h"
|
||||
|
||||
#include "../../lib/CGeneralTextHandler.h"
|
||||
#include "../../lib/TextOperations.h"
|
||||
#include "../../lib/CConfigHandler.h"
|
||||
#include "../../lib/campaign/CampaignState.h"
|
||||
#include "../../lib/mapping/CMap.h"
|
||||
@ -42,6 +41,7 @@
|
||||
#include "../../lib/serializer/CLoadFile.h"
|
||||
#include "../../lib/StartInfo.h"
|
||||
#include "../../lib/rmg/CMapGenOptions.h"
|
||||
#include "../../lib/Languages.h"
|
||||
|
||||
CMapOverview::CMapOverview(std::string mapName, std::string fileName, std::string date, ResourcePath resource, ESelectionScreen tabType)
|
||||
: CWindowObject(BORDERED | RCLICK_POPUP), resource(resource), mapName(mapName), fileName(fileName), date(date), tabType(tabType)
|
||||
@ -199,7 +199,7 @@ CMapOverviewWidget::CMapOverviewWidget(CMapOverview& parent):
|
||||
if(p.date.empty())
|
||||
{
|
||||
std::time_t time = boost::filesystem::last_write_time(*CResourceHandler::get()->getResourceName(ResourcePath(p.resource.getName(), p.tabType == ESelectionScreen::campaignList ? EResType::CAMPAIGN : EResType::MAP)));
|
||||
w->setText(vstd::getFormattedDateTime(time));
|
||||
w->setText(TextOperations::getFormattedDateTimeLocal(time));
|
||||
}
|
||||
else
|
||||
w->setText(p.date);
|
||||
|
@ -124,70 +124,22 @@ CSpellWindow::CSpellWindow(const CGHeroInstance * _myHero, CPlayerInterface * _m
|
||||
offL = offR = offT = offB = offRM = 0;
|
||||
spellsPerPage = 12;
|
||||
}
|
||||
|
||||
pos = background->center(Point(pos.w/2 + pos.x, pos.h/2 + pos.y));
|
||||
|
||||
//initializing castable spells
|
||||
mySpells.reserve(CGI->spellh->objects.size());
|
||||
for(const CSpell * spell : CGI->spellh->objects)
|
||||
if(settings["general"]["enableUiEnhancements"].Bool())
|
||||
{
|
||||
if(!spell->isCreatureAbility() && myHero->canCastThisSpell(spell))
|
||||
mySpells.push_back(spell);
|
||||
}
|
||||
std::sort(mySpells.begin(), mySpells.end(), spellsorter);
|
||||
Rect r(90, isBigSpellbook ? 480 : 420, isBigSpellbook ? 160 : 110, 16);
|
||||
const ColorRGBA rectangleColor = ColorRGBA(0, 0, 0, 75);
|
||||
const ColorRGBA borderColor = ColorRGBA(128, 100, 75);
|
||||
const ColorRGBA grayedColor = ColorRGBA(158, 130, 105);
|
||||
searchBoxRectangle = std::make_shared<TransparentFilledRectangle>(r.resize(1), rectangleColor, borderColor);
|
||||
searchBoxDescription = std::make_shared<CLabel>(r.center().x, r.center().y, FONT_SMALL, ETextAlignment::CENTER, grayedColor, CGI->generaltexth->translate("vcmi.spellBook.search"));
|
||||
|
||||
//initializing sizes of spellbook's parts
|
||||
for(auto & elem : sitesPerTabAdv)
|
||||
elem = 0;
|
||||
for(auto & elem : sitesPerTabBattle)
|
||||
elem = 0;
|
||||
|
||||
for(const auto spell : mySpells)
|
||||
{
|
||||
int * sitesPerOurTab = spell->isCombat() ? sitesPerTabBattle : sitesPerTabAdv;
|
||||
|
||||
++sitesPerOurTab[4];
|
||||
|
||||
spell->forEachSchool([&sitesPerOurTab](const SpellSchool & school, bool & stop)
|
||||
{
|
||||
++sitesPerOurTab[school];
|
||||
});
|
||||
}
|
||||
if(sitesPerTabAdv[4] % spellsPerPage == 0)
|
||||
sitesPerTabAdv[4]/=spellsPerPage;
|
||||
else
|
||||
sitesPerTabAdv[4] = sitesPerTabAdv[4]/spellsPerPage + 1;
|
||||
|
||||
for(int v=0; v<4; ++v)
|
||||
{
|
||||
if(sitesPerTabAdv[v] <= spellsPerPage - 2)
|
||||
sitesPerTabAdv[v] = 1;
|
||||
else
|
||||
{
|
||||
if((sitesPerTabAdv[v] - spellsPerPage - 2) % spellsPerPage == 0)
|
||||
sitesPerTabAdv[v] = (sitesPerTabAdv[v] - spellsPerPage - 2) / spellsPerPage + 1;
|
||||
else
|
||||
sitesPerTabAdv[v] = (sitesPerTabAdv[v] - spellsPerPage - 2) / spellsPerPage + 2;
|
||||
}
|
||||
}
|
||||
|
||||
if(sitesPerTabBattle[4] % spellsPerPage == 0)
|
||||
sitesPerTabBattle[4]/=spellsPerPage;
|
||||
else
|
||||
sitesPerTabBattle[4] = sitesPerTabBattle[4]/spellsPerPage + 1;
|
||||
|
||||
for(int v=0; v<4; ++v)
|
||||
{
|
||||
if(sitesPerTabBattle[v] <= spellsPerPage - 2)
|
||||
sitesPerTabBattle[v] = 1;
|
||||
else
|
||||
{
|
||||
if((sitesPerTabBattle[v] - spellsPerPage - 2) % spellsPerPage == 0)
|
||||
sitesPerTabBattle[v] = (sitesPerTabBattle[v] - spellsPerPage - 2) / spellsPerPage + 1;
|
||||
else
|
||||
sitesPerTabBattle[v] = (sitesPerTabBattle[v] - spellsPerPage - 2) / spellsPerPage + 2;
|
||||
}
|
||||
searchBox = std::make_shared<CTextInput>(r, FONT_SMALL, std::bind(&CSpellWindow::searchInput, this));
|
||||
}
|
||||
|
||||
processSpells();
|
||||
|
||||
//numbers of spell pages computed
|
||||
|
||||
@ -253,7 +205,7 @@ CSpellWindow::CSpellWindow(const CGHeroInstance * _myHero, CPlayerInterface * _m
|
||||
|
||||
selectedTab = battleSpellsOnly ? myInt->localState->spellbookSettings.spellbookLastTabBattle : myInt->localState->spellbookSettings.spellbookLastTabAdvmap;
|
||||
schoolTab->setFrame(selectedTab, 0);
|
||||
int cp = battleSpellsOnly ? myInt->localState->spellbookSettings.spellbookLastPageBattle : myInt->localState->spellbookSettings.spellbokLastPageAdvmap;
|
||||
int cp = battleSpellsOnly ? myInt->localState->spellbookSettings.spellbookLastPageBattle : myInt->localState->spellbookSettings.spellbookLastPageAdvmap;
|
||||
// spellbook last page battle index is not reset after battle, so this needs to stay here
|
||||
vstd::abetween(cp, 0, std::max(0, pagesWithinCurrentTab() - 1));
|
||||
setCurrentPage(cp);
|
||||
@ -292,14 +244,114 @@ std::shared_ptr<IImage> CSpellWindow::createBigSpellBook()
|
||||
Canvas tmp5 = Canvas(Point(409, 141));
|
||||
tmp5.draw(img, Point(0, 0), Rect(100, 38 + 45, 509 - 15, 400 - 38));
|
||||
canvas.drawScaled(tmp5, Point(90, 45), Point(615, 415));
|
||||
// carpet
|
||||
Canvas tmp6 = Canvas(Point(590, 59));
|
||||
tmp6.draw(img, Point(0, 0), Rect(15, 484, 590, 59));
|
||||
canvas.drawScaled(tmp6, Point(0, 545), Point(800, 59));
|
||||
// remove bookmarks
|
||||
for (int i = 0; i < 56; i++)
|
||||
canvas.draw(Canvas(canvas, Rect(i < 30 ? 268 : 327, 464, 1, 46)), Point(269 + i, 464));
|
||||
for (int i = 0; i < 56; i++)
|
||||
canvas.draw(Canvas(canvas, Rect(469, 464, 1, 42)), Point(470 + i, 464));
|
||||
for (int i = 0; i < 57; i++)
|
||||
canvas.draw(Canvas(canvas, Rect(i < 30 ? 564 : 630, 464, 1, 44)), Point(565 + i, 464));
|
||||
for (int i = 0; i < 56; i++)
|
||||
canvas.draw(Canvas(canvas, Rect(656, 464, 1, 47)), Point(657 + i, 464));
|
||||
// draw bookmarks
|
||||
canvas.draw(img, Point(278, 464), Rect(220, 405, 37, 47));
|
||||
canvas.draw(img, Point(481, 465), Rect(354, 406, 37, 41));
|
||||
canvas.draw(img, Point(575, 465), Rect(417, 406, 37, 45));
|
||||
canvas.draw(img, Point(667, 465), Rect(478, 406, 37, 47));
|
||||
|
||||
return GH.renderHandler().createImage(canvas.getInternalSurface());
|
||||
}
|
||||
|
||||
void CSpellWindow::searchInput()
|
||||
{
|
||||
if(searchBox)
|
||||
searchBoxDescription->setEnabled(searchBox->getText().empty());
|
||||
|
||||
processSpells();
|
||||
|
||||
int cp = 0;
|
||||
// spellbook last page battle index is not reset after battle, so this needs to stay here
|
||||
vstd::abetween(cp, 0, std::max(0, pagesWithinCurrentTab() - 1));
|
||||
setCurrentPage(cp);
|
||||
computeSpellsPerArea();
|
||||
}
|
||||
|
||||
void CSpellWindow::processSpells()
|
||||
{
|
||||
mySpells.clear();
|
||||
|
||||
//initializing castable spells
|
||||
mySpells.reserve(CGI->spellh->objects.size());
|
||||
for(const CSpell * spell : CGI->spellh->objects)
|
||||
{
|
||||
bool searchTextFound = !searchBox || boost::algorithm::contains(boost::algorithm::to_lower_copy(spell->getNameTranslated()), boost::algorithm::to_lower_copy(searchBox->getText()));
|
||||
if(!spell->isCreatureAbility() && myHero->canCastThisSpell(spell) && searchTextFound)
|
||||
mySpells.push_back(spell);
|
||||
}
|
||||
std::sort(mySpells.begin(), mySpells.end(), spellsorter);
|
||||
|
||||
//initializing sizes of spellbook's parts
|
||||
for(auto & elem : sitesPerTabAdv)
|
||||
elem = 0;
|
||||
for(auto & elem : sitesPerTabBattle)
|
||||
elem = 0;
|
||||
|
||||
for(const auto spell : mySpells)
|
||||
{
|
||||
int * sitesPerOurTab = spell->isCombat() ? sitesPerTabBattle : sitesPerTabAdv;
|
||||
|
||||
++sitesPerOurTab[4];
|
||||
|
||||
spell->forEachSchool([&sitesPerOurTab](const SpellSchool & school, bool & stop)
|
||||
{
|
||||
++sitesPerOurTab[school];
|
||||
});
|
||||
}
|
||||
if(sitesPerTabAdv[4] % spellsPerPage == 0)
|
||||
sitesPerTabAdv[4]/=spellsPerPage;
|
||||
else
|
||||
sitesPerTabAdv[4] = sitesPerTabAdv[4]/spellsPerPage + 1;
|
||||
|
||||
for(int v=0; v<4; ++v)
|
||||
{
|
||||
if(sitesPerTabAdv[v] <= spellsPerPage - 2)
|
||||
sitesPerTabAdv[v] = 1;
|
||||
else
|
||||
{
|
||||
if((sitesPerTabAdv[v] - spellsPerPage - 2) % spellsPerPage == 0)
|
||||
sitesPerTabAdv[v] = (sitesPerTabAdv[v] - spellsPerPage - 2) / spellsPerPage + 1;
|
||||
else
|
||||
sitesPerTabAdv[v] = (sitesPerTabAdv[v] - spellsPerPage - 2) / spellsPerPage + 2;
|
||||
}
|
||||
}
|
||||
|
||||
if(sitesPerTabBattle[4] % spellsPerPage == 0)
|
||||
sitesPerTabBattle[4]/=spellsPerPage;
|
||||
else
|
||||
sitesPerTabBattle[4] = sitesPerTabBattle[4]/spellsPerPage + 1;
|
||||
|
||||
for(int v=0; v<4; ++v)
|
||||
{
|
||||
if(sitesPerTabBattle[v] <= spellsPerPage - 2)
|
||||
sitesPerTabBattle[v] = 1;
|
||||
else
|
||||
{
|
||||
if((sitesPerTabBattle[v] - spellsPerPage - 2) % spellsPerPage == 0)
|
||||
sitesPerTabBattle[v] = (sitesPerTabBattle[v] - spellsPerPage - 2) / spellsPerPage + 1;
|
||||
else
|
||||
sitesPerTabBattle[v] = (sitesPerTabBattle[v] - spellsPerPage - 2) / spellsPerPage + 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CSpellWindow::fexitb()
|
||||
{
|
||||
(myInt->battleInt ? myInt->localState->spellbookSettings.spellbookLastTabBattle : myInt->localState->spellbookSettings.spellbookLastTabAdvmap) = selectedTab;
|
||||
(myInt->battleInt ? myInt->localState->spellbookSettings.spellbookLastPageBattle : myInt->localState->spellbookSettings.spellbokLastPageAdvmap) = currentPage;
|
||||
(myInt->battleInt ? myInt->localState->spellbookSettings.spellbookLastPageBattle : myInt->localState->spellbookSettings.spellbookLastPageAdvmap) = currentPage;
|
||||
|
||||
close();
|
||||
}
|
||||
@ -595,7 +647,7 @@ void CSpellWindow::SpellArea::clickPressed(const Point & cursorPosition)
|
||||
auto guard = vstd::makeScopeGuard([this]()
|
||||
{
|
||||
owner->myInt->localState->spellbookSettings.spellbookLastTabAdvmap = owner->selectedTab;
|
||||
owner->myInt->localState->spellbookSettings.spellbokLastPageAdvmap = owner->currentPage;
|
||||
owner->myInt->localState->spellbookSettings.spellbookLastPageAdvmap = owner->currentPage;
|
||||
});
|
||||
|
||||
if(mySpell->getTargetType() == spells::AimType::LOCATION)
|
||||
|
@ -26,6 +26,8 @@ class CLabel;
|
||||
class CGStatusBar;
|
||||
class CPlayerInterface;
|
||||
class CSpellWindow;
|
||||
class CTextInput;
|
||||
class TransparentFilledRectangle;
|
||||
|
||||
/// The spell window
|
||||
class CSpellWindow : public CWindowObject
|
||||
@ -80,6 +82,10 @@ class CSpellWindow : public CWindowObject
|
||||
|
||||
std::vector<std::shared_ptr<InteractiveArea>> interactiveAreas;
|
||||
|
||||
std::shared_ptr<CTextInput> searchBox;
|
||||
std::shared_ptr<TransparentFilledRectangle> searchBoxRectangle;
|
||||
std::shared_ptr<CLabel> searchBoxDescription;
|
||||
|
||||
bool isBigSpellbook;
|
||||
int spellsPerPage;
|
||||
int offL;
|
||||
@ -99,6 +105,8 @@ class CSpellWindow : public CWindowObject
|
||||
const CGHeroInstance * myHero; //hero whose spells are presented
|
||||
CPlayerInterface * myInt;
|
||||
|
||||
void processSpells();
|
||||
void searchInput();
|
||||
void computeSpellsPerArea(); //recalculates spellAreas::mySpell
|
||||
|
||||
void setCurrentPage(int value);
|
||||
|
@ -331,7 +331,7 @@ void CTradeWindow::setMode(EMarketMode Mode)
|
||||
}
|
||||
}
|
||||
|
||||
void CTradeWindow::artifactSelected(CHeroArtPlace *slot)
|
||||
void CTradeWindow::artifactSelected(CArtPlace * slot)
|
||||
{
|
||||
assert(mode == EMarketMode::ARTIFACT_RESOURCE);
|
||||
items[1][0]->setArtInstance(slot->getArt());
|
||||
|
@ -40,7 +40,7 @@ public:
|
||||
void getPositionsFor(std::vector<Rect> &poss, bool Left, EType type) const;
|
||||
void setMode(EMarketMode Mode); //mode setter
|
||||
|
||||
void artifactSelected(CHeroArtPlace *slot); //used when selling artifacts -> called when user clicked on artifact slot
|
||||
void artifactSelected(CArtPlace * slot); //used when selling artifacts -> called when user clicked on artifact slot
|
||||
virtual void selectionChanged(bool side) = 0; //true == left
|
||||
virtual Point selectionOffset(bool Left) const = 0;
|
||||
virtual std::string updateSlotSubtitle(bool Left) const = 0;
|
||||
|
@ -409,7 +409,9 @@ CLevelWindow::CLevelWindow(const CGHeroInstance * hero, PrimarySkill pskill, std
|
||||
box = std::make_shared<CComponentBox>(comps, Rect(75, 300, pos.w - 150, 100));
|
||||
}
|
||||
|
||||
portrait = std::make_shared<CAnimImage>(AnimationPath::builtin("PortraitsLarge"), hero->getIconIndex(), 0, 170, 66);
|
||||
portrait = std::make_shared<CHeroArea>(170, 66, hero);
|
||||
portrait->addClickCallback(nullptr);
|
||||
portrait->addRClickCallback([hero](){ GH.windows().createAndPushWindow<CRClickPopupInt>(std::make_shared<CHeroWindow>(hero)); });
|
||||
ok = std::make_shared<CButton>(Point(297, 413), AnimationPath::builtin("IOKAY"), CButton::tooltip(), std::bind(&CLevelWindow::close, this), EShortcut::GLOBAL_ACCEPT);
|
||||
|
||||
//%s has gained a level.
|
||||
|
@ -35,6 +35,7 @@ class CGStatusBar;
|
||||
class CTextBox;
|
||||
class CGarrisonInt;
|
||||
class CGarrisonSlot;
|
||||
class CHeroArea;
|
||||
|
||||
enum class EUserEvent;
|
||||
|
||||
@ -129,7 +130,7 @@ public:
|
||||
/// Raised up level window where you can select one out of two skills
|
||||
class CLevelWindow : public CWindowObject
|
||||
{
|
||||
std::shared_ptr<CAnimImage> portrait;
|
||||
std::shared_ptr<CHeroArea> portrait;
|
||||
std::shared_ptr<CButton> ok;
|
||||
std::shared_ptr<CLabel> mainTitle;
|
||||
std::shared_ptr<CLabel> levelTitle;
|
||||
|
@ -1,6 +1,6 @@
|
||||
set(VCMI_VERSION_MAJOR 1)
|
||||
set(VCMI_VERSION_MINOR 4)
|
||||
set(VCMI_VERSION_PATCH 1)
|
||||
set(VCMI_VERSION_PATCH 2)
|
||||
add_definitions(
|
||||
-DVCMI_VERSION_MAJOR=${VCMI_VERSION_MAJOR}
|
||||
-DVCMI_VERSION_MINOR=${VCMI_VERSION_MINOR}
|
||||
|
@ -1873,6 +1873,7 @@
|
||||
}
|
||||
],
|
||||
"index" : 127,
|
||||
"class" : "SPECIAL",
|
||||
"type" : ["HERO"]
|
||||
},
|
||||
"armageddonsBlade":
|
||||
@ -1917,6 +1918,7 @@
|
||||
}
|
||||
],
|
||||
"index" : 128,
|
||||
"class" : "SPECIAL",
|
||||
"type" : ["HERO"]
|
||||
},
|
||||
"angelicAlliance":
|
||||
|
@ -935,5 +935,16 @@
|
||||
"grassHills" : { "index" :208, "handler": "static", "types" : { "object" : { "index" : 0} } },
|
||||
"roughHills" : { "index" :209, "handler": "static", "types" : { "object" : { "index" : 0} } },
|
||||
"subterraneanRocks" : { "index" :210, "handler": "static", "types" : { "object" : { "index" : 0} } },
|
||||
"swampFoliage" : { "index" :211, "handler": "static", "types" : { "object" : { "index" : 0} } }
|
||||
"swampFoliage" : { "index" :211, "handler": "static", "types" : { "object" : { "index" : 0} } },
|
||||
|
||||
/// special object to handle invalid / unknown objects on some user-made maps
|
||||
"nothing" : {
|
||||
"index" : 0,
|
||||
"handler": "generic",
|
||||
"types" : {
|
||||
"nothing" : {
|
||||
"index" : 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -615,7 +615,7 @@
|
||||
},
|
||||
"infoBarCreatureManagement": {
|
||||
"type" : "boolean",
|
||||
"default" : false
|
||||
"default" : true
|
||||
},
|
||||
"enableLargeSpellbook" : {
|
||||
"type": "boolean",
|
||||
|
@ -1221,7 +1221,7 @@
|
||||
"effects" : {
|
||||
"attacksNearestCreature" : {
|
||||
"type" : "ATTACKS_NEAREST_CREATURE",
|
||||
"duration" : "UNTIL_ATTACK"
|
||||
"duration" : "UNTIL_OWN_ATTACK"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -85,7 +85,8 @@
|
||||
"N", "N", "N",
|
||||
"N", "N", "N"
|
||||
],
|
||||
"mapping" : { "normal" : "49-72", "dirt" : "21-44", "sand" : "0-23", "water" : "20-32", "rock": "0-7", "hota" : "77-117" }
|
||||
"decoration" : true,
|
||||
"mapping" : { "normal" : "49-56,57-72", "dirt" : "21-28,29-44", "sand" : "0-11,12-23", "water" : "20-32", "rock": "0-7", "hota" : "77-101,102-117" }
|
||||
},
|
||||
// Mixed transitions
|
||||
{
|
||||
|
@ -222,7 +222,7 @@
|
||||
{
|
||||
"name": "chessFieldTurn",
|
||||
"callback": "parseAndSetTimer_turn",
|
||||
"help": "vcmi.optionsTab.chessFieldTurn.help"
|
||||
"help": "vcmi.optionsTab.chessFieldTurnAccumulate.help"
|
||||
},
|
||||
{
|
||||
"name": "chessFieldBattle",
|
||||
@ -232,7 +232,7 @@
|
||||
{
|
||||
"name": "chessFieldUnit",
|
||||
"callback": "parseAndSetTimer_unit",
|
||||
"help": "vcmi.optionsTab.chessFieldUnit.help"
|
||||
"help": "vcmi.optionsTab.chessFieldUnitAccumulate.help"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -1,34 +0,0 @@
|
||||
{
|
||||
"items":
|
||||
[
|
||||
{ //backgound color
|
||||
"type": "drawRect",
|
||||
"rect": {"x": 4, "y": 4, "w": 72, "h": 24},
|
||||
"color": [10, 10, 10, 255]
|
||||
},
|
||||
|
||||
{ //clocks icon
|
||||
"type": "image",
|
||||
"image": "VCMI/BATTLEQUEUE/STATESSMALL",
|
||||
"frame": 1,
|
||||
"position": {"x": 4, "y": 6}
|
||||
},
|
||||
|
||||
{ //timer field label
|
||||
"name": "timer",
|
||||
"type": "label",
|
||||
"font": "big",
|
||||
"alignment": "left",
|
||||
"color": "yellow",
|
||||
"text": "",
|
||||
"position": {"x": 26, "y": 2}
|
||||
},
|
||||
],
|
||||
|
||||
"variables":
|
||||
{
|
||||
"notificationTime": [0, 1, 2, 3, 4, 5, 20],
|
||||
"notificationSound": "WE5",
|
||||
"textColorFromPlayerColor": true
|
||||
}
|
||||
}
|
8
debian/changelog
vendored
8
debian/changelog
vendored
@ -1,9 +1,15 @@
|
||||
vcmi (1.4.1) jammy; urgency=medium
|
||||
vcmi (1.4.2) jammy; urgency=medium
|
||||
|
||||
* New upstream release
|
||||
|
||||
-- Ivan Savenko <saven.ivan@gmail.com> Fri, 22 Dec 2023 16:00:00 +0200
|
||||
|
||||
vcmi (1.4.1) jammy; urgency=medium
|
||||
|
||||
* New upstream release
|
||||
|
||||
-- Ivan Savenko <saven.ivan@gmail.com> Tue, 12 Dec 2023 16:00:00 +0200
|
||||
|
||||
vcmi (1.4.0) jammy; urgency=medium
|
||||
|
||||
* New upstream release
|
||||
|
@ -1,5 +1,6 @@
|
||||
[](https://github.com/vcmi/vcmi/actions/workflows/github.yml)
|
||||
[](https://github.com/vcmi/vcmi/releases/tag/1.4.0)
|
||||
[](https://github.com/vcmi/vcmi/releases/tag/1.4.1)
|
||||
[](https://github.com/vcmi/vcmi/releases)
|
||||
|
||||
# VCMI Project
|
||||
|
@ -13,4 +13,5 @@ Bonus may have any of these durations. They acts in disjunction.
|
||||
- UNTIL_BEING_ATTACKED: removed after any damage-inflicting attack
|
||||
- UNTIL_ATTACK: removed after attack and counterattacks are performed
|
||||
- STACK_GETS_TURN: removed when stack gets its turn - used for defensive stance
|
||||
- COMMANDER_KILLED
|
||||
- COMMANDER_KILLED
|
||||
- UNTIL_OWN_ATTACK: removed after attack (not counterattack) is performed
|
@ -36,7 +36,7 @@ Gives specific creature in every slot, with optional amount. Examples:
|
||||
|
||||
### Movement points
|
||||
|
||||
`nwcnebuchadnezzar` or `vcminahar` or `vcmimove` - give 1000000 movement points and free ship boarding for 1 day
|
||||
`nwcnebuchadnezzar` or `vcminahar` or `vcmimove` - give unlimited (or specified amount of) movement points and free ship boarding
|
||||
Alternative usage: `vcmimove <amount>` - gives specified amount of movement points
|
||||
|
||||
### Resources
|
||||
@ -57,10 +57,22 @@ Alternative usage: `vcmilevel <amount>` - advances hero by specified number of l
|
||||
- `vcmiolorin` or `vcmiexp` - gives selected hero 10000 experience
|
||||
Alternative usage: `vcmiexp <amount>` - gives selected hero specified amount of experience
|
||||
|
||||
### Luck and morale
|
||||
|
||||
`nwcfollowthewhiterabbit` or `vcmiluck` - the currently selected hero permanently gains maximum luck
|
||||
`nwcmorpheus` or `vcmimorale` - the currently selected hero permanently gains maximum morale
|
||||
|
||||
### Puzzle map
|
||||
|
||||
`nwcoracle` or `vcmiobelisk` - reveals the puzzle map
|
||||
|
||||
### Finishing the game
|
||||
|
||||
`nwcredpill` or `vcmisilmaril` or `vcmiwin` - player wins
|
||||
`nwcbluepill` or `vcmimelkor` or `vcmilose` - player loses
|
||||
`nwcredpill` or `vcmisilmaril` or `vcmiwin` - player wins
|
||||
`nwcbluepill` or `vcmimelkor` or `vcmilose` - player loses
|
||||
|
||||
### Misc
|
||||
`nwctheone` or `vcmigod` - reveals the whole map, gives 5 archangels in each empty slot, unlimited movement points and permanent flight
|
||||
|
||||
## Using cheat codes on other players
|
||||
By default, all cheat codes apply to current player. Alternatively, it is possible to specify player that you want to target:
|
||||
|
@ -5,7 +5,7 @@ VCMI_LIB_NAMESPACE_BEGIN
|
||||
namespace vstd
|
||||
{
|
||||
|
||||
DLL_LINKAGE std::string getFormattedDateTime(std::time_t dt);
|
||||
DLL_LINKAGE std::string getFormattedDateTime(std::time_t dt, std::string format);
|
||||
DLL_LINKAGE std::string getDateTimeISO8601Basic(std::time_t dt);
|
||||
|
||||
}
|
||||
|
@ -1,56 +1,94 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component type="desktop-application">
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<component type="desktop">
|
||||
<id>eu.vcmi.VCMI</id>
|
||||
<metadata_license>CC-BY-SA-4.0</metadata_license>
|
||||
<project_license>GPL-2.0-or-later</project_license>
|
||||
<name>VCMI</name>
|
||||
<summary>Open-source game engine for Heroes of Might and Magic III</summary>
|
||||
<summary xml:lang="cs">Herní engine s otevřeným kódem pro Heroes of Might and Magic III</summary>
|
||||
<summary xml:lang="de">Open-Source-Spielengine für Heroes of Might and Magic III</summary>
|
||||
<developer_name>VCMI Team</developer_name>
|
||||
<developer_name xml:lang="cs">Tým VCMI</developer_name>
|
||||
<metadata_license>CC-BY-SA-4.0</metadata_license>
|
||||
<project_license>GPL-2.0-or-later</project_license>
|
||||
<description>
|
||||
<p>VCMI is an open-source engine for Heroes of Might and Magic III with new possibilities. Years of intensive work resulted in an impressive amount of features. Among the current features are:</p>
|
||||
<p xml:lang="cs">VCMI je engine s otevřeným kódem a novými možnostmi pro Heroes of Might and Magic III. Roky usilovné práce vyústily v úchvatném počtu nových funkcí. Mezi současnými funkcemi jsou:</p>
|
||||
<p xml:lang="de">VCMI ist eine Open-Source-Engine für Heroes of Might and Magic III mit neuen Möglichkeiten. Jahrelange intensive Arbeit führte zu einer beeindruckenden Anzahl von Features. Zu den aktuellen Features gehören:</p>
|
||||
<ul>
|
||||
<li>Complete gameplay mechanics</li>
|
||||
<li xml:lang="cs">Kompletní herní mechaniky</li>
|
||||
<li xml:lang="de">Vollständige Spielmechanik</li>
|
||||
<li>Almost all objects, abilities, spells and other content</li>
|
||||
<li xml:lang="cs">Skoro všechny předměty, schopnosti, kouzla a ostatní obsah</li>
|
||||
<li xml:lang="de">Fast alle Objekte, Fähigkeiten, Zaubersprüche und andere Inhalte</li>
|
||||
<li>Basic battle AI and adventure AI</li>
|
||||
<li xml:lang="cs">Základní AI boje a mapy světa</li>
|
||||
<li xml:lang="de">Grundlegende Kampf- und Abenteuer-KI</li>
|
||||
<li>Many GUI improvements: high resolutions, stack queue, creature window</li>
|
||||
<li xml:lang="cs">Mnoho vylepšení rozhraní: vyšší rozlišení, fronta oddílů a okno bojovníků</li>
|
||||
<li xml:lang="de">Viele GUI-Verbesserungen: Hohe Auflösungen, Truppenwarteschlange, Kreaturenfenster</li>
|
||||
<li>Advanced and easy mod support - add new towns, creatures, heroes, artifacts and spells without limits or conflicts</li>
|
||||
<li xml:lang="cs">Pokročilá a jednoduchá podpora modifikací - přidání nových měst, bojovníků, hrdinů, artefaktů a kouzel bez limitů a konfliktů</li>
|
||||
<li xml:lang="de">Erweiterte und einfache Mod-Unterstützung - füge neue Städte, Kreaturen, Helden, Artefakte und Zaubersprüche ohne Einschränkungen oder Konflikte hinzu</li>
|
||||
<li>Launcher for easy configuration - download mods from our server and install them immediately!</li>
|
||||
<li xml:lang="cs">Spouštěč pro jednoduché nastavení - stahujte modifikace z našeho serveru a hned je instalujte!</li>
|
||||
<li xml:lang="de">Launcher für einfache Konfiguration - Mods von unserem Server herunterladen und sofort installieren!</li>
|
||||
<li>Random map generator that supports objects added by mods</li>
|
||||
<li xml:lang="cs">Náhodný generátor map, který podporuje předměty přidané modifikacemi</li>
|
||||
<li xml:lang="de">Zufallsgenerator für Karten, der von Mods hinzugefügte Objekte unterstützt</li>
|
||||
</ul>
|
||||
<p>Note: In order to play the game using VCMI you need to own data files for Heroes of Might and Magic III: The Shadow of Death.</p>
|
||||
<p xml:lang="cs">Poznámka: pokud chcete hrát hru přes VCMI, musíte vlastnit datové soubory Heroes of Might and Magic III: The Shadow of Death.</p>
|
||||
<p xml:lang="de">Hinweis: Um das Spiel mit VCMI spielen zu können, sind die Originaldateien für Heroes of Might and Magic III: The Shadow of Death erforderlich.</p>
|
||||
<p>If you want help, please check our forum, bug tracker or GitHub page.</p>
|
||||
<p xml:lang="cs">Pokud chcete pomoct, prosíme, podívejte se na naše fórum nebo GitHub.</p>
|
||||
<p xml:lang="de">Wird Hilfe benötigt, besucht bitte unser Forum, den Bugtracker oder die GitHub-Seite.</p>
|
||||
</description>
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<image>https://play-lh.googleusercontent.com/-ZErg8hUyc3TScVQZYh30KzaUDWmnIGRcN3WPCQimdviOJVoMkjDdIW19WqX0KZO7mk=w2560-h1440</image>
|
||||
<image type="source">https://play-lh.googleusercontent.com/-ZErg8hUyc3TScVQZYh30KzaUDWmnIGRcN3WPCQimdviOJVoMkjDdIW19WqX0KZO7mk=w2560-h1440</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://play-lh.googleusercontent.com/8Uuuir7_0pDCPohacS7nd6CQuvaOO7nKmKWo-A-EysRY8uIK5qLsv0cpMxT3AFu2DA=w2560-h1440</image>
|
||||
<image type="source">https://play-lh.googleusercontent.com/8Uuuir7_0pDCPohacS7nd6CQuvaOO7nKmKWo-A-EysRY8uIK5qLsv0cpMxT3AFu2DA=w2560-h1440</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://play-lh.googleusercontent.com/993tSmsQh1qgb1_XQUxD1wmS8Zuiydf0LsQK_nU2fAiJl62n0_Vl_5JMVK-J9lvVeQ=w2560-h1440</image>
|
||||
<image type="source">https://play-lh.googleusercontent.com/993tSmsQh1qgb1_XQUxD1wmS8Zuiydf0LsQK_nU2fAiJl62n0_Vl_5JMVK-J9lvVeQ=w2560-h1440</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://play-lh.googleusercontent.com/N3fn4cqX2iN0t9jzEo0vgEMBpUYWyRgOz8AtDsMLmF-BTyxO4l2uoAderEIhXPvPsg=w2560-h1440</image>
|
||||
<image type="source">https://play-lh.googleusercontent.com/N3fn4cqX2iN0t9jzEo0vgEMBpUYWyRgOz8AtDsMLmF-BTyxO4l2uoAderEIhXPvPsg=w2560-h1440</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://play-lh.googleusercontent.com/9wSQsPlMPSBAzekEcw1OVpzeOvYiHrYRYHgpa1aRk31pvR752gu_cUZws5x8JMCACw=w2560-h1440</image>
|
||||
<image type="source">https://play-lh.googleusercontent.com/9wSQsPlMPSBAzekEcw1OVpzeOvYiHrYRYHgpa1aRk31pvR752gu_cUZws5x8JMCACw=w2560-h1440</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://play-lh.googleusercontent.com/nU_MSwmEhiQ14Sx9xI3QFF1FhL7BYTDMbEYQg-XglSYwIMpYZDpP92_ybTtu4cVJSxo=w2560-h1440</image>
|
||||
<image type="source">https://play-lh.googleusercontent.com/nU_MSwmEhiQ14Sx9xI3QFF1FhL7BYTDMbEYQg-XglSYwIMpYZDpP92_ybTtu4cVJSxo=w2560-h1440</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://play-lh.googleusercontent.com/rhI5moPCKQpYdjnRaJJ_CdIxSAXUkrH7ddghuPWaW0vcyaltd-ZGZG4Kl6v3YKGVlzU=w2560-h1440</image>
|
||||
<image type="source">https://play-lh.googleusercontent.com/rhI5moPCKQpYdjnRaJJ_CdIxSAXUkrH7ddghuPWaW0vcyaltd-ZGZG4Kl6v3YKGVlzU=w2560-h1440</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://play-lh.googleusercontent.com/1zecL5SvayVkNoIHijeS_rm0Yr_XyHbp_dmSx70NXhjckvnezwvWkpINYBHAy4o8EaM=w2560-h1440</image>
|
||||
<image type="source">https://play-lh.googleusercontent.com/1zecL5SvayVkNoIHijeS_rm0Yr_XyHbp_dmSx70NXhjckvnezwvWkpINYBHAy4o8EaM=w2560-h1440</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://play-lh.googleusercontent.com/e5ibvuWm442dYN2z_pAwDC3Ktc7XOY6FEI4N7BkFB7DqGi3Q-Vl46KqoJ_EFSrXRNw=w2560-h1440</image>
|
||||
<image type="source">https://play-lh.googleusercontent.com/e5ibvuWm442dYN2z_pAwDC3Ktc7XOY6FEI4N7BkFB7DqGi3Q-Vl46KqoJ_EFSrXRNw=w2560-h1440</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://play-lh.googleusercontent.com/wD6xJK2nuzVyKUFODfQs2SEbUuSyEglojpp_FE6GeAuzdA_R44Dp6gTyN70KCwpRtD9M=w2560-h1440</image>
|
||||
<image type="source">https://play-lh.googleusercontent.com/wD6xJK2nuzVyKUFODfQs2SEbUuSyEglojpp_FE6GeAuzdA_R44Dp6gTyN70KCwpRtD9M=w2560-h1440</image>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<releases>
|
||||
<release version="1.4.2" date="2023-12-22" type="stable"/>
|
||||
<release version="1.4.1" date="2023-12-12" type="stable"/>
|
||||
<release version="1.4.0" date="2023-12-08" type="stable"/>
|
||||
<release version="1.3.2" date="2023-09-15" type="stable"/>
|
||||
<release version="1.3.1" date="2023-08-18" type="stable"/>
|
||||
<release version="1.3.0" date="2023-08-04" type="stable"/>
|
||||
<release version="1.2.1" date="2023-04-28" type="stable"/>
|
||||
<release version="1.2.0" date="2023-04-14" type="stable"/>
|
||||
<release version="1.1.1" date="2023-02-03" type="stable"/>
|
||||
<release version="1.1.0" date="2022-12-23" type="stable"/>
|
||||
<release version="1.0.0" date="2022-09-11" type="stable"/>
|
||||
<release version="0.99" date="2016-11-01" type="stable"/>
|
||||
</releases>
|
||||
<url type="homepage">https://vcmi.eu/</url>
|
||||
<url type="bugtracker">https://github.com/vcmi/vcmi/issues</url>
|
||||
<url type="faq">https://vcmi.eu/faq/</url>
|
||||
@ -58,33 +96,15 @@
|
||||
<url type="translate">https://github.com/vcmi/vcmi/blob/master/docs/modders/Translations.md</url>
|
||||
<url type="contact">https://discord.gg/chBT42V</url>
|
||||
<url type="vcs-browser">https://github.com/vcmi/vcmi</url>
|
||||
<recommends>
|
||||
<control>keyboard</control>
|
||||
<control>pointing</control>
|
||||
<control>touch</control>
|
||||
</recommends>
|
||||
<categories>
|
||||
<category>Game</category>
|
||||
<category>StrategyGame</category>
|
||||
</categories>
|
||||
<releases>
|
||||
<release version="1.4.1" date="2023-12-22" />
|
||||
<release version="1.4.0" date="2023-12-08" />
|
||||
<release version="1.3.2" date="2023-09-15" />
|
||||
<release version="1.3.1" date="2023-08-18" />
|
||||
<release version="1.3.0" date="2023-08-04" />
|
||||
<release version="1.2.1" date="2023-04-28" />
|
||||
<release version="1.2.0" date="2023-04-14" />
|
||||
<release version="1.1.1" date="2023-02-03" />
|
||||
<release version="1.1.0" date="2022-12-23" />
|
||||
<release version="1.0.0" date="2022-09-11" />
|
||||
<release version="0.99" date="2016-11-01" />
|
||||
</releases>
|
||||
<keywords>
|
||||
<keyword translate="no">heroes3</keyword>
|
||||
<keyword translate="no">homm3</keyword>
|
||||
</keywords>
|
||||
<developer_name>VCMI Team</developer_name>
|
||||
<recommends>
|
||||
<control>pointing</control>
|
||||
<control>keyboard</control>
|
||||
<control>touch</control>
|
||||
</recommends>
|
||||
<content_rating type="oars-1.1">
|
||||
<content_attribute id="violence-cartoon">moderate</content_attribute>
|
||||
<content_attribute id="violence-fantasy">moderate</content_attribute>
|
||||
@ -98,4 +118,8 @@
|
||||
<binary>vcmilauncher</binary>
|
||||
<binary>vcmiserver</binary>
|
||||
</provides>
|
||||
<keywords>
|
||||
<keyword>heroes3</keyword>
|
||||
<keyword>homm3</keyword>
|
||||
</keywords>
|
||||
</component>
|
||||
|
@ -136,14 +136,14 @@ void MainWindow::detectPreferredLanguage()
|
||||
for (auto const & vcmiLang : Languages::getLanguageList())
|
||||
if (vcmiLang.tagIETF == userLang.toStdString())
|
||||
selectedLanguage = vcmiLang.identifier;
|
||||
}
|
||||
|
||||
logGlobal->info("Selected language: %s", selectedLanguage);
|
||||
|
||||
if (!selectedLanguage.empty())
|
||||
{
|
||||
Settings node = settings.write["general"]["language"];
|
||||
node->String() = selectedLanguage;
|
||||
if (!selectedLanguage.empty())
|
||||
{
|
||||
logGlobal->info("Selected language: %s", selectedLanguage);
|
||||
Settings node = settings.write["general"]["language"];
|
||||
node->String() = selectedLanguage;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -591,7 +591,7 @@ void CModListView::downloadFile(QString file, QString url, QString description,
|
||||
this, SLOT(downloadFinished(QStringList,QStringList,QStringList)));
|
||||
|
||||
connect(manager.get(), SIGNAL(extractionProgress(qint64,qint64)),
|
||||
this, SLOT(downloadProgress(qint64,qint64)));
|
||||
this, SLOT(extractionProgress(qint64,qint64)));
|
||||
|
||||
connect(modModel, &CModListModel::dataChanged, filterModel, &QAbstractItemModel::dataChanged);
|
||||
|
||||
@ -613,6 +613,14 @@ void CModListView::downloadProgress(qint64 current, qint64 max)
|
||||
ui->progressBar->setValue(current / (1024 * 1024));
|
||||
}
|
||||
|
||||
void CModListView::extractionProgress(qint64 current, qint64 max)
|
||||
{
|
||||
// display progress, in extracted files
|
||||
ui->progressBar->setVisible(true);
|
||||
ui->progressBar->setMaximum(max);
|
||||
ui->progressBar->setValue(current);
|
||||
}
|
||||
|
||||
void CModListView::downloadFinished(QStringList savedFiles, QStringList failedFiles, QStringList errors)
|
||||
{
|
||||
QString title = tr("Download failed");
|
||||
|
@ -98,6 +98,7 @@ private slots:
|
||||
void dataChanged(const QModelIndex & topleft, const QModelIndex & bottomRight);
|
||||
void modSelected(const QModelIndex & current, const QModelIndex & previous);
|
||||
void downloadProgress(qint64 current, qint64 max);
|
||||
void extractionProgress(qint64 current, qint64 max);
|
||||
void downloadFinished(QStringList savedFiles, QStringList failedFiles, QStringList errors);
|
||||
void modelReset();
|
||||
void hideProgressBar();
|
||||
|
@ -24,7 +24,9 @@ namespace
|
||||
{
|
||||
QString detectModArchive(QString path, QString modName, std::vector<std::string> & filesToExtract)
|
||||
{
|
||||
filesToExtract = ZipArchive::listFiles(qstringToPath(path));
|
||||
ZipArchive archive(qstringToPath(path));
|
||||
|
||||
filesToExtract = archive.listFiles();
|
||||
|
||||
QString modDirName;
|
||||
|
||||
@ -285,14 +287,23 @@ bool CModManager::doInstallMod(QString modname, QString archivePath)
|
||||
if(!modDirName.size())
|
||||
return addError(modname, "Mod archive is invalid or corrupted");
|
||||
|
||||
auto futureExtract = std::async(std::launch::async, [&archivePath, &destDir, &filesToExtract]()
|
||||
std::atomic<int> filesCounter = 0;
|
||||
|
||||
auto futureExtract = std::async(std::launch::async, [&archivePath, &destDir, &filesCounter, &filesToExtract]()
|
||||
{
|
||||
return ZipArchive::extract(qstringToPath(archivePath), qstringToPath(destDir), filesToExtract);
|
||||
ZipArchive archive(qstringToPath(archivePath));
|
||||
for (auto const & file : filesToExtract)
|
||||
{
|
||||
if (!archive.extract(qstringToPath(destDir), file))
|
||||
return false;
|
||||
++filesCounter;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
while(futureExtract.wait_for(std::chrono::milliseconds(50)) != std::future_status::ready)
|
||||
while(futureExtract.wait_for(std::chrono::milliseconds(10)) != std::future_status::ready)
|
||||
{
|
||||
emit extractionProgress(0, 0);
|
||||
emit extractionProgress(filesCounter, filesToExtract.size());
|
||||
qApp->processEvents();
|
||||
}
|
||||
|
||||
|
1207
launcher/translation/czech.ts
Normal file
1207
launcher/translation/czech.ts
Normal file
File diff suppressed because it is too large
Load Diff
@ -93,6 +93,16 @@ int AFactionMember::getPrimSkillLevel(PrimarySkill id) const
|
||||
|
||||
int AFactionMember::moraleValAndBonusList(TConstBonusListPtr & bonusList) const
|
||||
{
|
||||
int32_t maxGoodMorale = VLC->settings()->getVector(EGameSettings::COMBAT_GOOD_MORALE_DICE).size();
|
||||
int32_t maxBadMorale = - (int32_t) VLC->settings()->getVector(EGameSettings::COMBAT_BAD_MORALE_DICE).size();
|
||||
|
||||
if(getBonusBearer()->hasBonusOfType(BonusType::MAX_MORALE))
|
||||
{
|
||||
if(bonusList && !bonusList->empty())
|
||||
bonusList = std::make_shared<const BonusList>();
|
||||
return maxGoodMorale;
|
||||
}
|
||||
|
||||
static const auto unaffectedByMoraleSelector = Selector::type()(BonusType::NON_LIVING).Or(Selector::type()(BonusType::UNDEAD))
|
||||
.Or(Selector::type()(BonusType::SIEGE_WEAPON)).Or(Selector::type()(BonusType::NO_MORALE));
|
||||
|
||||
@ -109,14 +119,21 @@ int AFactionMember::moraleValAndBonusList(TConstBonusListPtr & bonusList) const
|
||||
static const std::string cachingStrMor = "type_MORALE";
|
||||
bonusList = getBonusBearer()->getBonuses(moraleSelector, cachingStrMor);
|
||||
|
||||
int32_t maxGoodMorale = VLC->settings()->getVector(EGameSettings::COMBAT_GOOD_MORALE_DICE).size();
|
||||
int32_t maxBadMorale = - (int32_t) VLC->settings()->getVector(EGameSettings::COMBAT_BAD_MORALE_DICE).size();
|
||||
|
||||
return std::clamp(bonusList->totalValue(), maxBadMorale, maxGoodMorale);
|
||||
}
|
||||
|
||||
int AFactionMember::luckValAndBonusList(TConstBonusListPtr & bonusList) const
|
||||
{
|
||||
int32_t maxGoodLuck = VLC->settings()->getVector(EGameSettings::COMBAT_GOOD_LUCK_DICE).size();
|
||||
int32_t maxBadLuck = - (int32_t) VLC->settings()->getVector(EGameSettings::COMBAT_BAD_LUCK_DICE).size();
|
||||
|
||||
if(getBonusBearer()->hasBonusOfType(BonusType::MAX_LUCK))
|
||||
{
|
||||
if(bonusList && !bonusList->empty())
|
||||
bonusList = std::make_shared<const BonusList>();
|
||||
return maxGoodLuck;
|
||||
}
|
||||
|
||||
if(getBonusBearer()->hasBonusOfType(BonusType::NO_LUCK))
|
||||
{
|
||||
if(bonusList && !bonusList->empty())
|
||||
@ -128,9 +145,6 @@ int AFactionMember::luckValAndBonusList(TConstBonusListPtr & bonusList) const
|
||||
static const std::string cachingStrLuck = "type_LUCK";
|
||||
bonusList = getBonusBearer()->getBonuses(luckSelector, cachingStrLuck);
|
||||
|
||||
int32_t maxGoodLuck = VLC->settings()->getVector(EGameSettings::COMBAT_GOOD_LUCK_DICE).size();
|
||||
int32_t maxBadLuck = - (int32_t) VLC->settings()->getVector(EGameSettings::COMBAT_BAD_LUCK_DICE).size();
|
||||
|
||||
return std::clamp(bonusList->totalValue(), maxBadLuck, maxGoodLuck);
|
||||
}
|
||||
|
||||
|
@ -625,7 +625,7 @@ void CArtHandler::makeItCommanderArt(CArtifact * a, bool onlyCommander)
|
||||
a->possibleSlots[ArtBearer::COMMANDER].push_back(ArtifactPosition(slot));
|
||||
}
|
||||
|
||||
bool CArtHandler::legalArtifact(const ArtifactID & id)
|
||||
bool CArtHandler::legalArtifact(const ArtifactID & id) const
|
||||
{
|
||||
auto art = id.toArtifact();
|
||||
//assert ( (!art->constituents) || art->constituents->size() ); //artifacts is not combined or has some components
|
||||
@ -648,18 +648,6 @@ bool CArtHandler::legalArtifact(const ArtifactID & id)
|
||||
return false;
|
||||
}
|
||||
|
||||
void CArtHandler::initAllowedArtifactsList(const std::set<ArtifactID> & allowed)
|
||||
{
|
||||
allowedArtifacts.clear();
|
||||
|
||||
for (ArtifactID i : allowed)
|
||||
{
|
||||
if (legalArtifact(ArtifactID(i)))
|
||||
allowedArtifacts.push_back(i.toArtifact());
|
||||
//keep im mind that artifact can be worn by more than one type of bearer
|
||||
}
|
||||
}
|
||||
|
||||
std::set<ArtifactID> CArtHandler::getDefaultAllowed() const
|
||||
{
|
||||
std::set<ArtifactID> allowedArtifacts;
|
||||
|
@ -141,15 +141,11 @@ public:
|
||||
class DLL_LINKAGE CArtHandler : public CHandlerBase<ArtifactID, Artifact, CArtifact, ArtifactService>
|
||||
{
|
||||
public:
|
||||
/// List of artifacts allowed on the map
|
||||
std::vector<const CArtifact *> allowedArtifacts;
|
||||
|
||||
void addBonuses(CArtifact *art, const JsonNode &bonusList);
|
||||
|
||||
static CArtifact::EartClass stringToClass(const std::string & className); //TODO: rework EartClass to make this a constructor
|
||||
|
||||
bool legalArtifact(const ArtifactID & id);
|
||||
void initAllowedArtifactsList(const std::set<ArtifactID> & allowed);
|
||||
bool legalArtifact(const ArtifactID & id) const;
|
||||
static void makeItCreatureArt(CArtifact * a, bool onlyCreature = true);
|
||||
static void makeItCommanderArt(CArtifact * a, bool onlyCommander = true);
|
||||
|
||||
|
@ -64,10 +64,7 @@ SpellID CScrollArtifactInstance::getScrollSpellID() const
|
||||
auto artInst = static_cast<const CArtifactInstance*>(this);
|
||||
const auto bonus = artInst->getBonusLocalFirst(Selector::type()(BonusType::SPELL));
|
||||
if(!bonus)
|
||||
{
|
||||
logMod->warn("Warning: %s doesn't bear any spell!", artInst->nodeName());
|
||||
return SpellID::NONE;
|
||||
}
|
||||
return bonus->subtype.as<SpellID>();
|
||||
}
|
||||
|
||||
@ -165,6 +162,11 @@ bool CArtifactInstance::isCombined() const
|
||||
return artType->isCombined();
|
||||
}
|
||||
|
||||
bool CArtifactInstance::isScroll() const
|
||||
{
|
||||
return artType->isScroll();
|
||||
}
|
||||
|
||||
void CArtifactInstance::putAt(CArtifactSet & set, const ArtifactPosition slot)
|
||||
{
|
||||
auto placementMap = set.putArtifact(slot, this);
|
||||
|
@ -87,6 +87,7 @@ public:
|
||||
bool canBePutAt(const CArtifactSet * artSet, ArtifactPosition slot = ArtifactPosition::FIRST_AVAILABLE,
|
||||
bool assumeDestRemoved = false) const;
|
||||
bool isCombined() const;
|
||||
bool isScroll() const;
|
||||
void putAt(CArtifactSet & set, const ArtifactPosition slot);
|
||||
void removeFrom(CArtifactSet & set, const ArtifactPosition slot);
|
||||
void move(CArtifactSet & srcSet, const ArtifactPosition srcSlot, CArtifactSet & dstSet, const ArtifactPosition dstSlot);
|
||||
|
@ -721,6 +721,11 @@ bool CGameInfoCallback::isPlayerMakingTurn(PlayerColor player) const
|
||||
return gs->actingPlayers.count(player);
|
||||
}
|
||||
|
||||
CGameInfoCallback::CGameInfoCallback():
|
||||
gs(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
CGameInfoCallback::CGameInfoCallback(CGameState * GS):
|
||||
gs(GS)
|
||||
{
|
||||
|
@ -134,7 +134,7 @@ class DLL_LINKAGE CGameInfoCallback : public IGameInfoCallback
|
||||
protected:
|
||||
CGameState * gs;//todo: replace with protected const getter, only actual Server and Client objects should hold game state
|
||||
|
||||
CGameInfoCallback() = default;
|
||||
CGameInfoCallback();
|
||||
CGameInfoCallback(CGameState * GS);
|
||||
bool hasAccess(std::optional<PlayerColor> playerId) const;
|
||||
|
||||
|
@ -118,11 +118,10 @@ void GameSettings::load(const JsonNode & input)
|
||||
|
||||
const JsonNode & GameSettings::getValue(EGameSettings option) const
|
||||
{
|
||||
assert(option < EGameSettings::OPTIONS_COUNT);
|
||||
auto index = static_cast<size_t>(option);
|
||||
|
||||
assert(!gameSettings[index].isNull());
|
||||
return gameSettings[index];
|
||||
assert(!gameSettings.at(index).isNull());
|
||||
return gameSettings.at(index);
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -310,63 +310,73 @@ JsonMap & JsonNode::Struct()
|
||||
const bool boolDefault = false;
|
||||
bool JsonNode::Bool() const
|
||||
{
|
||||
if (getType() == JsonType::DATA_NULL)
|
||||
return boolDefault;
|
||||
assert(getType() == JsonType::DATA_BOOL);
|
||||
return std::get<bool>(data);
|
||||
assert(getType() == JsonType::DATA_NULL || getType() == JsonType::DATA_BOOL);
|
||||
|
||||
if (getType() == JsonType::DATA_BOOL)
|
||||
return std::get<bool>(data);
|
||||
|
||||
return boolDefault;
|
||||
}
|
||||
|
||||
const double floatDefault = 0;
|
||||
double JsonNode::Float() const
|
||||
{
|
||||
if(getType() == JsonType::DATA_NULL)
|
||||
return floatDefault;
|
||||
assert(getType() == JsonType::DATA_NULL || getType() == JsonType::DATA_INTEGER || getType() == JsonType::DATA_FLOAT);
|
||||
|
||||
if(getType() == JsonType::DATA_FLOAT)
|
||||
return std::get<double>(data);
|
||||
|
||||
if(getType() == JsonType::DATA_INTEGER)
|
||||
return static_cast<double>(std::get<si64>(data));
|
||||
|
||||
assert(getType() == JsonType::DATA_FLOAT);
|
||||
return std::get<double>(data);
|
||||
return floatDefault;
|
||||
}
|
||||
|
||||
const si64 integetDefault = 0;
|
||||
const si64 integerDefault = 0;
|
||||
si64 JsonNode::Integer() const
|
||||
{
|
||||
if(getType() == JsonType::DATA_NULL)
|
||||
return integetDefault;
|
||||
assert(getType() == JsonType::DATA_NULL || getType() == JsonType::DATA_INTEGER || getType() == JsonType::DATA_FLOAT);
|
||||
|
||||
if(getType() == JsonType::DATA_INTEGER)
|
||||
return std::get<si64>(data);
|
||||
|
||||
if(getType() == JsonType::DATA_FLOAT)
|
||||
return static_cast<si64>(std::get<double>(data));
|
||||
|
||||
assert(getType() == JsonType::DATA_INTEGER);
|
||||
return std::get<si64>(data);
|
||||
return integerDefault;
|
||||
}
|
||||
|
||||
const std::string stringDefault = std::string();
|
||||
const std::string & JsonNode::String() const
|
||||
{
|
||||
if (getType() == JsonType::DATA_NULL)
|
||||
return stringDefault;
|
||||
assert(getType() == JsonType::DATA_STRING);
|
||||
return std::get<std::string>(data);
|
||||
assert(getType() == JsonType::DATA_NULL || getType() == JsonType::DATA_STRING);
|
||||
|
||||
if (getType() == JsonType::DATA_STRING)
|
||||
return std::get<std::string>(data);
|
||||
|
||||
return stringDefault;
|
||||
}
|
||||
|
||||
const JsonVector vectorDefault = JsonVector();
|
||||
const JsonVector & JsonNode::Vector() const
|
||||
{
|
||||
if (getType() == JsonType::DATA_NULL)
|
||||
return vectorDefault;
|
||||
assert(getType() == JsonType::DATA_VECTOR);
|
||||
return std::get<JsonVector>(data);
|
||||
assert(getType() == JsonType::DATA_NULL || getType() == JsonType::DATA_VECTOR);
|
||||
|
||||
if (getType() == JsonType::DATA_VECTOR)
|
||||
return std::get<JsonVector>(data);
|
||||
|
||||
return vectorDefault;
|
||||
}
|
||||
|
||||
const JsonMap mapDefault = JsonMap();
|
||||
const JsonMap & JsonNode::Struct() const
|
||||
{
|
||||
if (getType() == JsonType::DATA_NULL)
|
||||
return mapDefault;
|
||||
assert(getType() == JsonType::DATA_STRUCT);
|
||||
return std::get<JsonMap>(data);
|
||||
assert(getType() == JsonType::DATA_NULL || getType() == JsonType::DATA_STRUCT);
|
||||
|
||||
if (getType() == JsonType::DATA_STRUCT)
|
||||
return std::get<JsonMap>(data);
|
||||
|
||||
return mapDefault;
|
||||
}
|
||||
|
||||
JsonNode & JsonNode::operator[](const std::string & child)
|
||||
|
@ -384,8 +384,9 @@ namespace JsonRandom
|
||||
ArtifactID loadArtifact(const JsonNode & value, CRandomGenerator & rng, const Variables & variables)
|
||||
{
|
||||
std::set<ArtifactID> allowedArts;
|
||||
for (auto const * artifact : VLC->arth->allowedArtifacts)
|
||||
allowedArts.insert(artifact->getId());
|
||||
for(const auto & artifact : VLC->arth->objects)
|
||||
if (IObjectInterface::cb->isAllowed(artifact->getId()) && VLC->arth->legalArtifact(artifact->getId()))
|
||||
allowedArts.insert(artifact->getId());
|
||||
|
||||
std::set<ArtifactID> potentialPicks = filterKeys(value, allowedArts, variables);
|
||||
|
||||
|
@ -68,6 +68,9 @@ struct Options
|
||||
/// primary IETF language tag
|
||||
std::string tagIETF;
|
||||
|
||||
/// DateTime format
|
||||
std::string dateTimeFormat;
|
||||
|
||||
/// Ruleset for plural forms in this language
|
||||
EPluralForms pluralForms = EPluralForms::NONE;
|
||||
|
||||
@ -79,27 +82,27 @@ inline const auto & getLanguageList()
|
||||
{
|
||||
static const std::array<Options, 20> languages
|
||||
{ {
|
||||
{ "czech", "Czech", "Čeština", "CP1250", "cs", EPluralForms::CZ_3, true },
|
||||
{ "chinese", "Chinese", "简体中文", "GBK", "zh", EPluralForms::VI_1, true }, // Note: actually Simplified Chinese
|
||||
{ "english", "English", "English", "CP1252", "en", EPluralForms::EN_2, true },
|
||||
{ "finnish", "Finnish", "Suomi", "CP1252", "fi", EPluralForms::EN_2, true },
|
||||
{ "french", "French", "Français", "CP1252", "fr", EPluralForms::FR_2, true },
|
||||
{ "german", "German", "Deutsch", "CP1252", "de", EPluralForms::EN_2, true },
|
||||
{ "hungarian", "Hungarian", "Magyar", "CP1250", "hu", EPluralForms::EN_2, true },
|
||||
{ "italian", "Italian", "Italiano", "CP1250", "it", EPluralForms::EN_2, true },
|
||||
{ "korean", "Korean", "한국어", "CP949", "ko", EPluralForms::VI_1, true },
|
||||
{ "polish", "Polish", "Polski", "CP1250", "pl", EPluralForms::PL_3, true },
|
||||
{ "portuguese", "Portuguese", "Português", "CP1252", "pt", EPluralForms::EN_2, true }, // Note: actually Brazilian Portuguese
|
||||
{ "russian", "Russian", "Русский", "CP1251", "ru", EPluralForms::UK_3, true },
|
||||
{ "spanish", "Spanish", "Español", "CP1252", "es", EPluralForms::EN_2, true },
|
||||
{ "swedish", "Swedish", "Svenska", "CP1252", "sv", EPluralForms::EN_2, true },
|
||||
{ "turkish", "Turkish", "Türkçe", "CP1254", "tr", EPluralForms::EN_2, true },
|
||||
{ "ukrainian", "Ukrainian", "Українська", "CP1251", "uk", EPluralForms::UK_3, true },
|
||||
{ "vietnamese", "Vietnamese", "Tiếng Việt", "UTF-8", "vi", EPluralForms::VI_1, true }, // Fan translation uses special encoding
|
||||
{ "czech", "Czech", "Čeština", "CP1250", "cs", "%d.%m.%Y %T", EPluralForms::CZ_3, true },
|
||||
{ "chinese", "Chinese", "简体中文", "GBK", "zh", "%F %T", EPluralForms::VI_1, true }, // Note: actually Simplified Chinese
|
||||
{ "english", "English", "English", "CP1252", "en", "%F %T", EPluralForms::EN_2, true }, // English uses international date/time format here
|
||||
{ "finnish", "Finnish", "Suomi", "CP1252", "fi", "%d.%m.%Y %T", EPluralForms::EN_2, true },
|
||||
{ "french", "French", "Français", "CP1252", "fr", "%d/%m/%Y %T", EPluralForms::FR_2, true },
|
||||
{ "german", "German", "Deutsch", "CP1252", "de", "%d.%m.%Y %T", EPluralForms::EN_2, true },
|
||||
{ "hungarian", "Hungarian", "Magyar", "CP1250", "hu", "%Y. %m. %d. %T", EPluralForms::EN_2, true },
|
||||
{ "italian", "Italian", "Italiano", "CP1250", "it", "%d/%m/%Y %T", EPluralForms::EN_2, true },
|
||||
{ "korean", "Korean", "한국어", "CP949", "ko", "%F %T", EPluralForms::VI_1, true },
|
||||
{ "polish", "Polish", "Polski", "CP1250", "pl", "%d.%m.%Y %T", EPluralForms::PL_3, true },
|
||||
{ "portuguese", "Portuguese", "Português", "CP1252", "pt", "%d/%m/%Y %T", EPluralForms::EN_2, true }, // Note: actually Brazilian Portuguese
|
||||
{ "russian", "Russian", "Русский", "CP1251", "ru", "%d.%m.%Y %T", EPluralForms::UK_3, true },
|
||||
{ "spanish", "Spanish", "Español", "CP1252", "es", "%d/%m/%Y %T", EPluralForms::EN_2, true },
|
||||
{ "swedish", "Swedish", "Svenska", "CP1252", "sv", "%F %T", EPluralForms::EN_2, true },
|
||||
{ "turkish", "Turkish", "Türkçe", "CP1254", "tr", "%d.%m.%Y %T", EPluralForms::EN_2, true },
|
||||
{ "ukrainian", "Ukrainian", "Українська", "CP1251", "uk", "%d.%m.%Y %T", EPluralForms::UK_3, true },
|
||||
{ "vietnamese", "Vietnamese", "Tiếng Việt", "UTF-8", "vi", "%d/%m/%Y %T", EPluralForms::VI_1, true }, // Fan translation uses special encoding
|
||||
|
||||
{ "other_cp1250", "Other (East European)", "", "CP1250", "", EPluralForms::NONE, false },
|
||||
{ "other_cp1251", "Other (Cyrillic Script)", "", "CP1251", "", EPluralForms::NONE, false },
|
||||
{ "other_cp1252", "Other (West European)", "", "CP1252", "", EPluralForms::NONE, false }
|
||||
{ "other_cp1250", "Other (East European)", "", "CP1250", "", "", EPluralForms::NONE, false },
|
||||
{ "other_cp1251", "Other (Cyrillic Script)", "", "CP1251", "", "", EPluralForms::NONE, false },
|
||||
{ "other_cp1252", "Other (West European)", "", "CP1252", "", "", EPluralForms::NONE, false }
|
||||
} };
|
||||
static_assert(languages.size() == static_cast<size_t>(ELanguages::COUNT), "Languages array is missing a value!");
|
||||
|
||||
|
@ -11,6 +11,10 @@
|
||||
#include "TextOperations.h"
|
||||
|
||||
#include "CGeneralTextHandler.h"
|
||||
#include "Languages.h"
|
||||
#include "CConfigHandler.h"
|
||||
|
||||
#include <vstd/DateUtils.h>
|
||||
|
||||
#include <boost/locale.hpp>
|
||||
|
||||
@ -210,4 +214,9 @@ std::string TextOperations::escapeString(std::string input)
|
||||
return input;
|
||||
}
|
||||
|
||||
std::string TextOperations::getFormattedDateTimeLocal(std::time_t dt)
|
||||
{
|
||||
return vstd::getFormattedDateTime(dt, Languages::getLanguageOptions(settings["general"]["language"].String()).dateTimeFormat);
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -56,6 +56,9 @@ namespace TextOperations
|
||||
|
||||
/// replaces all symbols that normally need escaping with appropriate escape sequences
|
||||
std::string escapeString(std::string input);
|
||||
|
||||
/// get formatted DateTime depending on the language selected
|
||||
DLL_LINKAGE std::string getFormattedDateTimeLocal(std::time_t dt);
|
||||
};
|
||||
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user