diff --git a/.github/workflows/github.yml b/.github/workflows/github.yml index fc40fd23a..1fec92b84 100644 --- a/.github/workflows/github.yml +++ b/.github/workflows/github.yml @@ -17,20 +17,22 @@ env: jobs: build: strategy: - fail-fast: false matrix: include: - platform: linux-qt6 os: ubuntu-24.04 test: 0 + before_install: linux_qt6.sh preset: linux-clang-test - platform: linux os: ubuntu-24.04 test: 1 + before_install: linux_qt5.sh preset: linux-gcc-test - platform: linux os: ubuntu-20.04 test: 0 + before_install: linux_qt5.sh preset: linux-gcc-debug - platform: mac-intel os: macos-13 @@ -38,8 +40,10 @@ jobs: pack: 1 pack_type: Release extension: dmg + before_install: macos.sh preset: macos-conan-ninja-release conan_profile: macos-intel + conan_prebuilts: dependencies-mac-intel conan_options: --options with_apple_system_libs=True artifact_platform: intel - platform: mac-arm @@ -48,8 +52,10 @@ jobs: pack: 1 pack_type: Release extension: dmg + before_install: macos.sh preset: macos-arm-conan-ninja-release conan_profile: macos-arm + conan_prebuilts: dependencies-mac-arm conan_options: --options with_apple_system_libs=True artifact_platform: arm - platform: ios @@ -58,8 +64,10 @@ jobs: pack: 1 pack_type: Release extension: ipa + before_install: macos.sh preset: ios-release-conan-ccache conan_profile: ios-arm64 + conan_prebuilts: dependencies-ios conan_options: --options with_apple_system_libs=True - platform: msvc os: windows-latest @@ -67,40 +75,45 @@ jobs: pack: 1 pack_type: RelWithDebInfo extension: exe + before_install: msvc.sh preset: windows-msvc-release - - platform: mingw - os: ubuntu-22.04 + - platform: mingw_x86_64 + os: ubuntu-24.04 test: 0 pack: 1 pack_type: Release extension: exe - cpack_args: -D CPACK_NSIS_EXECUTABLE=`which makensis` cmake_args: -G Ninja + before_install: mingw.sh preset: windows-mingw-conan-linux conan_profile: mingw64-linux.jinja - - platform: mingw-32 - os: ubuntu-22.04 + conan_prebuilts: dependencies-mingw-x86-64 + - platform: mingw_x86 + os: ubuntu-24.04 test: 0 pack: 1 pack_type: Release extension: exe - cpack_args: -D CPACK_NSIS_EXECUTABLE=`which makensis` cmake_args: -G Ninja + before_install: mingw.sh preset: windows-mingw-conan-linux conan_profile: mingw32-linux.jinja + conan_prebuilts: dependencies-mingw-x86 - platform: android-32 - os: macos-14 + os: ubuntu-24.04 extension: apk preset: android-conan-ninja-release - conan_profile: android-32 - conan_options: --conf tools.android:ndk_path=$ANDROID_NDK_ROOT + before_install: android.sh + conan_profile: android-32-ndk + conan_prebuilts: dependencies-android-armeabi-v7a artifact_platform: armeabi-v7a - platform: android-64 - os: macos-14 + os: ubuntu-24.04 extension: apk preset: android-conan-ninja-release - conan_profile: android-64 - conan_options: --conf tools.android:ndk_path=$ANDROID_NDK_ROOT + before_install: android.sh + conan_profile: android-64-ndk + conan_prebuilts: dependencies-android-arm64-v8a artifact_platform: arm64-v8a runs-on: ${{ matrix.os }} defaults: @@ -108,15 +121,21 @@ jobs: shell: bash steps: - - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@v4 with: submodules: recursive - - name: Dependencies - run: source '${{github.workspace}}/CI/${{matrix.platform}}/before_install.sh' + - name: Prepare CI + if: "${{ matrix.before_install != '' }}" + run: source '${{github.workspace}}/CI/before_install/${{matrix.before_install}}' env: VCMI_BUILD_PLATFORM: x64 + - name: Install Conan Dependencies + if: "${{ matrix.conan_prebuilts != '' }}" + run: source '${{github.workspace}}/CI/install_conan_dependencies.sh' '${{matrix.conan_prebuilts}}' + # ensure the ccache for each PR is separate so they don't interfere with each other # fall back to ccache of the vcmi/vcmi repo if no PR-specific ccache is found - name: ccache for PRs @@ -158,15 +177,13 @@ jobs: mkdir -p ~/.local/share/vcmi/ mv h3_assets/* ~/.local/share/vcmi/ - - uses: actions/setup-python@v5 + - name: Install Conan if: "${{ matrix.conan_profile != '' }}" - with: - python-version: '3.10' + run: pipx install 'conan<2.0' - - name: Conan setup + - name: Install Conan profile if: "${{ matrix.conan_profile != '' }}" run: | - pip3 install 'conan<2.0' conan profile new default --detect conan install . \ --install-folder=conan-generated \ @@ -178,7 +195,13 @@ jobs: env: GENERATE_ONLY_BUILT_CONFIG: 1 - - uses: actions/setup-java@v4 + # Workaround for gradle not discovering SDK that was installed via conan + - name: Find Android NDK + if: ${{ startsWith(matrix.platform, 'android') }} + run: sudo ln -s -T /home/runner/.conan/data/android-ndk/r25c/_/_/package/4db1be536558d833e52e862fd84d64d75c2b3656/bin /usr/local/lib/android/sdk/ndk/25.2.9519653 + + - name: Install Java + uses: actions/setup-java@v4 if: ${{ startsWith(matrix.platform, 'android') }} with: distribution: 'temurin' @@ -243,11 +266,13 @@ jobs: if: ${{ matrix.pack == 1 }} run: | cd '${{github.workspace}}/out/build/${{matrix.preset}}' - CPACK_PATH=`which -a cpack | grep -m1 -v -i chocolatey` - counter=0; until "$CPACK_PATH" -C ${{matrix.pack_type}} ${{ matrix.cpack_args }} || ((counter > 20)); do sleep 3; ((counter++)); done - test -f '${{github.workspace}}/CI/${{matrix.platform}}/post_pack.sh' \ - && '${{github.workspace}}/CI/${{matrix.platform}}/post_pack.sh' '${{github.workspace}}' "$(ls '${{ env.VCMI_PACKAGE_FILE_NAME }}'.*)" - rm -rf _CPack_Packages + + # Workaround for CPack bug on macOS 13 + counter=0 + until cpack -C ${{matrix.pack_type}} || ((counter > 20)); do + sleep 3 + ((counter++)) + done - name: Artifacts if: ${{ matrix.pack == 1 }} @@ -269,7 +294,7 @@ jobs: echo "ANDROID_APK_PATH=$ANDROID_APK_PATH" >> $GITHUB_ENV echo "ANDROID_AAB_PATH=$ANDROID_AAB_PATH" >> $GITHUB_ENV - - name: Android apk artifacts + - name: Upload android apk artifacts if: ${{ startsWith(matrix.platform, 'android') }} uses: actions/upload-artifact@v4 with: @@ -277,15 +302,15 @@ jobs: path: | ${{ env.ANDROID_APK_PATH }} - - name: Android aab artifacts - if: ${{ startsWith(matrix.platform, 'android') }} + - name: Upload Android aab artifacts + if: ${{ startsWith(matrix.platform, 'android') && github.ref == 'refs/heads/master' }} uses: actions/upload-artifact@v4 with: name: ${{ env.VCMI_PACKAGE_FILE_NAME }} - ${{ matrix.platform }} - aab path: | ${{ env.ANDROID_AAB_PATH }} - - name: Symbols + - name: Upload debug symbols if: ${{ matrix.platform == 'msvc' }} uses: actions/upload-artifact@v4 with: @@ -344,11 +369,6 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - if: "${{ matrix.conan_profile != '' }}" - with: - python-version: '3.10' - - name: Ensure LF line endings run: | find . -path ./.git -prune -o -path ./AI/FuzzyLite -prune -o -path ./test/googletest \ @@ -359,4 +379,4 @@ jobs: - name: Validate JSON run: | sudo apt install python3-jstyleson - python3 CI/linux-qt6/validate_json.py + python3 CI/validate_json.py diff --git a/AI/BattleAI/AttackPossibility.cpp b/AI/BattleAI/AttackPossibility.cpp index c22b7ccad..c55de09b2 100644 --- a/AI/BattleAI/AttackPossibility.cpp +++ b/AI/BattleAI/AttackPossibility.cpp @@ -58,7 +58,7 @@ void DamageCache::buildObstacleDamageCache(std::shared_ptr hb, return u->alive() && !u->isTurret() && u->getPosition().isValid(); }); - std::shared_ptr inner = std::make_shared(hb->env, hb); + auto inner = std::make_shared(hb->env, hb); for(auto stack : stacks) { diff --git a/AI/Nullkiller/AIGateway.cpp b/AI/Nullkiller/AIGateway.cpp index 99172b213..d683a9657 100644 --- a/AI/Nullkiller/AIGateway.cpp +++ b/AI/Nullkiller/AIGateway.cpp @@ -17,7 +17,6 @@ #include "../../lib/mapObjects/ObjectTemplate.h" #include "../../lib/mapObjects/CGHeroInstance.h" #include "../../lib/CConfigHandler.h" -#include "../../lib/CHeroHandler.h" #include "../../lib/IGameSettings.h" #include "../../lib/gameState/CGameState.h" #include "../../lib/serializer/CTypeList.h" @@ -649,12 +648,12 @@ void AIGateway::showBlockingDialog(const std::string & text, const std::vectordangerEvaluator->evaluateDanger(target, hero.get()); auto ratio = static_cast(danger) / hero->getTotalStrength(); - answer = 1; + answer = true; if(topObj->id != goalObjectID && nullkiller->dangerEvaluator->evaluateDanger(topObj) > 0) { // no if we do not aim to visit this object - answer = 0; + answer = false; } logAi->trace("Query hook: %s(%s) by %s danger ratio %f", target.toString(), topObj->getObjectName(), hero.name(), ratio); diff --git a/AI/Nullkiller/AIUtility.cpp b/AI/Nullkiller/AIUtility.cpp index 0cedca08c..5d79c7261 100644 --- a/AI/Nullkiller/AIUtility.cpp +++ b/AI/Nullkiller/AIUtility.cpp @@ -14,7 +14,6 @@ #include "../../lib/UnlockGuard.h" #include "../../lib/CConfigHandler.h" -#include "../../lib/CHeroHandler.h" #include "../../lib/mapObjects/MapObjects.h" #include "../../lib/mapping/CMapDefines.h" #include "../../lib/gameState/QuestInfo.h" diff --git a/AI/Nullkiller/Analyzers/HeroManager.cpp b/AI/Nullkiller/Analyzers/HeroManager.cpp index b5c07d62e..e18961663 100644 --- a/AI/Nullkiller/Analyzers/HeroManager.cpp +++ b/AI/Nullkiller/Analyzers/HeroManager.cpp @@ -11,7 +11,6 @@ #include "../StdInc.h" #include "../Engine/Nullkiller.h" #include "../../../lib/mapObjects/MapObjects.h" -#include "../../../lib/CHeroHandler.h" #include "../../../lib/IGameSettings.h" namespace NKAI diff --git a/AI/Nullkiller/Goals/CaptureObject.h b/AI/Nullkiller/Goals/CaptureObject.h index e219e37ec..2073cd2fe 100644 --- a/AI/Nullkiller/Goals/CaptureObject.h +++ b/AI/Nullkiller/Goals/CaptureObject.h @@ -31,7 +31,7 @@ namespace Goals { objid = obj->id.getNum(); tile = obj->visitablePos(); - name = obj->typeName; + name = obj->getTypeName(); } bool operator==(const CaptureObject & other) const override; diff --git a/AI/Nullkiller/Goals/ExecuteHeroChain.cpp b/AI/Nullkiller/Goals/ExecuteHeroChain.cpp index 1a39ff776..0391a4585 100644 --- a/AI/Nullkiller/Goals/ExecuteHeroChain.cpp +++ b/AI/Nullkiller/Goals/ExecuteHeroChain.cpp @@ -31,7 +31,7 @@ ExecuteHeroChain::ExecuteHeroChain(const AIPath & path, const CGObjectInstance * #if NKAI_TRACE_LEVEL >= 1 targetName = obj->getObjectName() + tile.toString(); #else - targetName = obj->typeName + tile.toString(); + targetName = obj->getTypeName() + tile.toString(); #endif } else diff --git a/AI/Nullkiller/Pathfinding/AIPathfinderConfig.cpp b/AI/Nullkiller/Pathfinding/AIPathfinderConfig.cpp index 98bcddcec..7bb43fabb 100644 --- a/AI/Nullkiller/Pathfinding/AIPathfinderConfig.cpp +++ b/AI/Nullkiller/Pathfinding/AIPathfinderConfig.cpp @@ -13,7 +13,7 @@ #include "Rules/AIMovementAfterDestinationRule.h" #include "Rules/AIMovementToDestinationRule.h" #include "Rules/AIPreviousNodeRule.h" -#include "../Engine//Nullkiller.h" +#include "../Engine/Nullkiller.h" #include "../../../lib/pathfinder/CPathfinder.h" diff --git a/AI/Nullkiller/Pathfinding/Actors.cpp b/AI/Nullkiller/Pathfinding/Actors.cpp index 1af649e66..4d3a86a28 100644 --- a/AI/Nullkiller/Pathfinding/Actors.cpp +++ b/AI/Nullkiller/Pathfinding/Actors.cpp @@ -182,7 +182,7 @@ ExchangeResult HeroActor::tryExchangeNoLock(const ChainActor * specialActor, con return &actor == specialActor; }); - result.actor = &(dynamic_cast(result.actor)->specialActors[index]); + result.actor = &(dynamic_cast(result.actor)->specialActors.at(index)); return result; } @@ -440,7 +440,7 @@ int DwellingActor::getInitialTurn(bool waitForGrowth, int dayOfWeek) std::string DwellingActor::toString() const { - return dwelling->typeName + dwelling->visitablePos().toString(); + return dwelling->getTypeName() + dwelling->visitablePos().toString(); } CCreatureSet * DwellingActor::getDwellingCreatures(const CGDwelling * dwelling, bool waitForGrowth) diff --git a/AI/Nullkiller/Pathfinding/Actors.h b/AI/Nullkiller/Pathfinding/Actors.h index 4451bda24..1f653fbd3 100644 --- a/AI/Nullkiller/Pathfinding/Actors.h +++ b/AI/Nullkiller/Pathfinding/Actors.h @@ -113,7 +113,7 @@ public: static const int SPECIAL_ACTORS_COUNT = 7; private: - ChainActor specialActors[SPECIAL_ACTORS_COUNT]; + std::array specialActors; std::unique_ptr exchangeMap; void setupSpecialActors(); diff --git a/AI/VCAI/AIUtility.cpp b/AI/VCAI/AIUtility.cpp index a7c4c2f7a..63a64c43b 100644 --- a/AI/VCAI/AIUtility.cpp +++ b/AI/VCAI/AIUtility.cpp @@ -15,7 +15,6 @@ #include "../../lib/UnlockGuard.h" #include "../../lib/CConfigHandler.h" -#include "../../lib/CHeroHandler.h" #include "../../lib/mapObjects/CGTownInstance.h" #include "../../lib/mapObjects/CQuest.h" #include "../../lib/mapping/CMapDefines.h" diff --git a/AI/VCAI/MapObjectsEvaluator.cpp b/AI/VCAI/MapObjectsEvaluator.cpp index e430c1f08..fa038725e 100644 --- a/AI/VCAI/MapObjectsEvaluator.cpp +++ b/AI/VCAI/MapObjectsEvaluator.cpp @@ -12,7 +12,6 @@ #include "../../lib/GameConstants.h" #include "../../lib/VCMI_Lib.h" #include "../../lib/CCreatureHandler.h" -#include "../../lib/CHeroHandler.h" #include "../../lib/mapObjects/CompoundMapObjectID.h" #include "../../lib/mapObjectConstructors/AObjectTypeHandler.h" #include "../../lib/mapObjects/CGHeroInstance.h" diff --git a/AI/VCAI/VCAI.cpp b/AI/VCAI/VCAI.cpp index f9ebb1657..462023437 100644 --- a/AI/VCAI/VCAI.cpp +++ b/AI/VCAI/VCAI.cpp @@ -20,7 +20,6 @@ #include "../../lib/mapObjects/MapObjects.h" #include "../../lib/mapObjects/ObjectTemplate.h" #include "../../lib/CConfigHandler.h" -#include "../../lib/CHeroHandler.h" #include "../../lib/IGameSettings.h" #include "../../lib/gameState/CGameState.h" #include "../../lib/bonuses/Limiters.h" diff --git a/CCallback.cpp b/CCallback.cpp index 72b6e8b78..61c741cc8 100644 --- a/CCallback.cpp +++ b/CCallback.cpp @@ -18,7 +18,6 @@ #include "lib/mapObjects/CGHeroInstance.h" #include "lib/mapObjects/CGTownInstance.h" #include "lib/texts/CGeneralTextHandler.h" -#include "lib/CHeroHandler.h" #include "lib/CArtHandler.h" #include "lib/GameConstants.h" #include "lib/CPlayerState.h" diff --git a/CI/android-32/before_install.sh b/CI/android-32/before_install.sh deleted file mode 100755 index 67cacaddf..000000000 --- a/CI/android-32/before_install.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash - -DEPS_FILENAME=dependencies-android-32 -. CI/android/before_install.sh diff --git a/CI/android-64/before_install.sh b/CI/android-64/before_install.sh deleted file mode 100755 index af0a36874..000000000 --- a/CI/android-64/before_install.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash - -DEPS_FILENAME=dependencies-android-64 -. CI/android/before_install.sh diff --git a/CI/android/before_install.sh b/CI/android/before_install.sh deleted file mode 100755 index 146d52110..000000000 --- a/CI/android/before_install.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash - -echo "ANDROID_NDK_ROOT=$ANDROID_HOME/ndk/25.2.9519653" >> $GITHUB_ENV - -brew install ninja - -. CI/install_conan_dependencies.sh "$DEPS_FILENAME" \ No newline at end of file diff --git a/CI/before_install/android.sh b/CI/before_install/android.sh new file mode 100644 index 000000000..9fba7de9f --- /dev/null +++ b/CI/before_install/android.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +sudo apt-get update +sudo apt-get install ninja-build diff --git a/CI/linux/before_install.sh b/CI/before_install/linux_qt5.sh similarity index 80% rename from CI/linux/before_install.sh rename to CI/before_install/linux_qt5.sh index 5df49a521..ebf9faeb1 100644 --- a/CI/linux/before_install.sh +++ b/CI/before_install/linux_qt5.sh @@ -1,6 +1,5 @@ #!/bin/sh -sudo apt remove needrestart sudo apt-get update # Dependencies @@ -9,6 +8,6 @@ sudo apt-get update # - debian build settings at debian/control sudo apt-get install libboost-dev libboost-filesystem-dev libboost-system-dev libboost-thread-dev libboost-program-options-dev libboost-locale-dev libboost-iostreams-dev \ libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev \ -qtbase5-dev \ +qtbase5-dev qttools5-dev \ ninja-build zlib1g-dev libavformat-dev libswscale-dev libtbb-dev libluajit-5.1-dev \ -libminizip-dev libfuzzylite-dev qttools5-dev libsqlite3-dev # Optional dependencies +libminizip-dev libfuzzylite-dev libsqlite3-dev # Optional dependencies diff --git a/CI/linux-qt6/before_install.sh b/CI/before_install/linux_qt6.sh similarity index 76% rename from CI/linux-qt6/before_install.sh rename to CI/before_install/linux_qt6.sh index b88d42704..422b50e98 100644 --- a/CI/linux-qt6/before_install.sh +++ b/CI/before_install/linux_qt6.sh @@ -1,9 +1,11 @@ #!/bin/sh -sudo apt remove needrestart sudo apt-get update # Dependencies +# In case of change in dependencies list please also update: +# - developer docs at docs/developer/Building_Linux.md +# - debian build settings at debian/control sudo apt-get install libboost-dev libboost-filesystem-dev libboost-system-dev libboost-thread-dev libboost-program-options-dev libboost-locale-dev libboost-iostreams-dev \ libsdl2-dev libsdl2-image-dev libsdl2-mixer-dev libsdl2-ttf-dev \ qt6-base-dev qt6-base-dev-tools qt6-tools-dev qt6-tools-dev-tools qt6-l10n-tools \ diff --git a/CI/mac/before_install.sh b/CI/before_install/macos.sh old mode 100755 new mode 100644 similarity index 66% rename from CI/mac/before_install.sh rename to CI/before_install/macos.sh index ed11e87df..0664cc910 --- a/CI/mac/before_install.sh +++ b/CI/before_install/macos.sh @@ -3,5 +3,3 @@ echo DEVELOPER_DIR=/Applications/Xcode_14.2.app >> $GITHUB_ENV brew install ninja - -. CI/install_conan_dependencies.sh "$DEPS_FILENAME" diff --git a/CI/before_install/mingw.sh b/CI/before_install/mingw.sh new file mode 100644 index 000000000..30a865d49 --- /dev/null +++ b/CI/before_install/mingw.sh @@ -0,0 +1,7 @@ +#!/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 +sudo update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-w64-mingw32-g++-posix diff --git a/CI/msvc/before_install.sh b/CI/before_install/msvc.sh similarity index 100% rename from CI/msvc/before_install.sh rename to CI/before_install/msvc.sh diff --git a/CI/conan/base/cross-macro.j2 b/CI/conan/base/cross-macro.j2 index 7f4edf0ee..ba3c53212 100644 --- a/CI/conan/base/cross-macro.j2 +++ b/CI/conan/base/cross-macro.j2 @@ -10,7 +10,7 @@ STRIP={{ target_host }}-strip {%- endmacro -%} {% macro generate_env_win32(target_host) -%} -CONAN_SYSTEM_LIBRARY_LOCATION=/usr/lib/gcc/{{ target_host }}/10-posix/ +CONAN_SYSTEM_LIBRARY_LOCATION=/usr/lib/gcc/{{ target_host }}/13-posix/ RC={{ target_host }}-windres {%- endmacro -%} diff --git a/CI/install_conan_dependencies.sh b/CI/install_conan_dependencies.sh index 2b14811d0..593f96e30 100644 --- a/CI/install_conan_dependencies.sh +++ b/CI/install_conan_dependencies.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -RELEASE_TAG="1.2" +RELEASE_TAG="1.3" FILENAME="$1" DOWNLOAD_URL="https://github.com/vcmi/vcmi-dependencies/releases/download/$RELEASE_TAG/$FILENAME.txz" diff --git a/CI/ios/before_install.sh b/CI/ios/before_install.sh deleted file mode 100755 index a8326e1fd..000000000 --- a/CI/ios/before_install.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -echo DEVELOPER_DIR=/Applications/Xcode_14.2.app >> $GITHUB_ENV - -. CI/install_conan_dependencies.sh "dependencies-ios" diff --git a/CI/linux-qt6/upload_package.sh b/CI/linux-qt6/upload_package.sh deleted file mode 100644 index 1a2485251..000000000 --- a/CI/linux-qt6/upload_package.sh +++ /dev/null @@ -1 +0,0 @@ -#!/bin/sh diff --git a/CI/linux/upload_package.sh b/CI/linux/upload_package.sh deleted file mode 100644 index 1a2485251..000000000 --- a/CI/linux/upload_package.sh +++ /dev/null @@ -1 +0,0 @@ -#!/bin/sh diff --git a/CI/mac-arm/before_install.sh b/CI/mac-arm/before_install.sh deleted file mode 100755 index 41701758b..000000000 --- a/CI/mac-arm/before_install.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash - -DEPS_FILENAME=dependencies-mac-arm -. CI/mac/before_install.sh diff --git a/CI/mac-intel/before_install.sh b/CI/mac-intel/before_install.sh deleted file mode 100755 index a96955b20..000000000 --- a/CI/mac-intel/before_install.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env bash - -DEPS_FILENAME=dependencies-mac-intel -. CI/mac/before_install.sh diff --git a/CI/mingw-32/before_install.sh b/CI/mingw-32/before_install.sh deleted file mode 100644 index 857f4a716..000000000 --- a/CI/mingw-32/before_install.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/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; - -. CI/install_conan_dependencies.sh "dependencies-mingw-32" diff --git a/CI/mingw/before_install.sh b/CI/mingw/before_install.sh deleted file mode 100755 index 70fbaf0d5..000000000 --- a/CI/mingw/before_install.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/usr/bin/env bash - -sudo apt-get update -sudo apt-get install ninja-build mingw-w64 nsis -sudo update-alternatives --set x86_64-w64-mingw32-g++ /usr/bin/x86_64-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-x86-64-dev_10.0.0-3_all.deb \ - && sudo dpkg -i mingw-w64-x86-64-dev_10.0.0-3_all.deb; - -. CI/install_conan_dependencies.sh "dependencies-mingw" diff --git a/CI/msvc/build_script.bat b/CI/msvc/build_script.bat deleted file mode 100644 index 5bd1d8485..000000000 --- a/CI/msvc/build_script.bat +++ /dev/null @@ -1,6 +0,0 @@ -cd %APPVEYOR_BUILD_FOLDER% -cd build_%VCMI_BUILD_PLATFORM% - -cmake --build . --config %VCMI_BUILD_CONFIGURATION% -- /maxcpucount:2 - -cpack diff --git a/CI/msvc/coverity_build_script.bat b/CI/msvc/coverity_build_script.bat deleted file mode 100644 index 9fe2cbf2a..000000000 --- a/CI/msvc/coverity_build_script.bat +++ /dev/null @@ -1,5 +0,0 @@ -cd %APPVEYOR_BUILD_FOLDER% -cd build_%VCMI_BUILD_PLATFORM% - -echo Building with coverity... -cov-build.exe --dir cov-int cmake --build . --config %VCMI_BUILD_CONFIGURATION% -- /maxcpucount:2 diff --git a/CI/msvc/coverity_upload_script.ps b/CI/msvc/coverity_upload_script.ps deleted file mode 100644 index e830ae970..000000000 --- a/CI/msvc/coverity_upload_script.ps +++ /dev/null @@ -1,17 +0,0 @@ -7z a "$Env:APPVEYOR_BUILD_FOLDER\$Env:APPVEYOR_PROJECT_NAME.zip" "$Env:APPVEYOR_BUILD_FOLDER\build_$Env:VCMI_BUILD_PLATFORM\cov-int\" - -# cf. http://stackoverflow.com/a/25045154/335418 -Remove-item alias:curl - -Write-Host "Uploading Coverity analysis result..." -ForegroundColor "Green" - -curl --silent --show-error ` - --output curl-out.txt ` - --form token="$Env:coverity_token" ` - --form email="$Env:coverity_email" ` - --form "file=@$Env:APPVEYOR_BUILD_FOLDER\$Env:APPVEYOR_PROJECT_NAME.zip" ` - --form version="$Env:APPVEYOR_REPO_COMMIT" ` - --form description="CI server scheduled build." ` - https://scan.coverity.com/builds?project=vcmi%2Fvcmi - -cat .\curl-out.txt diff --git a/CI/linux-qt6/validate_json.py b/CI/validate_json.py similarity index 100% rename from CI/linux-qt6/validate_json.py rename to CI/validate_json.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 10c0ca817..78a4a7027 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -180,11 +180,6 @@ else() add_definitions(-DVCMI_NO_EXTRA_VERSION) endif(ENABLE_GITVERSION) -# Precompiled header configuration -if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0 ) - set(ENABLE_PCH OFF) # broken -endif() - if(ENABLE_PCH) macro(enable_pch name) target_precompile_headers(${name} PRIVATE $<$:>) @@ -328,7 +323,6 @@ if(MINGW OR MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4244") # 4244: conversion from 'xxx' to 'yyy', possible loss of data set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4267") # 4267: conversion from 'xxx' to 'yyy', possible loss of data set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4275") # 4275: non dll-interface class 'xxx' used as base for dll-interface class - #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4800") # 4800: implicit conversion from 'xxx' to bool. Possible information loss if(ENABLE_STRICT_COMPILATION) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /WX") # Treats all compiler warnings as errors @@ -493,14 +487,23 @@ if (ENABLE_CLIENT) if(TARGET SDL2_image::SDL2_image) add_library(SDL2::Image ALIAS SDL2_image::SDL2_image) endif() + if(TARGET SDL2_image::SDL2_image-static) + add_library(SDL2::Image ALIAS SDL2_image::SDL2_image-static) + endif() find_package(SDL2_mixer REQUIRED) if(TARGET SDL2_mixer::SDL2_mixer) add_library(SDL2::Mixer ALIAS SDL2_mixer::SDL2_mixer) endif() + if(TARGET SDL2_mixer::SDL2_mixer-static) + add_library(SDL2::Mixer ALIAS SDL2_mixer::SDL2_mixer-static) + endif() find_package(SDL2_ttf REQUIRED) if(TARGET SDL2_ttf::SDL2_ttf) add_library(SDL2::TTF ALIAS SDL2_ttf::SDL2_ttf) endif() + if(TARGET SDL2_ttf::SDL2_ttf-static) + add_library(SDL2::TTF ALIAS SDL2_ttf::SDL2_ttf-static) + endif() endif() if(ENABLE_LOBBY) @@ -727,7 +730,7 @@ endif() if(WIN32) if(TBB_FOUND AND MSVC) - install_vcpkg_imported_tgt(TBB::tbb) + install_vcpkg_imported_tgt(TBB::tbb) endif() if(USING_CONAN) @@ -737,7 +740,9 @@ if(WIN32) ${dep_files} "${CMAKE_SYSROOT}/bin/*.dll" "${CMAKE_SYSROOT}/lib/*.dll" - "${CONAN_SYSTEM_LIBRARY_LOCATION}/*.dll") + "${CONAN_SYSTEM_LIBRARY_LOCATION}/libgcc_s_dw2-1.dll" # for 32-bit only? + "${CONAN_SYSTEM_LIBRARY_LOCATION}/libgcc_s_seh-1.dll" # for 64-bit only? + "${CONAN_SYSTEM_LIBRARY_LOCATION}/libstdc++-6.dll") else() file(GLOB dep_files ${dep_files} diff --git a/Mods/vcmi/config/vcmi/chinese.json b/Mods/vcmi/config/vcmi/chinese.json index a36a923ce..44960a60a 100644 --- a/Mods/vcmi/config/vcmi/chinese.json +++ b/Mods/vcmi/config/vcmi/chinese.json @@ -581,7 +581,7 @@ "core.bonus.GARGOYLE.description": "不能被复活或治疗", "core.bonus.GENERAL_DAMAGE_REDUCTION.name": "减少伤害 (${val}%)", "core.bonus.GENERAL_DAMAGE_REDUCTION.description": "减少从远程和近战中遭受的物理伤害", - "core.bonus.HATE.name": "${subtype.creature}的死敌", + "core.bonus.HATE.name": "憎恨${subtype.creature}", "core.bonus.HATE.description": "对${subtype.creature}造成额外${val}%伤害", "core.bonus.HEALER.name": "治疗者", "core.bonus.HEALER.description": "可以治疗友军单位", diff --git a/Mods/vcmi/config/vcmi/czech.json b/Mods/vcmi/config/vcmi/czech.json index 57625bd43..f0e0e0410 100644 --- a/Mods/vcmi/config/vcmi/czech.json +++ b/Mods/vcmi/config/vcmi/czech.json @@ -12,14 +12,21 @@ "vcmi.adventureMap.monsterThreat.levels.9" : "Převažující", "vcmi.adventureMap.monsterThreat.levels.10" : "Smrtelná", "vcmi.adventureMap.monsterThreat.levels.11" : "Nemožná", + "vcmi.adventureMap.monsterLevel" : "\n\nÚroveň %LEVEL %TOWN %ATTACK_TYPE jednotka", + "vcmi.adventureMap.monsterMeleeType" : "útok zblízka", + "vcmi.adventureMap.monsterRangedType" : "útok na dálku", + "vcmi.adventureMap.search.hover" : "Prohledat mapový objekt", + "vcmi.adventureMap.search.help" : "Vyberte objekt na mapě pro prohledání.", "vcmi.adventureMap.confirmRestartGame" : "Jste si jisti, že chcete restartovat hru?", - "vcmi.adventureMap.noTownWithMarket" : "Nejsou dostupná jakákoliv tržiště!", - "vcmi.adventureMap.noTownWithTavern" : "Nejsou dostupná jakákoliv města s krčmou!", + "vcmi.adventureMap.noTownWithMarket" : "Nejsou dostupné žádne tržnice!", + "vcmi.adventureMap.noTownWithTavern" : "Nejsou dostupná žádná města s putykou!", "vcmi.adventureMap.spellUnknownProblem" : "Neznámý problém s tímto kouzlem! Další informace nejsou k dispozici.", "vcmi.adventureMap.playerAttacked" : "Hráč byl napaden: %s", "vcmi.adventureMap.moveCostDetails" : "Body pohybu - Cena: %TURNS tahů + %POINTS bodů, zbylé body: %REMAINING", "vcmi.adventureMap.moveCostDetailsNoTurns" : "Body pohybu - Cena: %POINTS bodů, zbylé body: %REMAINING", + "vcmi.adventureMap.movementPointsHeroInfo" : "(Body pohybu: %REMAINING / %POINTS)", + "vcmi.adventureMap.replayOpponentTurnNotImplemented" : "Omlouváme se, přehrání tahu soupeře ještě není implementováno!", "vcmi.capitalColors.0" : "Červený", "vcmi.capitalColors.1" : "Modrý", @@ -29,7 +36,7 @@ "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", @@ -41,11 +48,11 @@ "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.heroGetArtifacts" : "Získat artefakty od jiného hrdiny", "vcmi.radialWheel.heroSwapArtifacts" : "Vyměnit artefakty s jiným hrdinou", "vcmi.radialWheel.heroDismiss" : "Propustit hrdinu", @@ -56,6 +63,13 @@ "vcmi.spellBook.search" : "hledat...", + "vcmi.spellResearch.canNotAfford" : "Nemáte dostatek prostředků k nahrazení {%SPELL1} za {%SPELL2}. Stále však můžete toto kouzlo zrušit a pokračovat ve výzkumu kouzel.", + "vcmi.spellResearch.comeAgain" : "Výzkum už byl dnes proveden. Vraťte se zítra.", + "vcmi.spellResearch.pay" : "Chcete nahradit {%SPELL1} za {%SPELL2}? Nebo zrušit toto kouzlo a pokračovat ve výzkumu kouzel?", + "vcmi.spellResearch.research" : "Prozkoumat toto kouzlo", + "vcmi.spellResearch.skip" : "Přeskočit toto kouzlo", + "vcmi.spellResearch.abort" : "Přerušit", + "vcmi.mainMenu.serverConnecting" : "Připojování...", "vcmi.mainMenu.serverAddressEnter" : "Zadejte adresu:", "vcmi.mainMenu.serverConnectionFailed" : "Připojování selhalo", @@ -70,9 +84,14 @@ "vcmi.lobby.noPreview" : "bez náhledu", "vcmi.lobby.noUnderground" : "bez podzemí", "vcmi.lobby.sortDate" : "Řadit mapy dle data změny", - "vcmi.lobby.backToLobby" : "Vrátit se do předsíně", - - "vcmi.lobby.login.title" : "Online předsíň VCMI", + "vcmi.lobby.backToLobby" : "Vrátit se do lobby", + "vcmi.lobby.author" : "Autor", + "vcmi.lobby.handicap" : "Handicap", + "vcmi.lobby.handicap.resource" : "Dává hráčům odpovídající zdroje navíc k běžným startovním zdrojům. Jsou povoleny záporné hodnoty, ale jsou omezeny na celkovou hodnotu 0 (hráč nikdy nezačíná se zápornými zdroji).", + "vcmi.lobby.handicap.income" : "Mění různé příjmy hráče podle procent. Výsledek je zaokrouhlen nahoru.", + "vcmi.lobby.handicap.growth" : "Mění rychlost růstu jednotel v městech vlastněných hráčem. Výsledek je zaokrouhlen nahoru.", + + "vcmi.lobby.login.title" : "Online lobby VCMI", "vcmi.lobby.login.username" : "Uživatelské jméno:", "vcmi.lobby.login.connecting" : "Připojování...", "vcmi.lobby.login.error" : "Chyba při připojování: %s", @@ -135,14 +154,15 @@ "vcmi.client.errors.invalidMap" : "{Neplatná mapa nebo kampaň}\n\nChyba při startu hry! Vybraná mapa nebo kampaň může být neplatná nebo poškozená. Důvod:\n%s", "vcmi.client.errors.missingCampaigns" : "{Chybějící datové soubory}\n\nDatové soubory kampaně nebyly nalezeny! Možná máte nekompletní nebo poškozené datové soubory Heroes 3. Prosíme, přeinstalujte hru.", "vcmi.server.errors.disconnected" : "{Chyba sítě}\n\nPřipojení k hernímu serveru bylo ztraceno!", + "vcmi.server.errors.playerLeft" : "{Hráč opustil hru}\n\nHráč %s se odpojil ze hry!", //%s -> player color "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.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.dimensionDoor.seaToLandError" : "It's not possible to teleport from sea to land or vice versa with a Dimension Door.", //TODO + + "vcmi.dimensionDoor.seaToLandError" : "Pomocí dimenzní brány není možné se teleportovat z moře na pevninu nebo naopak.", "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.", @@ -156,6 +176,38 @@ "vcmi.systemOptions.otherGroup" : "Ostatní nastavení", // unused right now "vcmi.systemOptions.townsGroup" : "Obrazovka města", + "vcmi.statisticWindow.statistics" : "Statistiky", + "vcmi.statisticWindow.tsvCopy" : "Zkopírovat data do schránky", + "vcmi.statisticWindow.selectView" : "Vybrat pohled", + "vcmi.statisticWindow.value" : "Hodnota", + "vcmi.statisticWindow.title.overview" : "Přehled", + "vcmi.statisticWindow.title.resources" : "Zdroje", + "vcmi.statisticWindow.title.income" : "Příjem", + "vcmi.statisticWindow.title.numberOfHeroes" : "Počet hrdinů", + "vcmi.statisticWindow.title.numberOfTowns" : "Počet měst", + "vcmi.statisticWindow.title.numberOfArtifacts" : "Počet artefaktů", + "vcmi.statisticWindow.title.numberOfDwellings" : "Počet obydlí", + "vcmi.statisticWindow.title.numberOfMines" : "Počet dolů", + "vcmi.statisticWindow.title.armyStrength" : "Síla armády", + "vcmi.statisticWindow.title.experience" : "Zkušenosti", + "vcmi.statisticWindow.title.resourcesSpentArmy" : "Náklady na armádu", + "vcmi.statisticWindow.title.resourcesSpentBuildings" : "Náklady na budovy", + "vcmi.statisticWindow.title.mapExplored" : "Prozkoumaná část mapy", + "vcmi.statisticWindow.param.playerName" : "Jméno hráče", + "vcmi.statisticWindow.param.daysSurvived" : "Počet přežitých dní", + "vcmi.statisticWindow.param.maxHeroLevel" : "Maximální úroveň hrdiny", + "vcmi.statisticWindow.param.battleWinRatioHero" : "Poměr výher (proti hrdinům)", + "vcmi.statisticWindow.param.battleWinRatioNeutral" : "Poměr výher (proti neutrálním jednotkám)", + "vcmi.statisticWindow.param.battlesHero" : "Bitev (proti hrdinům)", + "vcmi.statisticWindow.param.battlesNeutral" : "Bitej (proti neutrálním jednotkám)", + "vcmi.statisticWindow.param.maxArmyStrength" : "Maximální síla armády", + "vcmi.statisticWindow.param.tradeVolume" : "Objem obchodu", + "vcmi.statisticWindow.param.obeliskVisited" : "Navštívené obelisky", + "vcmi.statisticWindow.icon.townCaptured" : "Dobyto měst", + "vcmi.statisticWindow.icon.strongestHeroDefeated" : "Nejsilnější hrdina protivníka poražen", + "vcmi.statisticWindow.icon.grailFound" : "Nalezen Svatý grál", + "vcmi.statisticWindow.icon.defeated" : "Porážka", + "vcmi.systemOptions.fullscreenBorderless.hover" : "Celá obrazovka (bez okrajů)", "vcmi.systemOptions.fullscreenBorderless.help" : "{Celá obrazovka bez okrajů}\n\nPokud je vybráno, VCMI poběží v režimu celé obrazovky bez okrajů. V tomto režimu bude hra respektovat systémové rozlišení a ignorovat vybrané rozlišení ve hře.", "vcmi.systemOptions.fullscreenExclusive.hover" : "Celá obrazovka (exkluzivní)", @@ -169,18 +221,18 @@ "vcmi.systemOptions.scalingMenu.hover" : "Vybrat škálování rozhraní", "vcmi.systemOptions.scalingMenu.help" : "Změní škálování herního rozhraní.", "vcmi.systemOptions.longTouchButton.hover" : "Doba dlouhého podržení: %d ms", // Translation note: "ms" = "milliseconds" - "vcmi.systemOptions.longTouchButton.help" : "{Doba dlouhého podržení}\n\nPři používání dotykové obrazovky budou zobrazeno vyskakovací okno při podržení prstu na obrazovce, v milisekundách", + "vcmi.systemOptions.longTouchButton.help" : "{Doba dlouhého podržení}\n\nPři používání dotykové obrazovky bude zobrazeno vyskakovací okno při podržení prstu na obrazovce, v milisekundách", "vcmi.systemOptions.longTouchMenu.hover" : "Vybrat dobu dlouhého podržení", "vcmi.systemOptions.longTouchMenu.help" : "Změnit dobu dlouhého podržení.", "vcmi.systemOptions.longTouchMenu.entry" : "%d milisekund", "vcmi.systemOptions.framerateButton.hover" : "Zobrazit FPS", - "vcmi.systemOptions.framerateButton.help" : "{Zobrazit FPS}\n\nPřepne viditelnost počitadla snímků za sekundu v rohu obrazovky hry.", + "vcmi.systemOptions.framerateButton.help" : "{Zobrazit FPS}\n\nPřepne viditelnost počítadla 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.systemOptions.enableLargeSpellbookButton.help" : "{Velká kniha kouzel}\n\nPovolí větší knihu kouzel, do které se vejde více kouzel na jednu stranu. Animace změny stránek s tímto nastavením nefunguje.", "vcmi.systemOptions.audioMuteFocus.hover" : "Ztlumit při neaktivitě", "vcmi.systemOptions.audioMuteFocus.help" : "{Ztlumit při neaktivitě}\n\nZtlumit zvuk, pokud je okno hry v pozadí. Výjimkou jsou zprávy ve hře a zvuk nového tahu.", @@ -194,18 +246,24 @@ "vcmi.adventureOptions.showGrid.help" : "{Zobrazit mřížku}\n\nZobrazit překrytí mřížkou, zvýrazňuje hranice mezi dlaždicemi mapy světa.", "vcmi.adventureOptions.borderScroll.hover" : "Posouvání okraji", "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.infoBarCreatureManagement.hover" : "Správa jednotek v informačním panelu", + "vcmi.adventureOptions.infoBarCreatureManagement.help" : "{Správa jednotek v informačním panelu}\n\nUmožňuje přeskupovat jednotky v informačním panelu namísto procházení standardních informací.", "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.rightButtonDrag.hover" : "Přetahování pravým tlačítkem", + "vcmi.adventureOptions.rightButtonDrag.help" : "{Přetahování pravým tlačítkem}\n\nKdyž je povoleno, pohyb myší se stisknutým pravým tlačítkem bude posouvat pohled na mapě dobrodružství.", "vcmi.adventureOptions.smoothDragging.hover" : "Plynulé posouvání mapy", - "vcmi.adventureOptions.smoothDragging.help" : "{Plynulé posouvání mapy}\n\nWhen enabled, map dragging has a modern run out effect.", // TODO + "vcmi.adventureOptions.smoothDragging.help" : "{Plynulé posouvání mapy}\n\nPokud je tato možnost aktivována, posouvání mapy bude plynulé.", + "vcmi.adventureOptions.skipAdventureMapAnimations.hover" : "Přeskočit efekty mizení", + "vcmi.adventureOptions.skipAdventureMapAnimations.help" : "{Přeskočit efekty mizení}\n\nKdyž je povoleno, přeskočí se efekty mizení objektů a podobné efekty (sběr surovin, nalodění atd.). V některých případech zrychlí uživatelské rozhraní na úkor estetiky. Obzvláště užitečné v PvP hrách. Pro maximální rychlost pohybu je toto nastavení aktivní bez ohledu na další volby.", "vcmi.adventureOptions.mapScrollSpeed1.hover": "", "vcmi.adventureOptions.mapScrollSpeed5.hover": "", "vcmi.adventureOptions.mapScrollSpeed6.hover": "", "vcmi.adventureOptions.mapScrollSpeed1.help": "Nastavit posouvání mapy na velmi pomalé", "vcmi.adventureOptions.mapScrollSpeed5.help": "Nastavit posouvání mapy na velmi rychlé", "vcmi.adventureOptions.mapScrollSpeed6.help": "Nastavit posouvání mapy na okamžité", + "vcmi.adventureOptions.hideBackground.hover" : "Skrýt pozadí", + "vcmi.adventureOptions.hideBackground.help" : "{Skrýt pozadí}\n\nSkryje mapu dobrodružství na pozadí a místo ní zobrazí texturu.", "vcmi.battleOptions.queueSizeLabel.hover": "Zobrazit frontu pořadí tahů", "vcmi.battleOptions.queueSizeNoneButton.hover": "VYPNUTO", @@ -230,9 +288,13 @@ "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.battleOptions.endWithAutocombat.hover": "Ukončit bitvu", + "vcmi.battleOptions.endWithAutocombat.help": "{Ukončit bitvu}\n\nAutomatický boj okamžitě dohraje bitvu do konce.", + "vcmi.battleOptions.showQuickSpell.hover": "Zobrazit rychlý panel kouzel", + "vcmi.battleOptions.showQuickSpell.help": "{Zobrazit rychlý panel kouzel}\n\nZobrazí panel pro rychlý výběr kouzel.", - "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.adventureMap.revisitObject.hover" : "Znovu navštívit objekt", + "vcmi.adventureMap.revisitObject.help" : "{Znovu navštívit objekt}\n\nPokud hrdina právě stojí na objektu na mapě, může toto místo 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).", @@ -245,18 +307,18 @@ "vcmi.battleWindow.damageEstimation.damage.1" : "%d poškození", "vcmi.battleWindow.damageEstimation.kills" : "%d zahyne", "vcmi.battleWindow.damageEstimation.kills.1" : "%d zahyne", - - "vcmi.battleWindow.damageRetaliation.will" : "Zahyne ", - "vcmi.battleWindow.damageRetaliation.may" : "Možná zahyne ", - "vcmi.battleWindow.damageRetaliation.never" : "Nezahyne.", + + "vcmi.battleWindow.damageRetaliation.will" : "Provede odvetu", + "vcmi.battleWindow.damageRetaliation.may" : "Může provést odvetu", + "vcmi.battleWindow.damageRetaliation.never" : "Neprovede odvetu.", "vcmi.battleWindow.damageRetaliation.damage" : "(%DAMAGE).", "vcmi.battleWindow.damageRetaliation.damageKills" : "(%DAMAGE, %KILLS).", - "vcmi.battleWindow.killed" : "Zabito", //TODO - "vcmi.battleWindow.accurateShot.resultDescription.0" : "%d %s were killed by accurate shots!", - "vcmi.battleWindow.accurateShot.resultDescription.1" : "%d %s was killed with an accurate shot!", - "vcmi.battleWindow.accurateShot.resultDescription.2" : "%d %s were killed by accurate shots!", - "vcmi.battleWindow.endWithAutocombat" : "Are you sure you wish to end the battle with auto combat?", + "vcmi.battleWindow.killed" : "Zabito", + "vcmi.battleWindow.accurateShot.resultDescription.0" : "%d %s bylo zabito přesnými zásahy!", + "vcmi.battleWindow.accurateShot.resultDescription.1" : "%d %s byl zabit přesným zásahem!", + "vcmi.battleWindow.accurateShot.resultDescription.2" : "%d %s bylo zabito přesnými zásahy!", + "vcmi.battleWindow.endWithAutocombat" : "Opravdu chcete ukončit bitvu s automatickým bojem?", "vcmi.battleResultsWindow.applyResultsLabel" : "Použít výsledek bitvy", @@ -264,7 +326,7 @@ "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.RadialWheel" : "Přejetí otevře kruhovou nabídku pro různé akce, třeba správa hrdiny/jednotek 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.", @@ -276,26 +338,38 @@ "vcmi.otherOptions.compactTownCreatureInfo.hover": "Kompaktní informace o jednotkách", "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í!", + "vcmi.townHall.missingBase" : "Nejdříve musí být postavena základní budova %s", + "vcmi.townHall.noCreaturesToRecruit" : "Nejsou k dispozici žádné jednotky k najmutí!", + + "vcmi.townStructure.bank.borrow" : "Vstupujete do banky. Bankéř vás spatří a říká: \"Máme pro vás speciální nabídku. Můžete si vzít půjčku 2500 zlata na 5 dní. Každý den budete muset splácet 500 zlata.\"", + "vcmi.townStructure.bank.payBack" : "Vstupujete do banky. Bankéř vás spatří a říká: \"Již jste si vzali půjčku. Nejprve ji splaťte, než si vezmete další.\"", "vcmi.logicalExpressions.anyOf" : "Něco z následujících:", "vcmi.logicalExpressions.allOf" : "Všechny následující:", "vcmi.logicalExpressions.noneOf" : "Žádné z následujících:", - "vcmi.heroWindow.openCommander.hover" : "Open commander info window", - "vcmi.heroWindow.openCommander.help" : "Shows details about the commander of this hero.", - "vcmi.heroWindow.openBackpack.hover" : "Open artifact backpack window", - "vcmi.heroWindow.openBackpack.help" : "Opens window that allows easier artifact backpack management.", + "vcmi.heroWindow.openCommander.hover" : "Otevřít okno s informacemi o veliteli", + "vcmi.heroWindow.openCommander.help" : "Zobrazí podrobnosti o veliteli tohoto hrdiny.", + "vcmi.heroWindow.openBackpack.hover" : "Otevřít okno s artefakty", + "vcmi.heroWindow.openBackpack.help" : "Otevře okno, které umožňuje snadnější správu artefaktů v batohu.", + "vcmi.heroWindow.sortBackpackByCost.hover" : "Seřadit podle ceny", + "vcmi.heroWindow.sortBackpackByCost.help" : "Seřadí artefakty v batohu podle ceny.", + "vcmi.heroWindow.sortBackpackBySlot.hover" : "Seřadit podle slotu", + "vcmi.heroWindow.sortBackpackBySlot.help" : "Seřadí artefakty v batohu podle přiřazeného slotu.", + "vcmi.heroWindow.sortBackpackByClass.hover" : "Seřadit podle třídy", + "vcmi.heroWindow.sortBackpackByClass.help" : "Seřadí artefakty v batohu podle třídy artefaktu. Poklad, Menší, Větší, Relikvie.", + "vcmi.heroWindow.fusingArtifact.fusing" : "Máte všechny potřebné části k vytvoření %s. Chcete provést sloučení? {Při sloučení budou použity všechny části.}", - "vcmi.commanderWindow.artifactMessage" : "Chcete navrátit tento artefakt hrdinovi?", + "vcmi.tavernWindow.inviteHero" : "Pozvat hrdinu", + + "vcmi.commanderWindow.artifactMessage" : "Chcete tento artefakt vrátit hrdinovi?", "vcmi.creatureWindow.showBonuses.hover" : "Přepnout na zobrazení bonusů", - "vcmi.creatureWindow.showBonuses.help" : "Display all active bonuses of the commander.", - "vcmi.creatureWindow.showSkills.hover" : "Přepnout na zobrazení schoostí", - "vcmi.creatureWindow.showSkills.help" : "Display all learned skills of the commander.", + "vcmi.creatureWindow.showBonuses.help" : "Zobrazí všechny aktivní bonusy velitele.", + "vcmi.creatureWindow.showSkills.hover" : "Přepnout na zobrazení dovedností", + "vcmi.creatureWindow.showSkills.help" : "Zobrazí všechny naučené dovednosti velitele.", "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.creatureWindow.returnArtifact.help" : "Klikněte na toto tlačítko pro vrácení artefaktu do batohu hrdiny.", "vcmi.questLog.hideComplete.hover" : "Skrýt dokončené úkoly", "vcmi.questLog.hideComplete.help" : "Skrýt všechny dokončené úkoly.", @@ -371,21 +445,22 @@ "vcmi.optionsTab.extraOptions.help" : "Další herní možnosti", "vcmi.optionsTab.cheatAllowed.hover" : "Povolit cheaty", - "vcmi.optionsTab.unlimitedReplay.hover" : "Unlimited battle replay", + "vcmi.optionsTab.unlimitedReplay.hover" : "Neomezené opakování bitvy", "vcmi.optionsTab.cheatAllowed.help" : "{Povolit cheaty}\nPovolí zadávání cheatů během hry.", - "vcmi.optionsTab.unlimitedReplay.help" : "{Unlimited battle replay}\nNo limit of replaying battles.", + "vcmi.optionsTab.unlimitedReplay.help" : "{Neomezené opakování bitvy}\nŽádné omezení pro opakování bitev.", // 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!", "vcmi.map.victoryCondition.daysPassed.toSelf" : "Gratulace! Zvládli jste přežít. Vítězství je vaše!", - "vcmi.map.victoryCondition.eliminateMonsters.toOthers" : "Nepřítel porazil všechny bojovníky zamořující tuto zemi a nárokuje si vítězství!", + "vcmi.map.victoryCondition.eliminateMonsters.toOthers" : "Nepřítel porazil všechny jednotky zamořující tuto zemi a nárokuje si vítězství!", "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 utužte Andělskou alianci", + "vcmi.map.victoryCondition.angelicAlliancePartLost.toSelf" : "Bohužel, ztratili jste část Andělské aliance. Vše je ztraceno.", // few strings from WoG used by vcmi - "vcmi.stackExperience.description" : "» P o d r o b n o s t i z k u š e n o s t í o d d í l u «\n\nDruh bojovníka ................... : %s\nÚroveň hodnosti ................. : %s (%i)\nBody zkušeností ............... : %i\nZkušenostních bodů do další úrovně hodnosti .. : %i\nMaximum zkušeností na bitvu ... : %i%% (%i)\nPočet bojovníků v oddílu .... : %i\nMaximum nových rekrutů\n bez ztráty současné hodnosti .... : %i\nNásobič zkušeností ........... : %.2f\nNásobič vylepšení .............. : %.2f\nZkušnosti po 10. úrovně hodnosti ........ : %i\nMaximální počet nových rekrutů pro zachování\n 10. úrovně hodnosti s maximálními zkušenostmi: %i", + "vcmi.stackExperience.description" : "» P o d r o b n o s t i z k u š e n o s t í o d d í l u «\n\nDruh jednotky ................... : %s\nÚroveň hodnosti ................. : %s (%i)\nBody zkušeností ............... : %i\nZkušenostních bodů do další úrovně hodnosti .. : %i\nMaximum zkušeností na bitvu ... : %i%% (%i)\nPočet jednotek v oddílu .... : %i\nMaximum nových rekrutů\n bez ztráty současné hodnosti .... : %i\nNásobič zkušeností ........... : %.2f\nNásobič vylepšení .............. : %.2f\nZkušnosti po 10. úrovně hodnosti ........ : %i\nMaximální počet nových rekrutů pro zachování\n 10. úrovně hodnosti s maximálními zkušenostmi: %i", "vcmi.stackExperience.rank.0" : "Začátečník", "vcmi.stackExperience.rank.1" : "Učeň", "vcmi.stackExperience.rank.2" : "Trénovaný", @@ -398,151 +473,219 @@ "vcmi.stackExperience.rank.9" : "Mistr", "vcmi.stackExperience.rank.10" : "Eso", - "core.bonus.ADDITIONAL_ATTACK.name": "Dvojitý úder", + // Strings for HotA Seer Hut / Quest Guards + "core.seerhut.quest.heroClass.complete.0" : "Ah, vy jste %s. Tady máte dárek. Přijmete ho?", + "core.seerhut.quest.heroClass.complete.1" : "Ah, vy jste %s. Tady máte dárek. Přijmete ho?", + "core.seerhut.quest.heroClass.complete.2" : "Ah, vy jste %s. Tady máte dárek. Přijmete ho?", + "core.seerhut.quest.heroClass.complete.3" : "Stráže si všimly, že jste %s a nabízejí vám průchod. Přijmete to?", + "core.seerhut.quest.heroClass.complete.4" : "Stráže si všimly, že jste %s a nabízejí vám průchod. Přijmete to?", + "core.seerhut.quest.heroClass.complete.5" : "Stráže si všimly, že jste %s a nabízejí vám průchod. Přijmete to?", + "core.seerhut.quest.heroClass.description.0" : "Pošlete %s do %s", + "core.seerhut.quest.heroClass.description.1" : "Pošlete %s do %s", + "core.seerhut.quest.heroClass.description.2" : "Pošlete %s do %s", + "core.seerhut.quest.heroClass.description.3" : "Pošlete %s, aby otevřel bránu", + "core.seerhut.quest.heroClass.description.4" : "Pošlete %s, aby otevřel bránu", + "core.seerhut.quest.heroClass.description.5" : "Pošlete %s, aby otevřel bránu", + "core.seerhut.quest.heroClass.hover.0" : "(hledá hrdinu třídy %s)", + "core.seerhut.quest.heroClass.hover.1" : "(hledá hrdinu třídy %s)", + "core.seerhut.quest.heroClass.hover.2" : "(hledá hrdinu třídy %s)", + "core.seerhut.quest.heroClass.hover.3" : "(hledá hrdinu třídy %s)", + "core.seerhut.quest.heroClass.hover.4" : "(hledá hrdinu třídy %s)", + "core.seerhut.quest.heroClass.hover.5" : "(hledá hrdinu třídy %s)", + "core.seerhut.quest.heroClass.receive.0" : "Mám dárek pro %s.", + "core.seerhut.quest.heroClass.receive.1" : "Mám dárek pro %s.", + "core.seerhut.quest.heroClass.receive.2" : "Mám dárek pro %s.", + "core.seerhut.quest.heroClass.receive.3" : "Stráže říkají, že průchod povolí pouze %s.", + "core.seerhut.quest.heroClass.receive.4" : "Stráže říkají, že průchod povolí pouze %s.", + "core.seerhut.quest.heroClass.receive.5" : "Stráže říkají, že průchod povolí pouze %s.", + "core.seerhut.quest.heroClass.visit.0" : "Nejste %s. Nemám pro vás nic. Zmizte!", + "core.seerhut.quest.heroClass.visit.1" : "Nejste %s. Nemám pro vás nic. Zmizte!", + "core.seerhut.quest.heroClass.visit.2" : "Nejste %s. Nemám pro vás nic. Zmizte!", + "core.seerhut.quest.heroClass.visit.3" : "Stráže zde povolí průchod pouze %s.", + "core.seerhut.quest.heroClass.visit.4" : "Stráže zde povolí průchod pouze %s.", + "core.seerhut.quest.heroClass.visit.5" : "Stráže zde povolí průchod pouze %s.", + + "core.seerhut.quest.reachDate.complete.0" : "Jsem nyní volný. Tady máte, co jsem pro vás měl. Přijmete to?", + "core.seerhut.quest.reachDate.complete.1" : "Jsem nyní volný. Tady máte, co jsem pro vás měl. Přijmete to?", + "core.seerhut.quest.reachDate.complete.2" : "Jsem nyní volný. Tady máte, co jsem pro vás měl. Přijmete to?", + "core.seerhut.quest.reachDate.complete.3" : "Nyní můžete projít. Chcete pokračovat?", + "core.seerhut.quest.reachDate.complete.4" : "Nyní můžete projít. Chcete pokračovat?", + "core.seerhut.quest.reachDate.complete.5" : "Nyní můžete projít. Chcete pokračovat?", + "core.seerhut.quest.reachDate.description.0" : "Čekejte do %s pro %s", + "core.seerhut.quest.reachDate.description.1" : "Čekejte do %s pro %s", + "core.seerhut.quest.reachDate.description.2" : "Čekejte do %s pro %s", + "core.seerhut.quest.reachDate.description.3" : "Čekejte do %s, abyste otevřeli bránu", + "core.seerhut.quest.reachDate.description.4" : "Čekejte do %s, abyste otevřeli bránu", + "core.seerhut.quest.reachDate.description.5" : "Čekejte do %s, abyste otevřeli bránu", + "core.seerhut.quest.reachDate.hover.0" : "(Vraťte se nejdříve %s)", + "core.seerhut.quest.reachDate.hover.1" : "(Vraťte se nejdříve %s)", + "core.seerhut.quest.reachDate.hover.2" : "(Vraťte se nejdříve %s)", + "core.seerhut.quest.reachDate.hover.3" : "(Vraťte se nejdříve %s)", + "core.seerhut.quest.reachDate.hover.4" : "(Vraťte se nejdříve %s)", + "core.seerhut.quest.reachDate.hover.5" : "(Vraťte se nejdříve %s)", + "core.seerhut.quest.reachDate.receive.0" : "Jsem zaneprázdněný. Vraťte se nejdříve %s", + "core.seerhut.quest.reachDate.receive.1" : "Jsem zaneprázdněný. Vraťte se nejdříve %s", + "core.seerhut.quest.reachDate.receive.2" : "Jsem zaneprázdněný. Vraťte se nejdříve %s", + "core.seerhut.quest.reachDate.receive.3" : "Zavřeno do %s.", + "core.seerhut.quest.reachDate.receive.4" : "Zavřeno do %s.", + "core.seerhut.quest.reachDate.receive.5" : "Zavřeno do %s.", + "core.seerhut.quest.reachDate.visit.0" : "Jsem zaneprázdněný. Vraťte se nejdříve %s.", + "core.seerhut.quest.reachDate.visit.1" : "Jsem zaneprázdněný. Vraťte se nejdříve %s.", + "core.seerhut.quest.reachDate.visit.2" : "Jsem zaneprázdněný. Vraťte se nejdříve %s.", + "core.seerhut.quest.reachDate.visit.3" : "Zavřeno do %s.", + "core.seerhut.quest.reachDate.visit.4" : "Zavřeno do %s.", + "core.seerhut.quest.reachDate.visit.5" : "Zavřeno do %s.", + + "core.bonus.ADDITIONAL_ATTACK.name": "Dvojitý útok", "core.bonus.ADDITIONAL_ATTACK.description": "Útočí dvakrát", - "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": "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.ADDITIONAL_RETALIATION.name": "Další odvetné útoky", + "core.bonus.ADDITIONAL_RETALIATION.description": "Může odvetně zaútočit ${val} krát navíc", + "core.bonus.AIR_IMMUNITY.name": "Odolnost vůči vzdušné magii", + "core.bonus.AIR_IMMUNITY.description": "Imunní vůči všem kouzlům školy vzdušné magie", + "core.bonus.ATTACKS_ALL_ADJACENT.name": "Útok na všechny kolem", + "core.bonus.ATTACKS_ALL_ADJACENT.description": "Útočí na všechny sousední nepřátele", "core.bonus.BLOCKS_RETALIATION.name": "Žádná odveta", - "core.bonus.BLOCKS_RETALIATION.description": "Nepřítel nemůže zaútočit zpět", - "core.bonus.BLOCKS_RANGED_RETALIATION.name": "Žádná odveta na dálku", - "core.bonus.BLOCKS_RANGED_RETALIATION.description": "Nepřítel nemůže zaútočit zpět útokem na dálku", + "core.bonus.BLOCKS_RETALIATION.description": "Nepřítel nemůže odvetně zaútočit", + "core.bonus.BLOCKS_RANGED_RETALIATION.name": "Žádná střelecká odveta", + "core.bonus.BLOCKS_RANGED_RETALIATION.description": "Nepřítel nemůže odvetně zaútočit střeleckým útokem", "core.bonus.CATAPULT.name": "Katapult", "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_ALLY.description": "Snižuje náklady na kouzla pro hrdinu 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.CHANGES_SPELL_COST_FOR_ENEMY.description": "Zvyšuje náklady na kouzla nepřítele o ${val}", + "core.bonus.CHARGE_IMMUNITY.name": "Odolnost vůči Nájezdu", + "core.bonus.CHARGE_IMMUNITY.description": "Imunní vůči Nájezdu Jezdců a Šampionů", "core.bonus.DARKNESS.name": "Závoj temnoty", - "core.bonus.DARKNESS.description": "Vytvoří clonu temnoty v oblasti ${val} polí", + "core.bonus.DARKNESS.description": "Vytváří závoj temnoty s poloměrem ${val}", "core.bonus.DEATH_STARE.name": "Smrtící pohled (${val}%)", - "core.bonus.DEATH_STARE.description": "Má ${val}% šanci zabít jednu creature", + "core.bonus.DEATH_STARE.description": "Má ${val}% šanci zabít jednu jednotku", "core.bonus.DEFENSIVE_STANCE.name": "Obranný bonus", - "core.bonus.DEFENSIVE_STANCE.description": "+${val} obranné síly při obraně", + "core.bonus.DEFENSIVE_STANCE.description": "+${val} k obraně při bránění", "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": "Jednotka má povahu draka", - "core.bonus.EARTH_IMMUNITY.name": "Zemní odolnost", - "core.bonus.EARTH_IMMUNITY.description": "Imunní všem kouzlům školy zemské magie", + "core.bonus.DOUBLE_DAMAGE_CHANCE.name": "Smrtelný úder", + "core.bonus.DOUBLE_DAMAGE_CHANCE.description": "Má ${val}% šanci způsobit dvojnásobné základní poškození při útoku", + "core.bonus.DRAGON_NATURE.name": "Dračí povaha", + "core.bonus.DRAGON_NATURE.description": "Jednotka má Dračí povahu", + "core.bonus.EARTH_IMMUNITY.name": "Odolnost vůči zemské magii", + "core.bonus.EARTH_IMMUNITY.description": "Imunní vůči 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.ENCHANTER.description": "Může každé kolo sesílat masové kouzlo ${subtype.spell}", "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_ATTACK_REDUCTION.description": "When being attacked, ${val}% of the attacker's attack is ignored", - "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": "Imunní všem kouzlům školy ohnivé magie", + "core.bonus.ENCHANTED.description": "Je pod trvalým účinkem kouzla ${subtype.spell}", + "core.bonus.ENEMY_ATTACK_REDUCTION.name": "Ignorování útoku (${val}%)", + "core.bonus.ENEMY_ATTACK_REDUCTION.description": "Při útoku je ignorováno ${val}% útočníkovy síly", + "core.bonus.ENEMY_DEFENCE_REDUCTION.name": "Ignorování obrany (${val}%)", + "core.bonus.ENEMY_DEFENCE_REDUCTION.description": "Pří útoku nebude bráno v potaz ${val}% bodů obrany obránce", + "core.bonus.FIRE_IMMUNITY.name": "Odolnost vůči ohnivé magii", + "core.bonus.FIRE_IMMUNITY.description": "Imunní vůči všem kouzlům školy ohnivé magie", "core.bonus.FIRE_SHIELD.name": "Ohnivý štít (${val}%)", - "core.bonus.FIRE_SHIELD.description": "Odrazí část zranení útoku zblízka", + "core.bonus.FIRE_SHIELD.description": "Odrazí část zranění při útoku z blízka", "core.bonus.FIRST_STRIKE.name": "První úder", - "core.bonus.FIRST_STRIKE.description": "Tato jednotka provede odvetu ještě než je na ni zaútočeno", + "core.bonus.FIRST_STRIKE.description": "Tato jednotka útočí dříve, než je napadena", "core.bonus.FEAR.name": "Strach", - "core.bonus.FEAR.description": "Způsobí strach nepřátelskému oddílu", + "core.bonus.FEAR.description": "Vyvolává strach u nepřátelské jednotky", "core.bonus.FEARLESS.name": "Nebojácnost", - "core.bonus.FEARLESS.description": "Odolnost proti strachu", - "core.bonus.FEROCITY.name": "Ferocity", //TODO - "core.bonus.FEROCITY.description": "Attacks ${val} additional times if killed anybody", - "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.FEARLESS.description": "Imunní vůči schopnosti Strach", + "core.bonus.FEROCITY.name": "Zuřivost", + "core.bonus.FEROCITY.description": "Útočí ${val} krát navíc, pokud někoho zabije", + "core.bonus.FLYING.name": "Létání", + "core.bonus.FLYING.description": "Při pohybu létá (ignoruje překážky)", + "core.bonus.FREE_SHOOTING.name": "Střelba zblízka", + "core.bonus.FREE_SHOOTING.description": "Může použít výstřely i při útoku zblízka", "core.bonus.GARGOYLE.name": "Chrlič", - "core.bonus.GARGOYLE.description": "Cannot be raised or healed", // TODO + "core.bonus.GARGOYLE.description": "Nemůže být oživen ani vyléčen", "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": "Dává o ${val} % větší zranění jednotce ${subtype.creature}", + "core.bonus.HATE.name": "Nenávidí ${subtype.creature}", + "core.bonus.HATE.description": "Způsobuje ${val}% více poškození vůči ${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": "Nabití šampiona", + "core.bonus.HP_REGENERATION.description": "Každé kolo regeneruje ${val} bodů zdraví", + "core.bonus.JOUSTING.name": "Nájezd šampionů", "core.bonus.JOUSTING.description": "+${val}% poškození za každé projité pole", "core.bonus.KING.name": "Král", - "core.bonus.KING.description": "Zranitelný zabijákovi úrovně ${val} a vyšší", + "core.bonus.KING.description": "Zranitelný proti 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": "${val}% kouzelný kanál", - "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.LIMITED_SHOOTING_RANGE.name": "Omezený dostřel", + "core.bonus.LIMITED_SHOOTING_RANGE.description": "Není schopen zasáhnout jednotky vzdálenější než ${val} polí", + "core.bonus.LIFE_DRAIN.name": "Vysávání života (${val}%)", + "core.bonus.LIFE_DRAIN.description": "Vysává ${val}% způsobeného poškození", + "core.bonus.MANA_CHANNELING.name": "Kanál magie ${val}%", + "core.bonus.MANA_CHANNELING.description": "Poskytuje vašemu hrdinovi ${val}% many použité nepřítelem", + "core.bonus.MANA_DRAIN.name": "Vysávání many", + "core.bonus.MANA_DRAIN.description": "Vysává ${val} many každý tah", + "core.bonus.MAGIC_MIRROR.name": "Magické zrcadlo (${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.MAGIC_RESISTANCE.description": "Má ${val}% šanci odolat nepřátelskému kouzlu", + "core.bonus.MIND_IMMUNITY.name": "Imunita vůči kouzlům mysli", + "core.bonus.MIND_IMMUNITY.description": "Imunní vůči kouzlům mysli", + "core.bonus.NO_DISTANCE_PENALTY.name": "Žádná penalizace vzdálenosti", + "core.bonus.NO_DISTANCE_PENALTY.description": "Způsobuje 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_MORALE.description": "Jednotka je imunní vůči efektům 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.NO_WALL_PENALTY.description": "Plné poškození během obléhání", + "core.bonus.NON_LIVING.name": "Neživý", "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á odveta", + "core.bonus.RANGED_RETALIATION.name": "Střelecká odveta", "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.RECEPTIVE.name": "Vnímavý", + "core.bonus.RECEPTIVE.description": "Nemá imunitu na přátelská kouzla", "core.bonus.REBIRTH.name": "Znovuzrození (${val}%)", - "core.bonus.REBIRTH.description": "${val}% oddílu se po smrti znovu narodí", + "core.bonus.REBIRTH.description": "${val}% jednotek povstane po smrti", "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.REVENGE.name": "Msta", - "core.bonus.REVENGE.description": "Deals extra damage based on attacker's lost health in battle", //TODO + "core.bonus.RETURN_AFTER_STRIKE.description": "Navrátí se po útoku na zblízka", + "core.bonus.REVENGE.name": "Pomsta", + "core.bonus.REVENGE.description": "Způsobuje extra poškození na základě ztrát útočníka v bitvě", "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.SHOOTS_ALL_ADJACENT.name": "Střílí všude kolem", + "core.bonus.SHOOTS_ALL_ADJACENT.description": "Střelecký útok této jednotky zasáhne 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.SOUL_STEAL.description": "Získává ${val} nové jednotky 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.SPELLCASTER.description": "Může seslat kouzlo ${subtype.spell}", + "core.bonus.SPELL_AFTER_ATTACK.name": "Sesílá po útoku", + "core.bonus.SPELL_AFTER_ATTACK.description": "Má ${val}% šanci seslat ${subtype.spell} po útoku", + "core.bonus.SPELL_BEFORE_ATTACK.name": "Sesílá před útokem", + "core.bonus.SPELL_BEFORE_ATTACK.description": "Má ${val}% šanci seslat ${subtype.spell} před útokem", "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_DAMAGE_REDUCTION.description": "Poškození kouzly sníženo o ${val}%.", + "core.bonus.SPELL_IMMUNITY.name": "Imunita vůči kouzlům", + "core.bonus.SPELL_IMMUNITY.description": "Imunní vůči ${subtype.spell}", "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", //TODO + "core.bonus.SPELL_RESISTANCE_AURA.name": "Aura odporu", + "core.bonus.SPELL_RESISTANCE_AURA.description": "Jednotky poblíž získají ${val}% magickou odolnost", + "core.bonus.SUMMON_GUARDIANS.name": "Přivolání ochránců", + "core.bonus.SUMMON_GUARDIANS.description": "Na začátku bitvy přivolá ${subtype.creature} (${val}%)", + "core.bonus.SYNERGY_TARGET.name": "Synergizovatelný", + "core.bonus.SYNERGY_TARGET.description": "Tato jednotka je náchylná k synergickým efektům", "core.bonus.TWO_HEX_ATTACK_BREATH.name": "Dech", - "core.bonus.TWO_HEX_ATTACK_BREATH.description": "Dechový útok (dosah do dvou polí)", + "core.bonus.TWO_HEX_ATTACK_BREATH.description": "Útok dechem (dosah 2 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.TRANSMUTATION.description": "${val}% šance na přeměnu napadené jednotky na jiný typ", "core.bonus.UNDEAD.name": "Nemrtvý", "core.bonus.UNDEAD.description": "Jednotka je nemrtvá", - "core.bonus.UNLIMITED_RETALIATIONS.name": "Neomezené odvety", - "core.bonus.UNLIMITED_RETALIATIONS.description": "Může provést odvetu 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.UNLIMITED_RETALIATIONS.name": "Neomezené odvetné útoky", + "core.bonus.UNLIMITED_RETALIATIONS.description": "Může provést neomezený počet odvetných útoků", + "core.bonus.WATER_IMMUNITY.name": "Odolnost vůči vodní magii", + "core.bonus.WATER_IMMUNITY.description": "Imunní vůči 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í)" + "core.bonus.WIDE_BREATH.description": "Široký útok dechem (více polí)", + "core.bonus.DISINTEGRATE.name": "Rozpad", + "core.bonus.DISINTEGRATE.description": "Po smrti nezůstane žádné tělo", + "core.bonus.INVINCIBLE.name": "Neporazitelný", + "core.bonus.INVINCIBLE.description": "Nelze ovlivnit žádným efektem" } diff --git a/Mods/vcmi/config/vcmi/english.json b/Mods/vcmi/config/vcmi/english.json index ce9bc9e45..2cb7b5772 100644 --- a/Mods/vcmi/config/vcmi/english.json +++ b/Mods/vcmi/config/vcmi/english.json @@ -15,6 +15,8 @@ "vcmi.adventureMap.monsterLevel" : "\n\nLevel %LEVEL %TOWN %ATTACK_TYPE unit", "vcmi.adventureMap.monsterMeleeType" : "melee", "vcmi.adventureMap.monsterRangedType" : "ranged", + "vcmi.adventureMap.search.hover" : "Search map object", + "vcmi.adventureMap.search.help" : "Select object to search on map.", "vcmi.adventureMap.confirmRestartGame" : "Are you sure you want to restart the game?", "vcmi.adventureMap.noTownWithMarket" : "There are no available marketplaces!", @@ -356,6 +358,7 @@ "vcmi.heroWindow.sortBackpackBySlot.help" : "Sort artifacts in backpack by equipped slot.", "vcmi.heroWindow.sortBackpackByClass.hover" : "Sort by class", "vcmi.heroWindow.sortBackpackByClass.help" : "Sort artifacts in backpack by artifact class. Treasure, Minor, Major, Relic", + "vcmi.heroWindow.fusingArtifact.fusing" : "You possess all of the components needed for the fusion of the %s. Do you wish to perform the fusion? {All components will be consumed upon fusion.}", "vcmi.tavernWindow.inviteHero" : "Invite hero", diff --git a/Mods/vcmi/config/vcmi/german.json b/Mods/vcmi/config/vcmi/german.json index 24952b3f4..5d6abf103 100644 --- a/Mods/vcmi/config/vcmi/german.json +++ b/Mods/vcmi/config/vcmi/german.json @@ -15,6 +15,8 @@ "vcmi.adventureMap.monsterLevel" : "\n\nStufe %LEVEL %TOWN-Einheit (%ATTACK_TYPE)", "vcmi.adventureMap.monsterMeleeType" : "Nahkampf", "vcmi.adventureMap.monsterRangedType" : "Fernkampf", + "vcmi.adventureMap.search.hover" : "Suche Kartenobjekt", + "vcmi.adventureMap.search.help" : "Wähle Objekt das gesucht werden soll.", "vcmi.adventureMap.confirmRestartGame" : "Seid Ihr sicher, dass Ihr das Spiel neu starten wollt?", "vcmi.adventureMap.noTownWithMarket" : "Kein Marktplatz verfügbar!", diff --git a/Mods/vcmi/config/vcmi/polish.json b/Mods/vcmi/config/vcmi/polish.json index 2f8d0ce87..7f8840169 100644 --- a/Mods/vcmi/config/vcmi/polish.json +++ b/Mods/vcmi/config/vcmi/polish.json @@ -12,6 +12,9 @@ "vcmi.adventureMap.monsterThreat.levels.9" : "Przytłaczający", "vcmi.adventureMap.monsterThreat.levels.10" : "Śmiertelny", "vcmi.adventureMap.monsterThreat.levels.11" : "Nie do pokonania", + "vcmi.adventureMap.monsterLevel" : "\n\n%Jednostka %ATTACK_TYPE %LEVEL poziomu z miasta %TOWN", + "vcmi.adventureMap.monsterMeleeType" : "Walcząca wręcz", + "vcmi.adventureMap.monsterRangedType" : "Dystansowa", "vcmi.adventureMap.confirmRestartGame" : "Czy na pewno chcesz zrestartować grę?", "vcmi.adventureMap.noTownWithMarket" : "Brak dostępnego targowiska!", @@ -58,6 +61,13 @@ "vcmi.spellBook.search" : "szukaj...", + "vcmi.spellResearch.canNotAfford" : "Nie stać Cię na zastąpienie {%SPELL1} przez {%SPELL2}, ale za to możesz odrzucić ten czar i kontynuować badania.", + "vcmi.spellResearch.comeAgain" : "Badania zostały już przeprowadzone dzisiaj. Wróć jutro.", + "vcmi.spellResearch.pay" : "Czy chcesz zastąpić {%SPELL1} czarem {%SPELL2}? Czy odrzucić ten czar i kontynuować badania?", + "vcmi.spellResearch.research" : "Zamień zaklęcia", + "vcmi.spellResearch.skip" : "Kontynuuj badania", + "vcmi.spellResearch.abort" : "Anuluj", + "vcmi.mainMenu.serverConnecting" : "Łączenie...", "vcmi.mainMenu.serverAddressEnter" : "Wprowadź adres:", "vcmi.mainMenu.serverConnectionFailed" : "Połączenie nie powiodło się", @@ -142,6 +152,7 @@ "vcmi.client.errors.invalidMap" : "{Błędna mapa lub kampania}\n\nNie udało się stworzyć gry! Wybrana mapa lub kampania jest niepoprawna lub uszkodzona. Powód:\n%s", "vcmi.client.errors.missingCampaigns" : "{Brakujące pliki gry}\n\nPliki kampanii nie zostały znalezione! Możliwe że używasz niekompletnych lub uszkodzonych plików Heroes 3. Spróbuj ponownej instalacji plików gry.", "vcmi.server.errors.disconnected" : "{Błąd sieciowy}\n\nUtracono połączenie z serwerem!", + "vcmi.server.errors.playerLeft" : "{Rozłączenie z graczem}\n\n%s opuścił rozgrywkę!", //%s -> player color "vcmi.server.errors.existingProcess" : "Inny proces 'vcmiserver' został już uruchomiony, zakończ go nim przejdziesz dalej", "vcmi.server.errors.modsToEnable" : "{Następujące mody są wymagane do wczytania gry}", "vcmi.server.errors.modsToDisable" : "{Następujące mody muszą zostać wyłączone}", @@ -235,8 +246,10 @@ "vcmi.adventureOptions.borderScroll.help" : "{Przewijanie na brzegu mapy}\n\nPrzewijanie mapy przygody gdy kursor najeżdża na brzeg okna gry. Może być wyłączone poprzez przytrzymanie klawisza CTRL.", "vcmi.adventureOptions.infoBarCreatureManagement.hover" : "Zarządzanie armią w panelu informacyjnym", "vcmi.adventureOptions.infoBarCreatureManagement.help" : "{Zarządzanie armią w panelu informacyjnym}\n\nPozwala zarządzać jednostkami w panelu informacyjnym, zamiast przełączać między domyślnymi informacjami.", - "vcmi.adventureOptions.leftButtonDrag.hover" : "Przeciąganie mapy lewym kliknięciem", + "vcmi.adventureOptions.leftButtonDrag.hover" : "Przeciąganie lewym", "vcmi.adventureOptions.leftButtonDrag.help" : "{Przeciąganie mapy lewym kliknięciem}\n\nUmożliwia przesuwanie mapy przygody poprzez przeciąganie myszy z wciśniętym lewym przyciskiem.", + "vcmi.adventureOptions.rightButtonDrag.hover" : "Przeciąganie prawym", + "vcmi.adventureOptions.rightButtonDrag.help" : "{Przeciąganie mapy prawym kliknięciem}\n\nUmożliwia przesuwanie mapy przygody poprzez przeciąganie myszy z wciśniętym prawym przyciskiem.", "vcmi.adventureOptions.smoothDragging.hover" : "'Pływające' przeciąganie mapy", "vcmi.adventureOptions.smoothDragging.help" : "{'Pływające' przeciąganie mapy}\n\nPrzeciąganie mapy następuje ze stopniowo zanikającym przyspieszeniem.", "vcmi.adventureOptions.skipAdventureMapAnimations.hover" : "Pomiń efekty zanikania", @@ -337,6 +350,12 @@ "vcmi.heroWindow.openCommander.help" : "Wyświetla informacje o dowódcy przynależącym do tego bohatera", "vcmi.heroWindow.openBackpack.hover" : "Otwórz okno sakwy", "vcmi.heroWindow.openBackpack.help" : "Otwiera okno pozwalające łatwiej zarządzać artefaktami w sakwie", + "vcmi.heroWindow.sortBackpackByCost.hover" : "Sortuj wg. wartości", + "vcmi.heroWindow.sortBackpackByCost.help" : "Sortuj artefakty w sakwie według wartości", + "vcmi.heroWindow.sortBackpackBySlot.hover" : "Sortuj wg. miejsc", + "vcmi.heroWindow.sortBackpackBySlot.help" : "Sortuj artefakty w sakwie według umiejscowienia na ciele", + "vcmi.heroWindow.sortBackpackByClass.hover" : "Sortuj wg. jakości", + "vcmi.heroWindow.sortBackpackByClass.help" : "Sortuj artefakty w sakwie według jakości: Skarb, Pomniejszy, Potężny, Relikt", "vcmi.tavernWindow.inviteHero" : "Zaproś bohatera", @@ -663,5 +682,7 @@ "core.bonus.WIDE_BREATH.name": "Szerokie zionięcie", "core.bonus.WIDE_BREATH.description": "Szeroki atak zionięciem (wiele heksów)", "core.bonus.DISINTEGRATE.name": "Rozpadanie", - "core.bonus.DISINTEGRATE.description": "Po śmierci nie pozostaje żaden trup" + "core.bonus.DISINTEGRATE.description": "Po śmierci nie pozostaje żaden trup", + "core.bonus.INVINCIBLE.name": "Niezwyciężony", + "core.bonus.INVINCIBLE.description": "Nic nie może mieć na niego wpływu" } diff --git a/Mods/vcmi/config/vcmi/portuguese.json b/Mods/vcmi/config/vcmi/portuguese.json index cbf548f07..d8388fe1f 100644 --- a/Mods/vcmi/config/vcmi/portuguese.json +++ b/Mods/vcmi/config/vcmi/portuguese.json @@ -12,7 +12,9 @@ "vcmi.adventureMap.monsterThreat.levels.9" : "Avassaladora", "vcmi.adventureMap.monsterThreat.levels.10" : "Mortal", "vcmi.adventureMap.monsterThreat.levels.11" : "Impossível", - "vcmi.adventureMap.monsterLevel" : "\n\nNível %LEVEL, unidade de %TOWN", + "vcmi.adventureMap.monsterLevel" : "\n\nNível %LEVEL, unidade %TOWN de ataque %ATTACK_TYPE", + "vcmi.adventureMap.monsterMeleeType" : "corpo a corpo", + "vcmi.adventureMap.monsterRangedType" : "à distância", "vcmi.adventureMap.confirmRestartGame" : "Tem certeza de que deseja reiniciar o jogo?", "vcmi.adventureMap.noTownWithMarket" : "Não há mercados disponíveis!", @@ -59,6 +61,13 @@ "vcmi.spellBook.search" : "Procurar...", + "vcmi.spellResearch.canNotAfford" : "Você não pode se dar ao luxo de substituir {%SPELL1} por {%SPELL2}. Mas você ainda pode descartar este feitiço e continuar a pesquisa de feitiços.", + "vcmi.spellResearch.comeAgain" : "A pesquisa já foi realizada hoje. Volte amanhã.", + "vcmi.spellResearch.pay" : "Gostaria de substituir {%SPELL1} por {%SPELL2}? Ou descartar este feitiço e continuar a pesquisa de feitiços?", + "vcmi.spellResearch.research" : "Pesquisar este Feitiço", + "vcmi.spellResearch.skip" : "Pular este Feitiço", + "vcmi.spellResearch.abort" : "Abortar", + "vcmi.mainMenu.serverConnecting" : "Conectando...", "vcmi.mainMenu.serverAddressEnter" : "Insira o endereço:", "vcmi.mainMenu.serverConnectionFailed" : "Falha ao conectar", @@ -143,6 +152,7 @@ "vcmi.client.errors.invalidMap" : "{Mapa ou campanha inválido}\n\nFalha ao iniciar o jogo! O mapa ou campanha selecionado pode ser inválido ou corrompido. Motivo:\n%s", "vcmi.client.errors.missingCampaigns" : "{Arquivos de dados ausentes}\n\nOs arquivos de dados das campanhas não foram encontrados! Você pode estar usando arquivos de dados incompletos ou corrompidos do Heroes 3. Por favor, reinstale os dados do jogo.", "vcmi.server.errors.disconnected" : "{Erro de Rede}\n\nA conexão com o servidor do jogo foi perdida!", + "vcmi.server.errors.playerLeft" : "{Jogador Saiu}\n\nO jogador %s desconectou-se do jogo!", //%s -> player color "vcmi.server.errors.existingProcess" : "Outro processo do servidor VCMI está em execução. Por favor, termine-o antes de iniciar um novo jogo.", "vcmi.server.errors.modsToEnable" : "{Os seguintes mods são necessários}", "vcmi.server.errors.modsToDisable" : "{Os seguintes mods devem ser desativados}", @@ -340,6 +350,12 @@ "vcmi.heroWindow.openCommander.help" : "Mostra detalhes sobre o comandante deste herói.", "vcmi.heroWindow.openBackpack.hover" : "Abrir janela da mochila de artefatos", "vcmi.heroWindow.openBackpack.help" : "Abre a janela que facilita o gerenciamento da mochila de artefatos.", + "vcmi.heroWindow.sortBackpackByCost.hover" : "Ordenar por custo", + "vcmi.heroWindow.sortBackpackByCost.help" : "Ordenar artefatos na mochila por custo.", + "vcmi.heroWindow.sortBackpackBySlot.hover" : "Ordenar por espaço", + "vcmi.heroWindow.sortBackpackBySlot.help" : "Ordenar artefatos na mochila por espaço equipado.", + "vcmi.heroWindow.sortBackpackByClass.hover" : "Ordenar por classe", + "vcmi.heroWindow.sortBackpackByClass.help" : "Ordenar artefatos na mochila por classe de artefato. Tesouro, Menor, Maior, Relíquia", "vcmi.tavernWindow.inviteHero" : "Convidar herói", diff --git a/Mods/vcmi/config/vcmi/swedish.json b/Mods/vcmi/config/vcmi/swedish.json index 57f0bae33..75958bbf5 100644 --- a/Mods/vcmi/config/vcmi/swedish.json +++ b/Mods/vcmi/config/vcmi/swedish.json @@ -40,12 +40,12 @@ "vcmi.heroOverview.secondarySkills" : "Sekundärförmågor", "vcmi.heroOverview.spells" : "Trollformler", - "vcmi.radialWheel.mergeSameUnit" : "Slå samman samma varelser", + "vcmi.radialWheel.mergeSameUnit" : "Slå samman varelser av samma sort", "vcmi.radialWheel.fillSingleUnit" : "Fyll på med enstaka varelser", "vcmi.radialWheel.splitSingleUnit" : "Dela av en enda varelse", "vcmi.radialWheel.splitUnitEqually" : "Dela upp varelser lika", "vcmi.radialWheel.moveUnit" : "Flytta varelser till en annan armé", - "vcmi.radialWheel.splitUnit" : "Dela upp varelse till en annan ruta", + "vcmi.radialWheel.splitUnit" : "Dela upp varelseförband till en annan ruta", "vcmi.radialWheel.heroGetArmy" : "Hämta armé från annan hjälte", "vcmi.radialWheel.heroSwapArmy" : "Byt armé med annan hjälte", @@ -54,13 +54,20 @@ "vcmi.radialWheel.heroSwapArtifacts" : "Byt artefakter med annan hjälte", "vcmi.radialWheel.heroDismiss" : "Avfärda hjälten", - "vcmi.radialWheel.moveTop" : "Flytta till toppen", + "vcmi.radialWheel.moveTop" : "Flytta längst upp", "vcmi.radialWheel.moveUp" : "Flytta upp", "vcmi.radialWheel.moveDown" : "Flytta nedåt", - "vcmi.radialWheel.moveBottom" : "Flytta till botten", + "vcmi.radialWheel.moveBottom" : "Flytta längst ner", "vcmi.spellBook.search" : "sök...", + "vcmi.spellResearch.canNotAfford" : "Du har inte råd att byta ut '{%SPELL1}' med '{%SPELL2}'. Du kan fortfarande göra dig av med den här trollformeln och forska vidare.", + "vcmi.spellResearch.comeAgain" : "Forskningen har redan gjorts idag. Kom tillbaka imorgon.", + "vcmi.spellResearch.pay" : "Vill du byta ut '{%SPELL1}' med '{%SPELL2}'? Eller vill du göra dig av med den valda trollformeln och forska vidare?", + "vcmi.spellResearch.research" : "Forska fram denna trollformel", + "vcmi.spellResearch.skip" : "Strunta i denna trollformel", + "vcmi.spellResearch.abort" : "Avbryt", + "vcmi.mainMenu.serverConnecting" : "Ansluter...", "vcmi.mainMenu.serverAddressEnter" : "Ange adress:", "vcmi.mainMenu.serverConnectionFailed" : "Misslyckades med att ansluta", @@ -343,6 +350,12 @@ "vcmi.heroWindow.openCommander.help" : "Visar detaljer om befälhavaren för den här hjälten.", "vcmi.heroWindow.openBackpack.hover" : "Öppna artefaktryggsäcksfönster", "vcmi.heroWindow.openBackpack.help" : "Öppnar fönster som gör det enklare att hantera artefaktryggsäcken.", + "vcmi.heroWindow.sortBackpackByCost.hover" : "Sortera efter kostnad", + "vcmi.heroWindow.sortBackpackByCost.help" : "Sorterar artefakter i ryggsäcken efter kostnad.", + "vcmi.heroWindow.sortBackpackBySlot.hover" : "Sortera efter plats", + "vcmi.heroWindow.sortBackpackBySlot.help" : "Sorterar artefakter i ryggsäcken efter utrustad plats.", + "vcmi.heroWindow.sortBackpackByClass.hover" : "Sortera efter klass", + "vcmi.heroWindow.sortBackpackByClass.help" : "Sorterar artefakter i ryggsäcken efter artefaktklass (skatt, mindre, större, relik)", "vcmi.tavernWindow.inviteHero" : "Bjud in hjälte", @@ -355,8 +368,8 @@ "vcmi.creatureWindow.returnArtifact.hover" : "Återlämna artefakt", "vcmi.creatureWindow.returnArtifact.help" : "Klicka på den här knappen för att lägga tillbaka artefakten i hjältens ryggsäck.", - "vcmi.questLog.hideComplete.hover" : "Gömmer alla slutförda uppdrag", - "vcmi.questLog.hideComplete.help" : "Dölj alla slutförda uppdrag.", + "vcmi.questLog.hideComplete.hover" : "Dölj alla slutförda uppdrag", + "vcmi.questLog.hideComplete.help" : "Gömmer undan alla slutförda uppdrag.", "vcmi.randomMapTab.widgets.randomTemplate" : "(Slumpmässig)", "vcmi.randomMapTab.widgets.templateLabel" : "Mall", @@ -365,22 +378,22 @@ "vcmi.randomMapTab.widgets.roadTypesLabel" : "Vägtyper", "vcmi.optionsTab.turnOptions.hover" : "Turomgångsalternativ", - "vcmi.optionsTab.turnOptions.help" : "Välj alternativ för turomgångs-timer och simultana turer", + "vcmi.optionsTab.turnOptions.help" : "Turomgångs-timer och samtidiga turomgångar (förinställningar)", "vcmi.optionsTab.chessFieldBase.hover" : "Bas-timern", "vcmi.optionsTab.chessFieldTurn.hover" : "Tur-timern", "vcmi.optionsTab.chessFieldBattle.hover" : "Strids-timern", "vcmi.optionsTab.chessFieldUnit.hover" : "Enhets-timern", - "vcmi.optionsTab.chessFieldBase.help" : "Används när {Tur-timern} når '0'. Ställs in en gång i början av spelet. När den når '0' avslutas den aktuella turomgången (pågående strid avslutas med förlust).", - "vcmi.optionsTab.chessFieldTurnAccumulate.help" : "Används utanför strid eller när {Strids-timern} tar slut. Återställs varje turomgång. Outnyttjad tid läggs till i {Bas-timern} till nästa turomgång.", + "vcmi.optionsTab.chessFieldBase.help" : "Används när {Tur-timern} når 0. Ställs in i början av spelet. Vid 0 avslutas turomgången (pågående strid avslutas med förlust).", + "vcmi.optionsTab.chessFieldTurnAccumulate.help" : "Används utanför strid eller när {Strids-timern} tar slut. Återställs varje turomgång. Outnyttjad tid läggs till i {Bas-timern}.", "vcmi.optionsTab.chessFieldTurnDiscard.help" : "Används utanför strid eller när {Strids-timern} tar slut. Återställs varje turomgång. Outnyttjad tid går förlorad.", "vcmi.optionsTab.chessFieldBattle.help" : "Används i strider med AI eller i PvP-strid när {Enhets-timern} tar slut. Återställs i början av varje strid.", - "vcmi.optionsTab.chessFieldUnitAccumulate.help" : "Används när du styr din enhet i PvP-strid. Outnyttjad tid läggs till i {Strids-timern} när enheten har avslutat sin turomgång.", - "vcmi.optionsTab.chessFieldUnitDiscard.help" : "Används när du styr din enhet i PvP-strid. Återställs i början av varje enhets turomgång. Outnyttjad tid går förlorad.", + "vcmi.optionsTab.chessFieldUnitAccumulate.help" : "Används när du styr dina enheter i PvP-strid. Outnyttjad tid läggs till i {Strids-timern} när enheten har avslutat sin turomgång.", + "vcmi.optionsTab.chessFieldUnitDiscard.help" : "Används när du styr dina enheter i PvP-strid. Återställs i början av varje enhets turomgång. Outnyttjad tid går förlorad.", "vcmi.optionsTab.accumulate" : "Ackumulera", - "vcmi.optionsTab.simturnsTitle" : "Simultana turomgångar", + "vcmi.optionsTab.simturnsTitle" : "Samtidiga turomgångar", "vcmi.optionsTab.simturnsMin.hover" : "Åtminstone i", "vcmi.optionsTab.simturnsMax.hover" : "Som mest i", "vcmi.optionsTab.simturnsAI.hover" : "(Experimentell) Simultana AI-turomgångar", @@ -388,7 +401,7 @@ "vcmi.optionsTab.simturnsMax.help" : "Spela samtidigt som andra spelare under ett angivet antal dagar eller tills en tillräckligt nära kontakt inträffar med en annan spelare", "vcmi.optionsTab.simturnsAI.help" : "{Simultana AI-turomgångar}\nExperimentellt alternativ. Tillåter AI-spelare att agera samtidigt som den mänskliga spelaren när simultana turomgångar är aktiverade.", - "vcmi.optionsTab.turnTime.select" : "Timer-inställningar för turomgångar", + "vcmi.optionsTab.turnTime.select" : "Ställ in turomgångs-timer", "vcmi.optionsTab.turnTime.unlimited" : "Obegränsat med tid", "vcmi.optionsTab.turnTime.classic.1" : "Klassisk timer: 1 minut", "vcmi.optionsTab.turnTime.classic.2" : "Klassisk timer: 2 minuter", @@ -403,15 +416,15 @@ "vcmi.optionsTab.turnTime.chess.2" : "Schack: 02:00 + 01:00 + 00:15 + 00:00", "vcmi.optionsTab.turnTime.chess.1" : "Schack: 01:00 + 01:00 + 00:00 + 00:00", - "vcmi.optionsTab.simturns.select" : "Simultana/samtidiga turomgångsinställningar", - "vcmi.optionsTab.simturns.none" : "Inga simultana/samtidiga turer", - "vcmi.optionsTab.simturns.tillContactMax" : "Sam-tur: Fram till kontakt", - "vcmi.optionsTab.simturns.tillContact1" : "Sam-tur: 1 vecka, bryt vid kontakt", - "vcmi.optionsTab.simturns.tillContact2" : "Sam-tur: 2 veckor, bryt vid kontakt", - "vcmi.optionsTab.simturns.tillContact4" : "Sam-tur: 1 månad, bryt vid kontakt", - "vcmi.optionsTab.simturns.blocked1" : "Sam-tur: 1 vecka, kontakter blockerade", - "vcmi.optionsTab.simturns.blocked2" : "Sam-tur: 2 veckor, kontakter blockerade", - "vcmi.optionsTab.simturns.blocked4" : "Sam-tur: 1 månad, kontakter blockerade", + "vcmi.optionsTab.simturns.select" : "Ställ in samtidiga turomgångar", + "vcmi.optionsTab.simturns.none" : "Inga samtidiga turomgångar", + "vcmi.optionsTab.simturns.tillContactMax" : "Samtur: Fram till närkontakt", + "vcmi.optionsTab.simturns.tillContact1" : "Samtur: 1 vecka (bryts vid närkontakt)", + "vcmi.optionsTab.simturns.tillContact2" : "Samtur: 2 veckor (bryts vid närkontakt)", + "vcmi.optionsTab.simturns.tillContact4" : "Samtur: 1 månad (bryts vid närkontakt)", + "vcmi.optionsTab.simturns.blocked1" : "Samtur: 1 vecka (närkontakt blockerad)", + "vcmi.optionsTab.simturns.blocked2" : "Samtur: 2 veckor (närkontakt blockerad)", + "vcmi.optionsTab.simturns.blocked4" : "Samtur: 1 månad (närkontakt blockerad)", // 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 @@ -521,155 +534,155 @@ "core.seerhut.quest.reachDate.visit.5" : "Stängt fram till %s.", "core.bonus.ADDITIONAL_ATTACK.name" : "Dubbelslag", - "core.bonus.ADDITIONAL_ATTACK.description" : "Attackerar två gånger", + "core.bonus.ADDITIONAL_ATTACK.description" : "Attackerar två gånger.", "core.bonus.ADDITIONAL_RETALIATION.name" : "Ytterligare motattacker", - "core.bonus.ADDITIONAL_RETALIATION.description" : "Kan slå tillbaka ${val} extra gånger", + "core.bonus.ADDITIONAL_RETALIATION.description" : "Kan slå tillbaka ${val} extra gång(er).", "core.bonus.AIR_IMMUNITY.name" : "Luft-immunitet", - "core.bonus.AIR_IMMUNITY.description" : "Immun mot alla trollformler från skolan för luftmagi", + "core.bonus.AIR_IMMUNITY.description" : "Immun mot alla luftmagi-trollformler.", "core.bonus.ATTACKS_ALL_ADJACENT.name" : "Attackera runtomkring", - "core.bonus.ATTACKS_ALL_ADJACENT.description" : "Attackerar alla angränsande fiender", - "core.bonus.BLOCKS_RETALIATION.name" : "Blockera närstrids-motattack", - "core.bonus.BLOCKS_RETALIATION.description" : "Fienden kan inte slå tillbaka/retaliera", - "core.bonus.BLOCKS_RANGED_RETALIATION.name" : "Blockera fjärrstrids-motattack", - "core.bonus.BLOCKS_RANGED_RETALIATION.description" : "Fienden kan inte retaliera på avstånd genom att använda en distansattack", - "core.bonus.CATAPULT.name" : "Katapult", - "core.bonus.CATAPULT.description" : "Attackerar belägringsmurar", - "core.bonus.CHANGES_SPELL_COST_FOR_ALLY.name" : "Minska trollformelkostnaden (${val})", - "core.bonus.CHANGES_SPELL_COST_FOR_ALLY.description" : "Minskar trollformelkostnaden för hjälten med ${val}", + "core.bonus.ATTACKS_ALL_ADJACENT.description" : "Attackerar alla angränsande fiender.", + "core.bonus.BLOCKS_RETALIATION.name" : "Retaliera ej i närstrid", + "core.bonus.BLOCKS_RETALIATION.description" : "Fienden kan inte slå tillbaka/retaliera.", + "core.bonus.BLOCKS_RANGED_RETALIATION.name" : "Retaliera ej på avstånd", + "core.bonus.BLOCKS_RANGED_RETALIATION.description" : "Fienden kan inte retaliera på avstånd.", + "core.bonus.CATAPULT.name" : "Katapult-attack", + "core.bonus.CATAPULT.description" : "Attackerar belägringsmurar.", + "core.bonus.CHANGES_SPELL_COST_FOR_ALLY.name" : "Minska magikostnad (${val})", + "core.bonus.CHANGES_SPELL_COST_FOR_ALLY.description" : "Minskar magikostnaden för hjälten med ${val}.", "core.bonus.CHANGES_SPELL_COST_FOR_ENEMY.name" : "Magisk dämpare (${val})", - "core.bonus.CHANGES_SPELL_COST_FOR_ENEMY.description": "Ökar trollformelkostnaden för fiendens trollformler med ${val}", + "core.bonus.CHANGES_SPELL_COST_FOR_ENEMY.description": "Ökar fiendens magikostnad med ${val}.", "core.bonus.CHARGE_IMMUNITY.name" : "Galoppanfalls-immunitet", - "core.bonus.CHARGE_IMMUNITY.description" : "Immun mot ryttares och tornerares galopperande ridanfall", + "core.bonus.CHARGE_IMMUNITY.description" : "Immun mot ryttares galopperande ridanfall.", "core.bonus.DARKNESS.name" : "I skydd av mörkret", - "core.bonus.DARKNESS.description" : "Skapar ett mörkerhölje med en rut-radie på ${val} som gäckar dina fiender", + "core.bonus.DARKNESS.description" : "Skapar ett mörkerhölje med rutradien ${val}.", "core.bonus.DEATH_STARE.name" : "Dödsblick (${val}%)", - "core.bonus.DEATH_STARE.description" : "Varje 'Dödsblick' har ${val}% chans att döda den översta fiendeenheten", + "core.bonus.DEATH_STARE.description" : "Varje dödsblick har ${val}% chans att döda.", "core.bonus.DEFENSIVE_STANCE.name" : "Försvarshållning", - "core.bonus.DEFENSIVE_STANCE.description" : "När du väljer att försvara en enhet så får den +${val} extra försvar", + "core.bonus.DEFENSIVE_STANCE.description" : "+${val} extra försvar när du försvarar dig.", "core.bonus.DESTRUCTION.name" : "Förintelse", - "core.bonus.DESTRUCTION.description" : "Har ${val}% chans att döda extra enheter efter attack", + "core.bonus.DESTRUCTION.description" : "${val}% chans att ta död på fler efter attack.", "core.bonus.DOUBLE_DAMAGE_CHANCE.name" : "Dödsstöt", - "core.bonus.DOUBLE_DAMAGE_CHANCE.description" : "Har ${val}% chans att utdela dubbel basskada vid attack", + "core.bonus.DOUBLE_DAMAGE_CHANCE.description" : "${val}% chans till dubbel basskada vid attack.", "core.bonus.DRAGON_NATURE.name" : "Drake", - "core.bonus.DRAGON_NATURE.description" : "Varelsen har en draknatur", + "core.bonus.DRAGON_NATURE.description" : "Varelsen har en draknatur.", "core.bonus.EARTH_IMMUNITY.name" : "Jord-immunitet", - "core.bonus.EARTH_IMMUNITY.description" : "Immun mot alla trollformler från skolan för jordmagi", + "core.bonus.EARTH_IMMUNITY.description" : "Immun mot alla jordmagi-trollformler.", "core.bonus.ENCHANTER.name" : "Förtrollare", - "core.bonus.ENCHANTER.description" : "Kan kasta ${subtyp.spell} på alla varje turomgång", + "core.bonus.ENCHANTER.description" : "Kastar mass-${subtype.spell} varje turomgång.", "core.bonus.ENCHANTED.name" : "Förtrollad", - "core.bonus.ENCHANTED.description" : "Påverkas av permanent ${subtype.spell}", + "core.bonus.ENCHANTED.description" : "Påverkas av permanent ${subtype.spell}.", "core.bonus.ENEMY_ATTACK_REDUCTION.name" : "Avfärda attack (${val}%)", - "core.bonus.ENEMY_ATTACK_REDUCTION.description" : "När du blir attackerad ignoreras ${val}% av angriparens attack", + "core.bonus.ENEMY_ATTACK_REDUCTION.description" : "Ignorerar ${val}% av angriparens attack.", "core.bonus.ENEMY_DEFENCE_REDUCTION.name" : "Förbigå försvar (${val}%)", - "core.bonus.ENEMY_DEFENCE_REDUCTION.description" : "När du attackerar ignoreras ${val}% av försvararens försvar", + "core.bonus.ENEMY_DEFENCE_REDUCTION.description" : "Din attack ignorerar ${val}% av fiendens försvar.", "core.bonus.FIRE_IMMUNITY.name" : "Eld-immunitet", - "core.bonus.FIRE_IMMUNITY.description" : "Immun mot alla trollformler från skolan för eldmagi", + "core.bonus.FIRE_IMMUNITY.description" : "Immun mot alla eldmagi-trollformler.", "core.bonus.FIRE_SHIELD.name" : "Eldsköld (${val}%)", - "core.bonus.FIRE_SHIELD.description" : "Reflekterar en del av närstridsskadorna", + "core.bonus.FIRE_SHIELD.description" : "Reflekterar en del av närstridsskadorna.", "core.bonus.FIRST_STRIKE.name" : "Första slaget", - "core.bonus.FIRST_STRIKE.description" : "Denna varelse gör en motattack innan den blir attackerad", + "core.bonus.FIRST_STRIKE.description" : "Retalierar innan den blir attackerad.", "core.bonus.FEAR.name" : "Rädsla", - "core.bonus.FEAR.description" : "Orsakar rädsla på ett fiendeförband", + "core.bonus.FEAR.description" : "Orsakar rädsla på ett fiendeförband.", "core.bonus.FEARLESS.name" : "Orädd", - "core.bonus.FEARLESS.description" : "Immun mot rädsla", + "core.bonus.FEARLESS.description" : "Immun mot rädsla.", "core.bonus.FEROCITY.name" : "Vildsint", - "core.bonus.FEROCITY.description" : "Attackerar ${val} extra gång(er) om någon dödas", + "core.bonus.FEROCITY.description" : "+${val} extra attack(er) om någon dödas.", "core.bonus.FLYING.name" : "Flygande", - "core.bonus.FLYING.description" : "Flyger vid förflyttning (ignorerar hinder)", + "core.bonus.FLYING.description" : "Flyger vid förflyttning (ignorerar hinder).", "core.bonus.FREE_SHOOTING.name" : "Skjut på nära håll", - "core.bonus.FREE_SHOOTING.description" : "Kan använda distansattacker på närstridsavstånd", + "core.bonus.FREE_SHOOTING.description" : "Använd distansattacker på närstridsavstånd.", "core.bonus.GARGOYLE.name" : "Stenfigur", - "core.bonus.GARGOYLE.description" : "Kan varken upplivas eller läkas", + "core.bonus.GARGOYLE.description" : "Kan varken upplivas eller läkas.", "core.bonus.GENERAL_DAMAGE_REDUCTION.name" : "Minska skada (${val}%)", - "core.bonus.GENERAL_DAMAGE_REDUCTION.description" : "Reducerar skadan från distans- och närstrids-attacker", - "core.bonus.HATE.name" : "Hatar ${subtyp.varelse}", - "core.bonus.HATE.description" : "Gör ${val}% mer skada mot ${subtyp.varelse}", + "core.bonus.GENERAL_DAMAGE_REDUCTION.description" : "Reducerar skadan från inkommande attacker.", + "core.bonus.HATE.name" : "Hatar: ${subtype.creature}", + "core.bonus.HATE.description" : "Gör ${val}% mer skada mot ${subtype.creature}.", "core.bonus.HEALER.name" : "Helare", - "core.bonus.HEALER.description" : "Helar/läker allierade enheter", + "core.bonus.HEALER.description" : "Helar/läker allierade enheter.", "core.bonus.HP_REGENERATION.name" : "Självläkande", - "core.bonus.HP_REGENERATION.description" : "Får tillbaka ${val} hälsa (träffpoäng) varje runda", + "core.bonus.HP_REGENERATION.description" : "Återfår ${val} hälsa (träffpoäng) varje runda.", "core.bonus.JOUSTING.name" : "Galopperande ridanfall", - "core.bonus.JOUSTING.description" : "Orsakar +${val}% mer skada för varje ruta som förflyttas innan attack", + "core.bonus.JOUSTING.description" : "+${val}% skada per rutförflyttning före attack.", "core.bonus.KING.name" : "Kung", - "core.bonus.KING.description" : "Sårbar för 'Dräpar'-nivå ${val} eller högre", - "core.bonus.LEVEL_SPELL_IMMUNITY.name" : "Förtrollningsimmunitet 1-${val}", - "core.bonus.LEVEL_SPELL_IMMUNITY.description" : "Immun mot trollformler på nivå 1-${val}", - "core.bonus.LIMITED_SHOOTING_RANGE.name" : "Begränsad räckvidd för skjutning", - "core.bonus.LIMITED_SHOOTING_RANGE.description" : "Kan inte sikta på enheter längre bort än ${val} rutor", - "core.bonus.LIFE_DRAIN.name" : "Dränerar livskraft (${val}%)", - "core.bonus.LIFE_DRAIN.description" : "Dränerar ${val}% hälsa (träffpoäng) av utdelad skada", - "core.bonus.MANA_CHANNELING.name" : "Kanalisera trollformelspoäng ${val}%", - "core.bonus.MANA_CHANNELING.description" : "Ger din hjälte ${val}% av fiendens spenderade trollformelspoäng i strid", - "core.bonus.MANA_DRAIN.name" : "Dränera trollformelspoäng", - "core.bonus.MANA_DRAIN.description" : "Dränerar ${val} trollformelspoäng varje tur", + "core.bonus.KING.description" : "Sårbar för Dräpar-nivå ${val} eller högre.", + "core.bonus.LEVEL_SPELL_IMMUNITY.name" : "Trolldomsimmunitet 1-${val}", + "core.bonus.LEVEL_SPELL_IMMUNITY.description" : "Immun mot nivå 1-${val}-trollformler.", + "core.bonus.LIMITED_SHOOTING_RANGE.name" : "Begränsad skjuträckvidd", + "core.bonus.LIMITED_SHOOTING_RANGE.description" : "Skjuträckvidd: ${val} rutor.", + "core.bonus.LIFE_DRAIN.name" : "Dränera livskraft (${val}%)", + "core.bonus.LIFE_DRAIN.description" : "Dränera ${val}% hälsa av den vållade skadan.", + "core.bonus.MANA_CHANNELING.name" : "Kanalisera magi (${val}%)", + "core.bonus.MANA_CHANNELING.description" : "Ger din hjälte ${val}% av fiendens spenderade mana.", + "core.bonus.MANA_DRAIN.name" : "Dränera mana", + "core.bonus.MANA_DRAIN.description" : "Dränerar ${val} mana från fienden varje tur.", "core.bonus.MAGIC_MIRROR.name" : "Magisk spegel (${val}%)", - "core.bonus.MAGIC_MIRROR.description" : "${val}% chans att reflektera en offensiv trollformel på en fiendeenhet", + "core.bonus.MAGIC_MIRROR.description" : "${val}% chans att reflektera skadliga trollformler.", "core.bonus.MAGIC_RESISTANCE.name" : "Magiskt motstånd (${val}%)", - "core.bonus.MAGIC_RESISTANCE.description" : "Har en ${val}% chans att motstå en skadlig trollformel", - "core.bonus.MIND_IMMUNITY.name" : "Immunitet mot sinnesförtrollningar", - "core.bonus.MIND_IMMUNITY.description" : "Immun mot förtrollningar som påverkar dina sinnen", - "core.bonus.NO_DISTANCE_PENALTY.name" : "Ingen avståndsbestraffning", - "core.bonus.NO_DISTANCE_PENALTY.description" : "Gör full skada på vilket avstånd som helst i strid", - "core.bonus.NO_MELEE_PENALTY.name" : "Ingen närstridsbestraffning", - "core.bonus.NO_MELEE_PENALTY.description" : "Varelsen har ingen närstridsbestraffning", - "core.bonus.NO_MORALE.name" : "Ingen Moralpåverkan", - "core.bonus.NO_MORALE.description" : "Är immun mot moraliska effekter och har alltid neutral moral", + "core.bonus.MAGIC_RESISTANCE.description" : "${val}% chans att motstå en skadlig trollformel.", + "core.bonus.MIND_IMMUNITY.name" : "Immun mot sinnesmagi", + "core.bonus.MIND_IMMUNITY.description" : "Immun mot magi som påverkar dina sinnen.", + "core.bonus.NO_DISTANCE_PENALTY.name" : "Långdistansskytt", + "core.bonus.NO_DISTANCE_PENALTY.description" : "Gör full skada på alla avstånd i strid.", + "core.bonus.NO_MELEE_PENALTY.name" : "Närstridsspecialist", + "core.bonus.NO_MELEE_PENALTY.description" : "Ingen närstridsbestraffning.", + "core.bonus.NO_MORALE.name" : "Ingen moralpåverkan", + "core.bonus.NO_MORALE.description" : "Immun mot moral-effekter (neutral moral).", "core.bonus.NO_WALL_PENALTY.name" : "Ingen murbestraffning", - "core.bonus.NO_WALL_PENALTY.description" : "Orsakar full skada mot fiender bakom en mur", + "core.bonus.NO_WALL_PENALTY.description" : "Gör full skada mot fiender bakom en mur.", "core.bonus.NON_LIVING.name" : "Icke levande", - "core.bonus.NON_LIVING.description" : "Påverkas inte av vissa effekter som levande/odöda gör", + "core.bonus.NON_LIVING.description" : "Immunitet mot många effekter.", "core.bonus.RANDOM_SPELLCASTER.name" : "Slumpmässig besvärjare", - "core.bonus.RANDOM_SPELLCASTER.description" : "Kan kasta trollformler som väljs slumpmässigt", + "core.bonus.RANDOM_SPELLCASTER.description" : "Kastar trollformler som väljs slumpmässigt.", "core.bonus.RANGED_RETALIATION.name" : "Motattacker på avstånd", - "core.bonus.RANGED_RETALIATION.description" : "Kan retaliera/motattackera på avstånd", - "core.bonus.RECEPTIVE.name" : "Mottaglig", - "core.bonus.RECEPTIVE.description" : "Ingen immunitet mot vänliga besvärjelser", + "core.bonus.RANGED_RETALIATION.description" : "Kan retaliera/motattackera på avstånd.", + "core.bonus.RECEPTIVE.name" : "Magiskt mottaglig", + "core.bonus.RECEPTIVE.description" : "Ingen immunitet mot vänliga trollformler.", "core.bonus.REBIRTH.name" : "Återfödelse (${val}%)", - "core.bonus.REBIRTH.description" : "${val}% av enheterna kommer att återuppväckas efter döden", + "core.bonus.REBIRTH.description" : "${val}% återuppväcks efter döden.", "core.bonus.RETURN_AFTER_STRIKE.name" : "Återvänder efter närstrid", - "core.bonus.RETURN_AFTER_STRIKE.description" : "Efter närstridsattack återvänder den till sin ursprungliga ruta", - "core.bonus.REVENGE.name" : "Hämnd", - "core.bonus.REVENGE.description" : "Orsakar mer skada om den själv blivit skadad", + "core.bonus.RETURN_AFTER_STRIKE.description" : "Återvänder till sin ruta efter attack.", + "core.bonus.REVENGE.name" : "Hämndlysten", + "core.bonus.REVENGE.description" : "Vållar mer skada om den själv blivit skadad.", "core.bonus.SHOOTER.name" : "Distans-attack", - "core.bonus.SHOOTER.description" : "Varelsen kan skjuta/attackera på avstånd", + "core.bonus.SHOOTER.description" : "Varelsen kan skjuta/attackera på avstånd.", "core.bonus.SHOOTS_ALL_ADJACENT.name" : "Skjuter alla i närheten", - "core.bonus.SHOOTS_ALL_ADJACENT.description" : "Dess distans-attacker drabbar alla mål i ett litet område", + "core.bonus.SHOOTS_ALL_ADJACENT.description" : "Distans-attack drabbar alla inom räckhåll.", "core.bonus.SOUL_STEAL.name" : "Själtjuv", - "core.bonus.SOUL_STEAL.description" : "Återuppväcker ${val} av sina egna för varje dödad fiendeenhet", + "core.bonus.SOUL_STEAL.description" : "För varje dödad fiende återuppväcks: ${val}.", "core.bonus.SPELLCASTER.name" : "Besvärjare", - "core.bonus.SPELLCASTER.description" : "Kan kasta ${subtype.spell}", + "core.bonus.SPELLCASTER.description" : "Kan kasta: ${subtype.spell}.", "core.bonus.SPELL_AFTER_ATTACK.name" : "Besvärja efter attack", - "core.bonus.SPELL_AFTER_ATTACK.description" : "Har ${val}% chans att kasta ${subtype.spell} efter anfall", + "core.bonus.SPELL_AFTER_ATTACK.description" : "${val}% chans för '${subtype.spell}' efter attack.", "core.bonus.SPELL_BEFORE_ATTACK.name" : "Besvärja före attack", - "core.bonus.SPELL_BEFORE_ATTACK.description" : "Har ${val}% chans att kasta ${subtype.spell} före anfall", + "core.bonus.SPELL_BEFORE_ATTACK.description" : "${val}% chans för '${subtype.spell}' före attack.", "core.bonus.SPELL_DAMAGE_REDUCTION.name" : "Trolldoms-resistens", - "core.bonus.SPELL_DAMAGE_REDUCTION.description" : "Skadan från trollformler är reducet med ${val}%.", + "core.bonus.SPELL_DAMAGE_REDUCTION.description" : "Reducerar magisk-skada med ${val}%.", "core.bonus.SPELL_IMMUNITY.name" : "Trolldoms-immunitet", - "core.bonus.SPELL_IMMUNITY.description" : "Immun mot ${subtype.spell}", - "core.bonus.SPELL_LIKE_ATTACK.name" : "Trolldomsliknande attack", - "core.bonus.SPELL_LIKE_ATTACK.description" : "Attackerar med ${subtype.spell}", + "core.bonus.SPELL_IMMUNITY.description" : "Immun mot '${subtype.spell}'.", + "core.bonus.SPELL_LIKE_ATTACK.name" : "Magisk attack", + "core.bonus.SPELL_LIKE_ATTACK.description" : "Attackerar med '${subtype.spell}'.", "core.bonus.SPELL_RESISTANCE_AURA.name" : "Motståndsaura", - "core.bonus.SPELL_RESISTANCE_AURA.description" : "Närbelägna förband får ${val}% magi-resistens", + "core.bonus.SPELL_RESISTANCE_AURA.description" : "Angränsande förband får ${val}% magi-resistens.", "core.bonus.SUMMON_GUARDIANS.name" : "Åkalla väktare", - "core.bonus.SUMMON_GUARDIANS.description" : "I början av striden åkallas ${subtype.creature} (${val}%)", + "core.bonus.SUMMON_GUARDIANS.description" : "Vid strid åkallas: ${subtype.creature} ${val}%.", "core.bonus.SYNERGY_TARGET.name" : "Synergibar", - "core.bonus.SYNERGY_TARGET.description" : "Denna varelse är sårbar för synergieffekt", + "core.bonus.SYNERGY_TARGET.description" : "Denna varelse är sårbar för synergieffekt.", "core.bonus.TWO_HEX_ATTACK_BREATH.name" : "Dödlig andedräkt", - "core.bonus.TWO_HEX_ATTACK_BREATH.description" : "Andningsattack (2 rutors räckvidd)", + "core.bonus.TWO_HEX_ATTACK_BREATH.description" : "Andningsattack (2 rutors räckvidd).", "core.bonus.THREE_HEADED_ATTACK.name" : "Trehövdad attack", - "core.bonus.THREE_HEADED_ATTACK.description" : "Attackerar tre angränsande enheter", + "core.bonus.THREE_HEADED_ATTACK.description" : "Attackerar upp till tre enheter framför sig.", "core.bonus.TRANSMUTATION.name" : "Transmutation", - "core.bonus.TRANSMUTATION.description" : "${val}% chans att förvandla angripen enhet till en annan typ", + "core.bonus.TRANSMUTATION.description" : "${val}% chans att förvandla angripen enhet.", "core.bonus.UNDEAD.name" : "Odöd", - "core.bonus.UNDEAD.description" : "Varelsen är odöd", + "core.bonus.UNDEAD.description" : "Varelsen är odöd.", "core.bonus.UNLIMITED_RETALIATIONS.name" : "Slår tillbaka varje gång", - "core.bonus.UNLIMITED_RETALIATIONS.description" : "Obegränsat antal motattacker", + "core.bonus.UNLIMITED_RETALIATIONS.description" : "Obegränsat antal motattacker.", "core.bonus.WATER_IMMUNITY.name" : "Vatten-immunitet", - "core.bonus.WATER_IMMUNITY.description" : "Immun mot alla trollformler från vattenmagiskolan", + "core.bonus.WATER_IMMUNITY.description" : "Immun mot alla vattenmagi-trollformler.", "core.bonus.WIDE_BREATH.name" : "Bred dödlig andedräkt", - "core.bonus.WIDE_BREATH.description" : "Bred andningsattack (flera rutor)", + "core.bonus.WIDE_BREATH.description" : "Bred andningsattack (flera rutor).", "core.bonus.DISINTEGRATE.name" : "Desintegrerar", - "core.bonus.DISINTEGRATE.description" : "Ingen kropp lämnas kvar efter dödsögonblicket", + "core.bonus.DISINTEGRATE.description" : "Ingen kropp lämnas kvar på slagfältet.", "core.bonus.INVINCIBLE.name" : "Oövervinnerlig", - "core.bonus.INVINCIBLE.description" : "Kan inte påverkas av någonting" + "core.bonus.INVINCIBLE.description" : "Kan inte påverkas av någonting." } diff --git a/client/ArtifactsUIController.cpp b/client/ArtifactsUIController.cpp index 73461a58a..649cd7304 100644 --- a/client/ArtifactsUIController.cpp +++ b/client/ArtifactsUIController.cpp @@ -74,7 +74,10 @@ bool ArtifactsUIController::askToAssemble(const CGHeroInstance * hero, const Art MetaString message = MetaString::createFromTextID(art->artType->getDescriptionTextID()); message.appendEOL(); message.appendEOL(); - message.appendRawString(CGI->generaltexth->allTexts[732]); // You possess all of the components needed to assemble the + if(combinedArt->isFused()) + message.appendRawString(CGI->generaltexth->translate("vcmi.heroWindow.fusingArtifact.fusing")); + else + message.appendRawString(CGI->generaltexth->allTexts[732]); // You possess all of the components needed to assemble the message.replaceName(ArtifactID(combinedArt->getId())); LOCPLINT->showYesNoDialog(message.toString(), [&assembleConfirmed, hero, slot, combinedArt]() { @@ -102,7 +105,7 @@ bool ArtifactsUIController::askToDisassemble(const CGHeroInstance * hero, const if(hero->tempOwner != LOCPLINT->playerID) return false; - if(art->isCombined()) + if(art->hasParts()) { if(ArtifactUtils::isSlotBackpack(slot) && !ArtifactUtils::isBackpackFreeSlots(hero, art->artType->getConstituents().size() - 1)) return false; diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index 6133cdd64..abf5abb9a 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -67,7 +67,6 @@ #include "../lib/CConfigHandler.h" #include "../lib/texts/CGeneralTextHandler.h" -#include "../lib/CHeroHandler.h" #include "../lib/CPlayerState.h" #include "../lib/CRandomGenerator.h" #include "../lib/CStack.h" diff --git a/client/Client.h b/client/Client.h index f8c7eaf12..ce1276b06 100644 --- a/client/Client.h +++ b/client/Client.h @@ -158,7 +158,7 @@ public: friend class CBattleCallback; //handling players actions void changeSpells(const CGHeroInstance * hero, bool give, const std::set & spells) override {}; - void setResearchedSpells(const CGTownInstance * town, int level, const std::vector spells, bool accepted) override {}; + void setResearchedSpells(const CGTownInstance * town, int level, const std::vector & spells, bool accepted) override {}; bool removeObject(const CGObjectInstance * obj, const PlayerColor & initiator) override {return false;}; void createBoat(const int3 & visitablePosition, BoatId type, PlayerColor initiator) override {}; void setOwner(const CGObjectInstance * obj, PlayerColor owner) override {}; diff --git a/client/ClientCommandManager.cpp b/client/ClientCommandManager.cpp index 775c9b806..203ea1c68 100644 --- a/client/ClientCommandManager.cpp +++ b/client/ClientCommandManager.cpp @@ -36,7 +36,6 @@ #include "../lib/modding/CModHandler.h" #include "../lib/modding/ContentTypeHandler.h" #include "../lib/modding/ModUtility.h" -#include "../lib/CHeroHandler.h" #include "../lib/VCMIDirs.h" #include "../lib/logging/VisualLogger.h" #include "../lib/serializer/Connection.h" diff --git a/client/NetPacksClient.cpp b/client/NetPacksClient.cpp index 91c8833b2..1c94e0d7d 100644 --- a/client/NetPacksClient.cpp +++ b/client/NetPacksClient.cpp @@ -32,7 +32,6 @@ #include "../lib/filesystem/FileInfo.h" #include "../lib/serializer/Connection.h" #include "../lib/texts/CGeneralTextHandler.h" -#include "../lib/CHeroHandler.h" #include "../lib/VCMI_Lib.h" #include "../lib/mapping/CMap.h" #include "../lib/VCMIDirs.h" diff --git a/client/PlayerLocalState.cpp b/client/PlayerLocalState.cpp index 519c39c94..66d3d69ff 100644 --- a/client/PlayerLocalState.cpp +++ b/client/PlayerLocalState.cpp @@ -24,7 +24,7 @@ PlayerLocalState::PlayerLocalState(CPlayerInterface & owner) { } -const PlayerSpellbookSetting & PlayerLocalState::getSpellbookSettings() +const PlayerSpellbookSetting & PlayerLocalState::getSpellbookSettings() const { return spellbookSettings; } @@ -347,7 +347,7 @@ void PlayerLocalState::deserialize(const JsonNode & source) { // this method must be called after player state has been initialized assert(currentSelection != nullptr); - assert(!ownedTowns.empty() || wanderingHeroes.empty()); + assert(!ownedTowns.empty() || !wanderingHeroes.empty()); auto oldHeroes = wanderingHeroes; auto oldTowns = ownedTowns; diff --git a/client/PlayerLocalState.h b/client/PlayerLocalState.h index 0cfda1f7a..3372b6052 100644 --- a/client/PlayerLocalState.h +++ b/client/PlayerLocalState.h @@ -55,7 +55,7 @@ public: void setHeroAsleep(const CGHeroInstance * hero); void setHeroAwaken(const CGHeroInstance * hero); - const PlayerSpellbookSetting & getSpellbookSettings(); + const PlayerSpellbookSetting & getSpellbookSettings() const; void setSpellbookSettings(const PlayerSpellbookSetting & newSettings); const std::vector & getOwnedTowns(); diff --git a/client/adventureMap/AdventureMapShortcuts.cpp b/client/adventureMap/AdventureMapShortcuts.cpp index fe7253cb0..d5c5ce321 100644 --- a/client/adventureMap/AdventureMapShortcuts.cpp +++ b/client/adventureMap/AdventureMapShortcuts.cpp @@ -24,6 +24,7 @@ #include "../windows/CKingdomInterface.h" #include "../windows/CSpellWindow.h" #include "../windows/CMarketWindow.h" +#include "../windows/GUIClasses.h" #include "../windows/settings/SettingsMainWindow.h" #include "AdventureMapInterface.h" #include "AdventureOptions.h" @@ -36,11 +37,14 @@ #include "../../lib/mapObjects/CGTownInstance.h" #include "../../lib/mapping/CMap.h" #include "../../lib/pathfinder/CGPathNode.h" +#include "../../lib/mapObjectConstructors/CObjectClassesHandler.h" AdventureMapShortcuts::AdventureMapShortcuts(AdventureMapInterface & owner) : owner(owner) , state(EAdventureState::NOT_INITIALIZED) , mapLevel(0) + , searchLast("") + , searchPos(0) {} void AdventureMapShortcuts::setState(EAdventureState newState) @@ -109,7 +113,9 @@ std::vector AdventureMapShortcuts::getShortcuts() { EShortcut::ADVENTURE_MOVE_HERO_EE, optionHeroSelected(), [this]() { this->moveHeroDirectional({+1, 0}); } }, { EShortcut::ADVENTURE_MOVE_HERO_NW, optionHeroSelected(), [this]() { this->moveHeroDirectional({-1, -1}); } }, { EShortcut::ADVENTURE_MOVE_HERO_NN, optionHeroSelected(), [this]() { this->moveHeroDirectional({ 0, -1}); } }, - { EShortcut::ADVENTURE_MOVE_HERO_NE, optionHeroSelected(), [this]() { this->moveHeroDirectional({+1, -1}); } } + { EShortcut::ADVENTURE_MOVE_HERO_NE, optionHeroSelected(), [this]() { this->moveHeroDirectional({+1, -1}); } }, + { EShortcut::ADVENTURE_SEARCH, optionSidePanelActive(),[this]() { this->search(false); } }, + { EShortcut::ADVENTURE_SEARCH_CONTINUE, optionSidePanelActive(),[this]() { this->search(true); } } }; return result; } @@ -457,6 +463,62 @@ void AdventureMapShortcuts::zoom( int distance) owner.hotkeyZoom(distance, false); } +void AdventureMapShortcuts::search(bool next) +{ + // get all relevant objects + std::vector visitableObjInstances; + for(auto & obj : LOCPLINT->cb->getAllVisitableObjs()) + if(obj->ID != MapObjectID::MONSTER && obj->ID != MapObjectID::HERO && obj->ID != MapObjectID::TOWN) + visitableObjInstances.push_back(obj->id); + + // count of elements for each group (map is already sorted) + std::map mapObjCount; + for(auto & obj : visitableObjInstances) + mapObjCount[{ LOCPLINT->cb->getObjInstance(obj)->getObjectName() }]++; + + // convert to vector for indexed access + std::vector> textCountList; + for (auto itr = mapObjCount.begin(); itr != mapObjCount.end(); ++itr) + textCountList.push_back(*itr); + + // get pos of last selection + int lastSel = 0; + for(int i = 0; i < textCountList.size(); i++) + if(textCountList[i].first == searchLast) + lastSel = i; + + // create texts + std::vector texts; + for(auto & obj : textCountList) + texts.push_back(obj.first + " (" + std::to_string(obj.second) + ")"); + + // function to center element from list on map + auto selectObjOnMap = [this, textCountList, visitableObjInstances](int index) + { + auto selObj = textCountList[index].first; + + // filter for matching objects + std::vector selVisitableObjInstances; + for(auto & obj : visitableObjInstances) + if(selObj == LOCPLINT->cb->getObjInstance(obj)->getObjectName()) + selVisitableObjInstances.push_back(obj); + + if(searchPos + 1 < selVisitableObjInstances.size() && searchLast == selObj) + searchPos++; + else + searchPos = 0; + + auto objInst = LOCPLINT->cb->getObjInstance(selVisitableObjInstances[searchPos]); + owner.centerOnObject(objInst); + searchLast = objInst->getObjectName(); + }; + + if(next) + selectObjOnMap(lastSel); + else + GH.windows().createAndPushWindow(texts, nullptr, CGI->generaltexth->translate("vcmi.adventureMap.search.hover"), CGI->generaltexth->translate("vcmi.adventureMap.search.help"), [selectObjOnMap](int index){ selectObjOnMap(index); }, lastSel, std::vector>(), true); +} + void AdventureMapShortcuts::nextObject() { const CGHeroInstance *h = LOCPLINT->localState->getCurrentHero(); diff --git a/client/adventureMap/AdventureMapShortcuts.h b/client/adventureMap/AdventureMapShortcuts.h index b32f3ea29..b314e7bbd 100644 --- a/client/adventureMap/AdventureMapShortcuts.h +++ b/client/adventureMap/AdventureMapShortcuts.h @@ -33,6 +33,9 @@ class AdventureMapShortcuts EAdventureState state; int mapLevel; + std::string searchLast; + int searchPos; + void showOverview(); void worldViewBack(); void worldViewScale1x(); @@ -71,6 +74,7 @@ class AdventureMapShortcuts void nextTown(); void nextObject(); void zoom( int distance); + void search(bool next); void moveHeroDirectional(const Point & direction); public: diff --git a/client/adventureMap/CList.cpp b/client/adventureMap/CList.cpp index e730224b4..121853931 100644 --- a/client/adventureMap/CList.cpp +++ b/client/adventureMap/CList.cpp @@ -29,7 +29,6 @@ #include "../render/Colors.h" #include "../../lib/texts/CGeneralTextHandler.h" -#include "../../lib/CHeroHandler.h" #include "../../lib/IGameSettings.h" #include "../../lib/mapObjects/CGHeroInstance.h" #include "../../lib/mapObjects/CGTownInstance.h" diff --git a/client/battle/BattleInterface.cpp b/client/battle/BattleInterface.cpp index cea4410d5..3017eff04 100644 --- a/client/battle/BattleInterface.cpp +++ b/client/battle/BattleInterface.cpp @@ -39,7 +39,6 @@ #include "../../lib/CStack.h" #include "../../lib/CConfigHandler.h" #include "../../lib/texts/CGeneralTextHandler.h" -#include "../../lib/CHeroHandler.h" #include "../../lib/gameState/InfoAboutArmy.h" #include "../../lib/mapObjects/CGTownInstance.h" #include "../../lib/networkPacks/PacksForClientBattle.h" diff --git a/client/battle/BattleInterfaceClasses.cpp b/client/battle/BattleInterfaceClasses.cpp index 5cf6aa340..add607dad 100644 --- a/client/battle/BattleInterfaceClasses.cpp +++ b/client/battle/BattleInterfaceClasses.cpp @@ -50,10 +50,11 @@ #include "../../lib/CStack.h" #include "../../lib/CConfigHandler.h" #include "../../lib/CCreatureHandler.h" +#include "../../lib/entities/hero/CHeroClass.h" +#include "../../lib/entities/hero/CHero.h" #include "../../lib/gameState/InfoAboutArmy.h" #include "../../lib/texts/CGeneralTextHandler.h" #include "../../lib/texts/TextOperations.h" -#include "../../lib/CHeroHandler.h" #include "../../lib/StartInfo.h" #include "../../lib/mapObjects/CGTownInstance.h" #include "../../lib/networkPacks/PacksForClientBattle.h" diff --git a/client/gui/Shortcut.h b/client/gui/Shortcut.h index 66019bd77..bd8c57a26 100644 --- a/client/gui/Shortcut.h +++ b/client/gui/Shortcut.h @@ -161,6 +161,8 @@ enum class EShortcut ADVENTURE_RESTART_GAME, ADVENTURE_TO_MAIN_MENU, ADVENTURE_QUIT_GAME, + ADVENTURE_SEARCH, + ADVENTURE_SEARCH_CONTINUE, // Move hero one tile in specified direction. Bound to cursors & numpad buttons ADVENTURE_MOVE_HERO_SW, diff --git a/client/gui/ShortcutHandler.cpp b/client/gui/ShortcutHandler.cpp index a4cffb8c4..19c3cc728 100644 --- a/client/gui/ShortcutHandler.cpp +++ b/client/gui/ShortcutHandler.cpp @@ -209,6 +209,8 @@ EShortcut ShortcutHandler::findShortcut(const std::string & identifier ) const {"adventureZoomIn", EShortcut::ADVENTURE_ZOOM_IN }, {"adventureZoomOut", EShortcut::ADVENTURE_ZOOM_OUT }, {"adventureZoomReset", EShortcut::ADVENTURE_ZOOM_RESET }, + {"adventureSearch", EShortcut::ADVENTURE_SEARCH }, + {"adventureSearchContinue", EShortcut::ADVENTURE_SEARCH_CONTINUE }, {"battleToggleHeroesStats", EShortcut::BATTLE_TOGGLE_HEROES_STATS}, {"battleToggleQueue", EShortcut::BATTLE_TOGGLE_QUEUE }, {"battleUseCreatureSpell", EShortcut::BATTLE_USE_CREATURE_SPELL }, diff --git a/client/lobby/CBonusSelection.cpp b/client/lobby/CBonusSelection.cpp index d1db2d671..e04b19f8c 100644 --- a/client/lobby/CBonusSelection.cpp +++ b/client/lobby/CBonusSelection.cpp @@ -38,10 +38,10 @@ #include "../gui/CGuiHandler.h" #include "../gui/Shortcut.h" #include "../gui/WindowHandler.h" +#include "../adventureMap/AdventureMapInterface.h" #include "../../lib/CConfigHandler.h" #include "../../lib/CCreatureHandler.h" -#include "../../lib/CHeroHandler.h" #include "../../lib/CSkillHandler.h" #include "../../lib/StartInfo.h" #include "../../lib/entities/building/CBuilding.h" @@ -49,6 +49,7 @@ #include "../../lib/entities/faction/CFaction.h" #include "../../lib/entities/faction/CTown.h" #include "../../lib/entities/faction/CTownHandler.h" +#include "../../lib/entities/hero/CHeroHandler.h" #include "../../lib/filesystem/Filesystem.h" #include "../../lib/texts/CGeneralTextHandler.h" @@ -389,10 +390,13 @@ void CBonusSelection::goBack() if(CSH->getState() != EClientState::GAMEPLAY) { GH.windows().popWindows(2); + CMM->playMusic(); } else { close(); + if(adventureInt) + adventureInt->onAudioResumed(); } // TODO: we can actually only pop bonus selection interface for custom campaigns // Though this would require clearing CLobbyScreen::bonusSel pointer when poping this interface @@ -403,7 +407,6 @@ void CBonusSelection::goBack() CSH->state = EClientState::LOBBY; } */ - CMM->playMusic(); } void CBonusSelection::startMap() diff --git a/client/lobby/CSelectionBase.cpp b/client/lobby/CSelectionBase.cpp index 9a767f5f7..13d79d672 100644 --- a/client/lobby/CSelectionBase.cpp +++ b/client/lobby/CSelectionBase.cpp @@ -43,7 +43,6 @@ #include "../render/IFont.h" #include "../render/IRenderHandler.h" -#include "../../lib/CHeroHandler.h" #include "../../lib/CRandomGenerator.h" #include "../../lib/CThreadHelper.h" #include "../../lib/filesystem/Filesystem.h" diff --git a/client/lobby/OptionsTab.cpp b/client/lobby/OptionsTab.cpp index 002904f9f..3aa94542e 100644 --- a/client/lobby/OptionsTab.cpp +++ b/client/lobby/OptionsTab.cpp @@ -39,12 +39,13 @@ #include "../../lib/entities/faction/CFaction.h" #include "../../lib/entities/faction/CTown.h" #include "../../lib/entities/faction/CTownHandler.h" +#include "../../lib/entities/hero/CHeroHandler.h" +#include "../../lib/entities/hero/CHeroClass.h" #include "../../lib/filesystem/Filesystem.h" #include "../../lib/networkPacks/PacksForLobby.h" #include "../../lib/texts/CGeneralTextHandler.h" #include "../../lib/CArtHandler.h" #include "../../lib/CConfigHandler.h" -#include "../../lib/CHeroHandler.h" #include "../../lib/mapping/CMapInfo.h" #include "../../lib/mapping/CMapHeader.h" diff --git a/client/lobby/SelectionTab.cpp b/client/lobby/SelectionTab.cpp index 06c736296..da1cdfac1 100644 --- a/client/lobby/SelectionTab.cpp +++ b/client/lobby/SelectionTab.cpp @@ -693,7 +693,7 @@ void SelectionTab::selectFileName(std::string fname) for(int i = (int)allItems.size() - 1; i >= 0; i--) { - if(allItems[i]->fileURI == fname) + if(boost::to_upper_copy(allItems[i]->fileURI) == fname) { auto [folderName, baseFolder, parentExists, fileInFolder] = checkSubfolder(allItems[i]->originalFileURI); curFolder = baseFolder != "" ? baseFolder + "/" : ""; @@ -704,7 +704,7 @@ void SelectionTab::selectFileName(std::string fname) for(int i = (int)curItems.size() - 1; i >= 0; i--) { - if(curItems[i]->fileURI == fname) + if(boost::to_upper_copy(curItems[i]->fileURI) == fname) { slider->scrollTo(i); selectAbs(i); diff --git a/client/mainmenu/CCampaignScreen.cpp b/client/mainmenu/CCampaignScreen.cpp index 4644ba18d..1957ce197 100644 --- a/client/mainmenu/CCampaignScreen.cpp +++ b/client/mainmenu/CCampaignScreen.cpp @@ -37,7 +37,6 @@ #include "../../lib/spells/CSpellHandler.h" #include "../../lib/CConfigHandler.h" #include "../../lib/CSkillHandler.h" -#include "../../lib/CHeroHandler.h" #include "../../lib/CCreatureHandler.h" #include "../../lib/campaign/CampaignHandler.h" diff --git a/client/mainmenu/CPrologEpilogVideo.cpp b/client/mainmenu/CPrologEpilogVideo.cpp index 3b68e5536..fbd7a9c22 100644 --- a/client/mainmenu/CPrologEpilogVideo.cpp +++ b/client/mainmenu/CPrologEpilogVideo.cpp @@ -48,6 +48,7 @@ CPrologEpilogVideo::CPrologEpilogVideo(CampaignScenarioPrologEpilog _spe, std::f if (videoPlayer->pos.h == 400) videoPlayer->moveBy(Point(0, 100)); + CCS->musich->setVolume(CCS->musich->getVolume() / 2); // background volume is too loud by default CCS->musich->playMusic(spe.prologMusic, true, true); voiceDurationMilliseconds = CCS->soundh->getSoundDurationMilliseconds(spe.prologVoice); voiceSoundHandle = CCS->soundh->playSound(spe.prologVoice); @@ -59,7 +60,10 @@ CPrologEpilogVideo::CPrologEpilogVideo(CampaignScenarioPrologEpilog _spe, std::f CCS->soundh->setCallback(voiceSoundHandle, onVoiceStop); text = std::make_shared(Rect(100, 500, 600, 100), EFonts::FONT_BIG, ETextAlignment::CENTER, Colors::METALLIC_GOLD, spe.prologText.toString()); - text->scrollTextTo(-50); // beginning of text in the vertical middle of black area + if(text->getLines().size() == 3) + text->scrollTextTo(-25); // beginning of text in the vertical middle of black area + else if(text->getLines().size() > 3) + text->scrollTextTo(-50); // beginning of text in the vertical middle of black area } void CPrologEpilogVideo::tick(uint32_t msPassed) @@ -88,6 +92,7 @@ void CPrologEpilogVideo::show(Canvas & to) void CPrologEpilogVideo::clickPressed(const Point & cursorPosition) { + CCS->musich->setVolume(CCS->musich->getVolume() * 2); // restore background volume close(); CCS->soundh->resetCallback(voiceSoundHandle); // reset callback to avoid memory corruption since 'this' will be destroyed CCS->soundh->stopSound(voiceSoundHandle); diff --git a/client/media/CSoundHandler.cpp b/client/media/CSoundHandler.cpp index 79562f15c..adfb1a2f7 100644 --- a/client/media/CSoundHandler.cpp +++ b/client/media/CSoundHandler.cpp @@ -147,18 +147,24 @@ uint32_t CSoundHandler::getSoundDurationMilliseconds(const AudioPath & sound) auto data = CResourceHandler::get()->load(resourcePath)->readAll(); - SDL_AudioSpec spec; - uint32_t audioLen; - uint8_t * audioBuf; uint32_t milliseconds = 0; - if(SDL_LoadWAV_RW(SDL_RWFromMem(data.first.get(), data.second), 1, &spec, &audioBuf, &audioLen) != nullptr) + Mix_Chunk * chunk = Mix_LoadWAV_RW(SDL_RWFromMem(data.first.get(), data.second), 1); + + int freq = 0; + Uint16 fmt = 0; + int channels = 0; + if(!Mix_QuerySpec(&freq, &fmt, &channels)) + return 0; + + if(chunk != nullptr) { - SDL_FreeWAV(audioBuf); - uint32_t sampleSize = SDL_AUDIO_BITSIZE(spec.format) / 8; - uint32_t sampleCount = audioLen / sampleSize; - uint32_t sampleLen = sampleCount / spec.channels; - milliseconds = 1000 * sampleLen / spec.freq; + Uint32 sampleSizeBytes = (fmt & 0xFF) / 8; + Uint32 samples = (chunk->alen / sampleSizeBytes); + Uint32 frames = (samples / channels); + milliseconds = ((frames * 1000) / freq); + + Mix_FreeChunk(chunk); } return milliseconds; diff --git a/client/media/CVideoHandler.cpp b/client/media/CVideoHandler.cpp index b13c2dfc0..b028e8c57 100644 --- a/client/media/CVideoHandler.cpp +++ b/client/media/CVideoHandler.cpp @@ -545,7 +545,7 @@ std::pair, si64> CAudioInstance::extractAudio(const Vide frameSamplesBuffer.resize(std::max(frameSamplesBuffer.size(), bytesToRead)); uint8_t * frameSamplesPtr = frameSamplesBuffer.data(); - int result = swr_convert(swr_ctx, &frameSamplesPtr, frame->nb_samples, (const uint8_t **)frame->data, frame->nb_samples); + int result = swr_convert(swr_ctx, &frameSamplesPtr, frame->nb_samples, const_cast(frame->data), frame->nb_samples); if (result < 0) throwFFmpegError(result); diff --git a/client/render/AssetGenerator.cpp b/client/render/AssetGenerator.cpp index 3d0d346e2..d887528e0 100644 --- a/client/render/AssetGenerator.cpp +++ b/client/render/AssetGenerator.cpp @@ -158,7 +158,7 @@ void AssetGenerator::createPlayerColoredBackground(const PlayerColor & player) assert(player.isValidPlayer()); if (!player.isValidPlayer()) { - logGlobal->error("Unable to colorize to invalid player color %d!", static_cast(player.getNum())); + logGlobal->error("Unable to colorize to invalid player color %d!", player.getNum()); return; } diff --git a/client/render/Graphics.cpp b/client/render/Graphics.cpp index 0c88f508a..9792e83e7 100644 --- a/client/render/Graphics.cpp +++ b/client/render/Graphics.cpp @@ -28,7 +28,6 @@ #include "../lib/modding/CModHandler.h" #include "../lib/modding/ModScope.h" #include "../lib/VCMI_Lib.h" -#include "../lib/CHeroHandler.h" #include diff --git a/client/renderSDL/CTrueTypeFont.cpp b/client/renderSDL/CTrueTypeFont.cpp index dcf3661d6..ddff8347e 100644 --- a/client/renderSDL/CTrueTypeFont.cpp +++ b/client/renderSDL/CTrueTypeFont.cpp @@ -64,9 +64,9 @@ int CTrueTypeFont::getFontStyle(const JsonNode &config) const CTrueTypeFont::CTrueTypeFont(const JsonNode & fontConfig): data(loadData(fontConfig)), font(loadFont(fontConfig), TTF_CloseFont), - dropShadow(!fontConfig["noShadow"].Bool()), + blended(true), outline(fontConfig["outline"].Bool()), - blended(true) + dropShadow(!fontConfig["noShadow"].Bool()) { assert(font); @@ -95,14 +95,14 @@ size_t CTrueTypeFont::getLineHeightScaled() const return TTF_FontHeight(font.get()); } -size_t CTrueTypeFont::getGlyphWidthScaled(const char *data) const +size_t CTrueTypeFont::getGlyphWidthScaled(const char *text) const { - return getStringWidthScaled(std::string(data, TextOperations::getUnicodeCharacterSize(*data))); + return getStringWidthScaled(std::string(text, TextOperations::getUnicodeCharacterSize(*text))); } -bool CTrueTypeFont::canRepresentCharacter(const char * data) const +bool CTrueTypeFont::canRepresentCharacter(const char * text) const { - uint32_t codepoint = TextOperations::getUnicodeCodepoint(data, TextOperations::getUnicodeCharacterSize(*data)); + uint32_t codepoint = TextOperations::getUnicodeCodepoint(text, TextOperations::getUnicodeCharacterSize(*text)); #if SDL_TTF_VERSION_ATLEAST(2, 0, 18) return TTF_GlyphIsProvided32(font.get(), codepoint); #elif SDL_TTF_VERSION_ATLEAST(2, 0, 12) @@ -114,10 +114,10 @@ bool CTrueTypeFont::canRepresentCharacter(const char * data) const #endif } -size_t CTrueTypeFont::getStringWidthScaled(const std::string & data) const +size_t CTrueTypeFont::getStringWidthScaled(const std::string & text) const { int width; - TTF_SizeUTF8(font.get(), data.c_str(), &width, nullptr); + TTF_SizeUTF8(font.get(), text.c_str(), &width, nullptr); return width; } diff --git a/client/widgets/CArtPlace.cpp b/client/widgets/CArtPlace.cpp index dbae173a2..954366315 100644 --- a/client/widgets/CArtPlace.cpp +++ b/client/widgets/CArtPlace.cpp @@ -217,9 +217,9 @@ void CArtPlace::setGestureCallback(const ClickFunctor & callback) void CArtPlace::addCombinedArtInfo(const std::map> & arts) { - for(const auto & availableArts : arts) + for(auto [combinedId, availableArts] : arts) { - const auto combinedArt = availableArts.first.toArtifact(); + const auto combinedArt = combinedId.toArtifact(); MetaString info; info.appendEOL(); info.appendEOL(); @@ -227,14 +227,20 @@ void CArtPlace::addCombinedArtInfo(const std::mapgetId()); info.appendRawString("}"); info.appendRawString(" (%d/%d)"); - info.replaceNumber(availableArts.second.size()); + info.replaceNumber(availableArts.size()); info.replaceNumber(combinedArt->getConstituents().size()); for(const auto part : combinedArt->getConstituents()) { + const auto found = std::find_if(availableArts.begin(), availableArts.end(), [part](const auto & availablePart) -> bool + { + return availablePart == part->getId() ? true : false; + }); + info.appendEOL(); - if(vstd::contains(availableArts.second, part->getId())) + if(found < availableArts.end()) { info.appendName(part->getId()); + availableArts.erase(found); } else { diff --git a/client/widgets/CArtifactsOfHeroBase.cpp b/client/widgets/CArtifactsOfHeroBase.cpp index 8318fdf89..6d857b010 100644 --- a/client/widgets/CArtifactsOfHeroBase.cpp +++ b/client/widgets/CArtifactsOfHeroBase.cpp @@ -268,11 +268,17 @@ void CArtifactsOfHeroBase::setSlotData(ArtPlacePtr artPlace, const ArtifactPosit std::map> arts; for(const auto combinedArt : slotInfo->artifact->artType->getPartOf()) { - arts.try_emplace(combinedArt->getId(), std::vector{}); + assert(combinedArt->isCombined()); + arts.try_emplace(combinedArt->getId()); + CArtifactFittingSet fittingSet(*curHero); for(const auto part : combinedArt->getConstituents()) { - if(curHero->hasArt(part->getId(), false, false)) + const auto partSlot = fittingSet.getArtPos(part->getId(), false, false); + if(partSlot != ArtifactPosition::PRE_FIRST) + { arts.at(combinedArt->getId()).emplace_back(part->getId()); + fittingSet.lockSlot(partSlot); + } } } artPlace->addCombinedArtInfo(arts); diff --git a/client/widgets/CComponent.cpp b/client/widgets/CComponent.cpp index f02ba67b9..80b800492 100644 --- a/client/widgets/CComponent.cpp +++ b/client/widgets/CComponent.cpp @@ -12,9 +12,6 @@ #include "Images.h" -#include -#include - #include "../gui/CGuiHandler.h" #include "../gui/CursorHandler.h" #include "../gui/TextAlignment.h" @@ -29,7 +26,6 @@ #include "../CGameInfo.h" #include "../../lib/ArtifactUtils.h" -#include "../../lib/CHeroHandler.h" #include "../../lib/entities/building/CBuilding.h" #include "../../lib/entities/faction/CFaction.h" #include "../../lib/entities/faction/CTown.h" @@ -42,6 +38,11 @@ #include "../../lib/CArtHandler.h" #include "../../lib/CArtifactInstance.h" +#include +#include +#include +#include + CComponent::CComponent(ComponentType Type, ComponentSubType Subtype, std::optional Val, ESize imageSize, EFonts font) { init(Type, Subtype, Val, imageSize, font, ""); diff --git a/client/widgets/ObjectLists.cpp b/client/widgets/ObjectLists.cpp index d2ad5c1ae..d9a257923 100644 --- a/client/widgets/ObjectLists.cpp +++ b/client/widgets/ObjectLists.cpp @@ -185,6 +185,9 @@ void CListBox::scrollTo(size_t which) //scroll down else if (first + items.size() <= which && which < totalSize) moveToPos(which - items.size() + 1); + + if(slider) + slider->scrollTo(which); } void CListBox::moveToPos(size_t which) diff --git a/client/widgets/TextControls.cpp b/client/widgets/TextControls.cpp index 8975fd469..16745214f 100644 --- a/client/widgets/TextControls.cpp +++ b/client/widgets/TextControls.cpp @@ -176,6 +176,11 @@ void CMultiLineLabel::setText(const std::string & Txt) CLabel::setText(Txt); } +std::vector CMultiLineLabel::getLines() +{ + return lines; +} + void CTextContainer::blitLine(Canvas & to, Rect destRect, std::string what) { const auto f = GH.renderHandler().loadFont(font); @@ -309,7 +314,7 @@ void CMultiLineLabel::splitText(const std::string & Txt, bool redrawAfter) lines.clear(); const auto & fontPtr = GH.renderHandler().loadFont(font); - int lineHeight = static_cast(fontPtr->getLineHeight()); + int lineHeight = fontPtr->getLineHeight(); lines = CMessage::breakText(Txt, pos.w, font); @@ -330,16 +335,16 @@ Rect CMultiLineLabel::getTextLocation() return pos; const auto & fontPtr = GH.renderHandler().loadFont(font); - Point textSize(pos.w, fontPtr->getLineHeight() * (int)lines.size()); - Point textOffset(pos.w - textSize.x, pos.h - textSize.y); + Point textSizeComputed(pos.w, fontPtr->getLineHeight() * lines.size()); //FIXME: how is this different from textSize member? + Point textOffset(pos.w - textSizeComputed.x, pos.h - textSizeComputed.y); switch(alignment) { - case ETextAlignment::TOPLEFT: return Rect(pos.topLeft(), textSize); - case ETextAlignment::TOPCENTER: return Rect(pos.topLeft(), textSize); - case ETextAlignment::CENTER: return Rect(pos.topLeft() + textOffset / 2, textSize); - case ETextAlignment::CENTERRIGHT: return Rect(pos.topLeft() + Point(textOffset.x, textOffset.y / 2), textSize); - case ETextAlignment::BOTTOMRIGHT: return Rect(pos.topLeft() + textOffset, textSize); + case ETextAlignment::TOPLEFT: return Rect(pos.topLeft(), textSizeComputed); + case ETextAlignment::TOPCENTER: return Rect(pos.topLeft(), textSizeComputed); + case ETextAlignment::CENTER: return Rect(pos.topLeft() + textOffset / 2, textSizeComputed); + case ETextAlignment::CENTERRIGHT: return Rect(pos.topLeft() + Point(textOffset.x, textOffset.y / 2), textSizeComputed); + case ETextAlignment::BOTTOMRIGHT: return Rect(pos.topLeft() + textOffset, textSizeComputed); } assert(0); return Rect(); diff --git a/client/widgets/TextControls.h b/client/widgets/TextControls.h index 6880e6b44..0c99c193b 100644 --- a/client/widgets/TextControls.h +++ b/client/widgets/TextControls.h @@ -96,6 +96,7 @@ public: CMultiLineLabel(Rect position, EFonts Font = FONT_SMALL, ETextAlignment Align = ETextAlignment::TOPLEFT, const ColorRGBA & Color = Colors::WHITE, const std::string & Text = ""); void setText(const std::string & Txt) override; + std::vector getLines(); void showAll(Canvas & to) override; void setVisibleSize(Rect visibleSize, bool redrawElement = true); diff --git a/client/widgets/markets/CMarketBase.cpp b/client/widgets/markets/CMarketBase.cpp index 02574dc67..8c6d78ec8 100644 --- a/client/widgets/markets/CMarketBase.cpp +++ b/client/widgets/markets/CMarketBase.cpp @@ -23,9 +23,9 @@ #include "../../../CCallback.h" +#include "../../../lib/entities/hero/CHeroHandler.h" #include "../../../lib/texts/CGeneralTextHandler.h" #include "../../../lib/mapObjects/CGHeroInstance.h" -#include "../../../lib/CHeroHandler.h" #include "../../../lib/mapObjects/CGMarket.h" CMarketBase::CMarketBase(const IMarket * market, const CGHeroInstance * hero) diff --git a/client/windows/CCastleInterface.cpp b/client/windows/CCastleInterface.cpp index aea486688..28984167b 100644 --- a/client/windows/CCastleInterface.cpp +++ b/client/windows/CCastleInterface.cpp @@ -2007,10 +2007,10 @@ void CMageGuildScreen::updateSpells(ObjectInstanceID tID) const CGTownInstance * town = LOCPLINT->cb->getTown(townId); - for(size_t i=0; igetTown()->mageLevel; i++) + for(uint32_t i=0; igetTown()->mageLevel; i++) { - size_t spellCount = town->spellsAtLevel((int)i+1,false); //spell at level with -1 hmmm? - for(size_t j=0; jspellsAtLevel(i+1,false); //spell at level with -1 hmmm? + for(uint32_t j=0; jmageGuildLevel() && town->spells[i].size()>j) spells.push_back(std::make_shared(positions[i][j], town->spells[i][j].toSpell(), townId)); @@ -2063,30 +2063,26 @@ void CMageGuildScreen::Scroll::clickPressed(const Point & cursorPosition) resComps.push_back(std::make_shared(ComponentType::RESOURCE, i->resType, i->resVal, CComponent::ESize::medium)); } - auto showSpellResearchDialog = [this, resComps, town, cost, newSpell](){ - std::vector>> pom; - for(int i = 0; i < 3; i++) - pom.emplace_back(AnimationPath::builtin("settingsWindow/button80"), nullptr); + std::vector>> pom; + for(int i = 0; i < 3; i++) + pom.emplace_back(AnimationPath::builtin("settingsWindow/button80"), nullptr); - auto text = CGI->generaltexth->translate(LOCPLINT->cb->getResourceAmount().canAfford(cost) ? "vcmi.spellResearch.pay" : "vcmi.spellResearch.canNotAfford"); - boost::replace_first(text, "%SPELL1", spell->id.toSpell()->getNameTranslated()); - boost::replace_first(text, "%SPELL2", newSpell.toSpell()->getNameTranslated()); - auto temp = std::make_shared(text, LOCPLINT->playerID, resComps, pom); + auto text = CGI->generaltexth->translate(LOCPLINT->cb->getResourceAmount().canAfford(cost) ? "vcmi.spellResearch.pay" : "vcmi.spellResearch.canNotAfford"); + boost::replace_first(text, "%SPELL1", spell->id.toSpell()->getNameTranslated()); + boost::replace_first(text, "%SPELL2", newSpell.toSpell()->getNameTranslated()); + auto temp = std::make_shared(text, LOCPLINT->playerID, resComps, pom); - temp->buttons[0]->setOverlay(std::make_shared(ImagePath::builtin("spellResearch/accept"))); - temp->buttons[0]->addCallback([this, town](){ LOCPLINT->cb->spellResearch(town, spell->id, true); }); - temp->buttons[0]->addPopupCallback([](){ CRClickPopup::createAndPush(CGI->generaltexth->translate("vcmi.spellResearch.research")); }); - temp->buttons[0]->setEnabled(LOCPLINT->cb->getResourceAmount().canAfford(cost)); - temp->buttons[1]->setOverlay(std::make_shared(ImagePath::builtin("spellResearch/reroll"))); - temp->buttons[1]->addCallback([this, town](){ LOCPLINT->cb->spellResearch(town, spell->id, false); }); - temp->buttons[1]->addPopupCallback([](){ CRClickPopup::createAndPush(CGI->generaltexth->translate("vcmi.spellResearch.skip")); }); - temp->buttons[2]->setOverlay(std::make_shared(ImagePath::builtin("spellResearch/close"))); - temp->buttons[2]->addPopupCallback([](){ CRClickPopup::createAndPush(CGI->generaltexth->translate("vcmi.spellResearch.abort")); }); + temp->buttons[0]->setOverlay(std::make_shared(ImagePath::builtin("spellResearch/accept"))); + temp->buttons[0]->addCallback([this, town](){ LOCPLINT->cb->spellResearch(town, spell->id, true); }); + temp->buttons[0]->addPopupCallback([](){ CRClickPopup::createAndPush(CGI->generaltexth->translate("vcmi.spellResearch.research")); }); + temp->buttons[0]->setEnabled(LOCPLINT->cb->getResourceAmount().canAfford(cost)); + temp->buttons[1]->setOverlay(std::make_shared(ImagePath::builtin("spellResearch/reroll"))); + temp->buttons[1]->addCallback([this, town](){ LOCPLINT->cb->spellResearch(town, spell->id, false); }); + temp->buttons[1]->addPopupCallback([](){ CRClickPopup::createAndPush(CGI->generaltexth->translate("vcmi.spellResearch.skip")); }); + temp->buttons[2]->setOverlay(std::make_shared(ImagePath::builtin("spellResearch/close"))); + temp->buttons[2]->addPopupCallback([](){ CRClickPopup::createAndPush(CGI->generaltexth->translate("vcmi.spellResearch.abort")); }); - GH.windows().pushWindow(temp); - }; - - showSpellResearchDialog(); + GH.windows().pushWindow(temp); } else LOCPLINT->showInfoDialog(spell->getDescriptionTranslated(0), std::make_shared(ComponentType::SPELL, spell->id)); diff --git a/client/windows/CCreatureWindow.cpp b/client/windows/CCreatureWindow.cpp index 6c5612d5d..293324c3e 100644 --- a/client/windows/CCreatureWindow.cpp +++ b/client/windows/CCreatureWindow.cpp @@ -31,7 +31,7 @@ #include "../../lib/CStack.h" #include "../../lib/CBonusTypeHandler.h" #include "../../lib/IGameSettings.h" -#include "../../lib/CHeroHandler.h" +#include "../../lib/entities/hero/CHeroHandler.h" #include "../../lib/gameState/CGameState.h" #include "../../lib/networkPacks/ArtifactLocation.h" #include "../../lib/texts/CGeneralTextHandler.h" diff --git a/client/windows/CExchangeWindow.cpp b/client/windows/CExchangeWindow.cpp index 0bd8d74a3..197ef9795 100644 --- a/client/windows/CExchangeWindow.cpp +++ b/client/windows/CExchangeWindow.cpp @@ -29,8 +29,8 @@ #include "../../CCallback.h" -#include "../lib/CHeroHandler.h" #include "../lib/CSkillHandler.h" +#include "../lib/entities/hero/CHeroHandler.h" #include "../lib/filesystem/Filesystem.h" #include "../lib/mapObjects/CGHeroInstance.h" #include "../lib/texts/CGeneralTextHandler.h" diff --git a/client/windows/CHeroOverview.cpp b/client/windows/CHeroOverview.cpp index b1719df4d..6043aefac 100644 --- a/client/windows/CHeroOverview.cpp +++ b/client/windows/CHeroOverview.cpp @@ -24,9 +24,10 @@ #include "../widgets/GraphicalPrimitiveCanvas.h" #include "../../lib/IGameSettings.h" +#include "../../lib/entities/hero/CHeroHandler.h" +#include "../../lib/entities/hero/CHeroClass.h" #include "../../lib/texts/CGeneralTextHandler.h" #include "../../lib/CCreatureHandler.h" -#include "../../lib/CHeroHandler.h" #include "../../lib/CSkillHandler.h" #include "../../lib/spells/CSpellHandler.h" diff --git a/client/windows/CHeroWindow.cpp b/client/windows/CHeroWindow.cpp index 809f937f0..9599fb567 100644 --- a/client/windows/CHeroWindow.cpp +++ b/client/windows/CHeroWindow.cpp @@ -35,11 +35,11 @@ #include "../lib/ArtifactUtils.h" #include "../lib/CArtHandler.h" #include "../lib/CConfigHandler.h" +#include "../lib/entities/hero/CHeroHandler.h" #include "../lib/texts/CGeneralTextHandler.h" -#include "../lib/CHeroHandler.h" #include "../lib/CSkillHandler.h" #include "../lib/mapObjects/CGHeroInstance.h" -#include "../../lib/networkPacks/ArtifactLocation.h" +#include "../lib/networkPacks/ArtifactLocation.h" void CHeroSwitcher::clickPressed(const Point & cursorPosition) { diff --git a/client/windows/CKingdomInterface.cpp b/client/windows/CKingdomInterface.cpp index 6c99bbca6..0d754741f 100644 --- a/client/windows/CKingdomInterface.cpp +++ b/client/windows/CKingdomInterface.cpp @@ -33,8 +33,8 @@ #include "../../lib/CConfigHandler.h" #include "../../lib/CCreatureHandler.h" +#include "../../lib/entities/hero/CHeroHandler.h" #include "../../lib/texts/CGeneralTextHandler.h" -#include "../../lib/CHeroHandler.h" #include "../../lib/IGameSettings.h" #include "../../lib/CSkillHandler.h" #include "../../lib/StartInfo.h" diff --git a/client/windows/GUIClasses.cpp b/client/windows/GUIClasses.cpp index 46406d4d4..ad630a77d 100644 --- a/client/windows/GUIClasses.cpp +++ b/client/windows/GUIClasses.cpp @@ -44,6 +44,7 @@ #include "../lib/entities/building/CBuilding.h" #include "../lib/entities/faction/CTownHandler.h" +#include "../lib/entities/hero/CHeroHandler.h" #include "../lib/mapObjectConstructors/CObjectClassesHandler.h" #include "../lib/mapObjectConstructors/CommonConstructors.h" #include "../lib/mapObjects/CGHeroInstance.h" @@ -53,7 +54,6 @@ #include "../lib/gameState/SThievesGuildInfo.h" #include "../lib/gameState/TavernHeroesPool.h" #include "../lib/texts/CGeneralTextHandler.h" -#include "../lib/CHeroHandler.h" #include "../lib/IGameSettings.h" #include "ConditionalWait.h" #include "../lib/CRandomGenerator.h" @@ -1480,39 +1480,47 @@ void CObjectListWindow::CItem::showPopupWindow(const Point & cursorPosition) parent->onPopup(index); } -CObjectListWindow::CObjectListWindow(const std::vector & _items, std::shared_ptr titleWidget_, std::string _title, std::string _descr, std::function Callback, size_t initialSelection, std::vector> images) +CObjectListWindow::CObjectListWindow(const std::vector & _items, std::shared_ptr titleWidget_, std::string _title, std::string _descr, std::function Callback, size_t initialSelection, std::vector> images, bool searchBoxEnabled) : CWindowObject(PLAYER_COLORED, ImagePath::builtin("TPGATE")), onSelect(Callback), selected(initialSelection), images(images) { OBJECT_CONSTRUCTION; + + addUsedEvents(KEYBOARD); + items.reserve(_items.size()); for(int id : _items) - { items.push_back(std::make_pair(id, LOCPLINT->cb->getObjInstance(ObjectInstanceID(id))->getObjectName())); - } + itemsVisible = items; - init(titleWidget_, _title, _descr); + init(titleWidget_, _title, _descr, searchBoxEnabled); + list->scrollTo(initialSelection - 4); // -4 is for centering (list have 9 elements) } -CObjectListWindow::CObjectListWindow(const std::vector & _items, std::shared_ptr titleWidget_, std::string _title, std::string _descr, std::function Callback, size_t initialSelection, std::vector> images) +CObjectListWindow::CObjectListWindow(const std::vector & _items, std::shared_ptr titleWidget_, std::string _title, std::string _descr, std::function Callback, size_t initialSelection, std::vector> images, bool searchBoxEnabled) : CWindowObject(PLAYER_COLORED, ImagePath::builtin("TPGATE")), onSelect(Callback), selected(initialSelection), images(images) { OBJECT_CONSTRUCTION; + + addUsedEvents(KEYBOARD); + items.reserve(_items.size()); for(size_t i=0; i<_items.size(); i++) items.push_back(std::make_pair(int(i), _items[i])); + itemsVisible = items; - init(titleWidget_, _title, _descr); + init(titleWidget_, _title, _descr, searchBoxEnabled); + list->scrollTo(initialSelection - 4); // -4 is for centering (list have 9 elements) } -void CObjectListWindow::init(std::shared_ptr titleWidget_, std::string _title, std::string _descr) +void CObjectListWindow::init(std::shared_ptr titleWidget_, std::string _title, std::string _descr, bool searchBoxEnabled) { titleWidget = titleWidget_; @@ -1527,24 +1535,51 @@ void CObjectListWindow::init(std::shared_ptr titleWidget_, std::stri titleWidget->pos.y =75 + pos.y - titleWidget->pos.h/2; } list = std::make_shared(std::bind(&CObjectListWindow::genItem, this, _1), - Point(14, 151), Point(0, 25), 9, items.size(), 0, 1, Rect(262, -32, 256, 256) ); + Point(14, 151), Point(0, 25), 9, itemsVisible.size(), 0, 1, Rect(262, -32, 256, 256) ); list->setRedrawParent(true); ok = std::make_shared(Point(15, 402), AnimationPath::builtin("IOKAY.DEF"), CButton::tooltip(), std::bind(&CObjectListWindow::elementSelected, this), EShortcut::GLOBAL_ACCEPT); ok->block(!list->size()); + + if(!searchBoxEnabled) + return; + + Rect r(50, 90, pos.w - 100, 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(r.resize(1), rectangleColor, borderColor); + searchBoxDescription = std::make_shared(r.center().x, r.center().y, FONT_SMALL, ETextAlignment::CENTER, grayedColor, CGI->generaltexth->translate("vcmi.spellBook.search")); + + searchBox = std::make_shared(r, FONT_SMALL, ETextAlignment::CENTER, true); + searchBox->setCallback([this](const std::string & text){ + searchBoxDescription->setEnabled(text.empty()); + + itemsVisible.clear(); + for(auto & item : items) + if(boost::algorithm::contains(boost::algorithm::to_lower_copy(item.second), boost::algorithm::to_lower_copy(text))) + itemsVisible.push_back(item); + + selected = 0; + list->resize(itemsVisible.size()); + list->scrollTo(0); + ok->block(!itemsVisible.size()); + + redraw(); + }); } std::shared_ptr CObjectListWindow::genItem(size_t index) { - if(index < items.size()) - return std::make_shared(this, index, items[index].second); + if(index < itemsVisible.size()) + return std::make_shared(this, index, itemsVisible[index].second); return std::shared_ptr(); } void CObjectListWindow::elementSelected() { std::function toCall = onSelect;//save - int where = items[selected].first; //required variables + int where = itemsVisible[selected].first; //required variables close();//then destroy window toCall(where);//and send selected object } @@ -1600,18 +1635,18 @@ void CObjectListWindow::keyPressed(EShortcut key) sel = 0; break; case EShortcut::MOVE_LAST: - sel = static_cast(items.size()); + sel = static_cast(itemsVisible.size()); break; default: return; } - vstd::abetween(sel, 0, items.size()-1); - list->scrollTo(sel); + vstd::abetween(sel, 0, itemsVisible.size()-1); + list->scrollTo(sel - 4); // -4 is for centering (list have 9 elements) changeSelection(sel); } -VideoWindow::VideoWindow(VideoPath video, ImagePath rim, bool showBackground, float scaleFactor, std::function closeCb) +VideoWindow::VideoWindow(const VideoPath & video, const ImagePath & rim, bool showBackground, float scaleFactor, const std::function & closeCb) : CWindowObject(BORDERED | SHADOW_DISABLED | NEEDS_ANIMATED_BACKGROUND), closeCb(closeCb) { OBJECT_CONSTRUCTION; diff --git a/client/windows/GUIClasses.h b/client/windows/GUIClasses.h index 5e58ad6d2..fb3740a02 100644 --- a/client/windows/GUIClasses.h +++ b/client/windows/GUIClasses.h @@ -45,6 +45,7 @@ class IImage; class VideoWidget; class VideoWidgetOnce; class GraphicalPrimitiveCanvas; +class TransparentFilledRectangle; enum class EUserEvent; @@ -186,9 +187,14 @@ class CObjectListWindow : public CWindowObject std::shared_ptr ok; std::shared_ptr exit; - std::vector< std::pair > items;//all items present in list + std::shared_ptr searchBox; + std::shared_ptr searchBoxRectangle; + std::shared_ptr searchBoxDescription; - void init(std::shared_ptr titleWidget_, std::string _title, std::string _descr); + std::vector< std::pair > items; //all items present in list + std::vector< std::pair > itemsVisible; //visible items present in list + + void init(std::shared_ptr titleWidget_, std::string _title, std::string _descr, bool searchBoxEnabled); void exitPressed(); public: size_t selected;//index of currently selected item @@ -200,8 +206,8 @@ public: /// Callback will be called when OK button is pressed, returns id of selected item. initState = initially selected item /// Image can be nullptr ///item names will be taken from map objects - CObjectListWindow(const std::vector &_items, std::shared_ptr titleWidget_, std::string _title, std::string _descr, std::function Callback, size_t initialSelection = 0, std::vector> images = {}); - CObjectListWindow(const std::vector &_items, std::shared_ptr titleWidget_, std::string _title, std::string _descr, std::function Callback, size_t initialSelection = 0, std::vector> images = {}); + CObjectListWindow(const std::vector &_items, std::shared_ptr titleWidget_, std::string _title, std::string _descr, std::function Callback, size_t initialSelection = 0, std::vector> images = {}, bool searchBoxEnabled = false); + CObjectListWindow(const std::vector &_items, std::shared_ptr titleWidget_, std::string _title, std::string _descr, std::function Callback, size_t initialSelection = 0, std::vector> images = {}, bool searchBoxEnabled = false); std::shared_ptr genItem(size_t index); void elementSelected();//call callback and close this window @@ -513,7 +519,7 @@ class VideoWindow : public CWindowObject void exit(bool skipped); public: - VideoWindow(VideoPath video, ImagePath rim, bool showBackground, float scaleFactor, std::function closeCb); + VideoWindow(const VideoPath & video, const ImagePath & rim, bool showBackground, float scaleFactor, const std::function & closeCb); void clickPressed(const Point & cursorPosition) override; void keyPressed(EShortcut key) override; diff --git a/client/windows/InfoWindows.cpp b/client/windows/InfoWindows.cpp index cabeeef13..2719c08d5 100644 --- a/client/windows/InfoWindows.cpp +++ b/client/windows/InfoWindows.cpp @@ -187,11 +187,6 @@ bool CRClickPopup::isPopupWindow() const return true; } -void CRClickPopup::close() -{ - WindowBase::close(); -} - void CRClickPopup::createAndPush(const std::string & txt, const CInfoWindow::TCompsInfo & comps) { PlayerColor player = LOCPLINT ? LOCPLINT->playerID : PlayerColor(1); //if no player, then use blue diff --git a/client/windows/InfoWindows.h b/client/windows/InfoWindows.h index a06416934..81b661339 100644 --- a/client/windows/InfoWindows.h +++ b/client/windows/InfoWindows.h @@ -64,7 +64,6 @@ public: class CRClickPopup : public WindowBase { public: - void close() override; bool isPopupWindow() const override; static std::shared_ptr createCustomInfoWindow(Point position, const CGObjectInstance * specific); diff --git a/conanfile.py b/conanfile.py index c9c5df23d..302aba724 100644 --- a/conanfile.py +++ b/conanfile.py @@ -15,10 +15,11 @@ class VCMI(ConanFile): "minizip/[~1.2.12]", ] _clientRequires = [ - "sdl/[~2.26.1 || >=2.0.20 <=2.22.0]", # versions in between have broken sound - "sdl_image/[~2.0.5]", - "sdl_mixer/[~2.0.4]", - "sdl_ttf/[~2.0.18]", + # Versions between 2.5-2.8 have broken loading of palette sdl images which a lot of mods use + # there is workaround that require disabling cmake flag which is not available in conan recipes. + # Bug is fixed in version 2.8, however it is not available in conan at the moment + "sdl_image/2.0.5", + "sdl_ttf/[>=2.0.18]", "onetbb/[^2021.7 <2021.10]", # 2021.10+ breaks mobile builds due to added hwloc dependency "xz_utils/[>=5.2.5]", # Required for innoextract ] @@ -46,21 +47,41 @@ class VCMI(ConanFile): self.options["freetype"].shared = self.settings.os == "Android" # SDL_image and Qt depend on it, in iOS both are static - # Enable static libpng due to https://github.com/conan-io/conan-center-index/issues/15440, - # which leads to VCMI crashes of MinGW - self.options["libpng"].shared = not (self.settings.os == "Windows" and cross_building(self)) and self.settings.os != "iOS" + self.options["libpng"].shared = self.settings.os != "iOS" # static Qt for iOS is the only viable option at the moment self.options["qt"].shared = self.settings.os != "iOS" - if self.settings.os == "Android": - self.options["qt"].android_sdk = tools.get_env("ANDROID_HOME", default="") - # TODO: enable for all platforms if self.settings.os == "Android": self.options["bzip2"].shared = True self.options["libiconv"].shared = True self.options["zlib"].shared = True + # TODO: enable for all platforms? + if self.settings.os == "Windows": + self.options["sdl"].shared = True + self.options["sdl_image"].shared = True + self.options["sdl_mixer"].shared = True + self.options["sdl_ttf"].shared = True + + if self.settings.os == "iOS": + # TODO: ios - newer sdl fails to link + self.requires("sdl/2.26.1") + self.requires("sdl_mixer/2.0.4") + elif self.settings.os == "Android": + # On Android SDL version must be same as version of Java wrapper for SDL in VCMI source code + # Wrapper can be found in following directory: android/vcmi-app/src/main/java/org/libsdl/app + self.requires("sdl/2.26.5") + self.requires("sdl_mixer/2.0.4") + else: + # upcoming SDL version 3.0+ is not supported at the moment due to API breakage + # SDL versions between 2.22-2.26.1 have broken sound + self.requires("sdl/[^2.26 || >=2.0.20 <=2.22.0]") + self.requires("sdl_mixer/[>=2.0.4]") + + if self.settings.os == "Android": + self.options["qt"].android_sdk = tools.get_env("ANDROID_HOME", default="") + if self.options.default_options_of_requirements: return @@ -86,6 +107,7 @@ class VCMI(ConanFile): self.options["boost"].without_timer = True self.options["boost"].without_type_erasure = True self.options["boost"].without_wave = True + self.options["boost"].without_url = True self.options["ffmpeg"].disable_all_bitstream_filters = True self.options["ffmpeg"].disable_all_decoders = True @@ -149,8 +171,13 @@ class VCMI(ConanFile): self.options["sdl"].sdl2main = self.settings.os != "iOS" self.options["sdl"].vulkan = False + # bmp, png are the only ones that needs to be supported + # dds support may be useful for HD edition, but not supported by sdl_image at the moment + self.options["sdl_image"].gif = False self.options["sdl_image"].lbm = False self.options["sdl_image"].pnm = False + self.options["sdl_image"].pcx = False + #self.options["sdl_image"].qoi = False # sdl_image >=2.6 self.options["sdl_image"].svg = False self.options["sdl_image"].tga = False self.options["sdl_image"].with_libjpeg = False @@ -162,13 +189,17 @@ class VCMI(ConanFile): if is_apple_os(self): self.options["sdl_image"].imageio = True + # mp3, ogg and wav are the only ones that needs to be supported + # opus is nice to have, but fails to build in CI + # flac can be considered, but generally unnecessary self.options["sdl_mixer"].flac = False - self.options["sdl_mixer"].mad = False - self.options["sdl_mixer"].mikmod = False self.options["sdl_mixer"].modplug = False - self.options["sdl_mixer"].nativemidi = False self.options["sdl_mixer"].opus = False - self.options["sdl_mixer"].wav = False + if self.settings.os == "iOS" or self.settings.os == "Android": + # only available in older sdl_mixer version, removed in newer version + self.options["sdl_mixer"].mad = False + self.options["sdl_mixer"].mikmod = False + self.options["sdl_mixer"].nativemidi = False def _disableQtOptions(disableFlag, options): return " ".join([f"-{disableFlag}-{tool}" for tool in options]) diff --git a/config/battlefields.json b/config/battlefields.json index 9d9b12fa3..9f032e603 100644 --- a/config/battlefields.json +++ b/config/battlefields.json @@ -162,5 +162,5 @@ 159, 160, 161, 162, 163, 176, 177, 178, 179, 180] }, - "ship": { "graphics" : "CMBKDECK.BMP" } + "ship": { "graphics" : "CMBKDECK.BMP", "isSpecial" : true} } diff --git a/config/obstacles.json b/config/obstacles.json index 52c8de672..b9d5bc57d 100644 --- a/config/obstacles.json +++ b/config/obstacles.json @@ -538,7 +538,7 @@ }, "55": { - "allowedTerrains" : ["water"], + "specialBattlefields" : ["ship"], "width" : 3, "height" : 3, "blockedTiles" : [-15, -16, -33], diff --git a/config/schemas/artifact.json b/config/schemas/artifact.json index ab335a5ca..7143ddecc 100644 --- a/config/schemas/artifact.json +++ b/config/schemas/artifact.json @@ -61,6 +61,10 @@ "description" : "Optional, list of components for combinational artifacts", "items" : { "type" : "string" } }, + "fusedComponents" : { + "type" : "boolean", + "description" : "Used together with components fild. Marks the artifact as fused. Cannot be disassembled." + }, "bonuses" : { "type" : "array", "description" : "Bonuses provided by this artifact using bonus system", diff --git a/config/shortcutsConfig.json b/config/shortcutsConfig.json index 41ee66f22..e6c91b12c 100644 --- a/config/shortcutsConfig.json +++ b/config/shortcutsConfig.json @@ -56,6 +56,8 @@ "adventureZoomIn": "Keypad +", "adventureZoomOut": "Keypad -", "adventureZoomReset": "Backspace", + "adventureSearch": "Ctrl+F", + "adventureSearchContinue": "Alt+F", "battleAutocombat": "A", "battleAutocombatEnd": "Q", "battleCastSpell": "C", diff --git a/docs/modders/Entities_Format/Artifact_Format.md b/docs/modders/Entities_Format/Artifact_Format.md index 928496dc7..83b1adca2 100644 --- a/docs/modders/Entities_Format/Artifact_Format.md +++ b/docs/modders/Entities_Format/Artifact_Format.md @@ -67,6 +67,9 @@ In order to make functional artifact you also need: "artifact2", "artifact3" ], + + // Optional, by default is false. Set to true if components are supposed to be fused. + "fusedComponents" : true, // Creature id to use on battle field. If set, this artifact is war machine "warMachine" : "some.creature" diff --git a/docs/modders/File_Formats.md b/docs/modders/File_Formats.md index d1466e4cf..b80188625 100644 --- a/docs/modders/File_Formats.md +++ b/docs/modders/File_Formats.md @@ -25,13 +25,21 @@ For animations VCMI supports .def format from Heroes III as well as alternative ### Sounds -For sounds VCMI currently requires .wav format. Generally, VCMI will support any .wav parameters, however you might want to use high-bitrate versions, such as 44100 Hz or 48000 Hz, 32 bit, 1 or 2 channels +For sounds VCMI currently supports: +- .ogg/vorbis format - preferred for mods. Unlike wav, vorbis uses compression which may cause some data loss, however even 128kbit is generally undistinguishable from lossless formats +- .wav format. This is format used by H3. It is supported by vcmi, but it may result in large file sizes (and as result - large mods) -Support for additional formats, such as ogg/vorbis and ogg/opus is likely to be added in future +Generally, VCMI will support any audio parameters, however you might want to use high-bitrate versions, such as 44100 Hz or 48000 Hz, 32 bit, 1 or 2 channels + +Support for additional formats, such as ogg/opus or flac may be added in future ### Music -For sounds VCMI currently requires .mp3 format. Support for additional formats, such as ogg/vorbis and ogg/opus is likely to be added in future +For music VCMI currently supports: +- .ogg/vorbis format - preferred for mods. Generally offers better quality and lower sizes compared to mp3 +- .mp3 format. This is format used by H3 + +Support for additional formats, such as ogg/opus may be added in future ### Video diff --git a/launcher/translation/chinese.ts b/launcher/translation/chinese.ts index 11e156178..c80f1cfaa 100644 --- a/launcher/translation/chinese.ts +++ b/launcher/translation/chinese.ts @@ -639,267 +639,310 @@ Install successfully downloaded? CSettingsView + Off 关闭 - + Artificial Intelligence 人工智能 - + Interface Scaling 界面缩放 - + Neutral AI in battles 战场中立生物AI - + Enemy AI in battles 战场敌方玩家AI - + Additional repository 额外仓库 - + Downscaling Filter 图像缩小过滤器 - + Adventure Map Allies 冒险地图友方玩家 - + Online Lobby port 在线大厅端口 - + Autocombat AI in battles 自动战斗AI - + Sticks Sensitivity 摇杆灵敏度 - + Automatic (Linear) 自动(线性) - + Haptic Feedback 触觉反馈 - + Software Cursor 软件指针 - + + + Automatic 自动 - + + Mods Validation + 模组验证 + + + None - + xBRZ x2 xBRZ x2 - + xBRZ x3 xBRZ x3 - + xBRZ x4 xBRZ x4 - + + Full + 完备 + + + Use scalable fonts 使用可缩放字体 - + Online Lobby address 在线大厅地址 - + + Cursor Scaling + 指针缩放 + + + + Scalable + 可缩放字体 + + + + Miscellaneous + 杂项 + + + + Font Scaling (experimental) + 字体缩放(测试中) + + + + Original + 原始字体 + + + Upscaling Filter 图像放大过滤器 - + + Basic + 基本 + + + Use Relative Pointer Mode 使用相对指针模式 - + Nearest 最邻近 - + Linear 线性 - + Input - Touchscreen 输入 - 触屏 - + Adventure Map Enemies 冒险地图敌方玩家 - + Show Tutorial again 重新显示教程 - + Reset 重置 - + Network 网络 - + Audio 音频 - + Relative Pointer Speed 相对指针速度 - + Music Volume 音乐音量 - + Ignore SSL errors 忽略SSL错误 - + Input - Mouse 输入 - 鼠标 - + Long Touch Duration 长按触屏间隔 - + % % - + Controller Click Tolerance 控制器按键灵敏度 - + Touch Tap Tolerance 触屏点击灵敏度 - + Input - Controller 输入 - 控制器 - + Sound Volume 音效音量 - + Windowed 窗口化 - + Borderless fullscreen 无边框全屏 - + Exclusive fullscreen 独占全屏 - + Autosave limit (0 = off) 自动保存限制 (0 = 不限制) - + Framerate Limit 帧率限制 - + Autosave prefix 自动保存文件名前缀 - + Mouse Click Tolerance 鼠标点击灵敏度 - + Sticks Acceleration 摇杆加速度 - + empty = map name prefix 空 = 地图名称前缀 - + Refresh now 立即刷新 - + Default repository 默认仓库 - + Renderer 渲染器 @@ -909,7 +952,7 @@ Install successfully downloaded? 开启 - + Select display mode for game Windowed - game will run inside a window that covers part of your screen @@ -926,93 +969,93 @@ Fullscreen Exclusive Mode - game will cover entirety of your screen and will use 独占全屏模式 - 游戏会运行在一个覆盖全部屏幕的窗口,使用和你选择的分辨率。 - + Reserved screen area 保留屏幕区域 - + Heroes III Translation 发布版本里找不到这个项,不太清楚意义 英雄无敌3翻译 - + Check on startup 启动时检查更新 - + Fullscreen 全屏 - + General 通用设置 - + VCMI Language VCMI语言 - + Resolution 分辨率 - + Autosave 自动存档 - + VSync 垂直同步 - + Display index 显示器序号 - + Network port 网络端口 - + Video 视频设置 - + Show intro 显示开场动画 - + Active 激活 - + Disabled 禁用 - + Enable 启用 - + Not Installed 未安装 - + Install 安装 diff --git a/launcher/translation/czech.ts b/launcher/translation/czech.ts index f3a1225b1..5434843d7 100644 --- a/launcher/translation/czech.ts +++ b/launcher/translation/czech.ts @@ -54,7 +54,7 @@ Log files directory - Složka záznamů hry + Adresář souborů s logy @@ -176,7 +176,7 @@ Creatures - Bojovníci + Jednotky @@ -209,7 +209,7 @@ Downloadable - Stahovatelné + Ke stažení @@ -219,7 +219,7 @@ Updatable - Aktualizovatelné + K aktualizaci @@ -387,12 +387,12 @@ This mod can not be installed or enabled because the following dependencies are not present - Tato modifikace nemůže být nainstalována nebo povolena, protože následující závislosti nejsou přítomny + Tato modifikace nelze nainstalovat ani povolit, protože nejsou přítomny následující závislosti This mod can not be enabled because the following mods are incompatible with it - Tato modifikace nemůže být povolena, protože následující modifikace s ní nejsou kompatibilní + Tato modifikace nemůže být povolena, protože není kompatibilní s následujícími modifikacemi @@ -407,7 +407,7 @@ This is a submod and it cannot be installed or uninstalled separately from its parent mod - Toto je podmodifikace, která nemůže být nainstalována nebo odinstalována bez její rodičovské modifikace + Toto je podmodifikace a nelze ji nainstalovat ani odinstalovat samostatně bez hlavní modifikace @@ -442,17 +442,17 @@ Gog files - + Soubory GOG All files (*.*) - + Všechny soubory (*.*) Select files (configs, mods, maps, campaigns, gog files) to install... - + Vyberte soubory (konfigurace, modifikace, mapy, kampaně, soubory GOG) k instalaci... @@ -467,7 +467,7 @@ Downloading %1. %p% (%v MB out of %m MB) finished - + Stahování %1. %p% (%v MB z %m MB) dokončeno @@ -499,7 +499,7 @@ Nainstalovat úspěšně stažené? Installing chronicles - + Instalování kronik @@ -634,267 +634,310 @@ Nainstalovat úspěšně stažené? CSettingsView + Off Vypnuto - + Artificial Intelligence Umělá inteligence - + Interface Scaling Škálování rozhraní - + Neutral AI in battles Neutrální AI v bitvách - + Enemy AI in battles Nepřátelská AI v bitvách - + Additional repository Další repozitáře - + Downscaling Filter - + Filtr pro zmenšování - + Adventure Map Allies Spojenci na mapě světa - + Online Lobby port - Port online předsíně + Port online lobby - + Autocombat AI in battles AI automatického boje v bitvách - + Sticks Sensitivity Citlivost páček - + Automatic (Linear) - + Automaticky (Lineárně) - + Haptic Feedback Zpětná odezva - + Software Cursor Softwarový kurzor - + + + Automatic - + Automaticky - + + Mods Validation + Validace modifikací + + + None - + Nic - + xBRZ x2 - + xBRZ x2 - + xBRZ x3 - + xBRZ x3 - + xBRZ x4 - + xBRZ x4 - + + Full + Plné + + + Use scalable fonts - + Použít škálovatelná písma - + Online Lobby address Adresa online předsíně - + + Cursor Scaling + Škálování kurzoru + + + + Scalable + Škálovatelné + + + + Miscellaneous + Ostatní + + + + Font Scaling (experimental) + Škálování písma (experimentální) + + + + Original + Původní + + + Upscaling Filter Filtr škálování - + + Basic + Základní + + + Use Relative Pointer Mode Použít režim relativního ukazatele - + Nearest Nejbližší - + Linear Lineární - + Input - Touchscreen Vstup - dotyková obrazovka - + Adventure Map Enemies Nepřátelé na mapě světa - + Show Tutorial again - + Znovu zobrazi Tutoriál - + Reset - + Restart - + Network Síť - + Audio Zvuk - + Relative Pointer Speed Relativní rychlost myši - + Music Volume Hlasitost hudby - + Ignore SSL errors Ignorovat chyby SSL - + Input - Mouse Vstup - Myš - + Long Touch Duration Doba dlouhého podržení - + % % - + Controller Click Tolerance Odchylka klepnutí ovladače - + Touch Tap Tolerance Odchylka klepnutí dotykem - + Input - Controller Vstup - ovladač - + Sound Volume Hlasitost zvuků - + Windowed V okně - + Borderless fullscreen Celá obrazovka bez okrajů - + Exclusive fullscreen Exkluzivní celá obrazovka - + Autosave limit (0 = off) Limit aut. uložení (0=vypnuto) - + Framerate Limit Omezení snímků za sekundu - + Autosave prefix Předpona aut. uložení - + Mouse Click Tolerance Odchylka klepnutí myší - + Sticks Acceleration Zrychlení páček - + empty = map name prefix prázná = předpona - název mapy - + Refresh now Obnovit nyní - + Default repository Výchozí repozitář - + Renderer Vykreslovač @@ -904,7 +947,7 @@ Nainstalovat úspěšně stažené? Zapnuto - + Select display mode for game Windowed - game will run inside a window that covers part of your screen @@ -921,92 +964,92 @@ Celá obrazovka bez okrajů- hra poběží v okně, které zakryje vaši celou Exkluzivní celá obrazovka - hra zakryje vaši celou obrazovku a použije vybrané rozlišení. - + Reserved screen area Vyhrazená část obrazovky - + Heroes III Translation Překlad Heroes III - + Check on startup Zkontrolovat při zapnutí - + Fullscreen Celá obrazovka - + General Všeobecné - + VCMI Language Jazyk VCMI - + Resolution Rozlišení - + Autosave Automatické uložení - + VSync VSync - + Display index - + Monitor - + Network port Síťový port - + Video Zobrazení - + Show intro Zobrazit intro - + Active Aktivní - + Disabled Zakázáno - + Enable Povolit - + Not Installed Nenainstalováno - + Install Instalovat @@ -1016,35 +1059,35 @@ Exkluzivní celá obrazovka - hra zakryje vaši celou obrazovku a použije vybra File cannot opened - + Soubor nelze otevřít Invalid file selected - Vybrán neplatný soubor + Vybrán neplatný soubor You have to select an gog installer file! - + Musíte vybrat instalační soubor GOG! You have to select an chronicle installer file! - + Musíte vybrat instalační soubor kronik! Extracting error! - + Chyb při rozbalování! Heroes Chronicles - + Heroes Chronicles @@ -1111,13 +1154,13 @@ Before you can start playing, there are a few more steps that need to be complet Please keep in mind that in order to use VCMI you must own the original data files for Heroes® of Might and Magic® III: Complete or The Shadow of Death. Heroes® of Might and Magic® III HD is currently not supported! - Děkujeme za instalaci VCMI! + Děkujeme, že jste si nainstalovali VCMI! -Před začátkem hraní musíte ještě dokončit pár kroků. +Než začnete hrát, je třeba dokončit několik kroků. -Prosíme, mějte na paměti, že abyste mohli hrát VCMI, musíte vlastnit originální datové soubory Heroes® of Might and Magic® III: Complete nebo The Shadow of Death. +Pamatujte, že pro používání VCMI musíte vlastnit originální herní soubory pro Heroes® of Might and Magic® III: Complete nebo The Shadow of Death. -Heroes® of Might and Magic® III HD není v současnosti podporovaný! +Heroes® of Might and Magic® III HD momentálně není podporováno! @@ -1132,7 +1175,7 @@ Heroes® of Might and Magic® III HD není v současnosti podporovaný! You can manually copy directories Maps, Data and Mp3 from the original game directory to VCMI data directory that you can see on top of this page - Můžete ručně zkopírovat existující mapy, data a MP3 z originální složky hry do složky dat VCMI, kterou můžete vidět nahoře na této stránce. + Můžete ručně zkopírovat existující mapy, data a MP3 z originální složky hry do složky dat VCMI, kterou můžete vidět nahoře na této stránce @@ -1152,7 +1195,7 @@ Heroes® of Might and Magic® III HD není v současnosti podporovaný! Install a translation of Heroes III in your preferred language - Instalovat překlad Heroes III vašeho upřednostněného jazyka + Nainstalujte si překlad Heroes III dle preferovaného jazyka @@ -1179,7 +1222,7 @@ Offline instalátor obsahuje dvě části, .exe a .bin. Ujistěte se, že stahuj Optionally, you can install additional mods either now, or at any point later, using the VCMI Launcher - Nyní můžete volitelně nainstalovat další modifikace, nebo též kdykoliv potom pomocí spouštěče VCMI + Můžete si nyní, nebo kdykoliv později, nainstalovat další mody pomocí VCMI Launcheru, podle svých preferencí @@ -1189,12 +1232,12 @@ Offline instalátor obsahuje dvě části, .exe a .bin. Ujistěte se, že stahuj Install compatible version of "Horn of the Abyss", a fan-made Heroes III expansion ported by the VCMI team - + Instalovat kompatibilní verzi 'Horn of the Abyss', fanouškovského rozšíření Heroes III portovaného týmem VCMI Install compatible version of "In The Wake of Gods", a fan-made Heroes III expansion - + "Instalovat kompatibilní verzi In The Wake of Gods', fanouškovského rozšíření Heroes III portovaného týmem VCMI" @@ -1251,7 +1294,7 @@ Offline instalátor obsahuje dvě části, .exe a .bin. Ujistěte se, že stahuj Horn of the Abyss - + Horn of the Abyss @@ -1261,7 +1304,7 @@ Offline instalátor obsahuje dvě části, .exe a .bin. Ujistěte se, že stahuj In The Wake of Gods - + In The Wake of Gods @@ -1298,7 +1341,7 @@ Offline instalátor obsahuje dvě části, .exe a .bin. Ujistěte se, že stahuj File cannot be opened - + Soubor nelze otevřít @@ -1318,17 +1361,17 @@ Offline instalátor obsahuje dvě části, .exe a .bin. Ujistěte se, že stahuj You've provided GOG Galaxy installer! This file doesn't contain the game. Please download the offline backup game installer! - + Poskytli jste instalátor GOG Galaxy! Tento soubor neobsahuje hru. Prosím, stáhněte si záložní offline instalátor hry! Extracting error! - + Chyba při rozbalování! No Heroes III data! - Žádná data Heroes III! + Chybí data Heroes III! @@ -1354,15 +1397,15 @@ Prosíme vyberte složku s nainstalovanými daty Heroes III. Heroes III: HD Edition files are not supported by VCMI. Please select directory with Heroes III: Complete Edition or Heroes III: Shadow of Death. - Soubory Heroes III HD Edice nejsou podporována ve VCMI. -Prosíme vyberte složku s Heroes III: Complete Edition nebo Heroes III: Shadow of Death. + Soubory Heroes III HD Edice nejsou podporovány ve VCMI. +Prosím vyberte složku s Heroes III: Complete Edition nebo Heroes III: Shadow of Death. Unknown or unsupported Heroes III version found. Please select directory with Heroes III: Complete Edition or Heroes III: Shadow of Death. Nalezena neznámá nebo nepodporovaná verze Heroes III. -Prosíme vyberte složku s Heroes III: Complete Edition nebo Heroes III: Shadow of Death. +Prosím vyberte složku s Heroes III: Complete Edition nebo Heroes III: Shadow of Death. @@ -1379,17 +1422,18 @@ Prosíme vyberte složku s Heroes III: Complete Edition nebo Heroes III: Shadow Stream error while extracting files! error reason: - + Chyba při extrahování souborů! +Důvod chyby: Not a supported Inno Setup installer! - + Nepodporovaný Inno Setup instalátor! VCMI was compiled without innoextract support, which is needed to extract exe files! - + VCMI bylo zkompilováno bez podpory innoextract, která je potřebná pro extrahování EXE souborů! @@ -1490,7 +1534,7 @@ error reason: VCMI Launcher - Spouštěč VCMI + VCMI Launcher diff --git a/launcher/translation/english.ts b/launcher/translation/english.ts index 604274ac0..0114b4501 100644 --- a/launcher/translation/english.ts +++ b/launcher/translation/english.ts @@ -626,267 +626,310 @@ Install successfully downloaded? CSettingsView + Off - + Artificial Intelligence - + Interface Scaling - + Neutral AI in battles - + Enemy AI in battles - + Additional repository - + Adventure Map Allies - + Online Lobby port - + Autocombat AI in battles - + Sticks Sensitivity - + Automatic (Linear) - + Haptic Feedback - + Software Cursor - + + + Automatic - + + Mods Validation + + + + None - + xBRZ x2 - + xBRZ x3 - + xBRZ x4 - + + Full + + + + Use scalable fonts - + Online Lobby address - - Upscaling Filter + + Cursor Scaling - - Use Relative Pointer Mode - - - - - Nearest - - - - - Linear - - - - - Input - Touchscreen - - - - - Adventure Map Enemies + + Scalable + Miscellaneous + + + + + Font Scaling (experimental) + + + + + Original + + + + + Upscaling Filter + + + + + Basic + + + + + Use Relative Pointer Mode + + + + + Nearest + + + + + Linear + + + + + Input - Touchscreen + + + + + Adventure Map Enemies + + + + Show Tutorial again - + Reset - + Network - + Audio - + Relative Pointer Speed - + Music Volume - + Ignore SSL errors - + Input - Mouse - + Long Touch Duration - + % - + Controller Click Tolerance - + Touch Tap Tolerance - + Input - Controller - + Sound Volume - + Windowed - + Borderless fullscreen - + Exclusive fullscreen - + Autosave limit (0 = off) - + Downscaling Filter - + Framerate Limit - + Autosave prefix - + Mouse Click Tolerance - + Sticks Acceleration - + empty = map name prefix - + Refresh now - + Default repository - + Renderer @@ -896,7 +939,7 @@ Install successfully downloaded? - + Select display mode for game Windowed - game will run inside a window that covers part of your screen @@ -907,92 +950,92 @@ Fullscreen Exclusive Mode - game will cover entirety of your screen and will use - + Reserved screen area - + Heroes III Translation - + Check on startup - + Fullscreen - + General - + VCMI Language - + Resolution - + Autosave - + VSync - + Display index - + Network port - + Video - + Show intro - + Active - + Disabled - + Enable - + Not Installed - + Install diff --git a/launcher/translation/french.ts b/launcher/translation/french.ts index 04ab48984..bd7f7dc30 100644 --- a/launcher/translation/french.ts +++ b/launcher/translation/french.ts @@ -639,12 +639,13 @@ Installer les téchargements réussis? CSettingsView + Off Désactivé - + Artificial Intelligence Intelligence Artificielle @@ -654,187 +655,229 @@ Installer les téchargements réussis? Activé - + Enemy AI in battles IA ennemie dans les batailles - + Default repository Dépôt par défaut - + VSync Synchronisation verticalle - + Online Lobby port Port de la salle d'attente en ligne - + Autocombat AI in battles IA de combat automatique dans les batailles - + Sticks Sensitivity Sensibilité au batons - + Automatic (Linear) Automatique (Linéaire) - + Haptic Feedback Retour Tactile - + Software Cursor Curseur Logiciel - + + + Automatic Automatique - + + Mods Validation + + + + None Aucun - + xBRZ x2 xBRZ x2 - + xBRZ x3 xBRZ x3 - + xBRZ x4 xBRZ x4 - + + Full + + + + Use scalable fonts - + Online Lobby address Adresse de la salle d'attente en ligne - + + Cursor Scaling + + + + + Scalable + + + + + Miscellaneous + + + + + Font Scaling (experimental) + + + + + Original + + + + Upscaling Filter Filtre d'Agrandissement - + + Basic + + + + Use Relative Pointer Mode Utiliser le Mode de Pointeur Relatif - + Nearest Le plus Proche - + Linear Linéaire - + Input - Touchscreen Entrée - Écran tactile - + Network Réseau - + Downscaling Filter Filtre de Rétrécissement - + Show Tutorial again Remontrer le Didacticiel - + Reset Réinitialiser - + Audio Audio - + Relative Pointer Speed Vitesse de Pointeur Relatif - + Music Volume Volume de la Musique - + Ignore SSL errors Ignorer les erreurs SSL - + Input - Mouse Entrée - Sourie - + Long Touch Duration Durée de Touche Prolongée - + % % - + Controller Click Tolerance Tolérance au Clic de Contrôleur - + Touch Tap Tolerance Tolérance à la Frappe de Touche - + Input - Controller Entrée - Contrôleur - + Sound Volume Volume du Son - + Select display mode for game Windowed - game will run inside a window that covers part of your screen @@ -851,167 +894,167 @@ Mode fenêtré sans bord - le jeu s"exécutera dans une fenêtre qui couvre Mode exclusif plein écran - le jeu couvrira l"intégralité de votre écran et utilisera la résolution sélectionnée. - + Windowed Fenêtré - + Borderless fullscreen Fenêtré sans bord - + Exclusive fullscreen Plein écran exclusif - + Reserved screen area Zone d'écran réservée - + Neutral AI in battles IA neutre dans les batailles - + Autosave limit (0 = off) Limite de sauvegarde auto (0 = désactivé) - + Adventure Map Enemies Ennemis de la carte d"aventure - + Autosave prefix Préfix de sauvegarde auto. - + empty = map name prefix vide = prefix du nom de carte - + Interface Scaling Mise à l"échelle de l"interface - + Framerate Limit Limite de fréquence d"images - + Renderer Moteur de rendu - + Heroes III Translation Traduction de Heroes III - + Adventure Map Allies Alliés de la carte d"aventure - + Additional repository Dépôt supplémentaire - + Check on startup Vérifier au démarrage - + Mouse Click Tolerance Tolérance au Clic de Sourie - + Sticks Acceleration Accelération de Bâton - + Refresh now Actualiser maintenant - + Fullscreen Plein écran - + General Général - + VCMI Language Langue de VCMI - + Resolution Résolution - + Autosave Sauvegarde automatique - + Display index Index d'affichage - + Network port Port de réseau - + Video Vidéo - + Show intro Montrer l'intro - + Active Actif - + Disabled Désactivé - + Enable Activé - + Not Installed Pas Installé - + Install Installer diff --git a/launcher/translation/german.ts b/launcher/translation/german.ts index 659788841..90c01cbb3 100644 --- a/launcher/translation/german.ts +++ b/launcher/translation/german.ts @@ -634,267 +634,310 @@ Installation erfolgreich heruntergeladen? CSettingsView + Off Aus - + Artificial Intelligence Künstliche Intelligenz - + Interface Scaling Skalierung der Benutzeroberfläche - + Neutral AI in battles Neutrale KI in Kämpfen - + Enemy AI in battles Gegnerische KI in Kämpfen - + Additional repository Zusätzliches Repository - + Downscaling Filter - + Adventure Map Allies Abenteuerkarte Verbündete - + Online Lobby port Online-Lobby-Port - + Autocombat AI in battles Autokampf-KI in Kämpfen - + Sticks Sensitivity Sticks Empfindlichkeit - + Automatic (Linear) - + Haptic Feedback Haptisches Feedback - + Software Cursor Software-Cursor - + + + Automatic - + + Mods Validation + + + + None - + xBRZ x2 - + xBRZ x3 - + xBRZ x4 - + + Full + + + + Use scalable fonts - + Online Lobby address Adresse der Online-Lobby - + + Cursor Scaling + + + + + Scalable + + + + + Miscellaneous + + + + + Font Scaling (experimental) + + + + + Original + + + + Upscaling Filter Hochskalierungsfilter - + + Basic + + + + Use Relative Pointer Mode Relativen Zeigermodus verwenden - + Nearest Nearest - + Linear Linear - + Input - Touchscreen Eingabe - Touchscreen - + Adventure Map Enemies Abenteuerkarte Feinde - + Show Tutorial again Zeige Tutorial erneut - + Reset Zurücksetzen - + Network Netzwerk - + Audio Audio - + Relative Pointer Speed Relative Zeigergeschwindigkeit - + Music Volume Musik Lautstärke - + Ignore SSL errors SSL-Fehler ignorieren - + Input - Mouse Eingabe - Maus - + Long Touch Duration Dauer der Berührung für "lange Berührung" - + % % - + Controller Click Tolerance Toleranz bei Controller Klick - + Touch Tap Tolerance Toleranz bei Berührungen - + Input - Controller Eingabe - Controller - + Sound Volume Sound-Lautstärke - + Windowed Fenstermodus - + Borderless fullscreen Randloser Vollbildmodus - + Exclusive fullscreen Exklusiver Vollbildmodus - + Autosave limit (0 = off) Limit für Autospeicherung (0 = aus) - + Framerate Limit Limit der Bildrate - + Autosave prefix Präfix für Autospeicherung - + Mouse Click Tolerance Toleranz bei Mausklick - + Sticks Acceleration Sticks Beschleunigung - + empty = map name prefix leer = Kartenname als Präfix - + Refresh now Jetzt aktualisieren - + Default repository Standard Repository - + Renderer Renderer @@ -904,7 +947,7 @@ Installation erfolgreich heruntergeladen? An - + Select display mode for game Windowed - game will run inside a window that covers part of your screen @@ -921,92 +964,92 @@ Randloser Fenstermodus - das Spiel läuft in einem Fenster, das den gesamten Bil Exklusiver Vollbildmodus - das Spiel bedeckt den gesamten Bildschirm und verwendet die gewählte Auflösung. - + Reserved screen area Reservierter Bildschirmbereich - + Heroes III Translation Heroes III Übersetzung - + Check on startup Beim Start prüfen - + Fullscreen Vollbild - + General Allgemein - + VCMI Language VCMI-Sprache - + Resolution Auflösung - + Autosave Autospeichern - + VSync VSync - + Display index Anzeige-Index - + Network port Netzwerk-Port - + Video Video - + Show intro Intro anzeigen - + Active Aktiv - + Disabled Deaktiviert - + Enable Aktivieren - + Not Installed Nicht installiert - + Install Installieren diff --git a/launcher/translation/polish.ts b/launcher/translation/polish.ts index c30a428c1..43b478497 100644 --- a/launcher/translation/polish.ts +++ b/launcher/translation/polish.ts @@ -634,267 +634,310 @@ Zainstalować pomyślnie pobrane? CSettingsView + Off Wyłączony - + Artificial Intelligence Sztuczna Inteligencja - + Interface Scaling Skala interfejsu - + Neutral AI in battles AI bitewne jednostek neutralnych - + Enemy AI in battles AI bitewne wrogów - + Additional repository Dodatkowe repozytorium - + Downscaling Filter - + Adventure Map Allies AI sojuszników mapy przygody - + Online Lobby port Port lobby online - + Autocombat AI in battles AI szybkiej walki - + Sticks Sensitivity Czułość gałek - + Automatic (Linear) - + Haptic Feedback Wibracje - + Software Cursor Kursor programowy - + + + Automatic - + + Mods Validation + + + + None - + xBRZ x2 - + xBRZ x3 - + xBRZ x4 - + + Full + + + + Use scalable fonts - + Online Lobby address Adres lobby online - + + Cursor Scaling + + + + + Scalable + + + + + Miscellaneous + + + + + Font Scaling (experimental) + + + + + Original + + + + Upscaling Filter Filtr wyostrzający - + + Basic + + + + Use Relative Pointer Mode Użyj relatywnego trybu kursora - + Nearest Najbliższych - + Linear Liniowy - + Input - Touchscreen Sterowanie - Ekran dotykowy - + Adventure Map Enemies AI wrogów mapy przygody - + Show Tutorial again Pokaż ponownie samouczek - + Reset Zresetuj - + Network Sieć - + Audio Dźwięk i muzyka - + Relative Pointer Speed Prędkość kursora w trybie relatywnym - + Music Volume Głośność muzyki - + Ignore SSL errors Ignoruj błędy SSL - + Input - Mouse Sterowanie - Mysz - + Long Touch Duration Czas do długiego dotyku - + % % - + Controller Click Tolerance Tolerancja na kliknięcia poza elementami (kontroler) - + Touch Tap Tolerance Tolerancja na nietrafianie dotykiem w elementy - + Input - Controller Sterowanie - Kontroler - + Sound Volume Głośność dźwięku - + Windowed Okno - + Borderless fullscreen Pełny ekran (tryb okna) - + Exclusive fullscreen Pełny ekran klasyczny - + Autosave limit (0 = off) Limit autozapisów (0 = brak) - + Framerate Limit Limit FPS - + Autosave prefix Przedrostek autozapisu - + Mouse Click Tolerance Tolerancja na kliknięcia poza elementami (mysz) - + Sticks Acceleration Przyspieszenie gałek - + empty = map name prefix puste = przedrostek z nazwy mapy - + Refresh now Odśwież - + Default repository Domyślne repozytorium - + Renderer Renderer @@ -904,7 +947,7 @@ Zainstalować pomyślnie pobrane? Włączony - + Select display mode for game Windowed - game will run inside a window that covers part of your screen @@ -921,92 +964,92 @@ Pełny ekran w trybie okna - gra uruchomi się w oknie przysłaniającym cały e Pełny ekran klasyczny - gra przysłoni cały ekran uruchamiając się w wybranej przez ciebie rozdzielczości ekranu. - + Reserved screen area Zarezerwowany obszar ekranu - + Heroes III Translation Tłumaczenie Heroes III - + Check on startup Sprawdzaj przy uruchomieniu - + Fullscreen Pełny ekran - + General Ogólne - + VCMI Language Język VCMI - + Resolution Rozdzielczość - + Autosave Autozapis - + VSync Synchronizacja pionowa (VSync) - + Display index Numer wyświetlacza - + Network port Port sieciowy - + Video Obraz - + Show intro Pokaż intro - + Active Aktywny - + Disabled Wyłączone - + Enable Włącz - + Not Installed Nie zainstalowano - + Install Zainstaluj diff --git a/launcher/translation/portuguese.ts b/launcher/translation/portuguese.ts index 0f4108637..07369d655 100644 --- a/launcher/translation/portuguese.ts +++ b/launcher/translation/portuguese.ts @@ -634,267 +634,310 @@ O download da instalação foi bem-sucedido? CSettingsView + Off Desativado - + Artificial Intelligence Inteligência artificial - + Interface Scaling Escala da interface - + Neutral AI in battles IA neutra nas batalhas - + Enemy AI in battles IA inimiga em batalhas - + Additional repository Repositório adicional - + Adventure Map Allies Aliados do mapa de aventura - + Online Lobby port Porta da sala de espera on-line - + Autocombat AI in battles IA de combate automático nas batalhas - + Sticks Sensitivity Sensibilidade dos analógicos - + Automatic (Linear) Automático (linear) - + Haptic Feedback Resposta tátil - + Software Cursor Cursor por software - + + + Automatic Automático - + + Mods Validation + Validação de mods + + + None Nenhum - + xBRZ x2 xBRZ x2 - + xBRZ x3 xBRZ x3 - + xBRZ x4 xBRZ x4 - - Use scalable fonts - Usar fontes escaláveis + + Full + Completo - + + Use scalable fonts + Usar fontes escaláveis + + + Online Lobby address Endereço da sala de espera on-line - + + Cursor Scaling + Escala do cursor + + + + Scalable + Escalável + + + + Miscellaneous + Diversos + + + + Font Scaling (experimental) + Escala da fonte (experimental) + + + + Original + Original + + + Upscaling Filter Filtro de aumento de escala - + + Basic + Básico + + + Use Relative Pointer Mode Usar modo de ponteiro relativo - + Nearest Mais próximo - + Linear Linear - + Input - Touchscreen Entrada - tela de toque - + Adventure Map Enemies Inimigos do mapa de aventura - + Show Tutorial again Mostrar o tutorial novamente - + Reset Redefinir - + Network Linear - + Audio Áudio - + Relative Pointer Speed Velocidade do ponteiro relativo - + Music Volume Volume da música - + Ignore SSL errors Ignorar erros SSL - + Input - Mouse Entrada - mouse - + Long Touch Duration Duração do toque longo - + % % - + Controller Click Tolerance Tolerância de clique do controle - + Touch Tap Tolerance Tolerância de toque tátil - + Input - Controller Entrada - controle - + Sound Volume Volume do som - + Windowed Janela - + Borderless fullscreen Tela cheia sem bordas - + Exclusive fullscreen Tela cheia exclusiva - + Autosave limit (0 = off) Limite de salvamento automático (0 = sem limite) - + Downscaling Filter Filtro de redução de escala - + Framerate Limit Limite de taxa de quadros - + Autosave prefix Prefixo do salvamento automático - + Mouse Click Tolerance Tolerância de clique do mouse - + Sticks Acceleration Aceleração dos analógicos - + empty = map name prefix vazio = prefixo do mapa - + Refresh now Atualizar - + Default repository Repositório padrão - + Renderer Renderizador @@ -904,7 +947,7 @@ O download da instalação foi bem-sucedido? Ativado - + Select display mode for game Windowed - game will run inside a window that covers part of your screen @@ -921,92 +964,92 @@ Modo de janela sem bordas - o jogo será executado em uma janela que cobre toda Modo de tela cheia exclusivo - o jogo cobrirá toda a sua tela e usará a resolução selecionada. - + Reserved screen area Área de tela reservada - + Heroes III Translation Tradução do Heroes III - + Check on startup Verificar na inicialização - + Fullscreen Tela cheia - + General Geral - + VCMI Language Idioma do VCMI - + Resolution Resolução - + Autosave Salvamento automático - + VSync - VSync + Sincronização vertical (VSync) - + Display index Índice de exibição - + Network port Porta de rede - + Video Vídeo - + Show intro Mostrar introdução - + Active Ativo - + Disabled Desativado - + Enable Ativar - + Not Installed Não instalado - + Install Instalar diff --git a/launcher/translation/russian.ts b/launcher/translation/russian.ts index b63ae0386..20a45663b 100644 --- a/launcher/translation/russian.ts +++ b/launcher/translation/russian.ts @@ -626,11 +626,12 @@ Install successfully downloaded? CSettingsView - + Interface Scaling + Off Отключено @@ -641,292 +642,334 @@ Install successfully downloaded? Включено - + Neutral AI in battles - + Enemy AI in battles - + Additional repository - + Check on startup Проверять при запуске - + Fullscreen Полноэкранный режим - + General Общее - + VCMI Language Язык VCMI - + Artificial Intelligence Искусственный интеллект - + Adventure Map Allies - + Refresh now - + Adventure Map Enemies - + Online Lobby port - + Autocombat AI in battles - + Sticks Sensitivity - + Automatic (Linear) - + Haptic Feedback - + Software Cursor - + + + Automatic - + + Mods Validation + + + + None - + xBRZ x2 - + xBRZ x3 - + xBRZ x4 - + + Full + + + + Use scalable fonts - + Online Lobby address - - Upscaling Filter + + Cursor Scaling - - Use Relative Pointer Mode - - - - - VSync - - - - - Nearest - - - - - Linear - - - - - Input - Touchscreen - - - - - Network - - - - - Downscaling Filter + + Scalable + Miscellaneous + + + + + Font Scaling (experimental) + + + + + Original + + + + + Upscaling Filter + + + + + Basic + + + + + Use Relative Pointer Mode + + + + + VSync + + + + + Nearest + + + + + Linear + + + + + Input - Touchscreen + + + + + Network + + + + + Downscaling Filter + + + + Show Tutorial again - + Reset - + Audio - + Relative Pointer Speed - + Music Volume - + Ignore SSL errors - + Input - Mouse - + Long Touch Duration - + % - + Controller Click Tolerance - + Touch Tap Tolerance - + Input - Controller - + Sound Volume - + Windowed - + Borderless fullscreen - + Exclusive fullscreen - + Reserved screen area - + Autosave limit (0 = off) - + Framerate Limit - + Autosave prefix - + Mouse Click Tolerance - + Sticks Acceleration - + empty = map name prefix - + Default repository - + Renderer - + Select display mode for game Windowed - game will run inside a window that covers part of your screen @@ -937,62 +980,62 @@ Fullscreen Exclusive Mode - game will cover entirety of your screen and will use - + Heroes III Translation Перевод Героев III - + Resolution Разрешение экрана - + Autosave Автосохранение - + Display index Дисплей - + Network port Сетевой порт - + Video Графика - + Show intro Вступление - + Active Активен - + Disabled Отключен - + Enable Включить - + Not Installed Не установлен - + Install Установить diff --git a/launcher/translation/spanish.ts b/launcher/translation/spanish.ts index 0b853743b..a1e9e19f6 100644 --- a/launcher/translation/spanish.ts +++ b/launcher/translation/spanish.ts @@ -633,267 +633,310 @@ Instalar lo correctamente descargado? CSettingsView + Off Desactivado - + Artificial Intelligence Inteligencia Artificial - + Interface Scaling Escala de la interfaz - + Neutral AI in battles IA neutral en batallas - + Enemy AI in battles IA enemiga en batallas - + Additional repository Repositorio adicional - + Downscaling Filter - + Adventure Map Allies Aliados en el Mapa de aventuras - + Online Lobby port - + Autocombat AI in battles - + Sticks Sensitivity - + Automatic (Linear) - + Haptic Feedback - + Software Cursor - + + + Automatic - + + Mods Validation + + + + None - + xBRZ x2 - + xBRZ x3 - + xBRZ x4 - + + Full + + + + Use scalable fonts - + Online Lobby address - + + Cursor Scaling + + + + + Scalable + + + + + Miscellaneous + + + + + Font Scaling (experimental) + + + + + Original + + + + Upscaling Filter - + + Basic + + + + Use Relative Pointer Mode - + Nearest - + Linear - + Input - Touchscreen - + Adventure Map Enemies Enemigos en el Mapa de aventuras - + Show Tutorial again - + Reset - + Network - + Audio - + Relative Pointer Speed - + Music Volume - + Ignore SSL errors - + Input - Mouse - + Long Touch Duration - + % - + Controller Click Tolerance - + Touch Tap Tolerance - + Input - Controller - + Sound Volume - + Windowed Ventana - + Borderless fullscreen Ventana completa sin bordes - + Exclusive fullscreen Pantalla completa - + Autosave limit (0 = off) Límite de autosaves (0 = sin límite) - + Framerate Limit Límite de fotogramas - + Autosave prefix Prefijo autoguardado - + Mouse Click Tolerance - + Sticks Acceleration - + empty = map name prefix Vacio = prefijo del mapa - + Refresh now Actualizar - + Default repository Repositorio por defecto - + Renderer Render @@ -903,62 +946,62 @@ Instalar lo correctamente descargado? Activado - + Heroes III Translation Traducción de Heroes III - + Reserved screen area Área de pantalla reservada - + Fullscreen Pantalla completa - + General General - + VCMI Language Idioma de VCMI - + Resolution Resolución - + Autosave Autoguardado - + VSync Sincronización vertical - + Display index Mostrar índice - + Network port Puerto de red - + Video Vídeo - + Select display mode for game Windowed - game will run inside a window that covers part of your screen @@ -975,37 +1018,37 @@ Ventana sin bordes - el juego se ejecutará en una ventana que cubre completamen Pantalla completa - el juego cubrirá la totalidad de la pantalla y utilizará la resolución seleccionada. - + Show intro Mostrar introducción - + Check on startup Comprovar al inicio - + Active Activado - + Disabled Desactivado - + Enable Activar - + Not Installed No Instalado - + Install Instalar diff --git a/launcher/translation/swedish.ts b/launcher/translation/swedish.ts index deb1fd13b..f92834d02 100644 --- a/launcher/translation/swedish.ts +++ b/launcher/translation/swedish.ts @@ -634,12 +634,13 @@ Installation framgångsrikt nedladdad? CSettingsView + Off Inaktiverad - + Artificial Intelligence Artificiell intelligens @@ -649,187 +650,229 @@ Installation framgångsrikt nedladdad? Aktiverad - + Enemy AI in battles Fiendens AI i strider - + Default repository Standard-repositorie - + VSync Vertikal-synkronisering (VSync) - + Online Lobby port Port-numret till online-väntrummet - + Autocombat AI in battles Automatiska AI-strider - + Sticks Sensitivity Spak-känslighet - + Automatic (Linear) Automatisk (linjär) - + Haptic Feedback Haptisk återkoppling (vibrationer i kontrollen) - + Software Cursor Programvarustyrd muspekare - + + + Automatic Automatisk - + + Mods Validation + + + + None Inget - + xBRZ x2 xBRZ x2 - + xBRZ x3 xBRZ x3 - + xBRZ x4 xBRZ x4 - + + Full + + + + Use scalable fonts - + Online Lobby address Adressen till online-väntrummet - + + Cursor Scaling + + + + + Scalable + + + + + Miscellaneous + + + + + Font Scaling (experimental) + + + + + Original + + + + Upscaling Filter Uppskalnings-filter - + + Basic + + + + Use Relative Pointer Mode Använd läge för relativ muspekare - + Nearest Närmast - + Linear Linjär - + Input - Touchscreen Ingång/indata - Pekskärm - + Network Nätverk - + Downscaling Filter Nerskalnings-filter - + Show Tutorial again Visa handledningen/övningsgenomgången igen - + Reset Återställ - + Audio Ljud - + Relative Pointer Speed Relativ pekarhastighet - + Music Volume Musikvolym - + Ignore SSL errors Ignorera SSL-fel - + Input - Mouse Ingång/indata - Mus - + Long Touch Duration Utökad beröringslängd - + % % - + Controller Click Tolerance Tolerans för klick på styrenhet - + Touch Tap Tolerance Tolerans för pektryck - + Input - Controller Ingång/indata - Kontroll - + Sound Volume Ljudvolym - + Select display mode for game Windowed - game will run inside a window that covers part of your screen @@ -846,167 +889,167 @@ Kantlöst fönsterläge - spelet körs i ett fönster som täcker hela din skär Exklusivt helskärmsläge - spelet kommer att täcka hela skärmen och använda den valda upplösningen. - + Windowed Fönsterläge - + Borderless fullscreen Kantlös helskärm - + Exclusive fullscreen Exklusiv helskärm - + Reserved screen area Reserverat skärmområde - + Neutral AI in battles Neutralt AI i strider - + Autosave limit (0 = off) Antal platser för automatisk-sparning (0 = inaktiverad) - + Adventure Map Enemies Fiender på äventyskartan - + Autosave prefix Prefix för automatisk-sparning - + empty = map name prefix tomt = kartnamnsprefix - + Interface Scaling Gränssnittsskalning - + Framerate Limit Gräns ​​för bildhastighet - + Renderer Renderingsmotor - + Heroes III Translation Heroes III - Översättning - + Adventure Map Allies Allierade på äventyrskartan - + Additional repository Ytterligare repositorier - + Check on startup Kontrollera vid uppstart - + Mouse Click Tolerance Musklickstolerans - + Sticks Acceleration Styrspaks-acceleration - + Refresh now Uppdatera nu - + Fullscreen Helskärm - + General Allmänt - + VCMI Language VCMI-språk - + Resolution Upplösning - + Autosave Auto-spara - + Display index Visa index - + Network port Nätverksport - + Video Video - + Show intro Visa intro - + Active Aktiv - + Disabled Inaktiverad - + Enable Aktivera - + Not Installed Inte installerad - + Install Installera @@ -1151,7 +1194,7 @@ Exklusivt helskärmsläge - spelet kommer att täcka hela skärmen och använda If you own Heroes III on gog.com you can download backup offline installer from gog.com, and VCMI will import Heroes III data using offline installer. Offline installer consists of two parts, .exe and .bin. Make sure you download both of them. - Om du äger Heroes III från GOG.com kan du ladda ner backup offline-installationsprogrammet från 'GOG.com'. VCMI kommer att importera Heroes III-data med hjälp av offline-installationsprogrammet. Offline-installationsprogrammet består av två delar, en '.exe'- och en '.bin'fil. Se till att ladda ner båda. + Om du äger Heroes III från GOG.com kan du ladda ner backup offline-installationsprogrammet från 'GOG.com'. VCMI kommer att importera Heroes III-data med hjälp av offline-installationsprogrammet. Offline-installationsprogrammet består av två delar, en '.exe'- och en '.bin'fil. Se till att ladda ner båda. @@ -1166,12 +1209,12 @@ Offline installer consists of two parts, .exe and .bin. Make sure you download b VCMI on Github - VCMI på 'Github' + VCMI på 'Github' VCMI on Discord - VCMI på 'Discord' + VCMI på 'Discord' @@ -1245,7 +1288,7 @@ Heroes® of Might and Magic® III HD stöds för närvarande inte! Optionally, you can install additional mods either now, or at any point later, using the VCMI Launcher - Du kan välja att installera ytterligare moddar, antingen nu eller vid ett senare tillfälle med hjälp av 'VCMI Launchern' + Du kan välja att installera ytterligare moddar, antingen nu eller vid ett senare tillfälle med hjälp av 'VCMI Launchern' diff --git a/launcher/translation/ukrainian.ts b/launcher/translation/ukrainian.ts index ddfe4a510..efdf8ea08 100644 --- a/launcher/translation/ukrainian.ts +++ b/launcher/translation/ukrainian.ts @@ -634,267 +634,310 @@ Install successfully downloaded? CSettingsView + Off Ні - + Artificial Intelligence Штучний інтелект - + Interface Scaling Масштабування інтерфейсу - + Neutral AI in battles Нейтральний ШІ в боях - + Enemy AI in battles Ворожий ШІ в боях - + Additional repository Додатковий репозиторій - + Downscaling Filter - + Adventure Map Allies Союзники на мапі пригод - + Online Lobby port Порт онлайн лобі - + Autocombat AI in battles ШІ автобою - + Sticks Sensitivity Чутливість стиків - + Automatic (Linear) - + Haptic Feedback - + Software Cursor Програмний курсор - + + + Automatic - + + Mods Validation + + + + None - + xBRZ x2 - + xBRZ x3 - + xBRZ x4 - + + Full + + + + Use scalable fonts - + Online Lobby address Адреса онлайн-лобі - + + Cursor Scaling + + + + + Scalable + + + + + Miscellaneous + + + + + Font Scaling (experimental) + + + + + Original + + + + Upscaling Filter Фільтр масштабування - + + Basic + + + + Use Relative Pointer Mode Режим відносного вказівника - + Nearest Найближчий - + Linear Лінійний - + Input - Touchscreen Введення - Сенсорний екран - + Adventure Map Enemies Вороги на мапі пригод - + Show Tutorial again Повторно показати навчання - + Reset Скинути - + Network Мережа - + Audio Аудіо - + Relative Pointer Speed Швидкість відносного вказівника - + Music Volume Гучність музики - + Ignore SSL errors Ігнорувати помилки SSL - + Input - Mouse Введення - Миша - + Long Touch Duration Тривалість довгого дотику - + % % - + Controller Click Tolerance Допуск на натискання контролера - + Touch Tap Tolerance Допуск на натискання дотиком - + Input - Controller Введення - Контролер - + Sound Volume Гучність звуку - + Windowed У вікні - + Borderless fullscreen Повноекранне вікно - + Exclusive fullscreen Повноекранний (ексклюзивно) - + Autosave limit (0 = off) Кількість автозбережень - + Framerate Limit Обмеження частоти кадрів - + Autosave prefix Префікс назв автозбережень - + Mouse Click Tolerance Допуск кліків миші - + Sticks Acceleration Прискорення стиків - + empty = map name prefix (використовувати назву карти) - + Refresh now Оновити зараз - + Default repository Стандартний репозиторій - + Renderer Рендерер @@ -904,7 +947,7 @@ Install successfully downloaded? Так - + Select display mode for game Windowed - game will run inside a window that covers part of your screen @@ -921,92 +964,92 @@ Fullscreen Exclusive Mode - game will cover entirety of your screen and will use Повноекранний ексклюзивний режим - гра займатиме весь екран і використовуватиме вибрану роздільну здатність. - + Reserved screen area Зарезервована зона екрану - + Heroes III Translation Переклад Heroes III - + Check on startup Перевіряти на старті - + Fullscreen Повноекранний режим - + General Загальні налаштування - + VCMI Language Мова VCMI - + Resolution Роздільна здатність - + Autosave Автозбереження - + VSync Вертикальна синхронізація - + Display index Дісплей - + Network port Мережевий порт - + Video Графіка - + Show intro Вступні відео - + Active Активні - + Disabled Деактивований - + Enable Активувати - + Not Installed Не встановлено - + Install Встановити diff --git a/launcher/translation/vietnamese.ts b/launcher/translation/vietnamese.ts index c5263d4e9..0f96f2242 100644 --- a/launcher/translation/vietnamese.ts +++ b/launcher/translation/vietnamese.ts @@ -626,267 +626,310 @@ Install successfully downloaded? CSettingsView + Off Tắt - + Artificial Intelligence Trí tuệ nhân tạo - + Interface Scaling Phóng đại giao diện - + Neutral AI in battles Máy hoang dã trong trận đánh - + Enemy AI in battles Máy đối thủ trong trận đánh - + Additional repository Nguồn bổ sung - + Downscaling Filter - + Adventure Map Allies Máy liên minh ở bản đồ phiêu lưu - + Online Lobby port - + Autocombat AI in battles - + Sticks Sensitivity - + Automatic (Linear) - + Haptic Feedback - + Software Cursor - + + + Automatic - + + Mods Validation + + + + None - + xBRZ x2 - + xBRZ x3 - + xBRZ x4 - + + Full + + + + Use scalable fonts - + Online Lobby address - + + Cursor Scaling + + + + + Scalable + + + + + Miscellaneous + + + + + Font Scaling (experimental) + + + + + Original + + + + Upscaling Filter - + + Basic + + + + Use Relative Pointer Mode - + Nearest - + Linear - + Input - Touchscreen - + Adventure Map Enemies Máy đối thủ ở bản đồ phiêu lưu - + Show Tutorial again - + Reset - + Network - + Audio - + Relative Pointer Speed - + Music Volume - + Ignore SSL errors - + Input - Mouse - + Long Touch Duration - + % - + Controller Click Tolerance - + Touch Tap Tolerance - + Input - Controller - + Sound Volume - + Windowed Cửa sổ - + Borderless fullscreen Toàn màn hình không viền - + Exclusive fullscreen Toàn màn hình riêng biệt - + Autosave limit (0 = off) Giới hạn lưu tự động (0 = không giới hạn) - + Framerate Limit Giới hạn khung hình - + Autosave prefix Thêm tiền tố vào lưu tự động - + Mouse Click Tolerance - + Sticks Acceleration - + empty = map name prefix Rỗng = tên bản đồ - + Refresh now Làm mới - + Default repository Nguồn mặc định - + Renderer @@ -896,7 +939,7 @@ Install successfully downloaded? Bật - + Select display mode for game Windowed - game will run inside a window that covers part of your screen @@ -913,92 +956,92 @@ Toàn màn hình không viền - Trò chơi chạy toàn màn hình, dùng chung Toàn màn hình riêng biệt - Trò chơi chạy toàn màn hình và dùng độ phân giải được chọn. - + Reserved screen area Diện tích màn hình dành riêng - + Heroes III Translation Bản dịch Heroes III - + Check on startup Kiểm tra khi khởi động - + Fullscreen Toàn màn hình - + General Chung - + VCMI Language Ngôn ngữ VCMI - + Resolution Độ phân giải - + Autosave Tự động lưu - + VSync - + Display index Mục hiện thị - + Network port Cổng mạng - + Video Phim ảnh - + Show intro Hiện thị giới thiệu - + Active Bật - + Disabled Tắt - + Enable Bật - + Not Installed Chưa cài đặt - + Install Cài đặt diff --git a/lib/ArtifactUtils.cpp b/lib/ArtifactUtils.cpp index 7c95e435a..bfdb48468 100644 --- a/lib/ArtifactUtils.cpp +++ b/lib/ArtifactUtils.cpp @@ -202,21 +202,23 @@ DLL_LINKAGE std::vector ArtifactUtils::assemblyPossibilities( if(art->isCombined()) return arts; - for(const auto artifact : art->getPartOf()) + for(const auto combinedArt : art->getPartOf()) { - assert(artifact->isCombined()); + assert(combinedArt->isCombined()); bool possible = true; - - for(const auto constituent : artifact->getConstituents()) //check if all constituents are available + CArtifactFittingSet fittingSet(*artSet); + for(const auto part : combinedArt->getConstituents()) // check if all constituents are available { - if(!artSet->hasArt(constituent->getId(), onlyEquiped, false)) + const auto slot = fittingSet.getArtPos(part->getId(), onlyEquiped, false); + if(slot == ArtifactPosition::PRE_FIRST) { possible = false; break; } + fittingSet.lockSlot(slot); } if(possible) - arts.push_back(artifact); + arts.push_back(combinedArt); } return arts; } diff --git a/lib/CArtHandler.cpp b/lib/CArtHandler.cpp index 07b83dec3..1cd5afdda 100644 --- a/lib/CArtHandler.cpp +++ b/lib/CArtHandler.cpp @@ -56,11 +56,26 @@ const std::vector & CCombinedArtifact::getConstituents() const return constituents; } -const std::vector & CCombinedArtifact::getPartOf() const +const std::set & CCombinedArtifact::getPartOf() const { return partOf; } +void CCombinedArtifact::setFused(bool isFused) +{ + fused = isFused; +} + +bool CCombinedArtifact::isFused() const +{ + return fused; +} + +bool CCombinedArtifact::hasParts() const +{ + return isCombined() && !isFused(); +} + bool CScrollArtifact::isScroll() const { return static_cast(this)->getId() == ArtifactID::SPELL_SCROLL; @@ -203,7 +218,7 @@ bool CArtifact::canBePutAt(const CArtifactSet * artSet, ArtifactPosition slot, b auto artCanBePutAt = [this, simpleArtCanBePutAt](const CArtifactSet * artSet, ArtifactPosition slot, bool assumeDestRemoved) -> bool { - if(isCombined()) + if(hasParts()) { if(!simpleArtCanBePutAt(artSet, slot, assumeDestRemoved)) return false; @@ -606,19 +621,21 @@ void CArtHandler::loadType(CArtifact * art, const JsonNode & node) const void CArtHandler::loadComponents(CArtifact * art, const JsonNode & node) { - if (!node["components"].isNull()) + if(!node["components"].isNull()) { for(const auto & component : node["components"].Vector()) { - VLC->identifiers()->requestIdentifier("artifact", component, [=](si32 id) + VLC->identifiers()->requestIdentifier("artifact", component, [this, art](int32_t id) { // when this code is called both combinational art as well as component are loaded // so it is safe to access any of them art->constituents.push_back(ArtifactID(id).toArtifact()); - objects[id]->partOf.push_back(art); + objects[id]->partOf.insert(art); }); } } + if(!node["fusedComponents"].isNull()) + art->setFused(node["fusedComponents"].Bool()); } void CArtHandler::makeItCreatureArt(CArtifact * a, bool onlyCreature) @@ -767,8 +784,27 @@ bool CArtifactSet::hasArt(const ArtifactID & aid, bool onlyWorn, bool searchComb CArtifactSet::ArtPlacementMap CArtifactSet::putArtifact(const ArtifactPosition & slot, CArtifactInstance * art) { ArtPlacementMap resArtPlacement; + const auto putToSlot = [this](const ArtifactPosition & targetSlot, CArtifactInstance * targetArt, bool locked) + { + ArtSlotInfo * slotInfo; + if(targetSlot == ArtifactPosition::TRANSITION_POS) + { + slotInfo = &artifactsTransitionPos; + } + else if(ArtifactUtils::isSlotEquipment(targetSlot)) + { + slotInfo = &artifactsWorn[targetSlot]; + } + else + { + auto position = artifactsInBackpack.begin() + targetSlot - ArtifactPosition::BACKPACK_START; + slotInfo = &(*artifactsInBackpack.emplace(position)); + } + slotInfo->artifact = targetArt; + slotInfo->locked = locked; + }; - setNewArtSlot(slot, art, false); + putToSlot(slot, art, false); if(art->artType->isCombined() && ArtifactUtils::isSlotEquipment(slot)) { const CArtifactInstance * mainPart = nullptr; @@ -789,7 +825,7 @@ CArtifactSet::ArtPlacementMap CArtifactSet::putArtifact(const ArtifactPosition & partSlot = ArtifactUtils::getArtAnyPosition(this, part.art->getTypeId()); assert(ArtifactUtils::isSlotEquipment(partSlot)); - setNewArtSlot(partSlot, part.art, true); + putToSlot(partSlot, part.art, true); resArtPlacement.emplace(part.art, partSlot); } else @@ -877,7 +913,15 @@ const ArtSlotInfo * CArtifactSet::getSlot(const ArtifactPosition & pos) const void CArtifactSet::lockSlot(const ArtifactPosition & pos) { - setNewArtSlot(pos, nullptr, true); + if(pos == ArtifactPosition::TRANSITION_POS) + artifactsTransitionPos.locked = true; + else if(ArtifactUtils::isSlotEquipment(pos)) + artifactsWorn[pos].locked = true; + else + { + assert(artifactsInBackpack.size() > pos - ArtifactPosition::BACKPACK_START); + (artifactsInBackpack.begin() + pos - ArtifactPosition::BACKPACK_START)->locked = true; + } } bool CArtifactSet::isPositionFree(const ArtifactPosition & pos, bool onlyLockCheck) const @@ -891,28 +935,6 @@ bool CArtifactSet::isPositionFree(const ArtifactPosition & pos, bool onlyLockChe return true; //no slot means not used } -void CArtifactSet::setNewArtSlot(const ArtifactPosition & slot, CArtifactInstance * art, bool locked) -{ - assert(!vstd::contains(artifactsWorn, slot)); - - ArtSlotInfo * slotInfo; - if(slot == ArtifactPosition::TRANSITION_POS) - { - slotInfo = &artifactsTransitionPos; - } - else if(ArtifactUtils::isSlotEquipment(slot)) - { - slotInfo = &artifactsWorn[slot]; - } - else - { - auto position = artifactsInBackpack.begin() + slot - ArtifactPosition::BACKPACK_START; - slotInfo = &(*artifactsInBackpack.emplace(position)); - } - slotInfo->artifact = art; - slotInfo->locked = locked; -} - void CArtifactSet::artDeserializationFix(CBonusSystemNode *node) { for(auto & elem : artifactsWorn) diff --git a/lib/CArtHandler.h b/lib/CArtHandler.h index e82f43147..a902f22c8 100644 --- a/lib/CArtHandler.h +++ b/lib/CArtHandler.h @@ -46,14 +46,19 @@ namespace ArtBearer class DLL_LINKAGE CCombinedArtifact { protected: - CCombinedArtifact() = default; + CCombinedArtifact() : fused(false) {}; std::vector constituents; // Artifacts IDs a combined artifact consists of, or nullptr. - std::vector partOf; // Reverse map of constituents - combined arts that include this art + std::set partOf; // Reverse map of constituents - combined arts that include this art + bool fused; + public: bool isCombined() const; const std::vector & getConstituents() const; - const std::vector & getPartOf() const; + const std::set & getPartOf() const; + void setFused(bool isFused); + bool isFused() const; + bool hasParts() const; }; class DLL_LINKAGE CScrollArtifact @@ -224,8 +229,6 @@ public: const CArtifactInstance * getCombinedArtWithPart(const ArtifactID & partId) const; private: - void setNewArtSlot(const ArtifactPosition & slot, CArtifactInstance * art, bool locked); - void serializeJsonHero(JsonSerializeFormat & handler); void serializeJsonCreature(JsonSerializeFormat & handler); void serializeJsonCommander(JsonSerializeFormat & handler); diff --git a/lib/CArtifactInstance.cpp b/lib/CArtifactInstance.cpp index 6f191e46b..f65e6d95b 100644 --- a/lib/CArtifactInstance.cpp +++ b/lib/CArtifactInstance.cpp @@ -44,6 +44,11 @@ bool CCombinedArtifactInstance::isPart(const CArtifactInstance * supposedPart) c return false; } +bool CCombinedArtifactInstance::hasParts() const +{ + return !partsInfo.empty(); +} + const std::vector & CCombinedArtifactInstance::getPartsInfo() const { return partsInfo; diff --git a/lib/CArtifactInstance.h b/lib/CArtifactInstance.h index f679f8b44..6ff0bdbe0 100644 --- a/lib/CArtifactInstance.h +++ b/lib/CArtifactInstance.h @@ -38,6 +38,7 @@ public: void addPart(CArtifactInstance * art, const ArtifactPosition & slot); // Checks if supposed part inst is part of this combined art inst bool isPart(const CArtifactInstance * supposedPart) const; + bool hasParts() const; const std::vector & getPartsInfo() const; void addPlacementMap(const CArtifactSet::ArtPlacementMap & placementMap); diff --git a/lib/CCreatureSet.cpp b/lib/CCreatureSet.cpp index d11c6c527..95ae536ac 100644 --- a/lib/CCreatureSet.cpp +++ b/lib/CCreatureSet.cpp @@ -15,12 +15,12 @@ #include "CCreatureHandler.h" #include "VCMI_Lib.h" #include "IGameSettings.h" +#include "entities/hero/CHeroHandler.h" #include "mapObjects/CGHeroInstance.h" #include "modding/ModScope.h" #include "IGameCallback.h" #include "texts/CGeneralTextHandler.h" #include "spells/CSpellHandler.h" -#include "CHeroHandler.h" #include "IBonusTypeHandler.h" #include "serializer/JsonSerializeFormat.h" diff --git a/lib/CGameInfoCallback.cpp b/lib/CGameInfoCallback.cpp index b6017df9d..112f37fcd 100644 --- a/lib/CGameInfoCallback.cpp +++ b/lib/CGameInfoCallback.cpp @@ -479,6 +479,17 @@ std::vector CGameInfoCallback::getVisitableObjs(int3 return ret; } + +std::vector> CGameInfoCallback::getAllVisitableObjs() const +{ + std::vector> ret; + for(auto & obj : gs->map->objects) + if(obj->isVisitable() && obj->ID != Obj::EVENT && isVisible(obj)) + ret.push_back(obj); + + return ret; +} + const CGObjectInstance * CGameInfoCallback::getTopObj (int3 pos) const { return vstd::backOrNull(getVisitableObjs(pos)); diff --git a/lib/CGameInfoCallback.h b/lib/CGameInfoCallback.h index 91c51b5a7..25f15d53e 100644 --- a/lib/CGameInfoCallback.h +++ b/lib/CGameInfoCallback.h @@ -11,6 +11,7 @@ #include "int3.h" #include "ResourceSet.h" // for Res +#include "ConstTransitivePtr.h" #define ASSERT_IF_CALLED_WITH_PLAYER if(!getPlayerID()) {logGlobal->error(BOOST_CURRENT_FUNCTION); assert(0);} @@ -189,6 +190,7 @@ public: const CGObjectInstance * getObj(ObjectInstanceID objid, bool verbose = true) const override; virtual std::vector getBlockingObjs(int3 pos)const; std::vector getVisitableObjs(int3 pos, bool verbose = true) const override; + std::vector> getAllVisitableObjs() const; virtual std::vector getFlaggableObjects(int3 pos) const; virtual const CGObjectInstance * getTopObj (int3 pos) const; virtual PlayerColor getOwner(ObjectInstanceID heroID) const; diff --git a/lib/CHeroHandler.h b/lib/CHeroHandler.h deleted file mode 100644 index c2bd9d220..000000000 --- a/lib/CHeroHandler.h +++ /dev/null @@ -1,221 +0,0 @@ -/* - * CHeroHandler.h, part of VCMI engine - * - * Authors: listed in file AUTHORS in main folder - * - * License: GNU General Public License v2.0 or later - * Full text of license available in license.txt file, in main folder - * - */ -#pragma once - -#include -#include -#include -#include - -#include "ConstTransitivePtr.h" -#include "GameConstants.h" -#include "bonuses/Bonus.h" -#include "bonuses/BonusList.h" -#include "IHandlerBase.h" -#include "filesystem/ResourcePath.h" - -VCMI_LIB_NAMESPACE_BEGIN - -namespace vstd -{ -class RNG; -} - -class CHeroClass; -class CGHeroInstance; -struct BattleHex; -class JsonNode; -class JsonSerializeFormat; -class BattleField; - -enum class EHeroGender : int8_t -{ - DEFAULT = -1, // from h3m, instance has same gender as hero type - MALE = 0, - FEMALE = 1, -}; - -class DLL_LINKAGE CHero : public HeroType -{ - friend class CHeroHandler; - - HeroTypeID ID; - std::string identifier; - std::string modScope; - -public: - struct InitialArmyStack - { - ui32 minAmount; - ui32 maxAmount; - CreatureID creature; - }; - si32 imageIndex = 0; - - std::vector initialArmy; - - const CHeroClass * heroClass = nullptr; - std::vector > secSkillsInit; //initial secondary skills; first - ID of skill, second - level of skill (1 - basic, 2 - adv., 3 - expert) - BonusList specialty; - std::set spells; - bool haveSpellBook = false; - bool special = false; // hero is special and won't be placed in game (unless preset on map), e.g. campaign heroes - bool onlyOnWaterMap; // hero will be placed only if the map contains water - bool onlyOnMapWithoutWater; // hero will be placed only if the map does not contain water - EHeroGender gender = EHeroGender::MALE; // default sex: 0=male, 1=female - - /// Graphics - std::string iconSpecSmall; - std::string iconSpecLarge; - std::string portraitSmall; - std::string portraitLarge; - AnimationPath battleImage; - - CHero(); - virtual ~CHero(); - - int32_t getIndex() const override; - int32_t getIconIndex() const override; - std::string getJsonKey() const override; - std::string getModScope() const override; - HeroTypeID getId() const override; - void registerIcons(const IconRegistar & cb) const override; - - std::string getNameTranslated() const override; - std::string getBiographyTranslated() const override; - std::string getSpecialtyNameTranslated() const override; - std::string getSpecialtyDescriptionTranslated() const override; - std::string getSpecialtyTooltipTranslated() const override; - - std::string getNameTextID() const override; - std::string getBiographyTextID() const override; - std::string getSpecialtyNameTextID() const override; - std::string getSpecialtyDescriptionTextID() const override; - std::string getSpecialtyTooltipTextID() const override; - - void updateFrom(const JsonNode & data); - void serializeJson(JsonSerializeFormat & handler); -}; - -class DLL_LINKAGE CHeroClass : public HeroClass -{ - friend class CHeroClassHandler; - HeroClassID id; // use getId instead - std::string modScope; - std::string identifier; // use getJsonKey instead - -public: - enum EClassAffinity - { - MIGHT, - MAGIC - }; - - //double aggression; // not used in vcmi. - FactionID faction; - ui8 affinity; // affinity, using EClassAffinity enum - - // default chance for hero of specific class to appear in tavern, if field "tavern" was not set - // resulting chance = sqrt(town.chance * heroClass.chance) - ui32 defaultTavernChance; - - CreatureID commander; - - std::vector primarySkillInitial; // initial primary skills - std::vector primarySkillLowLevel; // probability (%) of getting point of primary skill when getting level - std::vector primarySkillHighLevel;// same for high levels (> 10) - - std::map secSkillProbability; //probabilities of gaining secondary skills (out of 112), in id order - - std::map selectionProbability; //probability of selection in towns - - AnimationPath imageBattleMale; - AnimationPath imageBattleFemale; - std::string imageMapMale; - std::string imageMapFemale; - - CHeroClass(); - - int32_t getIndex() const override; - int32_t getIconIndex() const override; - std::string getJsonKey() const override; - std::string getModScope() const override; - HeroClassID getId() const override; - void registerIcons(const IconRegistar & cb) const override; - - std::string getNameTranslated() const override; - std::string getNameTextID() const override; - - bool isMagicHero() const; - SecondarySkill chooseSecSkill(const std::set & possibles, vstd::RNG & rand) const; //picks secondary skill out from given possibilities - - void updateFrom(const JsonNode & data); - void serializeJson(JsonSerializeFormat & handler); - - EAlignment getAlignment() const; - - int tavernProbability(FactionID faction) const; -}; - -class DLL_LINKAGE CHeroClassHandler : public CHandlerBase -{ - void fillPrimarySkillData(const JsonNode & node, CHeroClass * heroClass, PrimarySkill pSkill) const; - -public: - std::vector loadLegacyData() override; - - void afterLoadFinalization() override; - - ~CHeroClassHandler(); - -protected: - const std::vector & getTypeNames() const override; - std::shared_ptr loadFromJson(const std::string & scope, const JsonNode & node, const std::string & identifier, size_t index) override; - -}; - -class DLL_LINKAGE CHeroHandler : public CHandlerBase -{ - /// expPerLEvel[i] is amount of exp needed to reach level i; - /// consists of 196 values. Any higher levels require experience larger that TExpType can hold - std::vector expPerLevel; - - /// helpers for loading to avoid huge load functions - void loadHeroArmy(CHero * hero, const JsonNode & node) const; - void loadHeroSkills(CHero * hero, const JsonNode & node) const; - void loadHeroSpecialty(CHero * hero, const JsonNode & node); - - void loadExperience(); - - std::vector> callAfterLoadFinalization; - -public: - ui32 level(TExpType experience) const; //calculates level corresponding to given experience amount - TExpType reqExp(ui32 level) const; //calculates experience required for given level - ui32 maxSupportedLevel() const; - - std::vector loadLegacyData() override; - - void beforeValidate(JsonNode & object) override; - void loadObject(std::string scope, std::string name, const JsonNode & data) override; - void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override; - void afterLoadFinalization() override; - - CHeroHandler(); - ~CHeroHandler(); - - std::set getDefaultAllowed() const; - -protected: - const std::vector & getTypeNames() const override; - std::shared_ptr loadFromJson(const std::string & scope, const JsonNode & node, const std::string & identifier, size_t index) override; -}; - -VCMI_LIB_NAMESPACE_END diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 37cb28106..0db2f9e50 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -87,6 +87,10 @@ set(lib_MAIN_SRCS entities/faction/CFaction.cpp entities/faction/CTown.cpp entities/faction/CTownHandler.cpp + entities/hero/CHero.cpp + entities/hero/CHeroClass.cpp + entities/hero/CHeroClassHandler.cpp + entities/hero/CHeroHandler.cpp events/ApplyDamage.cpp events/GameResumed.cpp @@ -270,7 +274,6 @@ set(lib_MAIN_SRCS CCreatureSet.cpp CGameInfoCallback.cpp CGameInterface.cpp - CHeroHandler.cpp CPlayerState.cpp CRandomGenerator.cpp CScriptingModule.cpp @@ -458,6 +461,11 @@ set(lib_MAIN_HEADERS entities/faction/CFaction.h entities/faction/CTown.h entities/faction/CTownHandler.h + entities/hero/CHero.h + entities/hero/CHeroClass.h + entities/hero/CHeroClassHandler.h + entities/hero/CHeroHandler.h + entities/hero/EHeroGender.h events/ApplyDamage.h events/GameResumed.h @@ -683,7 +691,6 @@ set(lib_MAIN_HEADERS CCreatureSet.h CGameInfoCallback.h CGameInterface.h - CHeroHandler.h ConstTransitivePtr.h Color.h CPlayerState.h diff --git a/lib/CPlayerState.cpp b/lib/CPlayerState.cpp index 2660377c6..069be91c1 100644 --- a/lib/CPlayerState.cpp +++ b/lib/CPlayerState.cpp @@ -22,9 +22,9 @@ VCMI_LIB_NAMESPACE_BEGIN PlayerState::PlayerState() : color(-1) - , playerLocalSettings(std::make_unique()) , human(false) , cheated(false) + , playerLocalSettings(std::make_unique()) , enteredWinningCheatCode(false) , enteredLosingCheatCode(false) , status(EPlayerStatus::INGAME) diff --git a/lib/IGameCallback.cpp b/lib/IGameCallback.cpp index fa73d0101..cb32dcb50 100644 --- a/lib/IGameCallback.cpp +++ b/lib/IGameCallback.cpp @@ -10,7 +10,6 @@ #include "StdInc.h" #include "IGameCallback.h" -#include "CHeroHandler.h" // for CHeroHandler #include "spells/CSpellHandler.h"// for CSpell #include "CSkillHandler.h"// for CSkill #include "CBonusTypeHandler.h" @@ -20,6 +19,7 @@ #include "bonuses/Propagators.h" #include "bonuses/Updaters.h" #include "entities/building/CBuilding.h" +#include "entities/hero/CHero.h" #include "networkPacks/ArtifactLocation.h" #include "serializer/CLoadFile.h" #include "serializer/CSaveFile.h" diff --git a/lib/IGameCallback.h b/lib/IGameCallback.h index fc1f104c3..1de95812d 100644 --- a/lib/IGameCallback.h +++ b/lib/IGameCallback.h @@ -94,7 +94,7 @@ public: virtual void showInfoDialog(InfoWindow * iw) = 0; virtual void changeSpells(const CGHeroInstance * hero, bool give, const std::set &spells)=0; - virtual void setResearchedSpells(const CGTownInstance * town, int level, const std::vector spells, bool accepted)=0; + virtual void setResearchedSpells(const CGTownInstance * town, int level, const std::vector & spells, bool accepted)=0; virtual bool removeObject(const CGObjectInstance * obj, const PlayerColor & initiator) = 0; virtual void createBoat(const int3 & visitablePosition, BoatId type, PlayerColor initiator) = 0; virtual void setOwner(const CGObjectInstance * objid, PlayerColor owner)=0; diff --git a/lib/StartInfo.cpp b/lib/StartInfo.cpp index b1abfe7b6..f6ca7d6cc 100644 --- a/lib/StartInfo.cpp +++ b/lib/StartInfo.cpp @@ -11,10 +11,10 @@ #include "StartInfo.h" #include "texts/CGeneralTextHandler.h" -#include "CHeroHandler.h" #include "VCMI_Lib.h" #include "entities/faction/CFaction.h" #include "entities/faction/CTownHandler.h" +#include "entities/hero/CHeroHandler.h" #include "rmg/CMapGenOptions.h" #include "mapping/CMapInfo.h" #include "campaign/CampaignState.h" diff --git a/lib/VCMI_Lib.cpp b/lib/VCMI_Lib.cpp index c516947bd..91d3da34b 100644 --- a/lib/VCMI_Lib.cpp +++ b/lib/VCMI_Lib.cpp @@ -14,7 +14,6 @@ #include "CArtHandler.h" #include "CBonusTypeHandler.h" #include "CCreatureHandler.h" -#include "CHeroHandler.h" #include "CConfigHandler.h" #include "RoadHandler.h" #include "RiverHandler.h" @@ -23,6 +22,8 @@ #include "spells/effects/Registry.h" #include "CSkillHandler.h" #include "entities/faction/CTownHandler.h" +#include "entities/hero/CHeroClassHandler.h" +#include "entities/hero/CHeroHandler.h" #include "texts/CGeneralTextHandler.h" #include "modding/CModHandler.h" #include "modding/CModInfo.h" diff --git a/lib/battle/BattleInfo.cpp b/lib/battle/BattleInfo.cpp index 5bbebc49c..8a8eb633c 100644 --- a/lib/battle/BattleInfo.cpp +++ b/lib/battle/BattleInfo.cpp @@ -15,7 +15,6 @@ #include "bonuses/Limiters.h" #include "bonuses/Updaters.h" #include "../CStack.h" -#include "../CHeroHandler.h" #include "../entities/building/TownFortifications.h" #include "../filesystem/Filesystem.h" #include "../mapObjects/CGTownInstance.h" diff --git a/lib/battle/CObstacleInstance.cpp b/lib/battle/CObstacleInstance.cpp index 098d980a2..6bb5c65f3 100644 --- a/lib/battle/CObstacleInstance.cpp +++ b/lib/battle/CObstacleInstance.cpp @@ -9,7 +9,6 @@ */ #include "StdInc.h" #include "CObstacleInstance.h" -#include "../CHeroHandler.h" #include "../ObstacleHandler.h" #include "../VCMI_Lib.h" diff --git a/lib/bonuses/Bonus.cpp b/lib/bonuses/Bonus.cpp index 2f1cb519b..a11e794f4 100644 --- a/lib/bonuses/Bonus.cpp +++ b/lib/bonuses/Bonus.cpp @@ -14,18 +14,18 @@ #include "Updaters.h" #include "Propagators.h" -#include "../VCMI_Lib.h" -#include "../spells/CSpellHandler.h" +#include "../CArtHandler.h" #include "../CCreatureHandler.h" #include "../CCreatureSet.h" -#include "../CHeroHandler.h" -#include "../texts/CGeneralTextHandler.h" #include "../CSkillHandler.h" -#include "../CArtHandler.h" #include "../TerrainHandler.h" -#include "../constants/StringConstants.h" +#include "../VCMI_Lib.h" #include "../battle/BattleInfo.h" +#include "../constants/StringConstants.h" +#include "../entities/hero/CHero.h" #include "../modding/ModUtility.h" +#include "../spells/CSpellHandler.h" +#include "../texts/CGeneralTextHandler.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/bonuses/Limiters.cpp b/lib/bonuses/Limiters.cpp index 914081139..0fa15f9d4 100644 --- a/lib/bonuses/Limiters.cpp +++ b/lib/bonuses/Limiters.cpp @@ -17,7 +17,6 @@ #include "../spells/CSpellHandler.h" #include "../CCreatureHandler.h" #include "../CCreatureSet.h" -#include "../CHeroHandler.h" #include "../texts/CGeneralTextHandler.h" #include "../CSkillHandler.h" #include "../CStack.h" diff --git a/lib/constants/EntityIdentifiers.cpp b/lib/constants/EntityIdentifiers.cpp index 599920523..2c3f183c5 100644 --- a/lib/constants/EntityIdentifiers.cpp +++ b/lib/constants/EntityIdentifiers.cpp @@ -29,12 +29,13 @@ #include "modding/IdentifierStorage.h" #include "modding/ModScope.h" #include "VCMI_Lib.h" -#include "CHeroHandler.h" #include "CArtHandler.h"//todo: remove #include "CCreatureHandler.h"//todo: remove #include "spells/CSpellHandler.h" //todo: remove #include "CSkillHandler.h"//todo: remove #include "entities/faction/CFaction.h" +#include "entities/hero/CHero.h" +#include "entities/hero/CHeroClass.h" #include "mapObjectConstructors/AObjectTypeHandler.h" #include "constants/StringConstants.h" #include "texts/CGeneralTextHandler.h" diff --git a/lib/entities/faction/CTownHandler.cpp b/lib/entities/faction/CTownHandler.cpp index 09a99ed71..91d05852b 100644 --- a/lib/entities/faction/CTownHandler.cpp +++ b/lib/entities/faction/CTownHandler.cpp @@ -13,9 +13,9 @@ #include "CTown.h" #include "CFaction.h" #include "../building/CBuilding.h" +#include "../hero/CHeroClassHandler.h" #include "../../CCreatureHandler.h" -#include "../../CHeroHandler.h" #include "../../IGameSettings.h" #include "../../TerrainHandler.h" #include "../../VCMI_Lib.h" diff --git a/lib/entities/hero/CHero.cpp b/lib/entities/hero/CHero.cpp new file mode 100644 index 000000000..4b9b363f1 --- /dev/null +++ b/lib/entities/hero/CHero.cpp @@ -0,0 +1,114 @@ +/* + * CHero.cpp, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#include "StdInc.h" +#include "CHero.h" + +#include "../../VCMI_Lib.h" +#include "../../texts/CGeneralTextHandler.h" + +VCMI_LIB_NAMESPACE_BEGIN + +CHero::CHero() = default; +CHero::~CHero() = default; + +int32_t CHero::getIndex() const +{ + return ID.getNum(); +} + +int32_t CHero::getIconIndex() const +{ + return imageIndex; +} + +std::string CHero::getJsonKey() const +{ + return modScope + ':' + identifier; +} + +std::string CHero::getModScope() const +{ + return modScope; +} + +HeroTypeID CHero::getId() const +{ + return ID; +} + +std::string CHero::getNameTranslated() const +{ + return VLC->generaltexth->translate(getNameTextID()); +} + +std::string CHero::getBiographyTranslated() const +{ + return VLC->generaltexth->translate(getBiographyTextID()); +} + +std::string CHero::getSpecialtyNameTranslated() const +{ + return VLC->generaltexth->translate(getSpecialtyNameTextID()); +} + +std::string CHero::getSpecialtyDescriptionTranslated() const +{ + return VLC->generaltexth->translate(getSpecialtyDescriptionTextID()); +} + +std::string CHero::getSpecialtyTooltipTranslated() const +{ + return VLC->generaltexth->translate(getSpecialtyTooltipTextID()); +} + +std::string CHero::getNameTextID() const +{ + return TextIdentifier("hero", modScope, identifier, "name").get(); +} + +std::string CHero::getBiographyTextID() const +{ + return TextIdentifier("hero", modScope, identifier, "biography").get(); +} + +std::string CHero::getSpecialtyNameTextID() const +{ + return TextIdentifier("hero", modScope, identifier, "specialty", "name").get(); +} + +std::string CHero::getSpecialtyDescriptionTextID() const +{ + return TextIdentifier("hero", modScope, identifier, "specialty", "description").get(); +} + +std::string CHero::getSpecialtyTooltipTextID() const +{ + return TextIdentifier("hero", modScope, identifier, "specialty", "tooltip").get(); +} + +void CHero::registerIcons(const IconRegistar & cb) const +{ + cb(getIconIndex(), 0, "UN32", iconSpecSmall); + cb(getIconIndex(), 0, "UN44", iconSpecLarge); + cb(getIconIndex(), 0, "PORTRAITSLARGE", portraitLarge); + cb(getIconIndex(), 0, "PORTRAITSSMALL", portraitSmall); +} + +void CHero::updateFrom(const JsonNode & data) +{ + //todo: CHero::updateFrom +} + +void CHero::serializeJson(JsonSerializeFormat & handler) +{ + +} + +VCMI_LIB_NAMESPACE_END diff --git a/lib/entities/hero/CHero.h b/lib/entities/hero/CHero.h new file mode 100644 index 000000000..1b96cc341 --- /dev/null +++ b/lib/entities/hero/CHero.h @@ -0,0 +1,87 @@ +/* + * CHero.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#pragma once + +#include + +#include "EHeroGender.h" + +#include "../../bonuses/BonusList.h" +#include "../../constants/EntityIdentifiers.h" +#include "../../filesystem/ResourcePath.h" + +VCMI_LIB_NAMESPACE_BEGIN + +class DLL_LINKAGE CHero : public HeroType +{ + friend class CHeroHandler; + + HeroTypeID ID; + std::string identifier; + std::string modScope; + +public: + struct InitialArmyStack + { + ui32 minAmount; + ui32 maxAmount; + CreatureID creature; + }; + si32 imageIndex = 0; + + std::vector initialArmy; + + const CHeroClass * heroClass = nullptr; + + //initial secondary skills; first - ID of skill, second - level of skill (1 - basic, 2 - adv., 3 - expert) + std::vector> secSkillsInit; + + BonusList specialty; + std::set spells; + bool haveSpellBook = false; + bool special = false; // hero is special and won't be placed in game (unless preset on map), e.g. campaign heroes + bool onlyOnWaterMap; // hero will be placed only if the map contains water + bool onlyOnMapWithoutWater; // hero will be placed only if the map does not contain water + EHeroGender gender = EHeroGender::MALE; // default sex: 0=male, 1=female + + /// Graphics + std::string iconSpecSmall; + std::string iconSpecLarge; + std::string portraitSmall; + std::string portraitLarge; + AnimationPath battleImage; + + CHero(); + virtual ~CHero(); + + int32_t getIndex() const override; + int32_t getIconIndex() const override; + std::string getJsonKey() const override; + std::string getModScope() const override; + HeroTypeID getId() const override; + void registerIcons(const IconRegistar & cb) const override; + + std::string getNameTranslated() const override; + std::string getBiographyTranslated() const override; + std::string getSpecialtyNameTranslated() const override; + std::string getSpecialtyDescriptionTranslated() const override; + std::string getSpecialtyTooltipTranslated() const override; + + std::string getNameTextID() const override; + std::string getBiographyTextID() const override; + std::string getSpecialtyNameTextID() const override; + std::string getSpecialtyDescriptionTextID() const override; + std::string getSpecialtyTooltipTextID() const override; + + void updateFrom(const JsonNode & data); + void serializeJson(JsonSerializeFormat & handler); +}; + +VCMI_LIB_NAMESPACE_END diff --git a/lib/entities/hero/CHeroClass.cpp b/lib/entities/hero/CHeroClass.cpp new file mode 100644 index 000000000..da6355e70 --- /dev/null +++ b/lib/entities/hero/CHeroClass.cpp @@ -0,0 +1,126 @@ +/* + * CHeroClass.cpp, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#include "StdInc.h" +#include "CHeroClass.h" + +#include "../faction/CFaction.h" + +#include "../../VCMI_Lib.h" +#include "../../texts/CGeneralTextHandler.h" + +#include + +VCMI_LIB_NAMESPACE_BEGIN + +SecondarySkill CHeroClass::chooseSecSkill(const std::set & possibles, vstd::RNG & rand) const //picks secondary skill out from given possibilities +{ + assert(!possibles.empty()); + + if (possibles.size() == 1) + return *possibles.begin(); + + int totalProb = 0; + for(const auto & possible : possibles) + if (secSkillProbability.count(possible) != 0) + totalProb += secSkillProbability.at(possible); + + if (totalProb == 0) // may trigger if set contains only banned skills (0 probability) + return *RandomGeneratorUtil::nextItem(possibles, rand); + + auto ran = rand.nextInt(totalProb - 1); + for(const auto & possible : possibles) + { + if (secSkillProbability.count(possible) != 0) + ran -= secSkillProbability.at(possible); + + if(ran < 0) + return possible; + } + + assert(0); // should not be possible + return *possibles.begin(); +} + +bool CHeroClass::isMagicHero() const +{ + return affinity == MAGIC; +} + +int CHeroClass::tavernProbability(FactionID targetFaction) const +{ + auto it = selectionProbability.find(targetFaction); + if (it != selectionProbability.end()) + return it->second; + return 0; +} + +EAlignment CHeroClass::getAlignment() const +{ + return faction.toEntity(VLC)->getAlignment(); +} + +int32_t CHeroClass::getIndex() const +{ + return id.getNum(); +} + +int32_t CHeroClass::getIconIndex() const +{ + return getIndex(); +} + +std::string CHeroClass::getJsonKey() const +{ + return modScope + ':' + identifier; +} + +std::string CHeroClass::getModScope() const +{ + return modScope; +} + +HeroClassID CHeroClass::getId() const +{ + return id; +} + +void CHeroClass::registerIcons(const IconRegistar & cb) const +{ + +} + +std::string CHeroClass::getNameTranslated() const +{ + return VLC->generaltexth->translate(getNameTextID()); +} + +std::string CHeroClass::getNameTextID() const +{ + return TextIdentifier("heroClass", modScope, identifier, "name").get(); +} + +void CHeroClass::updateFrom(const JsonNode & data) +{ + //TODO: CHeroClass::updateFrom +} + +void CHeroClass::serializeJson(JsonSerializeFormat & handler) +{ + +} + +CHeroClass::CHeroClass(): + faction(0), + affinity(0), + defaultTavernChance(0) +{ +} + +VCMI_LIB_NAMESPACE_END diff --git a/lib/entities/hero/CHeroClass.h b/lib/entities/hero/CHeroClass.h new file mode 100644 index 000000000..0d4edc5a6 --- /dev/null +++ b/lib/entities/hero/CHeroClass.h @@ -0,0 +1,85 @@ +/* + * CHeroClass.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#pragma once + +#include + +#include "../../constants/EntityIdentifiers.h" +#include "../../constants/Enumerations.h" +#include "../../filesystem/ResourcePath.h" + +VCMI_LIB_NAMESPACE_BEGIN + +namespace vstd +{ +class RNG; +} + +class DLL_LINKAGE CHeroClass : public HeroClass +{ + friend class CHeroClassHandler; + HeroClassID id; // use getId instead + std::string modScope; + std::string identifier; // use getJsonKey instead + +public: + enum EClassAffinity + { + MIGHT, + MAGIC + }; + + //double aggression; // not used in vcmi. + FactionID faction; + ui8 affinity; // affinity, using EClassAffinity enum + + // default chance for hero of specific class to appear in tavern, if field "tavern" was not set + // resulting chance = sqrt(town.chance * heroClass.chance) + ui32 defaultTavernChance; + + CreatureID commander; + + std::vector primarySkillInitial; // initial primary skills + std::vector primarySkillLowLevel; // probability (%) of getting point of primary skill when getting level + std::vector primarySkillHighLevel; // same for high levels (> 10) + + std::map secSkillProbability; //probabilities of gaining secondary skills (out of 112), in id order + + std::map selectionProbability; //probability of selection in towns + + AnimationPath imageBattleMale; + AnimationPath imageBattleFemale; + std::string imageMapMale; + std::string imageMapFemale; + + CHeroClass(); + + int32_t getIndex() const override; + int32_t getIconIndex() const override; + std::string getJsonKey() const override; + std::string getModScope() const override; + HeroClassID getId() const override; + void registerIcons(const IconRegistar & cb) const override; + + std::string getNameTranslated() const override; + std::string getNameTextID() const override; + + bool isMagicHero() const; + SecondarySkill chooseSecSkill(const std::set & possibles, vstd::RNG & rand) const; //picks secondary skill out from given possibilities + + void updateFrom(const JsonNode & data); + void serializeJson(JsonSerializeFormat & handler); + + EAlignment getAlignment() const; + + int tavernProbability(FactionID faction) const; +}; + +VCMI_LIB_NAMESPACE_END diff --git a/lib/entities/hero/CHeroClassHandler.cpp b/lib/entities/hero/CHeroClassHandler.cpp new file mode 100644 index 000000000..e9207a229 --- /dev/null +++ b/lib/entities/hero/CHeroClassHandler.cpp @@ -0,0 +1,226 @@ +/* + * CHeroClassHandler.cpp, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#include "StdInc.h" +#include "CHeroClassHandler.h" + +#include "CHeroClass.h" + +#include "../faction/CTown.h" +#include "../faction/CTownHandler.h" + +#include "../../CSkillHandler.h" +#include "../../IGameSettings.h" +#include "../../VCMI_Lib.h" +#include "../../constants/StringConstants.h" +#include "../../json/JsonNode.h" +#include "../../mapObjectConstructors/AObjectTypeHandler.h" +#include "../../mapObjectConstructors/CObjectClassesHandler.h" +#include "../../modding/IdentifierStorage.h" +#include "../../texts/CGeneralTextHandler.h" +#include "../../texts/CLegacyConfigParser.h" + +VCMI_LIB_NAMESPACE_BEGIN + +void CHeroClassHandler::fillPrimarySkillData(const JsonNode & node, CHeroClass * heroClass, PrimarySkill pSkill) const +{ + const auto & skillName = NPrimarySkill::names[pSkill.getNum()]; + auto currentPrimarySkillValue = static_cast(node["primarySkills"][skillName].Integer()); + int primarySkillLegalMinimum = VLC->engineSettings()->getVector(EGameSettings::HEROES_MINIMAL_PRIMARY_SKILLS)[pSkill.getNum()]; + + if(currentPrimarySkillValue < primarySkillLegalMinimum) + { + logMod->error("Hero class '%s' has incorrect initial value '%d' for skill '%s'. Value '%d' will be used instead.", + heroClass->getNameTranslated(), currentPrimarySkillValue, skillName, primarySkillLegalMinimum); + currentPrimarySkillValue = primarySkillLegalMinimum; + } + heroClass->primarySkillInitial.push_back(currentPrimarySkillValue); + heroClass->primarySkillLowLevel.push_back(static_cast(node["lowLevelChance"][skillName].Float())); + heroClass->primarySkillHighLevel.push_back(static_cast(node["highLevelChance"][skillName].Float())); +} + +const std::vector & CHeroClassHandler::getTypeNames() const +{ + static const std::vector typeNames = { "heroClass" }; + return typeNames; +} + +std::shared_ptr CHeroClassHandler::loadFromJson(const std::string & scope, const JsonNode & node, const std::string & identifier, size_t index) +{ + assert(identifier.find(':') == std::string::npos); + assert(!scope.empty()); + + std::string affinityStr[2] = { "might", "magic" }; + + auto heroClass = std::make_shared(); + + heroClass->id = HeroClassID(index); + heroClass->identifier = identifier; + heroClass->modScope = scope; + heroClass->imageBattleFemale = AnimationPath::fromJson(node["animation"]["battle"]["female"]); + heroClass->imageBattleMale = AnimationPath::fromJson(node["animation"]["battle"]["male"]); + //MODS COMPATIBILITY FOR 0.96 + heroClass->imageMapFemale = node["animation"]["map"]["female"].String(); + heroClass->imageMapMale = node["animation"]["map"]["male"].String(); + + VLC->generaltexth->registerString(scope, heroClass->getNameTextID(), node["name"].String()); + + if (vstd::contains(affinityStr, node["affinity"].String())) + { + heroClass->affinity = vstd::find_pos(affinityStr, node["affinity"].String()); + } + else + { + logGlobal->error("Mod '%s', hero class '%s': invalid affinity '%s'! Expected 'might' or 'magic'!", scope, identifier, node["affinity"].String()); + heroClass->affinity = CHeroClass::MIGHT; + } + + fillPrimarySkillData(node, heroClass.get(), PrimarySkill::ATTACK); + fillPrimarySkillData(node, heroClass.get(), PrimarySkill::DEFENSE); + fillPrimarySkillData(node, heroClass.get(), PrimarySkill::SPELL_POWER); + fillPrimarySkillData(node, heroClass.get(), PrimarySkill::KNOWLEDGE); + + auto percentSumm = std::accumulate(heroClass->primarySkillLowLevel.begin(), heroClass->primarySkillLowLevel.end(), 0); + if(percentSumm <= 0) + logMod->error("Hero class %s has wrong lowLevelChance values: must be above zero!", heroClass->identifier, percentSumm); + + percentSumm = std::accumulate(heroClass->primarySkillHighLevel.begin(), heroClass->primarySkillHighLevel.end(), 0); + if(percentSumm <= 0) + logMod->error("Hero class %s has wrong highLevelChance values: must be above zero!", heroClass->identifier, percentSumm); + + for(auto skillPair : node["secondarySkills"].Struct()) + { + int probability = static_cast(skillPair.second.Integer()); + VLC->identifiers()->requestIdentifier(skillPair.second.getModScope(), "skill", skillPair.first, [heroClass, probability](si32 skillID) + { + heroClass->secSkillProbability[skillID] = probability; + }); + } + + VLC->identifiers()->requestIdentifier ("creature", node["commander"], + [=](si32 commanderID) + { + heroClass->commander = CreatureID(commanderID); + }); + + heroClass->defaultTavernChance = static_cast(node["defaultTavern"].Float()); + for(const auto & tavern : node["tavern"].Struct()) + { + int value = static_cast(tavern.second.Float()); + + VLC->identifiers()->requestIdentifier(tavern.second.getModScope(), "faction", tavern.first, + [=](si32 factionID) + { + heroClass->selectionProbability[FactionID(factionID)] = value; + }); + } + + VLC->identifiers()->requestIdentifier("faction", node["faction"], + [=](si32 factionID) + { + heroClass->faction.setNum(factionID); + }); + + VLC->identifiers()->requestIdentifier(scope, "object", "hero", [=](si32 index) + { + JsonNode classConf = node["mapObject"]; + classConf["heroClass"].String() = identifier; + if (!node["compatibilityIdentifiers"].isNull()) + classConf["compatibilityIdentifiers"] = node["compatibilityIdentifiers"]; + classConf.setModScope(scope); + VLC->objtypeh->loadSubObject(identifier, classConf, index, heroClass->getIndex()); + }); + + return heroClass; +} + +std::vector CHeroClassHandler::loadLegacyData() +{ + size_t dataSize = VLC->engineSettings()->getInteger(EGameSettings::TEXTS_HERO_CLASS); + + objects.resize(dataSize); + std::vector h3Data; + h3Data.reserve(dataSize); + + CLegacyConfigParser parser(TextPath::builtin("DATA/HCTRAITS.TXT")); + + parser.endLine(); // header + parser.endLine(); + + for (size_t i=0; i set selection probability if it was not set before in tavern entries + for(auto & heroClass : objects) + { + for(auto & faction : VLC->townh->objects) + { + if (!faction->town) + continue; + if (heroClass->selectionProbability.count(faction->getId())) + continue; + + auto chance = static_cast(heroClass->defaultTavernChance * faction->town->defaultTavernChance); + heroClass->selectionProbability[faction->getId()] = static_cast(sqrt(chance) + 0.5); //FIXME: replace with std::round once MVS supports it + } + + // set default probabilities for gaining secondary skills where not loaded previously + for(int skillID = 0; skillID < VLC->skillh->size(); skillID++) + { + if(heroClass->secSkillProbability.count(skillID) == 0) + { + const CSkill * skill = (*VLC->skillh)[SecondarySkill(skillID)]; + logMod->trace("%s: no probability for %s, using default", heroClass->identifier, skill->getJsonKey()); + heroClass->secSkillProbability[skillID] = skill->gainChance[heroClass->affinity]; + } + } + } + + for(const auto & hc : objects) + { + if(!hc->imageMapMale.empty()) + { + JsonNode templ; + templ["animation"].String() = hc->imageMapMale; + VLC->objtypeh->getHandlerFor(Obj::HERO, hc->getIndex())->addTemplate(templ); + } + } +} + +CHeroClassHandler::~CHeroClassHandler() = default; + +VCMI_LIB_NAMESPACE_END diff --git a/lib/entities/hero/CHeroClassHandler.h b/lib/entities/hero/CHeroClassHandler.h new file mode 100644 index 000000000..e04a6dbf3 --- /dev/null +++ b/lib/entities/hero/CHeroClassHandler.h @@ -0,0 +1,37 @@ +/* + * CHeroClassHandler.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#pragma once + +#include + +#include "CHeroClass.h" // convenience include - users of handler generally also use its entity + +#include "../../IHandlerBase.h" +#include "../../constants/EntityIdentifiers.h" + +VCMI_LIB_NAMESPACE_BEGIN + +class DLL_LINKAGE CHeroClassHandler : public CHandlerBase +{ + void fillPrimarySkillData(const JsonNode & node, CHeroClass * heroClass, PrimarySkill pSkill) const; + +public: + std::vector loadLegacyData() override; + + void afterLoadFinalization() override; + + ~CHeroClassHandler(); + +protected: + const std::vector & getTypeNames() const override; + std::shared_ptr loadFromJson(const std::string & scope, const JsonNode & node, const std::string & identifier, size_t index) override; +}; + +VCMI_LIB_NAMESPACE_END diff --git a/lib/CHeroHandler.cpp b/lib/entities/hero/CHeroHandler.cpp similarity index 50% rename from lib/CHeroHandler.cpp rename to lib/entities/hero/CHeroHandler.cpp index 820f8404d..8b05df0eb 100644 --- a/lib/CHeroHandler.cpp +++ b/lib/entities/hero/CHeroHandler.cpp @@ -10,427 +10,22 @@ #include "StdInc.h" #include "CHeroHandler.h" -#include "filesystem/Filesystem.h" -#include "VCMI_Lib.h" -#include "constants/StringConstants.h" -#include "battle/BattleHex.h" -#include "CCreatureHandler.h" -#include "IGameSettings.h" -#include "CSkillHandler.h" -#include "BattleFieldHandler.h" -#include "bonuses/Limiters.h" -#include "bonuses/Updaters.h" -#include "entities/faction/CFaction.h" -#include "entities/faction/CTown.h" -#include "entities/faction/CTownHandler.h" -#include "json/JsonBonus.h" -#include "json/JsonUtils.h" -#include "mapObjectConstructors/AObjectTypeHandler.h" -#include "mapObjectConstructors/CObjectClassesHandler.h" -#include "modding/IdentifierStorage.h" -#include "texts/CGeneralTextHandler.h" -#include "texts/CLegacyConfigParser.h" +#include "CHero.h" -#include +#include "../../VCMI_Lib.h" +#include "../../constants/StringConstants.h" +#include "../../CCreatureHandler.h" +#include "../../IGameSettings.h" +#include "../../bonuses/Limiters.h" +#include "../../bonuses/Updaters.h" +#include "../../json/JsonBonus.h" +#include "../../json/JsonUtils.h" +#include "../../modding/IdentifierStorage.h" +#include "../../texts/CGeneralTextHandler.h" +#include "../../texts/CLegacyConfigParser.h" VCMI_LIB_NAMESPACE_BEGIN -CHero::CHero() = default; -CHero::~CHero() = default; - -int32_t CHero::getIndex() const -{ - return ID.getNum(); -} - -int32_t CHero::getIconIndex() const -{ - return imageIndex; -} - -std::string CHero::getJsonKey() const -{ - return modScope + ':' + identifier; -} - -std::string CHero::getModScope() const -{ - return modScope; -} - -HeroTypeID CHero::getId() const -{ - return ID; -} - -std::string CHero::getNameTranslated() const -{ - return VLC->generaltexth->translate(getNameTextID()); -} - -std::string CHero::getBiographyTranslated() const -{ - return VLC->generaltexth->translate(getBiographyTextID()); -} - -std::string CHero::getSpecialtyNameTranslated() const -{ - return VLC->generaltexth->translate(getSpecialtyNameTextID()); -} - -std::string CHero::getSpecialtyDescriptionTranslated() const -{ - return VLC->generaltexth->translate(getSpecialtyDescriptionTextID()); -} - -std::string CHero::getSpecialtyTooltipTranslated() const -{ - return VLC->generaltexth->translate(getSpecialtyTooltipTextID()); -} - -std::string CHero::getNameTextID() const -{ - return TextIdentifier("hero", modScope, identifier, "name").get(); -} - -std::string CHero::getBiographyTextID() const -{ - return TextIdentifier("hero", modScope, identifier, "biography").get(); -} - -std::string CHero::getSpecialtyNameTextID() const -{ - return TextIdentifier("hero", modScope, identifier, "specialty", "name").get(); -} - -std::string CHero::getSpecialtyDescriptionTextID() const -{ - return TextIdentifier("hero", modScope, identifier, "specialty", "description").get(); -} - -std::string CHero::getSpecialtyTooltipTextID() const -{ - return TextIdentifier("hero", modScope, identifier, "specialty", "tooltip").get(); -} - -void CHero::registerIcons(const IconRegistar & cb) const -{ - cb(getIconIndex(), 0, "UN32", iconSpecSmall); - cb(getIconIndex(), 0, "UN44", iconSpecLarge); - cb(getIconIndex(), 0, "PORTRAITSLARGE", portraitLarge); - cb(getIconIndex(), 0, "PORTRAITSSMALL", portraitSmall); -} - -void CHero::updateFrom(const JsonNode & data) -{ - //todo: CHero::updateFrom -} - -void CHero::serializeJson(JsonSerializeFormat & handler) -{ - -} - - -SecondarySkill CHeroClass::chooseSecSkill(const std::set & possibles, vstd::RNG & rand) const //picks secondary skill out from given possibilities -{ - assert(!possibles.empty()); - - if (possibles.size() == 1) - return *possibles.begin(); - - int totalProb = 0; - for(const auto & possible : possibles) - if (secSkillProbability.count(possible) != 0) - totalProb += secSkillProbability.at(possible); - - if (totalProb == 0) // may trigger if set contains only banned skills (0 probability) - return *RandomGeneratorUtil::nextItem(possibles, rand); - - auto ran = rand.nextInt(totalProb - 1); - for(const auto & possible : possibles) - { - if (secSkillProbability.count(possible) != 0) - ran -= secSkillProbability.at(possible); - - if(ran < 0) - return possible; - } - - assert(0); // should not be possible - return *possibles.begin(); -} - -bool CHeroClass::isMagicHero() const -{ - return affinity == MAGIC; -} - -int CHeroClass::tavernProbability(FactionID targetFaction) const -{ - auto it = selectionProbability.find(targetFaction); - if (it != selectionProbability.end()) - return it->second; - return 0; -} - -EAlignment CHeroClass::getAlignment() const -{ - return VLC->factions()->getById(faction)->getAlignment(); -} - -int32_t CHeroClass::getIndex() const -{ - return id.getNum(); -} - -int32_t CHeroClass::getIconIndex() const -{ - return getIndex(); -} - -std::string CHeroClass::getJsonKey() const -{ - return modScope + ':' + identifier; -} - -std::string CHeroClass::getModScope() const -{ - return modScope; -} - -HeroClassID CHeroClass::getId() const -{ - return id; -} - -void CHeroClass::registerIcons(const IconRegistar & cb) const -{ - -} - -std::string CHeroClass::getNameTranslated() const -{ - return VLC->generaltexth->translate(getNameTextID()); -} - -std::string CHeroClass::getNameTextID() const -{ - return TextIdentifier("heroClass", modScope, identifier, "name").get(); -} - -void CHeroClass::updateFrom(const JsonNode & data) -{ - //TODO: CHeroClass::updateFrom -} - -void CHeroClass::serializeJson(JsonSerializeFormat & handler) -{ - -} - -CHeroClass::CHeroClass(): - faction(0), - affinity(0), - defaultTavernChance(0) -{ -} - -void CHeroClassHandler::fillPrimarySkillData(const JsonNode & node, CHeroClass * heroClass, PrimarySkill pSkill) const -{ - const auto & skillName = NPrimarySkill::names[pSkill.getNum()]; - auto currentPrimarySkillValue = static_cast(node["primarySkills"][skillName].Integer()); - int primarySkillLegalMinimum = VLC->engineSettings()->getVector(EGameSettings::HEROES_MINIMAL_PRIMARY_SKILLS)[pSkill.getNum()]; - - if(currentPrimarySkillValue < primarySkillLegalMinimum) - { - logMod->error("Hero class '%s' has incorrect initial value '%d' for skill '%s'. Value '%d' will be used instead.", - heroClass->getNameTranslated(), currentPrimarySkillValue, skillName, primarySkillLegalMinimum); - currentPrimarySkillValue = primarySkillLegalMinimum; - } - heroClass->primarySkillInitial.push_back(currentPrimarySkillValue); - heroClass->primarySkillLowLevel.push_back(static_cast(node["lowLevelChance"][skillName].Float())); - heroClass->primarySkillHighLevel.push_back(static_cast(node["highLevelChance"][skillName].Float())); -} - -const std::vector & CHeroClassHandler::getTypeNames() const -{ - static const std::vector typeNames = { "heroClass" }; - return typeNames; -} - -std::shared_ptr CHeroClassHandler::loadFromJson(const std::string & scope, const JsonNode & node, const std::string & identifier, size_t index) -{ - assert(identifier.find(':') == std::string::npos); - assert(!scope.empty()); - - std::string affinityStr[2] = { "might", "magic" }; - - auto heroClass = std::make_shared(); - - heroClass->id = HeroClassID(index); - heroClass->identifier = identifier; - heroClass->modScope = scope; - heroClass->imageBattleFemale = AnimationPath::fromJson(node["animation"]["battle"]["female"]); - heroClass->imageBattleMale = AnimationPath::fromJson(node["animation"]["battle"]["male"]); - //MODS COMPATIBILITY FOR 0.96 - heroClass->imageMapFemale = node["animation"]["map"]["female"].String(); - heroClass->imageMapMale = node["animation"]["map"]["male"].String(); - - VLC->generaltexth->registerString(scope, heroClass->getNameTextID(), node["name"].String()); - - if (vstd::contains(affinityStr, node["affinity"].String())) - { - heroClass->affinity = vstd::find_pos(affinityStr, node["affinity"].String()); - } - else - { - logGlobal->error("Mod '%s', hero class '%s': invalid affinity '%s'! Expected 'might' or 'magic'!", scope, identifier, node["affinity"].String()); - heroClass->affinity = CHeroClass::MIGHT; - } - - fillPrimarySkillData(node, heroClass.get(), PrimarySkill::ATTACK); - fillPrimarySkillData(node, heroClass.get(), PrimarySkill::DEFENSE); - fillPrimarySkillData(node, heroClass.get(), PrimarySkill::SPELL_POWER); - fillPrimarySkillData(node, heroClass.get(), PrimarySkill::KNOWLEDGE); - - auto percentSumm = std::accumulate(heroClass->primarySkillLowLevel.begin(), heroClass->primarySkillLowLevel.end(), 0); - if(percentSumm <= 0) - logMod->error("Hero class %s has wrong lowLevelChance values: must be above zero!", heroClass->identifier, percentSumm); - - percentSumm = std::accumulate(heroClass->primarySkillHighLevel.begin(), heroClass->primarySkillHighLevel.end(), 0); - if(percentSumm <= 0) - logMod->error("Hero class %s has wrong highLevelChance values: must be above zero!", heroClass->identifier, percentSumm); - - for(auto skillPair : node["secondarySkills"].Struct()) - { - int probability = static_cast(skillPair.second.Integer()); - VLC->identifiers()->requestIdentifier(skillPair.second.getModScope(), "skill", skillPair.first, [heroClass, probability](si32 skillID) - { - heroClass->secSkillProbability[skillID] = probability; - }); - } - - VLC->identifiers()->requestIdentifier ("creature", node["commander"], - [=](si32 commanderID) - { - heroClass->commander = CreatureID(commanderID); - }); - - heroClass->defaultTavernChance = static_cast(node["defaultTavern"].Float()); - for(const auto & tavern : node["tavern"].Struct()) - { - int value = static_cast(tavern.second.Float()); - - VLC->identifiers()->requestIdentifier(tavern.second.getModScope(), "faction", tavern.first, - [=](si32 factionID) - { - heroClass->selectionProbability[FactionID(factionID)] = value; - }); - } - - VLC->identifiers()->requestIdentifier("faction", node["faction"], - [=](si32 factionID) - { - heroClass->faction.setNum(factionID); - }); - - VLC->identifiers()->requestIdentifier(scope, "object", "hero", [=](si32 index) - { - JsonNode classConf = node["mapObject"]; - classConf["heroClass"].String() = identifier; - if (!node["compatibilityIdentifiers"].isNull()) - classConf["compatibilityIdentifiers"] = node["compatibilityIdentifiers"]; - classConf.setModScope(scope); - VLC->objtypeh->loadSubObject(identifier, classConf, index, heroClass->getIndex()); - }); - - return heroClass; -} - -std::vector CHeroClassHandler::loadLegacyData() -{ - size_t dataSize = VLC->engineSettings()->getInteger(EGameSettings::TEXTS_HERO_CLASS); - - objects.resize(dataSize); - std::vector h3Data; - h3Data.reserve(dataSize); - - CLegacyConfigParser parser(TextPath::builtin("DATA/HCTRAITS.TXT")); - - parser.endLine(); // header - parser.endLine(); - - for (size_t i=0; i set selection probability if it was not set before in tavern entries - for(auto & heroClass : objects) - { - for(auto & faction : VLC->townh->objects) - { - if (!faction->town) - continue; - if (heroClass->selectionProbability.count(faction->getId())) - continue; - - auto chance = static_cast(heroClass->defaultTavernChance * faction->town->defaultTavernChance); - heroClass->selectionProbability[faction->getId()] = static_cast(sqrt(chance) + 0.5); //FIXME: replace with std::round once MVS supports it - } - - // set default probabilities for gaining secondary skills where not loaded previously - for(int skillID = 0; skillID < VLC->skillh->size(); skillID++) - { - if(heroClass->secSkillProbability.count(skillID) == 0) - { - const CSkill * skill = (*VLC->skillh)[SecondarySkill(skillID)]; - logMod->trace("%s: no probability for %s, using default", heroClass->identifier, skill->getJsonKey()); - heroClass->secSkillProbability[skillID] = skill->gainChance[heroClass->affinity]; - } - } - } - - for(const auto & hc : objects) - { - if(!hc->imageMapMale.empty()) - { - JsonNode templ; - templ["animation"].String() = hc->imageMapMale; - VLC->objtypeh->getHandlerFor(Obj::HERO, hc->getIndex())->addTemplate(templ); - } - } -} - -CHeroClassHandler::~CHeroClassHandler() = default; - CHeroHandler::~CHeroHandler() = default; CHeroHandler::CHeroHandler() diff --git a/lib/entities/hero/CHeroHandler.h b/lib/entities/hero/CHeroHandler.h new file mode 100644 index 000000000..d62911599 --- /dev/null +++ b/lib/entities/hero/CHeroHandler.h @@ -0,0 +1,59 @@ +/* + * CHeroHandler.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#pragma once + +#include + +#include "CHero.h" // convenience include - users of handler generally also use its entity + + +#include "../../GameConstants.h" +#include "../../IHandlerBase.h" + +VCMI_LIB_NAMESPACE_BEGIN + +class DLL_LINKAGE CHeroHandler : public CHandlerBase +{ + /// expPerLEvel[i] is amount of exp needed to reach level i; + /// consists of 196 values. Any higher levels require experience larger that TExpType can hold + std::vector expPerLevel; + + /// helpers for loading to avoid huge load functions + void loadHeroArmy(CHero * hero, const JsonNode & node) const; + void loadHeroSkills(CHero * hero, const JsonNode & node) const; + void loadHeroSpecialty(CHero * hero, const JsonNode & node); + + void loadExperience(); + + std::vector> callAfterLoadFinalization; + +public: + ui32 level(TExpType experience) const; //calculates level corresponding to given experience amount + TExpType reqExp(ui32 level) const; //calculates experience required for given level + ui32 maxSupportedLevel() const; + + std::vector loadLegacyData() override; + + void beforeValidate(JsonNode & object) override; + void loadObject(std::string scope, std::string name, const JsonNode & data) override; + void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override; + void afterLoadFinalization() override; + + CHeroHandler(); + ~CHeroHandler(); + + std::set getDefaultAllowed() const; + +protected: + const std::vector & getTypeNames() const override; + std::shared_ptr loadFromJson(const std::string & scope, const JsonNode & node, const std::string & identifier, size_t index) override; +}; + +VCMI_LIB_NAMESPACE_END diff --git a/lib/entities/hero/EHeroGender.h b/lib/entities/hero/EHeroGender.h new file mode 100644 index 000000000..2b9dfb61f --- /dev/null +++ b/lib/entities/hero/EHeroGender.h @@ -0,0 +1,21 @@ +/* + * EHeroGender.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ +#pragma once + +VCMI_LIB_NAMESPACE_BEGIN + + enum class EHeroGender : int8_t +{ + DEFAULT = -1, // from h3m, instance has same gender as hero type + MALE = 0, + FEMALE = 1, +}; + +VCMI_LIB_NAMESPACE_END diff --git a/lib/gameState/CGameState.cpp b/lib/gameState/CGameState.cpp index 7bba1770d..1ef3d9a12 100644 --- a/lib/gameState/CGameState.cpp +++ b/lib/gameState/CGameState.cpp @@ -18,7 +18,6 @@ #include "../ArtifactUtils.h" #include "../texts/CGeneralTextHandler.h" -#include "../CHeroHandler.h" #include "../CPlayerState.h" #include "../CStopWatch.h" #include "../IGameSettings.h" @@ -30,6 +29,8 @@ #include "../campaign/CampaignState.h" #include "../constants/StringConstants.h" #include "../entities/faction/CTownHandler.h" +#include "../entities/hero/CHero.h" +#include "../entities/hero/CHeroClass.h" #include "../filesystem/ResourcePath.h" #include "../json/JsonBonus.h" #include "../json/JsonUtils.h" diff --git a/lib/gameState/CGameStateCampaign.cpp b/lib/gameState/CGameStateCampaign.cpp index 2178da654..0416a8507 100644 --- a/lib/gameState/CGameStateCampaign.cpp +++ b/lib/gameState/CGameStateCampaign.cpp @@ -16,6 +16,8 @@ #include "../campaign/CampaignState.h" #include "../entities/building/CBuilding.h" #include "../entities/building/CBuildingHandler.h" +#include "../entities/hero/CHeroClass.h" +#include "../entities/hero/CHero.h" #include "../mapping/CMapEditManager.h" #include "../mapObjects/CGHeroInstance.h" #include "../mapObjects/CGTownInstance.h" @@ -23,13 +25,13 @@ #include "../mapObjectConstructors/AObjectTypeHandler.h" #include "../mapObjectConstructors/CObjectClassesHandler.h" #include "../StartInfo.h" -#include "../CHeroHandler.h" #include "../mapping/CMap.h" #include "../ArtifactUtils.h" #include "../CPlayerState.h" #include "../serializer/CMemorySerializer.h" #include +#include VCMI_LIB_NAMESPACE_BEGIN @@ -370,7 +372,7 @@ void CGameStateCampaign::replaceHeroesPlaceholders() heroToPlace->tempOwner = heroPlaceholder->tempOwner; heroToPlace->setAnchorPos(heroPlaceholder->anchorPos()); heroToPlace->setHeroType(heroToPlace->getHeroTypeID()); - heroToPlace->appearance = VLC->objtypeh->getHandlerFor(Obj::HERO, heroToPlace->getHeroTypeID())->getTemplates().front(); + heroToPlace->appearance = heroToPlace->getObjectHandler()->getTemplates().front(); gameState->map->removeBlockVisTiles(heroPlaceholder, true); gameState->map->objects[heroPlaceholder->id.getNum()] = nullptr; diff --git a/lib/gameState/GameStatistics.cpp b/lib/gameState/GameStatistics.cpp index 6e1c95e85..a6ee5041c 100644 --- a/lib/gameState/GameStatistics.cpp +++ b/lib/gameState/GameStatistics.cpp @@ -14,7 +14,6 @@ #include "../VCMIDirs.h" #include "CGameState.h" #include "TerrainHandler.h" -#include "CHeroHandler.h" #include "StartInfo.h" #include "HighScore.h" #include "../mapObjects/CGHeroInstance.h" diff --git a/lib/gameState/InfoAboutArmy.cpp b/lib/gameState/InfoAboutArmy.cpp index cb6ad5e95..54e8528a8 100644 --- a/lib/gameState/InfoAboutArmy.cpp +++ b/lib/gameState/InfoAboutArmy.cpp @@ -12,7 +12,9 @@ #include "../mapObjects/CGHeroInstance.h" #include "../mapObjects/CGTownInstance.h" -#include "../CHeroHandler.h" + +#include +#include VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/gameState/TavernHeroesPool.cpp b/lib/gameState/TavernHeroesPool.cpp index 44d085c13..3c0dfadbf 100644 --- a/lib/gameState/TavernHeroesPool.cpp +++ b/lib/gameState/TavernHeroesPool.cpp @@ -11,7 +11,6 @@ #include "TavernHeroesPool.h" #include "../mapObjects/CGHeroInstance.h" -#include "../CHeroHandler.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/json/JsonRandom.cpp b/lib/json/JsonRandom.cpp index 57f7a97a2..bfc65fa9d 100644 --- a/lib/json/JsonRandom.cpp +++ b/lib/json/JsonRandom.cpp @@ -13,6 +13,8 @@ #include #include +#include +#include #include "JsonBonus.h" @@ -23,8 +25,9 @@ #include "../CCreatureSet.h" #include "../spells/CSpellHandler.h" #include "../CSkillHandler.h" -#include "../CHeroHandler.h" #include "../IGameCallback.h" +#include "../entities/hero/CHero.h" +#include "../entities/hero/CHeroClass.h" #include "../gameState/CGameState.h" #include "../mapObjects/IObjectInterface.h" #include "../modding/IdentifierStorage.h" diff --git a/lib/json/JsonValidator.cpp b/lib/json/JsonValidator.cpp index 0114f113d..3cb89846f 100644 --- a/lib/json/JsonValidator.cpp +++ b/lib/json/JsonValidator.cpp @@ -74,7 +74,7 @@ static int getLevenshteinDistance(const std::string & s, const std::string & t) /// Searches for keys similar to 'target' in 'candidates' map /// Returns closest match or empty string if no suitable candidates are found -static std::string findClosestMatch(JsonMap candidates, std::string target) +static std::string findClosestMatch(const JsonMap & candidates, const std::string & target) { // Maximum distance at which we can consider strings to be similar // If strings have more different symbols than this number then it is not a typo, but a completely different word diff --git a/lib/mapObjectConstructors/AObjectTypeHandler.cpp b/lib/mapObjectConstructors/AObjectTypeHandler.cpp index c431900aa..d842d9953 100644 --- a/lib/mapObjectConstructors/AObjectTypeHandler.cpp +++ b/lib/mapObjectConstructors/AObjectTypeHandler.cpp @@ -133,8 +133,6 @@ void AObjectTypeHandler::preInitObject(CGObjectInstance * obj) const { obj->ID = Obj(type); obj->subID = subtype; - obj->typeName = typeName; - obj->subTypeName = getJsonKey(); obj->blockVisit = blockVisit; obj->removable = removable; } diff --git a/lib/mapObjectConstructors/CObjectClassesHandler.cpp b/lib/mapObjectConstructors/CObjectClassesHandler.cpp index f8939be58..202372cf9 100644 --- a/lib/mapObjectConstructors/CObjectClassesHandler.cpp +++ b/lib/mapObjectConstructors/CObjectClassesHandler.cpp @@ -358,7 +358,7 @@ TObjectTypeHandler CObjectClassesHandler::getHandlerFor(MapObjectID type, MapObj return mapObjectTypes.front()->objectTypeHandlers.front(); auto subID = subtype.getNum(); - if (type == Obj::PRISON || type == Obj::HERO_PLACEHOLDER) + if (type == Obj::PRISON || type == Obj::HERO_PLACEHOLDER || type == Obj::SPELL_SCROLL) subID = 0; auto result = mapObjectTypes.at(type.getNum())->objectTypeHandlers.at(subID); diff --git a/lib/mapObjectConstructors/CommonConstructors.cpp b/lib/mapObjectConstructors/CommonConstructors.cpp index 421d2565f..b8194937c 100644 --- a/lib/mapObjectConstructors/CommonConstructors.cpp +++ b/lib/mapObjectConstructors/CommonConstructors.cpp @@ -11,7 +11,6 @@ #include "CommonConstructors.h" #include "../texts/CGeneralTextHandler.h" -#include "../CHeroHandler.h" #include "../IGameCallback.h" #include "../json/JsonRandom.h" #include "../constants/StringConstants.h" @@ -19,6 +18,7 @@ #include "../VCMI_Lib.h" #include "../entities/faction/CTownHandler.h" +#include "../entities/hero/CHeroClass.h" #include "../mapObjects/CGHeroInstance.h" #include "../mapObjects/CGMarket.h" #include "../mapObjects/CGTownInstance.h" diff --git a/lib/mapObjects/CGHeroInstance.cpp b/lib/mapObjects/CGHeroInstance.cpp index 37b7c5334..b14e727de 100644 --- a/lib/mapObjects/CGHeroInstance.cpp +++ b/lib/mapObjects/CGHeroInstance.cpp @@ -17,7 +17,6 @@ #include "../texts/CGeneralTextHandler.h" #include "../ArtifactUtils.h" -#include "../CHeroHandler.h" #include "../TerrainHandler.h" #include "../RoadHandler.h" #include "../IGameSettings.h" @@ -31,6 +30,8 @@ #include "../StartInfo.h" #include "CGTownInstance.h" #include "../entities/faction/CTownHandler.h" +#include "../entities/hero/CHeroHandler.h" +#include "../entities/hero/CHeroClass.h" #include "../battle/CBattleInfoEssentials.h" #include "../campaign/CampaignState.h" #include "../json/JsonBonus.h" @@ -339,12 +340,20 @@ void CGHeroInstance::initHero(vstd::RNG & rand, const HeroTypeID & SUBID) initHero(rand); } +TObjectTypeHandler CGHeroInstance::getObjectHandler() const +{ + if (ID == Obj::HERO) + return VLC->objtypeh->getHandlerFor(ID, getHeroClass()->getIndex()); + else // prison or random hero + return VLC->objtypeh->getHandlerFor(ID, 0); +} + void CGHeroInstance::initHero(vstd::RNG & rand) { assert(validTypes(true)); if (ID == Obj::HERO) - appearance = VLC->objtypeh->getHandlerFor(Obj::HERO, getHeroClass()->getIndex())->getTemplates().front(); + appearance = getObjectHandler()->getTemplates().front(); if(!vstd::contains(spells, SpellID::PRESET)) { diff --git a/lib/mapObjects/CGHeroInstance.h b/lib/mapObjects/CGHeroInstance.h index b127eb508..960bc89fa 100644 --- a/lib/mapObjects/CGHeroInstance.h +++ b/lib/mapObjects/CGHeroInstance.h @@ -14,6 +14,7 @@ #include "CArmedInstance.h" #include "IOwnableObject.h" +#include "../entities/hero/EHeroGender.h" #include "../CArtHandler.h" // For CArtifactSet VCMI_LIB_NAMESPACE_BEGIN @@ -24,7 +25,6 @@ class CGTownInstance; class CMap; struct TerrainTile; struct TurnInfo; -enum class EHeroGender : int8_t; class DLL_LINKAGE CGHeroPlaceholder : public CGObjectInstance { @@ -309,6 +309,8 @@ public: std::string getHoverText(PlayerColor player) const override; std::string getMovementPointsTextIfOwner(PlayerColor player) const; + TObjectTypeHandler getObjectHandler() const override; + void afterAddToMap(CMap * map) override; void afterRemoveFromMap(CMap * map) override; diff --git a/lib/mapObjects/CGObjectInstance.cpp b/lib/mapObjects/CGObjectInstance.cpp index aa902a452..7d53bfbb9 100644 --- a/lib/mapObjects/CGObjectInstance.cpp +++ b/lib/mapObjects/CGObjectInstance.cpp @@ -192,6 +192,16 @@ TObjectTypeHandler CGObjectInstance::getObjectHandler() const return VLC->objtypeh->getHandlerFor(ID, subID); } +std::string CGObjectInstance::getTypeName() const +{ + return getObjectHandler()->getTypeName(); +} + +std::string CGObjectInstance::getSubtypeName() const +{ + return getObjectHandler()->getSubTypeName(); +} + void CGObjectInstance::setPropertyDer( ObjProperty what, ObjPropertyID identifier ) {} @@ -350,8 +360,11 @@ void CGObjectInstance::serializeJson(JsonSerializeFormat & handler) //only save here, loading is handled by map loader if(handler.saving) { - handler.serializeString("type", typeName); - handler.serializeString("subtype", subTypeName); + std::string ourTypeName = getTypeName(); + std::string ourSubtypeName = getSubtypeName(); + + handler.serializeString("type", ourTypeName); + handler.serializeString("subtype", ourSubtypeName); handler.serializeInt("x", pos.x); handler.serializeInt("y", pos.y); diff --git a/lib/mapObjects/CGObjectInstance.h b/lib/mapObjects/CGObjectInstance.h index b5fdd7142..c201dd4db 100644 --- a/lib/mapObjects/CGObjectInstance.h +++ b/lib/mapObjects/CGObjectInstance.h @@ -43,8 +43,6 @@ public: int3 pos; std::string instanceName; - std::string typeName; - std::string subTypeName; CGObjectInstance(IGameCallback *cb); ~CGObjectInstance() override; @@ -52,6 +50,9 @@ public: MapObjectID getObjGroupIndex() const override; MapObjectSubID getObjTypeIndex() const override; + std::string getTypeName() const; + std::string getSubtypeName() const; + /// "center" tile from which the sight distance is calculated int3 getSightCenter() const; /// If true hero can visit this object only from neighbouring tiles and can't stand on this object @@ -100,7 +101,7 @@ public: std::optional getVisitSound(vstd::RNG & rng) const; std::optional getRemovalSound(vstd::RNG & rng) const; - TObjectTypeHandler getObjectHandler() const; + virtual TObjectTypeHandler getObjectHandler() const; /** VIRTUAL METHODS **/ @@ -142,8 +143,12 @@ public: template void serialize(Handler &h) { h & instanceName; - h & typeName; - h & subTypeName; + if (h.version < Handler::Version::REMOVE_OBJECT_TYPENAME) + { + std::string unused; + h & unused; + h & unused; + } h & pos; h & ID; subID.serializeIdentifier(h, ID); diff --git a/lib/mapObjects/CQuest.cpp b/lib/mapObjects/CQuest.cpp index 051349282..1cc466324 100644 --- a/lib/mapObjects/CQuest.cpp +++ b/lib/mapObjects/CQuest.cpp @@ -16,9 +16,9 @@ #include "../ArtifactUtils.h" #include "../CSoundBase.h" #include "../texts/CGeneralTextHandler.h" -#include "../CHeroHandler.h" #include "CGCreature.h" #include "../IGameCallback.h" +#include "../entities/hero/CHeroHandler.h" #include "../mapObjectConstructors/CObjectClassesHandler.h" #include "../serializer/JsonSerializeFormat.h" #include "../GameConstants.h" diff --git a/lib/mapping/CMap.cpp b/lib/mapping/CMap.cpp index 57e3a4c24..18f266758 100644 --- a/lib/mapping/CMap.cpp +++ b/lib/mapping/CMap.cpp @@ -13,11 +13,11 @@ #include "../CArtHandler.h" #include "../VCMI_Lib.h" #include "../CCreatureHandler.h" -#include "../CHeroHandler.h" #include "../GameSettings.h" #include "../RiverHandler.h" #include "../RoadHandler.h" #include "../TerrainHandler.h" +#include "../entities/hero/CHeroHandler.h" #include "../mapObjects/CGHeroInstance.h" #include "../mapObjects/CGTownInstance.h" #include "../mapObjects/CQuest.h" @@ -608,7 +608,7 @@ void CMap::setUniqueInstanceName(CGObjectInstance * obj) auto uid = uidCounter++; boost::format fmt("%s_%d"); - fmt % obj->typeName % uid; + fmt % obj->getTypeName() % uid; obj->instanceName = fmt.str(); } diff --git a/lib/mapping/CMapHeader.cpp b/lib/mapping/CMapHeader.cpp index ec9c74df8..66ed48dbd 100644 --- a/lib/mapping/CMapHeader.cpp +++ b/lib/mapping/CMapHeader.cpp @@ -12,9 +12,9 @@ #include "MapFormat.h" -#include "../CHeroHandler.h" #include "../VCMI_Lib.h" #include "../entities/faction/CTownHandler.h" +#include "../entities/hero/CHeroHandler.h" #include "../json/JsonUtils.h" #include "../modding/CModHandler.h" #include "../texts/CGeneralTextHandler.h" diff --git a/lib/mapping/CMapInfo.cpp b/lib/mapping/CMapInfo.cpp index 74ee2cd44..a13084ac9 100644 --- a/lib/mapping/CMapInfo.cpp +++ b/lib/mapping/CMapInfo.cpp @@ -25,7 +25,6 @@ #include "../texts/TextOperations.h" #include "../CCreatureHandler.h" #include "../IGameSettings.h" -#include "../CHeroHandler.h" #include "../CConfigHandler.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/mapping/MapFormatH3M.cpp b/lib/mapping/MapFormatH3M.cpp index 1fe7da29f..16e02db92 100644 --- a/lib/mapping/MapFormatH3M.cpp +++ b/lib/mapping/MapFormatH3M.cpp @@ -18,7 +18,6 @@ #include "../ArtifactUtils.h" #include "../CCreatureHandler.h" #include "../texts/CGeneralTextHandler.h" -#include "../CHeroHandler.h" #include "../CSkillHandler.h" #include "../CStopWatch.h" #include "../IGameSettings.h" @@ -27,6 +26,7 @@ #include "../TerrainHandler.h" #include "../VCMI_Lib.h" #include "../constants/StringConstants.h" +#include "../entities/hero/CHeroHandler.h" #include "../filesystem/CBinaryReader.h" #include "../filesystem/Filesystem.h" #include "../mapObjectConstructors/AObjectTypeHandler.h" diff --git a/lib/mapping/MapFormatJson.cpp b/lib/mapping/MapFormatJson.cpp index 0777defed..efbce4560 100644 --- a/lib/mapping/MapFormatJson.cpp +++ b/lib/mapping/MapFormatJson.cpp @@ -17,12 +17,12 @@ #include "CMap.h" #include "MapFormat.h" #include "../ArtifactUtils.h" -#include "../CHeroHandler.h" #include "../VCMI_Lib.h" #include "../RiverHandler.h" #include "../RoadHandler.h" #include "../TerrainHandler.h" #include "../entities/faction/CTownHandler.h" +#include "../entities/hero/CHeroHandler.h" #include "../mapObjectConstructors/AObjectTypeHandler.h" #include "../mapObjectConstructors/CObjectClassesHandler.h" #include "../mapObjects/ObjectTemplate.h" diff --git a/lib/mapping/MapIdentifiersH3M.cpp b/lib/mapping/MapIdentifiersH3M.cpp index 3e093227b..e75e58235 100644 --- a/lib/mapping/MapIdentifiersH3M.cpp +++ b/lib/mapping/MapIdentifiersH3M.cpp @@ -12,7 +12,6 @@ #include "MapIdentifiersH3M.h" #include "../VCMI_Lib.h" -#include "../CHeroHandler.h" #include "../entities/faction/CFaction.h" #include "../entities/faction/CTownHandler.h" #include "../filesystem/Filesystem.h" diff --git a/lib/modding/ContentTypeHandler.cpp b/lib/modding/ContentTypeHandler.cpp index 0a9acb0f4..c5f85add0 100644 --- a/lib/modding/ContentTypeHandler.cpp +++ b/lib/modding/ContentTypeHandler.cpp @@ -19,8 +19,9 @@ #include "../CCreatureHandler.h" #include "../CConfigHandler.h" #include "../entities/faction/CTownHandler.h" +#include "../entities/hero/CHeroClassHandler.h" +#include "../entities/hero/CHeroHandler.h" #include "../texts/CGeneralTextHandler.h" -#include "../CHeroHandler.h" #include "../CSkillHandler.h" #include "../CStopWatch.h" #include "../IGameSettings.h" @@ -197,8 +198,8 @@ void ContentTypeHandler::afterLoadFinalization() std::set conflictingMods; std::set resolvedConflicts; - for (auto const & conflictModData : conflictModData.Struct()) - conflictingMods.insert(conflictModData.first); + for (auto const & conflictModEntry: conflictModData.Struct()) + conflictingMods.insert(conflictModEntry.first); for (auto const & modID : conflictingMods) resolvedConflicts.merge(VLC->modh->getModDependencies(modID)); diff --git a/lib/networkPacks/NetPacksLib.cpp b/lib/networkPacks/NetPacksLib.cpp index 6ea83ab8f..225fe9365 100644 --- a/lib/networkPacks/NetPacksLib.cpp +++ b/lib/networkPacks/NetPacksLib.cpp @@ -20,7 +20,6 @@ #include "NetPackVisitor.h" #include "texts/CGeneralTextHandler.h" #include "CArtHandler.h" -#include "CHeroHandler.h" #include "VCMI_Lib.h" #include "mapping/CMap.h" #include "spells/CSpellHandler.h" @@ -1806,6 +1805,7 @@ void AssembledArtifact::applyGs(CGameState *gs) assert(hero); const auto transformedArt = hero->getArt(al.slot); assert(transformedArt); + const auto builtArt = artId.toArtifact(); assert(vstd::contains_if(ArtifactUtils::assemblyPossibilities(hero, transformedArt->getTypeId()), [=](const CArtifact * art)->bool { return art->getId() == builtArt->getId(); @@ -1817,14 +1817,11 @@ void AssembledArtifact::applyGs(CGameState *gs) // Find slots for all involved artifacts std::vector slotsInvolved; + CArtifactFittingSet artSet(*hero); for(const auto constituent : builtArt->getConstituents()) { - ArtifactPosition slot; - if(transformedArt->getTypeId() == constituent->getId()) - slot = transformedArtSlot; - else - slot = hero->getArtPos(constituent->getId(), false, false); - + const auto slot = artSet.getArtPos(constituent->getId(), false, false); + artSet.lockSlot(slot); assert(slot != ArtifactPosition::PRE_FIRST); slotsInvolved.emplace_back(slot); } @@ -1832,7 +1829,7 @@ void AssembledArtifact::applyGs(CGameState *gs) // Find a slot for combined artifact al.slot = transformedArtSlot; - for(const auto slot : slotsInvolved) + for(const auto & slot : slotsInvolved) { if(ArtifactUtils::isSlotEquipment(transformedArtSlot)) { @@ -1855,15 +1852,18 @@ void AssembledArtifact::applyGs(CGameState *gs) } // Delete parts from hero - for(const auto slot : slotsInvolved) + for(const auto & slot : slotsInvolved) { const auto constituentInstance = hero->getArt(slot); gs->map->removeArtifactInstance(*hero, slot); - if(ArtifactUtils::isSlotEquipment(al.slot) && slot != al.slot) - combinedArt->addPart(constituentInstance, slot); - else - combinedArt->addPart(constituentInstance, ArtifactPosition::PRE_FIRST); + if(!combinedArt->artType->isFused()) + { + if(ArtifactUtils::isSlotEquipment(al.slot) && slot != al.slot) + combinedArt->addPart(constituentInstance, slot); + else + combinedArt->addPart(constituentInstance, ArtifactPosition::PRE_FIRST); + } } // Put new combined artifacts @@ -2483,10 +2483,7 @@ void SetBankConfiguration::applyGs(CGameState *gs) const CArtifactInstance * ArtSlotInfo::getArt() const { if(locked) - { - logNetwork->warn("ArtifactLocation::getArt: This location is locked!"); return nullptr; - } return artifact; } diff --git a/lib/networkPacks/PacksForClient.h b/lib/networkPacks/PacksForClient.h index b9f678ba6..0413113dc 100644 --- a/lib/networkPacks/PacksForClient.h +++ b/lib/networkPacks/PacksForClient.h @@ -1108,8 +1108,8 @@ struct DLL_LINKAGE BulkMoveArtifacts : CArtifactOperationPack struct DLL_LINKAGE AssembledArtifact : CArtifactOperationPack { - ArtifactLocation al; //where assembly will be put - const CArtifact * builtArt; + ArtifactLocation al; + ArtifactID artId; void applyGs(CGameState * gs) override; @@ -1118,7 +1118,7 @@ struct DLL_LINKAGE AssembledArtifact : CArtifactOperationPack template void serialize(Handler & h) { h & al; - h & builtArt; + h & artId; } }; diff --git a/lib/rewardable/Interface.cpp b/lib/rewardable/Interface.cpp index f67250efe..7bef36108 100644 --- a/lib/rewardable/Interface.cpp +++ b/lib/rewardable/Interface.cpp @@ -11,10 +11,10 @@ #include "StdInc.h" #include "Interface.h" -#include "../CHeroHandler.h" #include "../TerrainHandler.h" #include "../CPlayerState.h" #include "../CSoundBase.h" +#include "../entities/hero/CHeroHandler.h" #include "../gameState/CGameState.h" #include "../spells/CSpellHandler.h" #include "../spells/ISpellMechanics.h" diff --git a/lib/rewardable/Limiter.cpp b/lib/rewardable/Limiter.cpp index 384ffea92..5e0d4bd80 100644 --- a/lib/rewardable/Limiter.cpp +++ b/lib/rewardable/Limiter.cpp @@ -17,7 +17,6 @@ #include "../networkPacks/Component.h" #include "../serializer/JsonSerializeFormat.h" #include "../constants/StringConstants.h" -#include "../CHeroHandler.h" #include "../CSkillHandler.h" #include "../ArtifactUtils.h" diff --git a/lib/rmg/CMapGenerator.cpp b/lib/rmg/CMapGenerator.cpp index 0e02212b9..c33a10dd4 100644 --- a/lib/rmg/CMapGenerator.cpp +++ b/lib/rmg/CMapGenerator.cpp @@ -17,11 +17,11 @@ #include "../CRandomGenerator.h" #include "../entities/faction/CTownHandler.h" #include "../entities/faction/CFaction.h" +#include "../entities/hero/CHero.h" #include "../mapObjectConstructors/AObjectTypeHandler.h" #include "../mapObjectConstructors/CObjectClassesHandler.h" #include "../mapping/CMapEditManager.h" #include "../CArtHandler.h" -#include "../CHeroHandler.h" #include "../constants/StringConstants.h" #include "../filesystem/Filesystem.h" #include "CZonePlacer.h" @@ -35,6 +35,7 @@ #include "modificators/RoadPlacer.h" #include +#include VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/rmg/modificators/ObstaclePlacer.cpp b/lib/rmg/modificators/ObstaclePlacer.cpp index 456ddbeb0..5447a256e 100644 --- a/lib/rmg/modificators/ObstaclePlacer.cpp +++ b/lib/rmg/modificators/ObstaclePlacer.cpp @@ -153,7 +153,7 @@ void ObstaclePlacer::postProcess(const rmg::Object & object) riverManager = zone.getModificator(); if(riverManager) { - const auto objTypeName = object.instances().front()->object().typeName; + const auto objTypeName = object.instances().front()->object().getTypeName(); if(objTypeName == "mountain") riverManager->riverSource().unite(object.getArea()); else if(objTypeName == "lake") diff --git a/lib/serializer/CSerializer.cpp b/lib/serializer/CSerializer.cpp index f8311a95b..3e7e84a6f 100644 --- a/lib/serializer/CSerializer.cpp +++ b/lib/serializer/CSerializer.cpp @@ -10,9 +10,9 @@ #include "StdInc.h" #include "CSerializer.h" +#include "../entities/hero/CHero.h" #include "../gameState/CGameState.h" #include "../mapping/CMap.h" -#include "../CHeroHandler.h" #include "../mapObjects/CGHeroInstance.h" #include "../mapObjects/CQuest.h" diff --git a/lib/serializer/ESerializationVersion.h b/lib/serializer/ESerializationVersion.h index d0fe579e4..7b4270bc9 100644 --- a/lib/serializer/ESerializationVersion.h +++ b/lib/serializer/ESerializationVersion.h @@ -64,6 +64,7 @@ enum class ESerializationVersion : int32_t SPELL_RESEARCH, // 865 - spell research LOCAL_PLAYER_STATE_DATA, // 866 - player state contains arbitrary client-side data REMOVE_TOWN_PTR, // 867 - removed pointer to CTown from CGTownInstance + REMOVE_OBJECT_TYPENAME, // 868 - remove typename from CGObjectInstance - CURRENT = REMOVE_TOWN_PTR + CURRENT = REMOVE_OBJECT_TYPENAME }; diff --git a/lib/serializer/RegisterTypes.h b/lib/serializer/RegisterTypes.h index 492d0e371..204d99432 100644 --- a/lib/serializer/RegisterTypes.h +++ b/lib/serializer/RegisterTypes.h @@ -9,7 +9,6 @@ */ #pragma once -#include "../CHeroHandler.h" #include "../CPlayerState.h" #include "../CStack.h" #include "../battle/BattleInfo.h" diff --git a/lib/serializer/SerializerReflection.cpp b/lib/serializer/SerializerReflection.cpp index 4862c62b7..ecb3427b8 100644 --- a/lib/serializer/SerializerReflection.cpp +++ b/lib/serializer/SerializerReflection.cpp @@ -19,6 +19,7 @@ #include "../RiverHandler.h" #include "../RoadHandler.h" #include "../TerrainHandler.h" +#include "../entities/hero/CHero.h" #include "../mapObjects/ObjectTemplate.h" #include "../mapping/CMapInfo.h" #include "../rmg/CMapGenOptions.h" diff --git a/lib/spells/BonusCaster.cpp b/lib/spells/BonusCaster.cpp index deb119a89..a2d8523b1 100644 --- a/lib/spells/BonusCaster.cpp +++ b/lib/spells/BonusCaster.cpp @@ -12,12 +12,12 @@ #include "BonusCaster.h" #include +#include #include "../battle/Unit.h" #include "../bonuses/Bonus.h" #include "../VCMI_Lib.h" #include "../CSkillHandler.h" -#include "../CHeroHandler.h" VCMI_LIB_NAMESPACE_BEGIN diff --git a/lib/spells/ISpellMechanics.cpp b/lib/spells/ISpellMechanics.cpp index a1488e1e8..24f40b067 100644 --- a/lib/spells/ISpellMechanics.cpp +++ b/lib/spells/ISpellMechanics.cpp @@ -36,7 +36,6 @@ #include "CSpellHandler.h" -#include "../CHeroHandler.h"//todo: remove #include "../IGameCallback.h"//todo: remove #include "../BattleFieldHandler.h" diff --git a/lib/spells/effects/Summon.cpp b/lib/spells/effects/Summon.cpp index e46cdc6da..e4d51bd5b 100644 --- a/lib/spells/effects/Summon.cpp +++ b/lib/spells/effects/Summon.cpp @@ -18,7 +18,6 @@ #include "../../battle/Unit.h" #include "../../serializer/JsonSerializeFormat.h" #include "../../CCreatureHandler.h" -#include "../../CHeroHandler.h" #include "../../mapObjects/CGHeroInstance.h" #include "../../networkPacks/PacksForClientBattle.h" diff --git a/lib/texts/TextLocalizationContainer.cpp b/lib/texts/TextLocalizationContainer.cpp index f45898cf7..eff0a692e 100644 --- a/lib/texts/TextLocalizationContainer.cpp +++ b/lib/texts/TextLocalizationContainer.cpp @@ -107,7 +107,7 @@ void TextLocalizationContainer::registerString(const std::string & identifierMod assert(!identifierModContext.empty()); assert(!localizedStringModContext.empty()); assert(UID.get().find("..") == std::string::npos); // invalid identifier - there is section that was evaluated to empty string - assert(stringsLocalizations.count(UID.get()) == 0 || identifierModContext == "map"); // registering already registered string? + assert(stringsLocalizations.count(UID.get()) == 0 || boost::algorithm::starts_with(UID.get(), "map") || boost::algorithm::starts_with(UID.get(), "header")); // registering already registered string? FIXME: "header" is a workaround. VMAP needs proper integration in translation system if(stringsLocalizations.count(UID.get()) > 0) { @@ -152,11 +152,9 @@ void TextLocalizationContainer::exportAllTexts(std::mapID.getNum()); addProperty("SubID", obj->subID); addProperty("InstanceName", obj->instanceName); - addProperty("TypeName", obj->typeName); - addProperty("SubTypeName", obj->subTypeName); if(obj->ID != Obj::HERO_PLACEHOLDER && !dynamic_cast(obj)) { diff --git a/mapeditor/inspector/portraitwidget.cpp b/mapeditor/inspector/portraitwidget.cpp index 669bb880c..af113be2e 100644 --- a/mapeditor/inspector/portraitwidget.cpp +++ b/mapeditor/inspector/portraitwidget.cpp @@ -10,8 +10,8 @@ #include "StdInc.h" #include "portraitwidget.h" #include "ui_portraitwidget.h" -#include "../../lib/CHeroHandler.h" #include "../Animation.h" +#include "../lib/entities/hero/CHeroHandler.h" PortraitWidget::PortraitWidget(CGHeroInstance & h, QWidget *parent): QDialog(parent), diff --git a/mapeditor/inspector/questwidget.cpp b/mapeditor/inspector/questwidget.cpp index df706c19d..8edd018de 100644 --- a/mapeditor/inspector/questwidget.cpp +++ b/mapeditor/inspector/questwidget.cpp @@ -16,12 +16,16 @@ #include "../lib/spells/CSpellHandler.h" #include "../lib/CArtHandler.h" #include "../lib/CCreatureHandler.h" -#include "../lib/CHeroHandler.h" #include "../lib/constants/StringConstants.h" #include "../lib/mapping/CMap.h" #include "../lib/mapObjects/CGHeroInstance.h" #include "../lib/mapObjects/CGCreature.h" +#include +#include +#include +#include + QuestWidget::QuestWidget(MapController & _controller, CQuest & _sh, QWidget *parent) : QDialog(parent), controller(_controller), diff --git a/mapeditor/inspector/rewardswidget.cpp b/mapeditor/inspector/rewardswidget.cpp index 4a8d7ab4c..b4710ff88 100644 --- a/mapeditor/inspector/rewardswidget.cpp +++ b/mapeditor/inspector/rewardswidget.cpp @@ -13,7 +13,6 @@ #include "../lib/VCMI_Lib.h" #include "../lib/CSkillHandler.h" #include "../lib/spells/CSpellHandler.h" -#include "../lib/CHeroHandler.h" #include "../lib/CArtHandler.h" #include "../lib/CCreatureHandler.h" #include "../lib/constants/StringConstants.h" @@ -24,6 +23,11 @@ #include "../lib/mapObjects/CGPandoraBox.h" #include "../lib/mapObjects/CQuest.h" +#include +#include +#include +#include + RewardsWidget::RewardsWidget(CMap & m, CRewardableObject & p, QWidget *parent) : QDialog(parent), map(m), diff --git a/mapeditor/mapcontroller.cpp b/mapeditor/mapcontroller.cpp index a30a90aa8..167ca42cc 100644 --- a/mapeditor/mapcontroller.cpp +++ b/mapeditor/mapcontroller.cpp @@ -13,6 +13,8 @@ #include "../lib/ArtifactUtils.h" #include "../lib/GameConstants.h" +#include "../lib/entities/hero/CHeroClass.h" +#include "../lib/entities/hero/CHeroHandler.h" #include "../lib/mapObjectConstructors/AObjectTypeHandler.h" #include "../lib/mapObjectConstructors/CObjectClassesHandler.h" #include "../lib/mapObjects/ObjectTemplate.h" @@ -25,7 +27,6 @@ #include "../lib/TerrainHandler.h" #include "../lib/CSkillHandler.h" #include "../lib/spells/CSpellHandler.h" -#include "../lib/CHeroHandler.h" #include "../lib/CRandomGenerator.h" #include "../lib/serializer/CMemorySerializer.h" #include "mapview.h" @@ -112,13 +113,6 @@ void MapController::repairMap(CMap * map) const allImpactedObjects.insert(allImpactedObjects.end(), map->predefinedHeroes.begin(), map->predefinedHeroes.end()); for(auto obj : allImpactedObjects) { - //setup proper names (hero name will be fixed later - if(obj->ID != Obj::HERO && obj->ID != Obj::PRISON && (obj->typeName.empty() || obj->subTypeName.empty())) - { - auto handler = VLC->objtypeh->getHandlerFor(obj->ID, obj->subID); - obj->typeName = handler->getTypeName(); - obj->subTypeName = handler->getSubTypeName(); - } //fix flags if(obj->getOwner() == PlayerColor::UNFLAGGABLE) { @@ -142,18 +136,7 @@ void MapController::repairMap(CMap * map) const auto const & type = VLC->heroh->objects[nih->subID]; assert(type->heroClass); - //TODO: find a way to get proper type name - if(obj->ID == Obj::HERO) - { - nih->typeName = "hero"; - nih->subTypeName = type->heroClass->getJsonKey(); - } - if(obj->ID == Obj::PRISON) - { - nih->typeName = "prison"; - nih->subTypeName = "prison"; - nih->subID = 0; - } + if(nih->ID == Obj::HERO) //not prison nih->appearance = VLC->objtypeh->getHandlerFor(Obj::HERO, type->heroClass->getIndex())->getTemplates().front(); //fix spellbook @@ -568,8 +551,6 @@ bool MapController::canPlaceObject(int level, CGObjectInstance * newObj, QString if(newObj->ID == Obj::GRAIL && objCounter >= 1) //special case for grail { - auto typeName = QString::fromStdString(newObj->typeName); - auto subTypeName = QString::fromStdString(newObj->subTypeName); error = QObject::tr("There can only be one grail object on the map."); return false; //maplimit reached } diff --git a/mapeditor/maphandler.cpp b/mapeditor/maphandler.cpp index c9b18ac32..70aac50b0 100644 --- a/mapeditor/maphandler.cpp +++ b/mapeditor/maphandler.cpp @@ -19,7 +19,6 @@ #include "../lib/mapObjects/CGHeroInstance.h" #include "../lib/mapObjects/ObjectTemplate.h" #include "../lib/mapObjects/MiscObjects.h" -#include "../lib/CHeroHandler.h" #include "../lib/GameConstants.h" const int tileSize = 32; diff --git a/mapeditor/mapsettings/abstractsettings.cpp b/mapeditor/mapsettings/abstractsettings.cpp index f75a77685..a21d2f24b 100644 --- a/mapeditor/mapsettings/abstractsettings.cpp +++ b/mapeditor/mapsettings/abstractsettings.cpp @@ -13,7 +13,6 @@ #include "../mapcontroller.h" #include "../../lib/mapObjects/CGHeroInstance.h" #include "../../lib/mapObjects/CGCreature.h" -#include "../../lib/CHeroHandler.h" #include "../../lib/mapObjects/CGCreature.h" //parses date for lose condition (1m 1w 1d) diff --git a/mapeditor/mapsettings/mapsettings.cpp b/mapeditor/mapsettings/mapsettings.cpp index 7e579cb81..f94783020 100644 --- a/mapeditor/mapsettings/mapsettings.cpp +++ b/mapeditor/mapsettings/mapsettings.cpp @@ -13,10 +13,10 @@ #include "ui_mapsettings.h" #include "mainwindow.h" -#include "../../lib/CSkillHandler.h" -#include "../../lib/spells/CSpellHandler.h" #include "../../lib/CArtHandler.h" -#include "../../lib/CHeroHandler.h" +#include "../../lib/CSkillHandler.h" +#include "../../lib/entities/hero/CHeroHandler.h" +#include "../../lib/spells/CSpellHandler.h" MapSettings::MapSettings(MapController & ctrl, QWidget *parent) : diff --git a/mapeditor/mapsettings/timedevent.cpp b/mapeditor/mapsettings/timedevent.cpp index 083bd1d72..772eea5c3 100644 --- a/mapeditor/mapsettings/timedevent.cpp +++ b/mapeditor/mapsettings/timedevent.cpp @@ -28,7 +28,7 @@ TimedEvent::TimedEvent(QListWidgetItem * t, QWidget *parent) : ui->eventMessageText->setPlainText(params.value("message").toString()); ui->eventAffectsCpu->setChecked(params.value("computerAffected").toBool()); ui->eventAffectsHuman->setChecked(params.value("humanAffected").toBool()); - ui->eventFirstOccurrence->setValue(params.value("firstOccurrence").toInt()); + ui->eventFirstOccurrence->setValue(params.value("firstOccurrence").toInt() + 1); ui->eventRepeatAfter->setValue(params.value("nextOccurrence").toInt()); auto playerList = params.value("players").toList(); @@ -68,7 +68,7 @@ void TimedEvent::on_TimedEvent_finished(int result) descriptor["message"] = ui->eventMessageText->toPlainText(); descriptor["humanAffected"] = QVariant::fromValue(ui->eventAffectsHuman->isChecked()); descriptor["computerAffected"] = QVariant::fromValue(ui->eventAffectsCpu->isChecked()); - descriptor["firstOccurrence"] = QVariant::fromValue(ui->eventFirstOccurrence->value()); + descriptor["firstOccurrence"] = QVariant::fromValue(ui->eventFirstOccurrence->value() - 1); descriptor["nextOccurrence"] = QVariant::fromValue(ui->eventRepeatAfter->value()); QVariantList players; diff --git a/mapeditor/mapsettings/timedevent.ui b/mapeditor/mapsettings/timedevent.ui index 4fef09168..104dd16b5 100644 --- a/mapeditor/mapsettings/timedevent.ui +++ b/mapeditor/mapsettings/timedevent.ui @@ -72,7 +72,11 @@ - + + + 1 + + diff --git a/mapeditor/translation/czech.ts b/mapeditor/translation/czech.ts index cfdc136c7..a7456cf42 100644 --- a/mapeditor/translation/czech.ts +++ b/mapeditor/translation/czech.ts @@ -67,22 +67,22 @@ Author - + Autor Author contact (e.g. email) - + Kontakt na autora (např. email) Map Creation Time - + Čas vytvoření mapy Map Version - + Verze mapy @@ -788,12 +788,12 @@ Set all mods having a game content as mandatory - + Nastavte všechny modifikace obsahující herní obsah jako povinné Full content mods - + Modifikace s kompletním herním obsahem @@ -836,7 +836,7 @@ Generate hero at main - + Vytvořit hrdinu v hlavním městě @@ -877,7 +877,7 @@ Portrait - + Portrét @@ -947,17 +947,17 @@ Can't place object - Nelze umístit objekt + Nelze umístit objekt There can only be one grail object on the map. - + Na mapě může být pouze jeden grál. Hero %1 cannot be created as NEUTRAL. - + Hrdina %1 nemůže být vytvořen jako NEUTRÁLNÍ. @@ -1129,7 +1129,7 @@ On select text - + Text při výběru @@ -1210,7 +1210,7 @@ Overflow - + Přetečení @@ -1473,37 +1473,37 @@ Build all - + Postavit vše Demolish all - + Zbořit vše Enable all - + Povolit vše Disable all - + Zakázat vše Type - Druh + Typ Enabled - + Povoleno Built - + Postaveno @@ -1511,77 +1511,77 @@ Town event - + Událost ve městě General - + Hlavní Event name - Název události + Název události Type event message text - Zadejte text zprávy události + Zadejte text události Day of first occurrence - Den prvního výskytu + Den prvního výskytu Repeat after (0 = no repeat) - Opakovat po (0 = bez opak.) + Opakovat po (0 = bez opakováí) Affected players - Ovlivnění hráči + Ovlivnění hráči affects human - ovlivňuje lidi + ovlivňuje lidi affects AI - ovlivňuje AI + ovlivňuje AI Resources - Zdroje + Zdroje Buildings - Budovy + Budovy Creatures - Jednotky + Jednotky OK - + OK Creature level %1 / Creature level %1 Upgrade - + Úroveň jednotky %1 / Úroveň jednotky%1 vylepšení Day %1 - %2 - + Den %1 - %2 @@ -1589,32 +1589,32 @@ Town events - + Události ve městě Timed events - Načasované události + Načasované události Add - Přidat + Přidat Remove - Odebrat + Odebrat Day %1 - %2 - + Den %1 - %2 New event - Nová událost + Nová událost @@ -1622,17 +1622,17 @@ Spells - Kouzla + Kouzla Customize spells - Přizpůsobit kouzla + Přizpůsobit kouzla Level 1 - Úroveň 1 + 1. stupeň @@ -1641,7 +1641,7 @@ Spell that may appear in mage guild - + Kouzlo, které se může objevit ve věži kouzel @@ -1650,27 +1650,27 @@ Spell that must appear in mage guild - + Kouzlo, které se musí objevit ve věži kouzel Level 2 - Úroveň 2 + 2. stupeň Level 3 - Úroveň 3 + 3. stupeň Level 4 - Úroveň 4 + 4. stupeň Level 5 - Úroveň 5 + 5. stupeň @@ -1722,7 +1722,7 @@ Map validation results - Výsledky posudku mapy + Výsledky ověření mapy @@ -1732,27 +1732,27 @@ No factions allowed for player %1 - + Pro hráče %1 nejsou povoleny žádné frakce No players allowed to play this map - Žádní hráči nejsou dovoleni hrát tuto mapu + Tato mapa neumožňuje hru žádnému hráči Map is allowed for one player and cannot be started - Mapa je pouze pro jednoho hráče na nemůže být spuštěna + Tato mapa je určena pouze pro jednoho hráče a nelze ji spustit No human players allowed to play this map - Žádní lidští hráči nejsou dovoleni hrát tuto mapu + Na této mapě není povolen žádný lidský hráč Armored instance %1 is UNFLAGGABLE but must have NEUTRAL or player owner - + Obrněná instance %1 nemůže být označena vlajkou, ale musí mít vlastníka nebo neutrálního nebo hráče @@ -1762,17 +1762,17 @@ Spell scroll %1 doesn't have instance assigned and must be removed - + Kouzelný svitek %1 nemá přiřazenou instanci a musí být odstraněn Artifact %1 is prohibited by map settings - + Artefakt %1 je zakázán nastavením mapy Player %1 has no towns and heroes assigned - + Hráč %1 nemá přiřazena žádná města ani hrdiny @@ -1797,7 +1797,7 @@ Hero %1 has an empty type and must be removed - + Hrdina %1 nemá přiřazený typ a musí být odstraněn @@ -1923,7 +1923,7 @@ Two level map - Dvě úrovně + Dvouvrstvá mapa @@ -2016,7 +2016,7 @@ Monster strength - Síla příšer + Síla jednotek @@ -2037,7 +2037,7 @@ Water content - Obsah vody + Vodní obsah @@ -2052,22 +2052,22 @@ Roads - Cesty + Cesty Dirt - + Hlína Gravel - + Štěrk Cobblestone - + Dlažba @@ -2115,7 +2115,7 @@ Filepath of the map to open. - Cesta k souboru mapy pro otevření. + Cesta k souboru mapy, kterou chcete otevřít. @@ -2135,7 +2135,7 @@ Delete original files, for the ones split / converted. - + Odstranit původní soubory pro ty, které byly rozděleny nebo převedeny. diff --git a/mapeditor/validator.cpp b/mapeditor/validator.cpp index b4a98df30..17c1d2dcc 100644 --- a/mapeditor/validator.cpp +++ b/mapeditor/validator.cpp @@ -12,12 +12,12 @@ #include "validator.h" #include "mapcontroller.h" #include "ui_validator.h" +#include "../lib/entities/hero/CHero.h" #include "../lib/mapping/CMap.h" #include "../lib/mapObjects/MapObjects.h" #include "../lib/modding/CModHandler.h" #include "../lib/modding/CModInfo.h" #include "../lib/spells/CSpellHandler.h" -#include "../lib/CHeroHandler.h" Validator::Validator(const CMap * map, QWidget *parent) : QDialog(parent), diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 663107a3b..398590968 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -29,7 +29,6 @@ #include "../lib/CCreatureHandler.h" #include "../lib/CCreatureSet.h" #include "../lib/texts/CGeneralTextHandler.h" -#include "../lib/CHeroHandler.h" #include "../lib/CPlayerState.h" #include "../lib/CRandomGenerator.h" #include "../lib/CSoundBase.h" @@ -48,6 +47,7 @@ #include "../lib/entities/building/CBuilding.h" #include "../lib/entities/faction/CTownHandler.h" +#include "../lib/entities/hero/CHeroHandler.h" #include "../lib/filesystem/FileInfo.h" #include "../lib/filesystem/Filesystem.h" @@ -1253,7 +1253,7 @@ void CGameHandler::changeSpells(const CGHeroInstance * hero, bool give, const st sendAndApply(cs); } -void CGameHandler::setResearchedSpells(const CGTownInstance * town, int level, const std::vector spells, bool accepted) +void CGameHandler::setResearchedSpells(const CGTownInstance * town, int level, const std::vector & spells, bool accepted) { SetResearchedSpells cs; cs.tid = town->id; @@ -2913,7 +2913,7 @@ bool CGameHandler::assembleArtifacts(ObjectInstanceID heroID, ArtifactPosition a AssembledArtifact aa; aa.al = dstLoc; - aa.builtArt = combinedArt; + aa.artId = assembleTo; sendAndApply(aa); } else @@ -2921,6 +2921,9 @@ bool CGameHandler::assembleArtifacts(ObjectInstanceID heroID, ArtifactPosition a if(!destArtifact->isCombined()) COMPLAIN_RET("assembleArtifacts: Artifact being attempted to disassemble is not a combined artifact!"); + if(!destArtifact->hasParts()) + COMPLAIN_RET("assembleArtifacts: Artifact being attempted to disassemble is fused combined artifact!"); + if(ArtifactUtils::isSlotBackpack(artifactSlot) && !ArtifactUtils::isBackpackFreeSlots(hero, destArtifact->artType->getConstituents().size() - 1)) COMPLAIN_RET("assembleArtifacts: Artifact being attempted to disassemble but backpack is full!"); diff --git a/server/CGameHandler.h b/server/CGameHandler.h index 4448cbd22..9d896f758 100644 --- a/server/CGameHandler.h +++ b/server/CGameHandler.h @@ -107,7 +107,7 @@ public: //from IGameCallback //do sth void changeSpells(const CGHeroInstance * hero, bool give, const std::set &spells) override; - void setResearchedSpells(const CGTownInstance * town, int level, const std::vector spells, bool accepted) override; + void setResearchedSpells(const CGTownInstance * town, int level, const std::vector & spells, bool accepted) override; bool removeObject(const CGObjectInstance * obj, const PlayerColor & initiator) override; void setOwner(const CGObjectInstance * obj, PlayerColor owner) override; void giveExperience(const CGHeroInstance * hero, TExpType val) override; diff --git a/server/CVCMIServer.cpp b/server/CVCMIServer.cpp index c0753d2a1..ef92050c1 100644 --- a/server/CVCMIServer.cpp +++ b/server/CVCMIServer.cpp @@ -15,9 +15,10 @@ #include "LobbyNetPackVisitors.h" #include "processors/PlayerMessageProcessor.h" -#include "../lib/CHeroHandler.h" #include "../lib/CPlayerState.h" #include "../lib/campaign/CampaignState.h" +#include "../lib/entities/hero/CHeroHandler.h" +#include "../lib/entities/hero/CHeroClass.h" #include "../lib/gameState/CGameState.h" #include "../lib/mapping/CMapDefines.h" #include "../lib/mapping/CMapInfo.h" @@ -299,17 +300,12 @@ void CVCMIServer::onDisconnected(const std::shared_ptr & con std::shared_ptr c = findConnection(connection); // player may have already disconnected via clientDisconnected call - if (c) + if (c && gh && getState() == EServerState::GAMEPLAY) { - //clientDisconnected(c); - - if(gh && getState() == EServerState::GAMEPLAY) - { - LobbyClientDisconnected lcd; - lcd.c = c; - lcd.clientId = c->connectionID; - handleReceivedPack(lcd); - } + LobbyClientDisconnected lcd; + lcd.c = c; + lcd.clientId = c->connectionID; + handleReceivedPack(lcd); } } diff --git a/server/processors/HeroPoolProcessor.cpp b/server/processors/HeroPoolProcessor.cpp index 44a50884a..976c74b6f 100644 --- a/server/processors/HeroPoolProcessor.cpp +++ b/server/processors/HeroPoolProcessor.cpp @@ -14,10 +14,11 @@ #include "../CGameHandler.h" #include "../../lib/CRandomGenerator.h" -#include "../../lib/CHeroHandler.h" #include "../../lib/CPlayerState.h" #include "../../lib/IGameSettings.h" #include "../../lib/StartInfo.h" +#include "../../lib/entities/hero/CHeroClass.h" +#include "../../lib/entities/hero/CHero.h" #include "../../lib/mapObjects/CGTownInstance.h" #include "../../lib/mapObjects/CGHeroInstance.h" #include "../../lib/networkPacks/PacksForClient.h" diff --git a/server/processors/PlayerMessageProcessor.cpp b/server/processors/PlayerMessageProcessor.cpp index 6ebc78375..38b4409d0 100644 --- a/server/processors/PlayerMessageProcessor.cpp +++ b/server/processors/PlayerMessageProcessor.cpp @@ -16,10 +16,10 @@ #include "../CVCMIServer.h" #include "../TurnTimerHandler.h" -#include "../../lib/CHeroHandler.h" #include "../../lib/CPlayerState.h" #include "../../lib/StartInfo.h" #include "../../lib/entities/building/CBuilding.h" +#include "../../lib/entities/hero/CHeroHandler.h" #include "../../lib/gameState/CGameState.h" #include "../../lib/mapObjects/CGTownInstance.h" #include "../../lib/mapObjects/CGHeroInstance.h" diff --git a/server/queries/VisitQueries.cpp b/server/queries/VisitQueries.cpp index 36ff95291..f5f34fbb3 100644 --- a/server/queries/VisitQueries.cpp +++ b/server/queries/VisitQueries.cpp @@ -50,7 +50,6 @@ void MapObjectVisitQuery::onRemoval(PlayerColor color) { gh->objectVisitEnded(visitingHero, players.front()); - //TODO or should it be destructor? //Can object visit affect 2 players and what would be desired behavior? if(removeObjectAfterVisit) gh->removeObject(visitedObject, color); @@ -78,7 +77,7 @@ void TownBuildingVisitQuery::onAdded(PlayerColor color) while (!visitedBuilding.empty() && owner->topQuery(color).get() == this) { visitingHero = visitedBuilding.back().hero; - auto * building = visitedTown->rewardableBuildings.at(visitedBuilding.back().building); + const auto * building = visitedTown->rewardableBuildings.at(visitedBuilding.back().building); building->onHeroVisit(visitingHero); visitedBuilding.pop_back(); } diff --git a/test/entity/CHeroClassTest.cpp b/test/entity/CHeroClassTest.cpp index db109ae94..23eb7266b 100644 --- a/test/entity/CHeroClassTest.cpp +++ b/test/entity/CHeroClassTest.cpp @@ -9,7 +9,7 @@ */ #include "StdInc.h" -#include "../../lib/CHeroHandler.h" +#include "../../lib/entities/hero/CHeroClass.h" namespace test { diff --git a/test/entity/CHeroTest.cpp b/test/entity/CHeroTest.cpp index edea854a5..92f0e190d 100644 --- a/test/entity/CHeroTest.cpp +++ b/test/entity/CHeroTest.cpp @@ -9,7 +9,7 @@ */ #include "StdInc.h" -#include "../../lib/CHeroHandler.h" +#include "../../lib/entities/hero/CHero.h" namespace test { diff --git a/test/map/MapComparer.cpp b/test/map/MapComparer.cpp index 28ace85c2..8d1744520 100644 --- a/test/map/MapComparer.cpp +++ b/test/map/MapComparer.cpp @@ -203,8 +203,8 @@ void MapComparer::compareObject(const CGObjectInstance * actual, const CGObjectI EXPECT_EQ(actual->instanceName, expected->instanceName); EXPECT_EQ(typeid(actual).name(), typeid(expected).name());//todo: remove and use just comparison - std::string actualFullID = boost::str(boost::format("%s(%d)|%s(%d) %d") % actual->typeName % actual->ID % actual->subTypeName % actual->subID % actual->tempOwner); - std::string expectedFullID = boost::str(boost::format("%s(%d)|%s(%d) %d") % expected->typeName % expected->ID % expected->subTypeName % expected->subID % expected->tempOwner); + std::string actualFullID = boost::str(boost::format("(%d)|(%d) %d") % actual->ID % actual->subID % actual->tempOwner); + std::string expectedFullID = boost::str(boost::format("(%d)|(%d) %d") % expected->ID % expected->subID % expected->tempOwner); EXPECT_EQ(actualFullID, expectedFullID); diff --git a/test/mock/mock_IGameCallback.h b/test/mock/mock_IGameCallback.h index af5dd1171..3ae574345 100644 --- a/test/mock/mock_IGameCallback.h +++ b/test/mock/mock_IGameCallback.h @@ -44,7 +44,7 @@ public: void showInfoDialog(InfoWindow * iw) override {} void changeSpells(const CGHeroInstance * hero, bool give, const std::set &spells) override {} - void setResearchedSpells(const CGTownInstance * town, int level, const std::vector spells, bool accepted) override {} + void setResearchedSpells(const CGTownInstance * town, int level, const std::vector & spells, bool accepted) override {} bool removeObject(const CGObjectInstance * obj, const PlayerColor & initiator) override {return false;} void createBoat(const int3 & visitablePosition, BoatId type, PlayerColor initiator) override {} void setOwner(const CGObjectInstance * objid, PlayerColor owner) override {}