mirror of
https://github.com/vcmi/vcmi.git
synced 2025-07-15 01:24:45 +02:00
Merge pull request #2565 from IvanSavenko/documentation
(1.3.2) Documentation import
This commit is contained in:
3
.gitattributes
vendored
Normal file
3
.gitattributes
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
*.json linguist-language=JSON-with-Comments
|
||||||
|
*.h linguist-language=C++
|
||||||
|
*.cpp linguist-language=C++
|
@ -430,8 +430,8 @@
|
|||||||
### MODDING:
|
### MODDING:
|
||||||
* All configurable objects from H3 now have their configuration in json
|
* All configurable objects from H3 now have their configuration in json
|
||||||
* Improvements to functionality of configurable objects
|
* Improvements to functionality of configurable objects
|
||||||
* Replaced `SECONDARY_SKILL_PREMY` bonus with separate bonuses for each skill. See https://wiki.vcmi.eu/List_of_all_bonus_types
|
* Replaced `SECONDARY_SKILL_PREMY` bonus with separate bonuses for each skill.
|
||||||
* Removed multiple bonuses that can be replaced with another bonus. See https://wiki.vcmi.eu/List_of_all_bonus_types
|
* Removed multiple bonuses that can be replaced with another bonus.
|
||||||
* It is now possible to define new hero movement sounds in terrains
|
* It is now possible to define new hero movement sounds in terrains
|
||||||
* Implemented translation support for mods
|
* Implemented translation support for mods
|
||||||
* Implemented translation support for .h3m maps and .h3c campaigns
|
* Implemented translation support for .h3m maps and .h3c campaigns
|
||||||
@ -756,7 +756,7 @@
|
|||||||
* Wall hit/miss sound will be played when using catapult during siege
|
* Wall hit/miss sound will be played when using catapult during siege
|
||||||
|
|
||||||
### SPELLS:
|
### SPELLS:
|
||||||
* New configuration format: http://wiki.vcmi.eu/index.php?title=Spell_Format
|
* New configuration format
|
||||||
|
|
||||||
### RANDOM MAP GENERATOR:
|
### RANDOM MAP GENERATOR:
|
||||||
* Towns from mods can be used
|
* Towns from mods can be used
|
||||||
@ -789,7 +789,6 @@
|
|||||||
* (linux) Added a SIGSEV violation handler to vcmiserver executable for logging stacktrace (for convenience)
|
* (linux) Added a SIGSEV violation handler to vcmiserver executable for logging stacktrace (for convenience)
|
||||||
|
|
||||||
### ADVENTURE AI:
|
### ADVENTURE AI:
|
||||||
More info at http://wiki.vcmi.eu/index.php?title=Adventure_AI
|
|
||||||
* AI will use fuzzy logic to compare and choose multiple possible subgoals.
|
* AI will use fuzzy logic to compare and choose multiple possible subgoals.
|
||||||
* AI will now use SectorMap to find a way to guarded / covered objects.
|
* AI will now use SectorMap to find a way to guarded / covered objects.
|
||||||
* Significantly improved exploration algorithm.
|
* Significantly improved exploration algorithm.
|
||||||
@ -812,7 +811,6 @@ More info at http://wiki.vcmi.eu/index.php?title=Adventure_AI
|
|||||||
* Extended building dependencies support
|
* Extended building dependencies support
|
||||||
|
|
||||||
### MODS:
|
### MODS:
|
||||||
* See http://wiki.vcmi.eu/index.php?title=Modding_changelog#0.94_-.3E_0.95 for format changes
|
|
||||||
* Custom victory/loss conditions for maps or campaigns
|
* Custom victory/loss conditions for maps or campaigns
|
||||||
* 7 days without towns loss condition is no longer hardcoded
|
* 7 days without towns loss condition is no longer hardcoded
|
||||||
* Only changed mods will be validated
|
* Only changed mods will be validated
|
||||||
@ -870,7 +868,6 @@ More info at http://wiki.vcmi.eu/index.php?title=Adventure_AI
|
|||||||
* Fixed crash at month of double population.
|
* Fixed crash at month of double population.
|
||||||
|
|
||||||
### MODS:
|
### MODS:
|
||||||
* See http://wiki.vcmi.eu/index.php?title=Modding_changelog#0.92_-.3E_0.93 for compatibility info.
|
|
||||||
* Improved json validation. Now it support most of features from latest json schema draft.
|
* Improved json validation. Now it support most of features from latest json schema draft.
|
||||||
* Icons use path to icon instead of image indexes.
|
* Icons use path to icon instead of image indexes.
|
||||||
* It is possible to edit data of another mod or H3 data via mods.
|
* It is possible to edit data of another mod or H3 data via mods.
|
||||||
|
45
README.md
45
README.md
@ -1,45 +0,0 @@
|
|||||||
[](https://github.com/vcmi/vcmi/actions/workflows/github.yml)
|
|
||||||
[](https://scan.coverity.com/projects/vcmi)
|
|
||||||
[](https://github.com/vcmi/vcmi/releases/tag/1.3.0)
|
|
||||||
[](https://github.com/vcmi/vcmi/releases/tag/1.3.1)
|
|
||||||
[](https://github.com/vcmi/vcmi/releases)
|
|
||||||
# VCMI Project
|
|
||||||
VCMI is work-in-progress attempt to recreate engine for Heroes III, giving it new and extended possibilities.
|
|
||||||
|
|
||||||
## Links
|
|
||||||
|
|
||||||
* Homepage: https://vcmi.eu/
|
|
||||||
* Wiki: https://wiki.vcmi.eu/
|
|
||||||
* Forums: https://forum.vcmi.eu/
|
|
||||||
* Bugtracker: https://github.com/vcmi/vcmi/issues
|
|
||||||
* Slack: https://slack.vcmi.eu/
|
|
||||||
* Discord: https://discord.gg/chBT42V
|
|
||||||
|
|
||||||
## Installation guides
|
|
||||||
|
|
||||||
To use VCMI you need to own original data files.
|
|
||||||
|
|
||||||
* [Android](https://wiki.vcmi.eu/Installation_on_Android)
|
|
||||||
* [Linux](https://wiki.vcmi.eu/Installation_on_Linux)
|
|
||||||
* [macOS](https://wiki.vcmi.eu/Installation_on_macOS)
|
|
||||||
* [Windows](https://wiki.vcmi.eu/Installation_on_Windows)
|
|
||||||
* [iOS](https://wiki.vcmi.eu/Installation_on_iOS)
|
|
||||||
|
|
||||||
## Building from source
|
|
||||||
|
|
||||||
Platform support is constantly tested by continuous integration and CMake configuration adjusted to generate nice looking projects for all major IDE. Following guides will help you to setup build environment with no effort:
|
|
||||||
|
|
||||||
* (optional) All platforms: [using Conan package manager to obtain prebuilt dependencies](docs/conan.md)
|
|
||||||
* [On Linux](https://wiki.vcmi.eu/How_to_build_VCMI_(Linux))
|
|
||||||
* [On Linux for Windows with Conan and mingw](https://wiki.vcmi.eu/How_to_build_VCMI_(Linux/Cmake/Conan))
|
|
||||||
* [On macOS](https://wiki.vcmi.eu/How_to_build_VCMI_(macOS))
|
|
||||||
* [On Windows using MSVC and Vcpkg](https://wiki.vcmi.eu/How_to_build_VCMI_(Windows/Vcpkg))
|
|
||||||
* [iOS on macOS](https://wiki.vcmi.eu/How_to_build_VCMI_(iOS))
|
|
||||||
* [Android on any OS](https://wiki.vcmi.eu/How_to_build_VCMI_(Android))
|
|
||||||
|
|
||||||
## Copyright and license
|
|
||||||
|
|
||||||
VCMI Project source code is licensed under GPL version 2 or later.
|
|
||||||
VCMI Project assets are licensed under CC-BY-SA 4.0. Assets sources and information about contributors are available under following link: [https://github.com/vcmi/vcmi-assets]
|
|
||||||
|
|
||||||
Copyright (C) 2007-2023 VCMI Team (check AUTHORS file for the contributors list)
|
|
@ -3,7 +3,7 @@
|
|||||||
<string name="url_project_page" translatable="false">https://vcmi.eu</string>
|
<string name="url_project_page" translatable="false">https://vcmi.eu</string>
|
||||||
<string name="url_project_repo" translatable="false">https://github.com/vcmi/vcmi</string>
|
<string name="url_project_repo" translatable="false">https://github.com/vcmi/vcmi</string>
|
||||||
<string name="url_launcher_repo" translatable="false">https://github.com/vcmi/vcmi-android</string>
|
<string name="url_launcher_repo" translatable="false">https://github.com/vcmi/vcmi-android</string>
|
||||||
<string name="url_launcher_privacy" translatable="false">https://github.com/vcmi/vcmi/wiki/VCMI-App-Privacy-Policy</string>
|
<string name="url_launcher_privacy" translatable="false">https://github.com/vcmi/vcmi/blob/master/docs/players/Privacy_Policy.md</string>
|
||||||
|
|
||||||
<string name="app_name">VCMI</string>
|
<string name="app_name">VCMI</string>
|
||||||
<string name="server_name">VCMI Server</string>
|
<string name="server_name">VCMI Server</string>
|
||||||
|
80
docs/Readme.md
Normal file
80
docs/Readme.md
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
[](https://github.com/vcmi/vcmi/actions/workflows/github.yml)
|
||||||
|
[](https://github.com/vcmi/vcmi/releases/tag/1.3.0)
|
||||||
|
[](https://github.com/vcmi/vcmi/releases/tag/1.3.1)
|
||||||
|
[](https://github.com/vcmi/vcmi/releases)
|
||||||
|
|
||||||
|
# VCMI Project
|
||||||
|
|
||||||
|
VCMI is work-in-progress attempt to recreate engine for Heroes III, giving it new and extended possibilities.
|
||||||
|
|
||||||
|
## Links
|
||||||
|
|
||||||
|
* Homepage: https://vcmi.eu/
|
||||||
|
* Forums: https://forum.vcmi.eu/
|
||||||
|
* Bugtracker: https://github.com/vcmi/vcmi/issues
|
||||||
|
* Slack: https://slack.vcmi.eu/
|
||||||
|
* Discord: https://discord.gg/chBT42V
|
||||||
|
|
||||||
|
## Latest release
|
||||||
|
|
||||||
|
Latest release can be found [in Github Releases page](https://github.com/vcmi/vcmi/releases/latest). As of right now we plan to have major releases around 3 times per year. Daily builds are still available at [builds.vcmi.download](https://builds.vcmi.download/branch/develop/) but they are not guaranteed to be stable. So we encourage everybody to use them and report found bugs so that we can fix them.
|
||||||
|
Loading saves made with different major version of VCMI is usually **not** supported, so you may want to finish your ongoing games before updating.
|
||||||
|
Please see corresponding installation guide articles for details for your platform.
|
||||||
|
|
||||||
|
## Installation guides
|
||||||
|
- [Windows](players/Installation_Windows.md)
|
||||||
|
- [macOS](players/Installation_macOS.md)
|
||||||
|
- [Linux](players/Installation_Linux.md)
|
||||||
|
- [Android](players/Installation_Android.md)
|
||||||
|
- [iOS](players/Installation_iOS.md)
|
||||||
|
|
||||||
|
## Documentation and guidelines for players
|
||||||
|
|
||||||
|
- [General information about VCMI Project](players/Manual.md)
|
||||||
|
- [Frequently asked questions](https://vcmi.eu/faq/) (external link)
|
||||||
|
- [Game mechanics](players/Game_Mechanics.md)
|
||||||
|
- [Bug reporting guidelines](players/Bug_Reporting_Guidelines.md)
|
||||||
|
- [Cheat codes](players/Cheat_Codes.md)
|
||||||
|
- [Privacy Policy](players/Privacy_Policy.md)
|
||||||
|
|
||||||
|
## Documentation and guidelines for game modders
|
||||||
|
|
||||||
|
- [Modding Guidelines](modders/Readme.md)
|
||||||
|
- [Mod File Format](modders/Mod_File_Format.md)
|
||||||
|
- [Bonus Format](modders/Bonus_Format.md)
|
||||||
|
- [Translations](modders/Translations.md)
|
||||||
|
- [Map Editor](modders/Map_Editor.md)
|
||||||
|
- [Campaign Format](modders/Campaign_Format.md)
|
||||||
|
- [Configurable Widgets](modders/Configurable_Widgets.md)
|
||||||
|
|
||||||
|
## Documentation and guidelines for developers
|
||||||
|
|
||||||
|
Development environment setup instructions:
|
||||||
|
- [Building VCMI for Android](developers/Building_Android.md)
|
||||||
|
- [Building VCMI for iOS](developers/Building_iOS.md)
|
||||||
|
- [Building VCMI for Linux](developers/Building_Linux.md)
|
||||||
|
- [Building VCMI for macOS](developers/Building_macOS.md)
|
||||||
|
- [Building VCMI for Windows](developers/Building_Windows.md)
|
||||||
|
- [Conan](developers/Conan.md)
|
||||||
|
|
||||||
|
Engine documentation: (NOTE: may be outdated)
|
||||||
|
- [Development with Qt Creator](developers/Development_with_Qt_Creator.md)
|
||||||
|
- [Coding Guidelines](developers/Coding_Guidelines.md)
|
||||||
|
- [Bonus System](developers/Bonus_System.md)
|
||||||
|
- [Code Structure](developers/Code_Structure.md)
|
||||||
|
- [Logging API](developers/Logging_API.md)
|
||||||
|
- [Lua Scripting System](developers/Lua_Scripting_System.md)
|
||||||
|
- [Serialization](developers/Serialization.md)
|
||||||
|
|
||||||
|
## Documentation and guidelines for maintainers
|
||||||
|
|
||||||
|
- [Project Infrastructure](maintainers/Project_Infrastructure.md)
|
||||||
|
- [Release Process](maintainers/Release_Process.md)
|
||||||
|
- [Ubuntu PPA](maintainers/Ubuntu_PPA.md)
|
||||||
|
|
||||||
|
## Copyright and license
|
||||||
|
|
||||||
|
VCMI Project source code is licensed under GPL version 2 or later.
|
||||||
|
VCMI Project assets are licensed under CC-BY-SA 4.0. Assets sources and information about contributors are available under following link: https://github.com/vcmi/vcmi-assets
|
||||||
|
|
||||||
|
Copyright (C) 2007-2023 VCMI Team (check AUTHORS file for the contributors list)
|
BIN
docs/developers/BattleField.png
Normal file
BIN
docs/developers/BattleField.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 135 KiB |
76
docs/developers/Bonus_System.md
Normal file
76
docs/developers/Bonus_System.md
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
< [Documentation](../Readme.md) / Bonus System
|
||||||
|
|
||||||
|
The bonus system of VCMI is a set of mechanisms that make handling of different bonuses for heroes, towns, players and units easier. The system consists of a set of nodes representing objects that can be a source or a subject of a bonus and two directed acyclic graphs (DAGs) representing inheritance and propagation of bonuses. Core of bonus system is defined in HeroBonus.h file.
|
||||||
|
|
||||||
|
## Propagation and inheritance
|
||||||
|
|
||||||
|
Each bonus originates from some node in the bonus system, and may have propagator and limiter objects attached to it. Bonuses are shared around as follows:
|
||||||
|
|
||||||
|
1. Bonuses with propagator are propagated to "matching" descendants in the red DAG - which descendants match is determined by the propagator. Bonuses without a propagator will not be propagated.
|
||||||
|
2. Bonuses without limiters are inherited by all descendants in the black DAG. If limiters are present, they can restrict inheritance to certain nodes.
|
||||||
|
|
||||||
|
Inheritance is the default means of sharing bonuses. A typical example is an artefact granting a bonus to attack/defense stat, which is inherited by the hero wearing it, and then by creatures in the hero's army.
|
||||||
|
A common limiter is by creature - e.g. the hero Eric has a specialty that grants bonuses to attack, defense and speed, but only to griffins.
|
||||||
|
Propagation is used when bonuses need to be shared in a different direction than the black DAG for inheritance. E.g. Magi and Archmagi on the battlefield reduce the cost of spells for the controlling hero.
|
||||||
|
|
||||||
|
### Technical Details
|
||||||
|
|
||||||
|
- Propagation is done by copying bonuses to the target nodes. This happens when bonuses are added.
|
||||||
|
- Inheritance is done on-the-fly when needed, by traversing the black DAG. Results are cached to improve performance.
|
||||||
|
- Whenever a node changes (e.g. bonus added), a global counter gets increased which is used to check whether cached results are still current.
|
||||||
|
|
||||||
|
## Operations on the graph
|
||||||
|
|
||||||
|
There are two basic types of operations that can be performed on the graph:
|
||||||
|
|
||||||
|
### Adding a new node
|
||||||
|
|
||||||
|
When node is attached to a new black parent (the only possibility - adding parent is the same as adding a child to it), the propagation system is triggered and works as follows:
|
||||||
|
- For the attached node and its all red ancestors
|
||||||
|
- For every bonus
|
||||||
|
- Call propagator giving the new descendant - then attach appropriately bonuses to the red descendant of attached node (or the node itself).
|
||||||
|
|
||||||
|
E.g. when a hero equips an artifact, the hero gets attached to the artifact to inherit its bonuses.
|
||||||
|
|
||||||
|
### Deleting an existing node
|
||||||
|
|
||||||
|
Analogically to the adding a new node, just remove propagated bonuses instead of adding them. Then update the hierarchy.
|
||||||
|
|
||||||
|
E.g. when a hero removes an artifact, the hero (which became a child of the artifact when equipping it) is removed from it.
|
||||||
|
|
||||||
|
Note that only *propagated* bonuses need to be handled when nodes are added or removed. *Inheritance* is done on-the-fly and thus automatic.
|
||||||
|
|
||||||
|
## Limiters
|
||||||
|
|
||||||
|
If multiple limiters are specified for a bonus, a child inherits the bonus only if all limiters say that it should.
|
||||||
|
|
||||||
|
So e.g. a list of multiple creature type limiters (with different creatures) would ensure that no creature inherits the bonus. In such a case, the solution is to use one bonus per creature.
|
||||||
|
|
||||||
|
## Propagators
|
||||||
|
|
||||||
|
## Updaters
|
||||||
|
|
||||||
|
Updaters are objects attached to bonuses. They can modify a bonus (typically by changing *val*) during inheritance, including bonuses that a node "inherits" from itself, based on properties (typically level) of the node it passes through. Which nodes update a bonus depends on the type of updater. E.g. updaters that perform updates based on hero level will update bonuses as the are inherited by heroes.
|
||||||
|
|
||||||
|
The following example shows an artifact providing a bonus based on the level of the hero that wears it:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
"core:greaterGnollsFlail":
|
||||||
|
{
|
||||||
|
"text" : { "description" : "This mighty flail increases the attack of all gnolls under the hero's command by twice the hero's level." },
|
||||||
|
"bonuses" : [
|
||||||
|
{
|
||||||
|
"limiters" : [
|
||||||
|
{
|
||||||
|
"parameters" : [ "gnoll", true ],
|
||||||
|
"type" : "CREATURE_TYPE_LIMITER"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"subtype" : "primSkill.attack",
|
||||||
|
"type" : "PRIMARY_SKILL",
|
||||||
|
"val" : 2,
|
||||||
|
"updater" : "TIMES_HERO_LEVEL"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
86
docs/developers/Building_Android.md
Normal file
86
docs/developers/Building_Android.md
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
< [Documentation](../Readme.md) / Building for Android
|
||||||
|
|
||||||
|
The following instructions apply to **v1.2 and later**. For earlier versions the best documentation is https://github.com/vcmi/vcmi-android/blob/master/building.txt (and reading scripts in that repo), however very limited to no support will be provided from our side if you wish to go down that rabbit hole.
|
||||||
|
|
||||||
|
*Note*: building has been tested only on Linux and macOS. It may or may not work on Windows out of the box.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
1. CMake 3.20+: download from your package manager or from https://cmake.org/download/
|
||||||
|
2. JDK 11, not necessarily from Oracle
|
||||||
|
3. Android command line tools or Android Studio for your OS: https://developer.android.com/studio/
|
||||||
|
4. Android NDK version **r25c (25.2.9519653)**, there're multiple ways to obtain it:
|
||||||
|
- - install with Android Studio
|
||||||
|
- - install with `sdkmanager` command line tool
|
||||||
|
- - download from https://developer.android.com/ndk/downloads
|
||||||
|
- - download with Conan, see [#NDK and Conan](#ndk-and-conan)
|
||||||
|
5. (optional) Ninja: download from your package manager or from https://github.com/ninja-build/ninja/releases
|
||||||
|
|
||||||
|
## Obtaining source code
|
||||||
|
|
||||||
|
Clone https://github.com/vcmi/vcmi with submodules. Example for command line:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
git clone --recurse-submodules https://github.com/vcmi/vcmi.git
|
||||||
|
```
|
||||||
|
|
||||||
|
## Obtaining dependencies
|
||||||
|
|
||||||
|
We use Conan package manager to build/consume dependencies, find detailed usage instructions [here](https://github.com/vcmi/vcmi/tree/develop/docs/conan.md). Note that the link points to the cutting-edge state in `develop` branch, for the latest release check the same document in the [master
|
||||||
|
branch](https://github.com/vcmi/vcmi/tree/master/docs/conan.md).
|
||||||
|
|
||||||
|
On the step where you need to replace **PROFILE**, choose:
|
||||||
|
- `android-32` to build for 32-bit architecture (armeabi-v7a)
|
||||||
|
- `android-64` to build for 64-bit architecture (aarch64-v8a)
|
||||||
|
|
||||||
|
### NDK and Conan
|
||||||
|
|
||||||
|
Conan must be aware of the NDK location when you execute `conan install`. There're multiple ways to achieve that as written in the [Conan docs](https://docs.conan.io/1/integrations/cross_platform/android.html):
|
||||||
|
|
||||||
|
- the easiest is to download NDK from Conan (option 1 in the docs), then all the magic happens automatically. You need to create your own Conan profile that imports our Android profile and adds 2 new lines (you can of course just copy everything from our profile into yours without including) and then pass this new profile to `conan install`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
include(/path/to/vcmi/CI/conan/android-64)
|
||||||
|
[tool_requires]
|
||||||
|
android-ndk/r25c
|
||||||
|
```
|
||||||
|
|
||||||
|
- to use an already installed NDK, you can simply pass it on the command line to `conan install`:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
conan install -c tools.android:ndk_path=/path/to/ndk ...
|
||||||
|
```
|
||||||
|
|
||||||
|
## Build process
|
||||||
|
|
||||||
|
Building for Android is a 2-step process. First, native C++ code is compiled to a shared library (unlike executable on other platforms), then Java code is compiled to an actual executable which will be loading the native shared library at runtime.
|
||||||
|
|
||||||
|
### C++ code
|
||||||
|
|
||||||
|
This is a traditional CMake project, you can build it from command line or some IDE. You're not required to pass any custom options (except Conan toolchain file), defaults are already good. If you wish to use your own CMake presets, inherit them from our `build-with-conan` preset. Example:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
cmake -S . -B ../build -G Ninja -D CMAKE_BUILD_TYPE=Debug --toolchain ...
|
||||||
|
cmake --build ../build
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also see a more detailed walkthrough on CMake configuration at [How to build VCMI (macOS)](../developers/Building_macOS.md).
|
||||||
|
|
||||||
|
### Java code
|
||||||
|
|
||||||
|
After the C++ part is built, native shared libraries are copied to the appropriate location of the Java project (they will be packaged in the APK). You can either open the Java project located in `android` directory of the repo in Android studio and work with it as with any Android project or build from command line.
|
||||||
|
|
||||||
|
Example how to build from command line in Bash shell, assumes that current working directory is VCMI repository:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# the following environment variables must be set
|
||||||
|
export JAVA_HOME=/path/to/jdk11
|
||||||
|
export ANDROID_HOME=/path/to/android/sdk
|
||||||
|
``
|
||||||
|
cd android
|
||||||
|
./gradlew assembleDebug
|
||||||
|
```
|
||||||
|
|
||||||
|
APK will appear in `android/vcmi-app/build/outputs/apk/debug` directory which you can then install to your device with `adb install -r /path/to/apk` (adb command is from Android command line tools).
|
||||||
|
|
||||||
|
If you wish to build and install to your device in single action, use `installDebug` instead of `assembleDebug`.
|
146
docs/developers/Building_Linux.md
Normal file
146
docs/developers/Building_Linux.md
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
< [Documentation](../Readme.md) / Building on Linux
|
||||||
|
|
||||||
|
# Compiling VCMI
|
||||||
|
|
||||||
|
- Current baseline requirement for building is Ubuntu 20.04
|
||||||
|
- Supported C++ compilers for UNIX-like systems are GCC 9+ and Clang 13+
|
||||||
|
|
||||||
|
Older distributions and compilers might work, but they aren't tested by Github CI (Actions)
|
||||||
|
|
||||||
|
# Installing dependencies
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
To compile, the following packages (and their development counterparts) are needed to build:
|
||||||
|
|
||||||
|
- CMake
|
||||||
|
- SDL2 with devel packages: mixer, image, ttf
|
||||||
|
- zlib and zlib-devel
|
||||||
|
- Boost C++ libraries v1.48+: program-options, filesystem, system, thread, locale
|
||||||
|
- Recommended, if you want to build launcher or map editor: Qt 5, widget and network modules
|
||||||
|
- Recommended, FFmpeg libraries, if you want to watch in-game videos: libavformat and libswscale. Their name could be libavformat-devel and libswscale-devel, or ffmpeg-libs-devel or similar names.
|
||||||
|
- Optional, if you want to build scripting modules: LuaJIT
|
||||||
|
|
||||||
|
## On Debian-based systems (e.g. Ubuntu)
|
||||||
|
|
||||||
|
For Ubuntu and Debian you need to install this list of packages:
|
||||||
|
|
||||||
|
`sudo apt-get install cmake g++ libsdl2-dev libsdl2-image-dev libsdl2-ttf-dev libsdl2-mixer-dev zlib1g-dev libavformat-dev libswscale-dev libboost-dev libboost-filesystem-dev libboost-system-dev libboost-thread-dev libboost-program-options-dev libboost-locale-dev qtbase5-dev libtbb-dev libluajit-5.1-dev qttools5-dev`
|
||||||
|
|
||||||
|
Alternatively if you have VCMI installed from repository or PPA you can use:
|
||||||
|
|
||||||
|
`sudo apt-get build-dep vcmi`
|
||||||
|
|
||||||
|
## On RPM-based distributions (e.g. Fedora)
|
||||||
|
|
||||||
|
`sudo yum install cmake gcc-c++ SDL2-devel SDL2_image-devel SDL2_ttf-devel SDL2_mixer-devel boost boost-devel boost-filesystem boost-system boost-thread boost-program-options boost-locale zlib-devel ffmpeg-devel ffmpeg-libs qt5-qtbase-devel tbb-devel luajit-devel fuzzylite-devel`
|
||||||
|
|
||||||
|
NOTE: `fuzzylite-devel` package is no longer available in recent version of Fedora, for example Fedora 38. It's not a blocker because VCMI bundles fuzzylite lib in its source code.
|
||||||
|
|
||||||
|
## On Arch-based distributions
|
||||||
|
|
||||||
|
On Arch-based distributions, there is a development package available for VCMI on the AUR.
|
||||||
|
|
||||||
|
It can be found at: <https://aur.archlinux.org/packages/vcmi-git/>
|
||||||
|
|
||||||
|
Information about building packages from the Arch User Repository (AUR) can be found at the Arch wiki.
|
||||||
|
|
||||||
|
# Getting the sources
|
||||||
|
|
||||||
|
VCMI is still in development. We recommend the following initial directory structure:
|
||||||
|
|
||||||
|
.
|
||||||
|
├── vcmi -> contains sources and is under git control
|
||||||
|
└── build -> contains build output, makefiles, object files,...
|
||||||
|
|
||||||
|
You can get latest sources with:
|
||||||
|
|
||||||
|
`git clone -b develop --recursive https://github.com/vcmi/vcmi.git`
|
||||||
|
|
||||||
|
# Compilation
|
||||||
|
|
||||||
|
## Configuring Makefiles
|
||||||
|
|
||||||
|
```sh
|
||||||
|
mkdir build && cd build
|
||||||
|
cmake ../vcmi
|
||||||
|
```
|
||||||
|
|
||||||
|
# Additional options that you may want to use:
|
||||||
|
|
||||||
|
## To enable debugging:
|
||||||
|
`cmake ../vcmi -DCMAKE_BUILD_TYPE=Debug`
|
||||||
|
|
||||||
|
**Notice**: The ../vcmi/ is not a typo, it will place makefile scripts into the build dir as the build dir is your working dir when calling CMake.
|
||||||
|
|
||||||
|
## Trigger build
|
||||||
|
|
||||||
|
`cmake --build . -- -j2`
|
||||||
|
(-j2 = compile with 2 threads, you can specify any value)
|
||||||
|
|
||||||
|
That will generate vcmiclient, vcmiserver, vcmilauncher as well as .so libraries in **build/bin/** directory.
|
||||||
|
|
||||||
|
# Package building
|
||||||
|
|
||||||
|
## RPM package
|
||||||
|
|
||||||
|
The first step is to prepare a RPM build environment. On Fedora systems you can follow this guide: http://fedoraproject.org/wiki/How_to_create_an_RPM_package#SPEC_file_overview
|
||||||
|
|
||||||
|
0. Enable RPMFusion free repo to access to ffmpeg libs:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo dnf install https://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm
|
||||||
|
```
|
||||||
|
|
||||||
|
NOTE: the stock ffmpeg from Fedora repo is no good as it has stripped lots of codecs
|
||||||
|
|
||||||
|
1. Perform a git clone from a tagged branch for the right Fedora version from https://github.com/rpmfusion/vcmi; for example for Fedora 38: <pre>git clone -b f38 --single-branch https://github.com/rpmfusion/vcmi.git</pre>
|
||||||
|
|
||||||
|
2. Copy all files to ~/rpmbuild/SPECS with command: <pre>cp vcmi/* ~/rpmbuild/SPECS</pre>
|
||||||
|
|
||||||
|
3. Fetch all sources by using spectool:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo dnf install rpmdevtools
|
||||||
|
spectool -g -R ~/rpmbuild/SPECS/vcmi.spec
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Fetch all dependencies required to build the RPM:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo dnf install dnf-plugins-core
|
||||||
|
sudo dnf builddep ~/rpmbuild/SPECS/vcmi.spec
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Go to ~/rpmbuild/SPECS and open terminal in this folder and type:
|
||||||
|
```sh
|
||||||
|
rpmbuild -ba ~/rpmbuild/SPECS/vcmi.spec
|
||||||
|
```
|
||||||
|
|
||||||
|
5. Generated RPM is in folder ~/rpmbuild/RPMS
|
||||||
|
|
||||||
|
If you want to package the generated RPM above for different processor architectures and operating systems you can use the tool mock.
|
||||||
|
Moreover, it is necessary to install mock-rpmfusion_free due to the packages ffmpeg-devel and ffmpeg-libs which aren't available in the standard RPM repositories(at least for Fedora). Go to ~/rpmbuild/SRPMS in terminal and type:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
mock -r fedora-38-aarch64-rpmfusion_free path_to_source_RPM
|
||||||
|
mock -r fedora-38-x86_64-rpmfusion_free path_to_source_RPM
|
||||||
|
```
|
||||||
|
|
||||||
|
For other distributions that uses RPM, chances are there might be a spec file for VCMI. If there isn't, you can adapt the RPMFusion's file
|
||||||
|
|
||||||
|
Available root environments and their names are listed in /etc/mock.
|
||||||
|
|
||||||
|
## Debian/Ubuntu
|
||||||
|
|
||||||
|
1. Install debhelper and devscripts packages
|
||||||
|
|
||||||
|
2. Run dpkg-buildpackage command from vcmi source directory
|
||||||
|
|
||||||
|
```sh
|
||||||
|
sudo apt-get install debhelper devscripts
|
||||||
|
cd /path/to/source
|
||||||
|
dpkg-buildpackage
|
||||||
|
```
|
||||||
|
|
||||||
|
To generate packages for different architectures see "-a" flag of dpkg-buildpackage command
|
133
docs/developers/Building_Windows.md
Normal file
133
docs/developers/Building_Windows.md
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
< [Documentation](../Readme.md) / Building on Windows
|
||||||
|
|
||||||
|
# Preparations
|
||||||
|
Windows builds can be made in more than one way and with more than one tool. This guide focuses on the simplest building process using Microsoft Visual Studio 2022
|
||||||
|
|
||||||
|
# Prerequisites
|
||||||
|
|
||||||
|
- Windows Vista or newer.
|
||||||
|
- [Microsoft Visual Studio](https://visualstudio.microsoft.com/downloads/)
|
||||||
|
- Git or git GUI, for example, SourceTree [download link](http://www.sourcetreeapp.com/download)
|
||||||
|
- CMake [download link](https://cmake.org/download/). During install after accepting license agreement make sure to check "Add CMake to the system PATH for all users".
|
||||||
|
- To unpack pre-build Vcpkg: [7-zip](http://www.7-zip.org/download.html)
|
||||||
|
- Optionally, to create installer: [NSIS](http://nsis.sourceforge.net/Main_Page)
|
||||||
|
|
||||||
|
## Choose an installation directory
|
||||||
|
|
||||||
|
Create a directory for VCMI development, eg. `C:\VCMI` We will call this directory `%VCMI_DIR%`
|
||||||
|
|
||||||
|
Warning! Replace `%VCMI_DIR%` with path you've chosen for VCMI installation in the following commands.
|
||||||
|
|
||||||
|
It is recommended to avoid non-ascii characters in the path to your working folders. The folder should not be write-protected by system.
|
||||||
|
|
||||||
|
Good locations:
|
||||||
|
- `C:\VCMI`
|
||||||
|
|
||||||
|
Bad locations:
|
||||||
|
- `C:\Users\Michał\VCMI (non-ascii character)`
|
||||||
|
- `C:\Program Files (x86)\VCMI (write protection)`
|
||||||
|
|
||||||
|
# Install VCMI dependencies
|
||||||
|
|
||||||
|
You have two options: to use pre-built libraries or build your own. We strongly recommend start with using pre-built ones.
|
||||||
|
|
||||||
|
## Option A. Use pre-built Vcpkg
|
||||||
|
|
||||||
|
### Download and unpack archive
|
||||||
|
|
||||||
|
Vcpkg Archives are available at our GitHub: https://github.com/vcmi/vcmi-deps-windows/releases
|
||||||
|
|
||||||
|
- Download latest version available.
|
||||||
|
EG: v1.6 assets - [vcpkg-export-x64-windows-v143.7z](https://github.com/vcmi/vcmi-deps-windows/releases/download/v1.6/vcpkg-export-x64-windows-v143.7z)
|
||||||
|
- Extract archive by right clicking on it and choosing "7-zip -> Extract Here".
|
||||||
|
|
||||||
|
### Move dependencies to target directory
|
||||||
|
Once extracted, a `vcpkg` directory will appear with `installed` and `scripts` subfolders inside.
|
||||||
|
Move extracted `vcpkg` directory into your `%VCMI_DIR%`
|
||||||
|
|
||||||
|
## Option B. Build Vcpkg on your own
|
||||||
|
|
||||||
|
Please be aware that if you're running 32-bit Windows version, then this is impossible due to <https://github.com/microsoft/vcpkg/issues/26036>
|
||||||
|
Be aware that building Vcpkg might take a lot of time depend on your CPU model and 10-20GB of disk space.
|
||||||
|
|
||||||
|
### Create initial directory
|
||||||
|
|
||||||
|
### Clone vcpkg
|
||||||
|
|
||||||
|
1. open SourceTree
|
||||||
|
2. File -\> Clone
|
||||||
|
3. select **<https://github.com/microsoft/vcpkg/>** as source
|
||||||
|
4. select **%VCMI_DIR%/vcpkg** as destination
|
||||||
|
5. click **Clone**
|
||||||
|
|
||||||
|
From command line use:
|
||||||
|
|
||||||
|
git clone https://github.com/microsoft/vcpkg.git %VCMI_DIR%/vcpkg
|
||||||
|
|
||||||
|
### Build vcpkg and dependencies
|
||||||
|
|
||||||
|
- Run
|
||||||
|
`%VCMI_DIR%/vcpkg/bootstrap-vcpkg.bat`
|
||||||
|
- For 32-bit build run:
|
||||||
|
`%VCMI_DIR%/vcpkg/vcpkg.exe install tbb:x64-windows fuzzylite:x64-windows sdl2:x64-windows sdl2-image:x64-windows sdl2-ttf:x64-windows sdl2-mixer[mpg123]:x64-windows boost:x64-windows qt5-base:x64-windows ffmpeg:x64-windows luajit:x64-windows`
|
||||||
|
- For 64-bit build run:
|
||||||
|
`%VCMI_DIR%/vcpkg/vcpkg.exe install install tbb:x86-windows fuzzylite:x86-windows sdl2:x86-windows sdl2-image:x86-windows sdl2-ttf:x86-windows sdl2-mixer[mpg123]:x86-windows boost:x86-windows qt5-base:x86-windows ffmpeg:x86-windows luajit:x86-windows`
|
||||||
|
|
||||||
|
For the list of the packages used you can also consult [vcmi-deps-windows readme](https://github.com/vcmi/vcmi-deps-windows) in case this article gets outdated a bit.
|
||||||
|
|
||||||
|
# Build VCMI
|
||||||
|
|
||||||
|
#### From GIT GUI
|
||||||
|
- Open SourceTree
|
||||||
|
- File -> Clone
|
||||||
|
- select `https://github.com/vcmi/vcmi/` as source
|
||||||
|
- select `%VCMI_DIR%/source` as destination
|
||||||
|
- expand Advanced Options and change Checkout Branch to `develop`
|
||||||
|
- tick `Recursive submodules`
|
||||||
|
- click Clone
|
||||||
|
|
||||||
|
#### From command line
|
||||||
|
- `git clone --recursive https://github.com/vcmi/vcmi.git %VCMI_DIR%/source`
|
||||||
|
|
||||||
|
## Generate solution for VCMI
|
||||||
|
- Create `%VCMI_DIR%/build` folder
|
||||||
|
- Open a command line prompt at `%VCMI_DIR%/build`
|
||||||
|
- Execute `cd %VCMI_DIR%/build`
|
||||||
|
- Create solution (Visual Studio 2022 64-bit) `cmake %VCMI_DIR%/source -DCMAKE_TOOLCHAIN_FILE=%VCMI_DIR%/vcpkg/scripts/buildsystems/vcpkg.cmake -G "Visual Studio 17 2022" -A x64`
|
||||||
|
|
||||||
|
## Compile VCMI with Visual Studio
|
||||||
|
- Open `%VCMI_DIR%/build/VCMI.sln` in Visual Studio
|
||||||
|
- Select `Release` build type in combobox
|
||||||
|
- Right click on `BUILD_ALL` project. This `BUILD_ALL` project should be in `CMakePredefinedTargets` tree in Solution Explorer.
|
||||||
|
- VCMI will be built in `%VCMI_DIR%/build/bin` folder!
|
||||||
|
|
||||||
|
# Create VCMI installer (This step is not required for just building & development)
|
||||||
|
|
||||||
|
Make sure NSIS is installed to default directory or have registry entry so CMake can find it.
|
||||||
|
After you build VCMI execute following commands from `%VCMI_DIR%/build`.
|
||||||
|
|
||||||
|
- for release build: `cpack`
|
||||||
|
- for debug build: `cpack -C Debug`
|
||||||
|
|
||||||
|
# Troubleshooting and workarounds
|
||||||
|
|
||||||
|
Vcpkg might be very unstable due to limited popularity and fact of using bleeding edge packages (such as most recent Boost). Using latest version of dependencies could also expose both problems in VCMI code or library interface changes that developers not checked yet. So if you're built Vcpkg yourself and can't get it working please try to use binary package.
|
||||||
|
|
||||||
|
Pre-built version we provide is always manually tested with all supported versions of MSVC for both Release and Debug builds and all known quirks are listed below.
|
||||||
|
|
||||||
|
#$# Build is successful but can not start new game
|
||||||
|
Make sure you have:
|
||||||
|
* Installed Heroes III from disk or using GOG installer
|
||||||
|
* Copied `Data`, `Maps` and `Mp3` folders from Heroes III to: `%USERPROFILE%\Documents\My Games\vcmi\`
|
||||||
|
|
||||||
|
### VCMI won't run since some library is missing
|
||||||
|
|
||||||
|
**If you open solution using vcmi.sln** Try to build INSTALL target and see if its output works as expected. Copy missing libraries or even all libraries from there to your build directory. Or run cpack and use produced installer and see if you can get libs from there. cpack -V will give more info. If cpack complains that it can not find dumpbin try Visual Studio Command Prompt (special version of cmd provided with Visual Studio with additional PATH) or modify PATH to have this tool available. Another alternative if you use prebuilt vcpkg package is to download latest msvc build, install it and copy missing/all libraries from there.
|
||||||
|
|
||||||
|
### Debug build is very slow
|
||||||
|
|
||||||
|
Debug builds with MSVC are generally extremely slow since it's not just VCMI binaries are built as debug, but every single dependency too and this usually means no optimizations at all. Debug information that available for release builds is often sufficient so just avoid full debug builds unless absolutely necessary. Instead use RelWithDebInfo configuration, optionally with Optimization Disabled (/Od) to avoid variables being optimized away Also Debug configuration might have some compilation issues because it is not checked via CI for now.
|
||||||
|
|
||||||
|
### I got crash within library XYZ.dll
|
||||||
|
|
||||||
|
VCPKG generated projects quite often have both debug and regular libs available to linker so it can select wrong lib. For stable RelWithDebInfo build you may try to remove debug folder from VCPKG/installed/x64-windows. Same is done on CI. Also it reduces package size at least twice.
|
70
docs/developers/Building_iOS.md
Normal file
70
docs/developers/Building_iOS.md
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
< [Documentation](../Readme.md) / Building for iOS
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
1. **macOS**
|
||||||
|
2. Xcode: <https://developer.apple.com/xcode/>
|
||||||
|
3. CMake 3.21+: `brew install --cask cmake` or get from <https://cmake.org/download/>
|
||||||
|
|
||||||
|
## Obtaining source code
|
||||||
|
|
||||||
|
Clone <https://github.com/vcmi/vcmi> with submodules. Example for command line:
|
||||||
|
|
||||||
|
`git clone --recurse-submodules https://github.com/vcmi/vcmi.git`
|
||||||
|
|
||||||
|
## Obtaining dependencies
|
||||||
|
|
||||||
|
There are 2 ways to get prebuilt dependencies:
|
||||||
|
|
||||||
|
- [Conan package manager](https://github.com/vcmi/vcmi/tree/develop/docs/conan.md) - recommended. Note that the link points to the cutting-edge state in `develop` branch, for the latest release check the same document in the [master branch (https://github.com/vcmi/vcmi/tree/master/docs/conan.md).
|
||||||
|
- [legacy manually built libraries](https://github.com/vcmi/vcmi-ios-deps) - can be used if you have Xcode 11/12 or to build for simulator / armv7 device
|
||||||
|
|
||||||
|
## Configuring project
|
||||||
|
|
||||||
|
Only Xcode generator (`-G Xcode`) is supported!
|
||||||
|
|
||||||
|
As a minimum, you must pass the following variables to CMake:
|
||||||
|
|
||||||
|
- `BUNDLE_IDENTIFIER_PREFIX`: unique bundle identifier prefix, something like `com.MY-NAME`
|
||||||
|
- (if using legacy dependencies) `CMAKE_PREFIX_PATH`: path to the downloaded dependencies, e.g. `~/Downloads/vcmi-ios-depends/build/iphoneos`
|
||||||
|
|
||||||
|
There're a few [CMake presets](https://cmake.org/cmake/help/latest/manual/cmake-presets.7.html): for device (Conan and legacy dependencies) and for simulator, named `ios-device-conan`, `ios-device` and `ios-simulator` respectively. You can also create your local "user preset" to avoid typing variables each time, see example [here](https://gist.github.com/kambala-decapitator/59438030c34b53aed7d3895aaa48b718).
|
||||||
|
|
||||||
|
Open terminal and `cd` to the directory with source code. Configuration example for device with Conan:
|
||||||
|
|
||||||
|
`cmake --preset ios-device-conan \`
|
||||||
|
` -D BUNDLE_IDENTIFIER_PREFIX=com.MY-NAME`
|
||||||
|
|
||||||
|
By default build directory containing Xcode project will appear at `../build-ios-device-conan`, but you can change it with `-B` option.
|
||||||
|
|
||||||
|
### Building for device
|
||||||
|
|
||||||
|
To be able to build for iOS device, you must also specify codesigning settings. If you don't know your development team ID, open the generated Xcode project, open project settings (click **VCMI** with blue icon on the very top in the left panel with files), select **vcmiclient** target, open **Signing & Capabilities** tab and select yout team. Now you can copy the value from **Build Settings** tab - `DEVELOPMENT_TEAM` variable (paste it in the Filter field on the right) - click the greenish value - Other... - copy. Now you can pass it in `CMAKE_XCODE_ATTRIBUTE_DEVELOPMENT_TEAM` variable when configuring the project to avoid selecting the team manually every time CMake re-generates the project.
|
||||||
|
|
||||||
|
Advanced users who know exact private key and provisioning profile to sign with, can use `CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY` and `CMAKE_XCODE_ATTRIBUTE_PROVISIONING_PROFILE_SPECIFIER` variables instead. In this case you must also pass `-D CMAKE_XCODE_ATTRIBUTE_CODE_SIGN_STYLE=Manual`.
|
||||||
|
|
||||||
|
## Building project
|
||||||
|
|
||||||
|
### From Xcode IDE
|
||||||
|
|
||||||
|
Open `VCMI.xcodeproj` from the build directory, select `vcmiclient` scheme (the only one with nice icon) with your destination device/simulator and hit Run (Cmd+R).
|
||||||
|
|
||||||
|
You must also install game files, see [Installation on iOS](../players/Installation_iOS.md). But this is not necessary if you are going to run on simulator, as it is able to use game data from your Mac located at `~/Library/Application Support/vcmi`.
|
||||||
|
|
||||||
|
### From command line
|
||||||
|
|
||||||
|
`cmake --build `<path to build directory>` --target vcmiclient -- -quiet`
|
||||||
|
|
||||||
|
You can pass additional xcodebuild options after the `--`. Here `-quiet` is passed to reduce amount of output.
|
||||||
|
|
||||||
|
Alternatively, you can invoke `xcodebuild` directly.
|
||||||
|
|
||||||
|
There's also `ios-release-conan` configure and build preset that is used to create release build on CI.
|
||||||
|
|
||||||
|
## Creating ipa file for distribution
|
||||||
|
|
||||||
|
Invoke `cpack` after building:
|
||||||
|
|
||||||
|
`cpack -C Release`
|
||||||
|
|
||||||
|
This will generate file with extension **ipa** if you use CMake 3.25+and **zip** otherwise (simply change extension to ipa).
|
123
docs/developers/Building_macOS.md
Normal file
123
docs/developers/Building_macOS.md
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
< [Documentation](../Readme.md) / Building on macOS
|
||||||
|
|
||||||
|
# Requirements
|
||||||
|
|
||||||
|
1. C++ toolchain, either of:
|
||||||
|
- Xcode Command Line Tools (aka CLT): `sudo xcode-select --install`
|
||||||
|
- Xcode IDE: <https://developer.apple.com/xcode/>
|
||||||
|
- (not tested) other C++ compilers, e.g. gcc/clang from [Homebrew](https://brew.sh/)
|
||||||
|
2. CMake: `brew install --cask cmake` or get from <https://cmake.org/download/>
|
||||||
|
3. (optional) Ninja: `brew install ninja` or get from <https://github.com/ninja-build/ninja/releases>
|
||||||
|
|
||||||
|
# Obtaining source code
|
||||||
|
|
||||||
|
Clone <https://github.com/vcmi/vcmi> with submodules. Example for command line:
|
||||||
|
|
||||||
|
`git clone --recurse-submodules https://github.com/vcmi/vcmi.git`
|
||||||
|
|
||||||
|
# Obtaining dependencies
|
||||||
|
|
||||||
|
There're 2 ways to get dependencies automatically.
|
||||||
|
|
||||||
|
## Conan package manager
|
||||||
|
|
||||||
|
Please find detailed instructions in [VCMI repository](https://github.com/vcmi/vcmi/tree/develop/docs/conan.md). Note that the link points to the cutting-edge state in `develop` branch, for the latest release check the same document in the [master branch](https://github.com/vcmi/vcmi/tree/master/docs/conan.md).
|
||||||
|
|
||||||
|
On the step where you need to replace **PROFILE**, choose:
|
||||||
|
|
||||||
|
- if you're on an Intel Mac: `macos-intel`
|
||||||
|
- if you're on an Apple Silicon Mac: `macos-arm`
|
||||||
|
|
||||||
|
Note: if you wish to build 1.0 release in non-`Release` configuration, you should define `USE_CONAN_WITH_ALL_CONFIGS=1` environment variable when executing `conan install`.
|
||||||
|
|
||||||
|
## Homebrew
|
||||||
|
|
||||||
|
1. [Install Homebrew](https://brew.sh/)
|
||||||
|
2. Install dependencies:
|
||||||
|
`brew install boost minizip sdl2 sdl2_image sdl2_mixer sdl2_ttf tbb`
|
||||||
|
3. If you want to watch in-game videos, also install FFmpeg:
|
||||||
|
`brew install ffmpeg@4`
|
||||||
|
4. Install Qt dependency in either of the ways (note that you can skip this if you're not going to build Launcher):
|
||||||
|
- `brew install qt@5` for Qt 5 or `brew install qt` for Qt 6
|
||||||
|
- using [Qt Online Installer](https://www.qt.io/download) - choose **Go open source**
|
||||||
|
|
||||||
|
# Preparing build environment
|
||||||
|
|
||||||
|
This applies only to Xcode-based toolchain. If `xcrun -f clang` prints errors, then use either of the following ways:
|
||||||
|
|
||||||
|
- select an Xcode instance from Xcode application - Preferences - Locations - Command Line Tools
|
||||||
|
- use `xcode-select` utility to set Xcode or Xcode Command Line Tools path: for example,
|
||||||
|
`sudo xcode-select -s /Library/Developer/CommandLineTools`
|
||||||
|
- set `DEVELOPER_DIR` environment variable pointing to Xcode or Xcode Command Line Tools path: for example, `export DEVELOPER_DIR=/Applications/Xcode.app`
|
||||||
|
|
||||||
|
# Configuring project for building
|
||||||
|
|
||||||
|
Note that if you wish to use Qt Creator IDE, you should skip this step and configure respective variables inside the IDE.
|
||||||
|
|
||||||
|
1. In Terminal `cd` to the source code directory
|
||||||
|
2. Start assembling CMake invocation: type `cmake -S . -B BUILD_DIR` where *BUILD_DIR* can be any path, **don't press Return**
|
||||||
|
3. Decide which CMake generator you want to use:
|
||||||
|
- Makefiles: no extra option needed or pass `-G 'Unix Makefiles'`
|
||||||
|
- Ninja (if you have installed it): pass `-G Ninja`
|
||||||
|
- Xcode IDE (if you have installed it): pass `-G Xcode`
|
||||||
|
4. If you picked Makefiles or Ninja, pick desired *build type* - either of Debug / RelWithDebInfo / Release / MinSizeRel - and pass it in `CMAKE_BUILD_TYPE` option, for example: `-D CMAKE_BUILD_TYPE=Release`. If you don't pass this option, `RelWithDebInfo` will be used.
|
||||||
|
5. If you don't want to build Launcher, pass `-D ENABLE_LAUNCHER=OFF`
|
||||||
|
6. You can also pass `-Wno-dev` if you're not interested in CMake developer warnings
|
||||||
|
7. Next step depends on the dependency manager you have picked:
|
||||||
|
- Conan: pass `-D CMAKE_TOOLCHAIN_FILE=conan-generated/conan_toolchain.cmake` where **conan-generated** must be replaced with your directory choice
|
||||||
|
- Homebrew: if you installed FFmpeg or Qt 5, you need to pass `-D "CMAKE_PREFIX_PATH="` variable. See below what you can insert after `=` (but **before the closing quote**), multiple values must be separated with `;` (semicolon):
|
||||||
|
- if you installed FFmpeg, insert `$(brew --prefix ffmpeg@4)`
|
||||||
|
- if you installed Qt 5 from Homebrew, insert:`$(brew --prefix qt@5)`
|
||||||
|
- if you installed Qt from Online Installer, insert your path to Qt directory, for example: `/Users/kambala/dev/Qt-libs/5.15.2/Clang64`
|
||||||
|
- example for FFmpeg + Qt 5: `-D "CMAKE_PREFIX_PATH=$(brew --prefix ffmpeg@4);$(brew --prefix qt@5)"`
|
||||||
|
8. now press Return
|
||||||
|
|
||||||
|
# Building project
|
||||||
|
|
||||||
|
You must also install game files to be able to run the built version, see [Installation on macOS](players/Installation_macOS.md).
|
||||||
|
|
||||||
|
## From Xcode IDE
|
||||||
|
|
||||||
|
Open `VCMI.xcodeproj` from the build directory, select `vcmiclient` scheme and hit Run (Cmd+R). To build Launcher, select `vcmilauncher` scheme instead.
|
||||||
|
|
||||||
|
## From command line
|
||||||
|
|
||||||
|
`cmake --build `<path to build directory>
|
||||||
|
|
||||||
|
- If using Makefiles generator, you'd want to utilize all your CPU cores by appending `-- -j$(sysctl -n hw.ncpu)` to the above
|
||||||
|
- If using Xcode generator, you can also choose which configuration to build by appending `--config `<configuration name> to the above, for example: `--config Debug`
|
||||||
|
|
||||||
|
# Packaging project into DMG file
|
||||||
|
|
||||||
|
After building, run `cpack` from the build directory. If using Xcode generator, also pass `-C `<configuration name> with the same configuration that you used to build the project.
|
||||||
|
|
||||||
|
If you use Conan, it's expected that you use **conan-generated** directory at step 4 of [Conan package manager](Conan.md).
|
||||||
|
|
||||||
|
# Running VCMI
|
||||||
|
|
||||||
|
You can run VCMI from DMG, but it's will also work from your IDE be it Xcode or Qt Creator.
|
||||||
|
|
||||||
|
Alternatively you can run binaries directly from "bin" directory:
|
||||||
|
|
||||||
|
BUILD_DIR/bin/vcmilauncher
|
||||||
|
BUILD_DIR/bin/vcmiclient
|
||||||
|
BUILD_DIR/bin/vcmiserver
|
||||||
|
|
||||||
|
CMake include commands to copy all needed assets from source directory into "bin" on each build. They'll work when you build from Xcode too.
|
||||||
|
|
||||||
|
# Some useful debugging tips
|
||||||
|
|
||||||
|
Anyone who might want to debug builds, but new to macOS could find following commands useful:
|
||||||
|
|
||||||
|
- To attach DMG file from command line use
|
||||||
|
`hdiutil attach vcmi-1.0.dmg`
|
||||||
|
- Detach volume:
|
||||||
|
`hdiutil detach /Volumes/vcmi-1.0`
|
||||||
|
- To view dependency paths
|
||||||
|
`otool -L /Volumes/vcmi-1.0/VCMI.app/Contents/MacOS/vcmiclient`
|
||||||
|
- To display load commands such as LC_RPATH
|
||||||
|
`otool -l /Volumes/vcmi-1.0/VCMI.app/Contents/MacOS/vcmiclient`
|
||||||
|
|
||||||
|
# Troubleshooting
|
||||||
|
|
||||||
|
In case of troubles you can always consult our CI build scripts or contact the dev team via slack
|
124
docs/developers/Code_Structure.md
Normal file
124
docs/developers/Code_Structure.md
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
< [Documentation](../Readme.md) / Code Structure
|
||||||
|
|
||||||
|
The code of VCMI is divided into several main parts: client, server, lib and AIs, each one in a separate binary file.
|
||||||
|
|
||||||
|
# The big picture
|
||||||
|
|
||||||
|
VCMI contains three core projects: VCMI_lib (dll / so), VCMI_client (executable) and VCMI_server (executable). Server handles all game mechanics and events. Client presents game state and events to player and collects input from him.
|
||||||
|
|
||||||
|
During the game, we have one (and only one) server and one or more (one for each player computer) clients.
|
||||||
|
|
||||||
|
Important: State of the game and its mechanics are synchronized between clients and server. All changes to the game state or mechanics must be done by server which will send appropriate notices to clients.
|
||||||
|
|
||||||
|
## Game state
|
||||||
|
|
||||||
|
It's basically CGameState class object and everything that's accessible from it: map (with objects), player statuses, game options, etc.
|
||||||
|
|
||||||
|
## Bonus system
|
||||||
|
|
||||||
|
One of the more important pieces of VCMI is the [bonus system](Bonus_System.md). It's described in a separate article.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Most of VCMI configuration files uses Json format and located in "config" directory
|
||||||
|
|
||||||
|
### Json parser and writer
|
||||||
|
|
||||||
|
# Client
|
||||||
|
|
||||||
|
## Main purposes of client
|
||||||
|
|
||||||
|
Client is responsible for:
|
||||||
|
- displaying state of game to human player
|
||||||
|
- capturing player's actions and sending requests to server
|
||||||
|
- displaying changes in state of game indicated by server
|
||||||
|
|
||||||
|
## Rendering of graphics
|
||||||
|
|
||||||
|
Rendering of graphics relies heavily on SDL. Currently we do not have any wrapper for SDL internal structures and most of rendering is about blitting surfaces using SDL_BlitSurface. We have a few function that make rendering easier or make specific parts of rendering (like printing text). They are places in client/SDL_Extensions and client/SDL_Framerate (the second one contains code responsible for keeping appropriate framerate, it should work more smart than just SDL_Delay(miliseconds)).
|
||||||
|
In rendering, Interface object system is quite helpful. Its base is CIntObject class that is basically a base class for our library of GUI components and other objects.
|
||||||
|
|
||||||
|
# Server
|
||||||
|
|
||||||
|
## Main purposes of server
|
||||||
|
|
||||||
|
Server is responsible for:
|
||||||
|
|
||||||
|
- maintaining state of the game
|
||||||
|
- handling requests from all clients participating in game
|
||||||
|
- informing all clients about changes in state of the game that are
|
||||||
|
visible to them
|
||||||
|
|
||||||
|
# Lib
|
||||||
|
|
||||||
|
## Main purposes of lib
|
||||||
|
|
||||||
|
VCMI_Lib is a library that contains code common to server and client, so we avoid it's duplication. Important: the library code is common for client and server and used by them, but the library instance (in opposition to the library as file) is not shared by them! Both client and server create their own "copies" of lib with all its class instances.
|
||||||
|
|
||||||
|
iOS platform pioneered single process build, where server is a static library and not a dedicated executable. For that to work, the lib had to be wrapped into special namespace that is defined by client and server targets on iOS, so that single process is able to contain 2 versions of the library. To make it more convenient, a few macros were introduced that can be found in [Global.h](https://github.com/vcmi/vcmi/blob/develop/Global.h). The most important ones are `VCMI_LIB_NAMESPACE_BEGIN` and `VCMI_LIB_NAMESPACE_END` which must be used anywhere a symbol from the lib is needed, otherwise building iOS (or any other platform that would use single process approach) fails.
|
||||||
|
|
||||||
|
Lib contains code responsible for:
|
||||||
|
|
||||||
|
- handling most of Heroes III files (.lod, .txt setting files)
|
||||||
|
- storing information common to server and client like state of the game
|
||||||
|
- managing armies, buildings, artifacts, spells, bonuses and other game objects
|
||||||
|
- handling general game mechanics and related actions (only adventure map objects; it's an unwanted remnant of past development - all game mechanics should be handled by the server)
|
||||||
|
- networking and serialization
|
||||||
|
|
||||||
|
### Serialization
|
||||||
|
|
||||||
|
The serialization framework can serialize basic types, several standard containers among smart pointers and custom objects. Its design is based on the [boost serialization libraries](http://www.boost.org/doc/libs/1_52_0/libs/serialization/doc/index.html).
|
||||||
|
In addition to the basic functionality it provides light-weight transfer of CGObjectInstance objects by sending only the index/id.
|
||||||
|
|
||||||
|
Serialization page for all the details.
|
||||||
|
|
||||||
|
### Wrapped namespace examples
|
||||||
|
|
||||||
|
#### Inside the lib
|
||||||
|
|
||||||
|
Both header and implementation of a new class inside the lib should have the following structure:
|
||||||
|
|
||||||
|
`<includes>`
|
||||||
|
`VCMI_LIB_NAMESPACE_BEGIN`
|
||||||
|
`<code>`
|
||||||
|
`VCMI_LIB_NAMESPACE_END`
|
||||||
|
|
||||||
|
#### Headers outside the lib
|
||||||
|
|
||||||
|
Forward declarations of the lib in headers of other parts of the project need to be wrapped in the macros:
|
||||||
|
|
||||||
|
`<includes>`
|
||||||
|
`VCMI_LIB_NAMESPACE_BEGIN`
|
||||||
|
`<lib forward declarations>`
|
||||||
|
`VCMI_LIB_NAMESPACE_END`
|
||||||
|
`<other forward declarations>`
|
||||||
|
`<classes>`
|
||||||
|
|
||||||
|
|
||||||
|
#### New project part
|
||||||
|
|
||||||
|
If you're creating new project part, place `VCMI_LIB_USING_NAMESPACE` in its `StdInc.h` to be able to use lib classes without explicit namespace in implementation files. Example: <https://github.com/vcmi/vcmi/blob/develop/launcher/StdInc.h>
|
||||||
|
|
||||||
|
# Artificial Intelligence
|
||||||
|
|
||||||
|
## StupidAI
|
||||||
|
|
||||||
|
Stupid AI is recent and used battle AI.
|
||||||
|
|
||||||
|
## Adventure AI
|
||||||
|
|
||||||
|
VCAI module is currently developed agent-based system driven by goals and heroes.
|
||||||
|
|
||||||
|
## Programming challenge
|
||||||
|
|
||||||
|
## Fuzzy logic
|
||||||
|
|
||||||
|
VCMI includes [FuzzyLite](http://code.google.com/p/fuzzy-lite/) library to make use of fuzzy rule-based algorithms. They are useful to handle uncertanity and resemble human behaviour who takes decisions based on rough observations. FuzzyLite is linked as separate static library in AI/FuzzyLite.lib file.
|
||||||
|
|
||||||
|
# Utilities
|
||||||
|
|
||||||
|
## Launcher
|
||||||
|
|
||||||
|
## Duels
|
||||||
|
|
||||||
|
## ERM parser
|
877
docs/developers/Coding_Guidelines.md
Normal file
877
docs/developers/Coding_Guidelines.md
Normal file
@ -0,0 +1,877 @@
|
|||||||
|
< [Documentation](../Readme.md) / Coding Guidelines
|
||||||
|
|
||||||
|
## C++ Standard
|
||||||
|
|
||||||
|
VCMI implementation bases on C++17 standard. Any feature is acceptable as long as it's will pass build on our CI, but there is list below on what is already being used.
|
||||||
|
|
||||||
|
Any compiler supporting C++17 should work, but this has not been thoroughly tested. You can find information about extensions and compiler support at http://en.cppreference.com/w/cpp/compiler_support
|
||||||
|
|
||||||
|
## Style Guidelines
|
||||||
|
|
||||||
|
In order to keep the code consistent, please use the following conventions. From here on 'good' and 'bad' are used to attribute things that would make the coding style match, or not match. It is not a judgment call on your coding abilities, but more of a style and look call. Please try to follow these guidelines to ensure prettiness.
|
||||||
|
|
||||||
|
### Indentation
|
||||||
|
|
||||||
|
Use tabs for indentation. If you are modifying someone else's code, try to keep the coding style similar.
|
||||||
|
|
||||||
|
### Where to put braces
|
||||||
|
|
||||||
|
Inside a code block put the opening brace on the next line after the current statement:
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
if(a)
|
||||||
|
{
|
||||||
|
code();
|
||||||
|
code();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
if(a) {
|
||||||
|
code();
|
||||||
|
code();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Avoid using unnecessary open/close braces, vertical space is usually limited:
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
if(a)
|
||||||
|
code();
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
if(a) {
|
||||||
|
code();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Unless there are either multiple hierarchical conditions being used or that the condition cannot fit into a single line.
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
if(a)
|
||||||
|
{
|
||||||
|
if(b)
|
||||||
|
code();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
if(a)
|
||||||
|
if(b)
|
||||||
|
code();
|
||||||
|
```
|
||||||
|
|
||||||
|
If there are brackets inside the body, outside brackets are required.
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
if(a)
|
||||||
|
{
|
||||||
|
for(auto elem : list)
|
||||||
|
{
|
||||||
|
code();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
if(a)
|
||||||
|
for(auto elem : list)
|
||||||
|
{
|
||||||
|
code();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If "else" branch has brackets then "if" should also have brackets even if it is one line.
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
if(a)
|
||||||
|
{
|
||||||
|
code();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(auto elem : list)
|
||||||
|
{
|
||||||
|
code();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
if(a)
|
||||||
|
code();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for(auto elem : list)
|
||||||
|
{
|
||||||
|
code();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If you intentionally want to avoid usage of "else if" and keep if body indent make sure to use braces.
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
if(a)
|
||||||
|
{
|
||||||
|
code();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(b)
|
||||||
|
code();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
if(a)
|
||||||
|
code();
|
||||||
|
else
|
||||||
|
if(b)
|
||||||
|
code();
|
||||||
|
```
|
||||||
|
|
||||||
|
When defining a method, use a new line for the brace, like this:
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
void method()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
void Method() {
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Use whitespace for clarity
|
||||||
|
|
||||||
|
Use white space in expressions liberally, except in the presence of parenthesis.
|
||||||
|
|
||||||
|
**Good:**
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
if(a + 5 > method(blah('a') + 4))
|
||||||
|
foo += 24;
|
||||||
|
```
|
||||||
|
|
||||||
|
**Bad:**
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
if(a+5>method(blah('a')+4))
|
||||||
|
foo+=24;
|
||||||
|
```
|
||||||
|
|
||||||
|
Between if, for, while,.. and the opening brace there shouldn't be a whitespace. The keywords are highlighted, so they don't need further separation.
|
||||||
|
|
||||||
|
### Where to put spaces
|
||||||
|
|
||||||
|
Use a space before and after the address or pointer character in a pointer declaration.
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
CIntObject * images[100];
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
CIntObject* images[100]; or
|
||||||
|
CIntObject *images[100];
|
||||||
|
```
|
||||||
|
|
||||||
|
Do not use spaces before parentheses.
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
if(a)
|
||||||
|
code();
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
if (a)
|
||||||
|
code();
|
||||||
|
```
|
||||||
|
|
||||||
|
Do not use extra spaces around conditions inside parentheses.
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
if(a && b)
|
||||||
|
code();
|
||||||
|
|
||||||
|
if(a && (b || c))
|
||||||
|
code();
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
if( a && b )
|
||||||
|
code();
|
||||||
|
|
||||||
|
if(a && ( b || c ))
|
||||||
|
code();
|
||||||
|
```
|
||||||
|
|
||||||
|
Do not use more than one space between operators.
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
if((a && b) || (c + 1 == d))
|
||||||
|
code();
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
if((a && b) || (c + 1 == d))
|
||||||
|
code();
|
||||||
|
|
||||||
|
if((a && b) || (c + 1 == d))
|
||||||
|
code();
|
||||||
|
```
|
||||||
|
|
||||||
|
### Where to use parentheses
|
||||||
|
|
||||||
|
When allocating objects, don't use parentheses for creating stack-based objects by zero param c-tors to avoid c++ most vexing parse and use parentheses for creating heap-based objects.
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
std::vector<int> v;
|
||||||
|
CGBoat btn = new CGBoat();
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
std::vector<int> v(); // shouldn't compile anyway
|
||||||
|
CGBoat btn = new CGBoat;
|
||||||
|
```
|
||||||
|
|
||||||
|
Avoid overuse of parentheses:
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
if(a && (b + 1))
|
||||||
|
return c == d;
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
if((a && (b + 1)))
|
||||||
|
return (c == d);
|
||||||
|
```
|
||||||
|
|
||||||
|
### Class declaration
|
||||||
|
|
||||||
|
Base class list must be on same line with class name.
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
class CClass : public CClassBaseOne, public CClassBaseOne
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
bool parameter;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CClass();
|
||||||
|
~CClass();
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
When 'private:', 'public:' and other labels are not on the line after opening brackets there must be a new line before them.
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
class CClass
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CClass();
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
class CClass
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
public:
|
||||||
|
CClass();
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
class CClass
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
int id;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CClass();
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
class CClass
|
||||||
|
{
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int id;
|
||||||
|
|
||||||
|
public:
|
||||||
|
CClass();
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Constructor base class and member initialization
|
||||||
|
|
||||||
|
Constructor member and base class initialization must be on new line, indented with tab with leading colon.
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
CClass::CClass()
|
||||||
|
: CClassBaseOne(true, nullptr), id(0), bool parameters(false)
|
||||||
|
{
|
||||||
|
code();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Switch statement
|
||||||
|
|
||||||
|
Switch statements have the case at the same indentation as the switch.
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
switch(alignment)
|
||||||
|
{
|
||||||
|
case EAlignment::EVIL:
|
||||||
|
do_that();
|
||||||
|
break;
|
||||||
|
case EAlignment::GOOD:
|
||||||
|
do_that();
|
||||||
|
break;
|
||||||
|
case EAlignment::NEUTRAL:
|
||||||
|
do_that();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
do_that();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
switch(alignment)
|
||||||
|
{
|
||||||
|
case EAlignment::EVIL:
|
||||||
|
do_that();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
do_that();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(alignment)
|
||||||
|
{
|
||||||
|
case EAlignment::EVIL:
|
||||||
|
do_that();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
do_that();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(alignment)
|
||||||
|
{
|
||||||
|
case EAlignment::EVIL:
|
||||||
|
{
|
||||||
|
do_that();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
do_that();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lambda expressions
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
auto lambda = [this, a, &b](int3 & tile, int index) -> bool
|
||||||
|
{
|
||||||
|
do_that();
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
auto lambda = [this,a,&b](int3 & tile, int index)->bool{do_that();};
|
||||||
|
```
|
||||||
|
|
||||||
|
Empty parameter list is required even if function takes no arguments.
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
auto lambda = []()
|
||||||
|
{
|
||||||
|
do_that();
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
auto lambda = []
|
||||||
|
{
|
||||||
|
do_that();
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Do not use inline lambda expressions inside if-else, for and other conditions.
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
auto lambda = []()
|
||||||
|
{
|
||||||
|
do_that();
|
||||||
|
};
|
||||||
|
if(lambda)
|
||||||
|
{
|
||||||
|
code();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
if([]()
|
||||||
|
{
|
||||||
|
do_that();
|
||||||
|
})
|
||||||
|
{
|
||||||
|
code();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Do not pass inline lambda expressions as parameter unless it's the last parameter.
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
auto lambda = []()
|
||||||
|
{
|
||||||
|
do_that();
|
||||||
|
};
|
||||||
|
obj->someMethod(lambda, true);
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
obj->someMethod([]()
|
||||||
|
{
|
||||||
|
do_that();
|
||||||
|
}, true);
|
||||||
|
```
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
obj->someMethod(true, []()
|
||||||
|
{
|
||||||
|
do_that();
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
### Serialization
|
||||||
|
|
||||||
|
Serialization of each element must be on it's own line since this make debugging easier.
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
template <typename Handler> void serialize(Handler & h, const int version)
|
||||||
|
{
|
||||||
|
h & identifier;
|
||||||
|
h & description;
|
||||||
|
h & name;
|
||||||
|
h & dependencies;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
template <typename Handler> void serialize(Handler & h, const int version)
|
||||||
|
{
|
||||||
|
h & identifier & description & name & dependencies;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Save backward compatibility code is exception when extra brackets are always useful.
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
template <typename Handler> void serialize(Handler & h, const int version)
|
||||||
|
{
|
||||||
|
h & identifier;
|
||||||
|
h & description;
|
||||||
|
if(version >= 123)
|
||||||
|
{
|
||||||
|
h & totalValue;
|
||||||
|
}
|
||||||
|
else if(!h.saving)
|
||||||
|
{
|
||||||
|
totalValue = 200;
|
||||||
|
}
|
||||||
|
h & name;
|
||||||
|
h & dependencies;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
template <typename Handler> void serialize(Handler & h, const int version)
|
||||||
|
{
|
||||||
|
h & identifier;
|
||||||
|
h & description;
|
||||||
|
if(version >= 123)
|
||||||
|
h & totalValue;
|
||||||
|
else if(!h.saving)
|
||||||
|
totalValue = 200;
|
||||||
|
h & name;
|
||||||
|
h & dependencies;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### File headers
|
||||||
|
|
||||||
|
For any new files, please paste the following info block at the very top of the source file:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
/*
|
||||||
|
* Name_of_File.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
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
```
|
||||||
|
|
||||||
|
The above notice have to be included both in header and source files (.h/.cpp).
|
||||||
|
|
||||||
|
### Code order in files
|
||||||
|
|
||||||
|
For any header or source file code must be in following order:
|
||||||
|
|
||||||
|
1. Licensing information
|
||||||
|
2. pragma once preprocessor directive
|
||||||
|
3. include directives
|
||||||
|
4. Forward declarations
|
||||||
|
5. All other code
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
/*
|
||||||
|
* Name_of_File.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 "Header.h"
|
||||||
|
|
||||||
|
class CGObjectInstance;
|
||||||
|
struct CPackForClient;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Where and how to comment
|
||||||
|
|
||||||
|
If you comment on the same line with code there must be one single space between code and slashes.
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
if(a)
|
||||||
|
{
|
||||||
|
code(); //Do something
|
||||||
|
}
|
||||||
|
else // Do something.
|
||||||
|
{
|
||||||
|
code(); // Do something.
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
if(a)
|
||||||
|
{
|
||||||
|
code();//Do something
|
||||||
|
}
|
||||||
|
else // Do something.
|
||||||
|
{
|
||||||
|
code(); // TODO:
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If you add single-line comment on own line slashes must have same indent as code around:
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
// Do something
|
||||||
|
if(a)
|
||||||
|
{
|
||||||
|
//Do something
|
||||||
|
for(auto item : list)
|
||||||
|
code();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
// Do something
|
||||||
|
if(a)
|
||||||
|
{
|
||||||
|
//Do something
|
||||||
|
for(auto item : list)
|
||||||
|
code();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Avoid comments inside multi-line if-else conditions. If your conditions are too hard to understand without additional comments this usually means that code need refactoring. Example given below is need improvement though. **FIXME**
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
bool isMyHeroAlive = a && b || (c + 1 > 15);
|
||||||
|
bool canMyHeroMove = myTurn && hero.movePoints > 0;
|
||||||
|
if(isMyHeroAlive && canMyHeroMove)
|
||||||
|
{
|
||||||
|
code();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
if((a && b || (c + 1 > 15)) //Check if hero still alive
|
||||||
|
&& myTurn && hero.movePoints > 0) //Check if hero can move
|
||||||
|
{
|
||||||
|
code();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You should write a comment before the class definition which describes shortly the class. 1-2 sentences are enough. Methods and class data members should be commented if they aren't self-describing only. Getters/Setters, simple methods where the purpose is clear or similar methods shouldn't be commented, because vertical space is usually limited. The style of documentation comments should be the three slashes-style: ///.
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
/// Returns true if a debug/trace log message will be logged, false if not.
|
||||||
|
/// Useful if performance is important and concatenating the log message is a expensive task.
|
||||||
|
bool isDebugEnabled() const;
|
||||||
|
bool isTraceEnabled() const;
|
||||||
|
```
|
||||||
|
|
||||||
|
The above example doesn't follow a strict scheme on how to comment a method. It describes two methods in one go. Comments should be kept short.
|
||||||
|
|
||||||
|
If you need a more detailed description for a method you can use such style:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
/// <A short one line description>
|
||||||
|
///
|
||||||
|
/// <Longer description>
|
||||||
|
/// <May span multiple lines or paragraphs as needed>
|
||||||
|
///
|
||||||
|
/// @param Description of method's or function's input parameter
|
||||||
|
/// @param ...
|
||||||
|
/// @return Description of the return value
|
||||||
|
```
|
||||||
|
|
||||||
|
A good essay about writing comments: http://ardalis.com/when-to-comment-your-code
|
||||||
|
|
||||||
|
### Casing
|
||||||
|
|
||||||
|
Local variables and methods start with a lowercase letter and use the camel casing. Classes/Structs start with an uppercase letter and use the camel casing as well. Macros and constants are written uppercase.
|
||||||
|
|
||||||
|
### Line length
|
||||||
|
|
||||||
|
The line length for c++ source code is 120 columns. If your function declaration arguments go beyond this point, please align your arguments to match the opening brace. For best results use the same number of tabs used on the first line followed by enough spaces to align the arguments.
|
||||||
|
|
||||||
|
### Warnings
|
||||||
|
|
||||||
|
Avoid use of #pragma to disable warnings. Compile at warning level 3. Avoid commiting code with new warnings.
|
||||||
|
|
||||||
|
### File/directory naming
|
||||||
|
|
||||||
|
Compilation units(.cpp,.h files) start with a uppercase letter and are named like the name of a class which resides in that file if possible. Header only files start with a uppercase letter. JSON files start with a lowercase letter and use the camel casing.
|
||||||
|
|
||||||
|
Directories start with a lowercase letter and use the camel casing where necessary.
|
||||||
|
|
||||||
|
### Logging
|
||||||
|
|
||||||
|
Outdated. There is separate entry for [Logging API](Logging_API.md)
|
||||||
|
|
||||||
|
If you want to trace the control flow of VCMI, then you should use the macro LOG_TRACE or LOG_TRACE_PARAMS. The first one prints a message when the function is entered or leaved. The name of the function will also be logged. In addition to this the second macro, let's you specify parameters which you want to print. You should print traces with parameters like this:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
LOG_TRACE_PARAMS(logGlobal, "hero '%s', spellId '%d', pos '%s'.", hero, spellId, pos);
|
||||||
|
```
|
||||||
|
|
||||||
|
When using the macro every "simple" parameter should be logged. The parameter can be a number, a string or a type with a ostream operator\<\<. You should not log contents of a whole text file, a byte array or sth. like this. If there is a simple type with a few members you want to log, you should write an ostream operator\<\<. The produced message can look like this:
|
||||||
|
|
||||||
|
`{BattleAction: side '0', stackNumber '1', actionType 'Walk and attack', destinationTile '{BattleHex: x '7', y '1', hex '24'}', additionalInfo '7', selectedStack '-1'}`
|
||||||
|
|
||||||
|
The name of the type should be logged first, e.g. {TYPE_NAME: members...}. The members of the object will be logged like logging trace parameters. Collection types (vector, list, ...) should be logged this way: \[{BattleHex: ...}, {...}\] There is no format which has to be followed strictly, so if there is a reason to format members/objects in a different way, then this is ok.
|
||||||
|
|
||||||
|
## Best practices
|
||||||
|
|
||||||
|
### Avoid code duplication
|
||||||
|
|
||||||
|
Avoid code duplication or don't repeat yourself(DRY) is the most important aspect in programming. Code duplication of any kind can lead to inconsistency and is much harder to maintain. If one part of the system gets changed you have to change the code in several places. This process is error-prone and leads often to problems. Here you can read more about the DRY principle: [<http://en.wikipedia.org/wiki/Don%27t_repeat_yourself>](http://en.wikipedia.org/wiki/Don%27t_repeat_yourself)
|
||||||
|
|
||||||
|
### Do not use uncommon abbrevations
|
||||||
|
|
||||||
|
Do not use uncommon abbrevations for class, method, parameter and global object names.
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
CArt * getRandomArt(...)
|
||||||
|
class CIntObject
|
||||||
|
```
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
CArtifact * getRandomArtifact(...)
|
||||||
|
class CInterfaceObject
|
||||||
|
```
|
||||||
|
|
||||||
|
### Loop handling
|
||||||
|
|
||||||
|
Use range-based for loops. It should be used in any case except you absolutely need iterator, then you may use a simple for loop.
|
||||||
|
|
||||||
|
The loop counter should be of type int, unless you are sure you won't need negative indices -- then use size_t.
|
||||||
|
|
||||||
|
### Include guards
|
||||||
|
|
||||||
|
Use #pragma once instead of the traditional #ifndef/#define/#endif include guards.
|
||||||
|
|
||||||
|
### Pre compiled header file
|
||||||
|
|
||||||
|
The header StdInc.h should be included in every compilation unit. It has to be included before any C macro and before any c++ statements. Pre compiled header should not be changed, except any important thing is missing. The StdInc includes most Boost libraries and nearly all standard STL and C libraries, so you don’t have to include them by yourself.
|
||||||
|
|
||||||
|
### Enumeration handling
|
||||||
|
|
||||||
|
Do not declare enumerations in global namespace. It is better to use strongly typed enum or to wrap them in class or namespace to avoid polluting global namespace:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
enum class EAlignment
|
||||||
|
{
|
||||||
|
GOOD,
|
||||||
|
EVIL,
|
||||||
|
NEUTRAL
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace EAlignment
|
||||||
|
{
|
||||||
|
enum EAlignment
|
||||||
|
{
|
||||||
|
GOOD, EVIL, NEUTRAL
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Avoid senseless comments
|
||||||
|
|
||||||
|
If the comment duplicates the name of commented member, it's better if it wouldn't exist at all. It just increases maintenance cost. Bad:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
size_t getHeroesCount(); //gets count of heroes (surprise?)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Class handling
|
||||||
|
|
||||||
|
There is no definitive rule which has to be followed strictly. You can freely decide if you want to pack your own classes, where you are programming on, all in one file or each in one file. It's more important that you feel comfortable with the code, than consistency overall the project. VCMI has several container class files, so if you got one additional class to them than just add it to them instead of adding new files.
|
||||||
|
|
||||||
|
### Functions and interfaces
|
||||||
|
|
||||||
|
Don't return const objects or primitive types from functions -- it's pointless. Also, don't return pointers to non-const game data objects from callbacks to player interfaces.
|
||||||
|
|
||||||
|
Bad:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
const std::vector<CGObjectInstance *> guardingCreatures(int3 pos) const;
|
||||||
|
```
|
||||||
|
|
||||||
|
Good:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
std::vector<const CGObjectInstance *> guardingCreatures(int3 pos) const;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Sources
|
||||||
|
|
||||||
|
[Mono project coding guidelines](http://www.mono-project.com/Coding_Guidelines)
|
@ -1,3 +1,5 @@
|
|||||||
|
< [Documentation](../Readme.md) / Using Conan
|
||||||
|
|
||||||
# Using dependencies from Conan
|
# Using dependencies from Conan
|
||||||
|
|
||||||
[Conan](https://conan.io/) is a package manager for C/C++. We provide prebuilt binary dependencies for some platforms that are used by our CI, but they can also be consumed by users to build VCMI. However, it's not required to use only the prebuilt binaries: you can build them from source as well.
|
[Conan](https://conan.io/) is a package manager for C/C++. We provide prebuilt binary dependencies for some platforms that are used by our CI, but they can also be consumed by users to build VCMI. However, it's not required to use only the prebuilt binaries: you can build them from source as well.
|
||||||
@ -8,12 +10,10 @@ The following platforms are supported and known to work, others might require ch
|
|||||||
|
|
||||||
- **macOS**: x86_64 (Intel) - target 10.13 (High Sierra), arm64 (Apple Silicon) - target 11.0 (Big Sur)
|
- **macOS**: x86_64 (Intel) - target 10.13 (High Sierra), arm64 (Apple Silicon) - target 11.0 (Big Sur)
|
||||||
- **iOS**: arm64 - target 12.0
|
- **iOS**: arm64 - target 12.0
|
||||||
- **Windows**: x86_64 and x86 fully supported with building from Linux
|
|
||||||
- **Android**: armeabi-v7a (32-bit ARM) - target 4.4 (API level 19), aarch64-v8a (64-bit ARM) - target 5.0 (API level 21)
|
|
||||||
|
|
||||||
## Getting started
|
## Getting started
|
||||||
|
|
||||||
1. [Install Conan](https://docs.conan.io/en/latest/installation.html). Currently we support only Conan v1, you can install it with `pip` like this: `pip3 install 'conan<2.0'`
|
1. [Install Conan](https://docs.conan.io/en/latest/installation.html)
|
||||||
2. Execute in terminal: `conan profile new default --detect`
|
2. Execute in terminal: `conan profile new default --detect`
|
||||||
|
|
||||||
## Download dependencies
|
## Download dependencies
|
||||||
@ -22,45 +22,36 @@ The following platforms are supported and known to work, others might require ch
|
|||||||
|
|
||||||
1. Check if your build environment can use the prebuilt binaries: basically, that your compiler version (or Xcode major version) matches the information below. If you're unsure, simply advance to the next step.
|
1. Check if your build environment can use the prebuilt binaries: basically, that your compiler version (or Xcode major version) matches the information below. If you're unsure, simply advance to the next step.
|
||||||
|
|
||||||
- **macOS**: libraries are built with Apple clang 14 (Xcode 14.2), should be consumable by Xcode and Xcode CLT 14.x (older library versions are also available for Xcode 13, see Releases in the respective repo)
|
- macOS: libraries are built with Apple clang 13 (Xcode 13.4.1), should be consumable by Xcode and Xcode CLT 13.x
|
||||||
- **iOS**: libraries are built with Apple clang 14 (Xcode 14.2), should be consumable by Xcode 14.x (older library versions are also available for Xcode 13, see Releases in the respective repo)
|
- iOS: libraries are built with Apple clang 13 (Xcode 13.4.1), should be consumable by Xcode 13.x
|
||||||
- **Windows**: libraries are built with x86_64-mingw-w64-gcc version 10 (which is available in repositories of Ubuntu 22.04)
|
|
||||||
- **Android**: libraries are built with NDK r25c (25.2.9519653)
|
|
||||||
|
|
||||||
2. Download the binaries archive and unpack it to `~/.conan` directory:
|
2. Download the binaries archive and unpack it to `~/.conan` directory:
|
||||||
|
|
||||||
- [macOS](https://github.com/vcmi/vcmi-deps-macos/releases/latest): pick **intel.txz** if you have Intel Mac, otherwise - **intel-cross-arm.txz**
|
- [macOS](https://github.com/vcmi/vcmi-deps-macos/releases/latest): pick **intel.txz** if you have Intel Mac, otherwise - **intel-cross-arm.txz**
|
||||||
- [iOS](https://github.com/vcmi/vcmi-ios-deps/releases/latest)
|
- [iOS](https://github.com/vcmi/vcmi-ios-deps/releases/latest)
|
||||||
- [Windows](https://github.com/vcmi/vcmi-deps-windows-conan/releases/latest): pick **vcmi-deps-windows-conan-w64.tgz**
|
|
||||||
if you want x86, otherwise pick **vcmi-deps-windows-conan.tgz**
|
|
||||||
- [Android](https://github.com/vcmi/vcmi-dependencies/releases)
|
|
||||||
|
|
||||||
3. Only if you have Apple Silicon Mac and trying to build for macOS or iOS:
|
3. Only if you have Apple Silicon Mac and trying to build for macOS or iOS: follow [instructions how to build Qt host tools for Apple Silicon](https://github.com/vcmi/vcmi-ios-deps#note-for-arm-macs), on step 3 copy them to `~/.conan/data/qt/5.15.x/_/_/package/SOME_HASH/bin` (`5.15.x` and `SOME_HASH` are placeholders).
|
||||||
|
|
||||||
1. Open file `~/.conan/data/qt/5.15.x/_/_/export/conanfile.py` (`5.15.x` is a placeholder), search for string `Designer` (there should be only one match), comment this line and the one above it by inserting `#` in the beginning, and save the file.
|
|
||||||
2. (optional) If you don't want to use Rosetta, follow [instructions how to build Qt host tools for Apple Silicon](https://github.com/vcmi/vcmi-ios-deps#note-for-arm-macs), on step 3 copy them to `~/.conan/data/qt/5.15.x/_/_/package/SOME_HASH/bin` (`5.15.x` and `SOME_HASH` are placeholders). Make sure **not** to copy `qt.conf`!
|
|
||||||
|
|
||||||
## Generate CMake integration
|
## Generate CMake integration
|
||||||
|
|
||||||
Conan needs to generate CMake toolchain file to make dependencies available to CMake. See `CMakeDeps` and `CMakeToolchain` [in the official documentation](https://docs.conan.io/en/latest/reference/conanfile/tools/cmake.html) for details.
|
Conan needs to generate CMake toolchain file to make dependencies available to CMake. See `CMakeDeps` and `CMakeToolchain` [in the official documentation](https://docs.conan.io/en/latest/reference/conanfile/tools/cmake.html) for details.
|
||||||
|
|
||||||
In terminal `cd` to the VCMI source directory and run the following command. Also check subsections for additional requirements on consuming prebuilt binaries.
|
In terminal `cd` to the VCMI source directory and run the following command. If you want to download prebuilt binaries from ConanCenter, also read the [next section](#using-prebuilt-binaries-from-conancenter).
|
||||||
|
|
||||||
<pre>
|
```sh
|
||||||
conan install . \
|
conan install . \
|
||||||
--install-folder=<b><i>conan-generated</i></b> \
|
--install-folder=<b><i>conan-generated</i></b> \
|
||||||
--no-imports \
|
--no-imports \
|
||||||
--build=<b><i>never</i></b> \
|
--build=<b><i>never</i></b> \
|
||||||
--profile:build=default \
|
--profile:build=default \
|
||||||
--profile:host=<b><i>CI/conan/PROFILE</i></b>
|
--profile:host=<b><i>CI/conan/PROFILE</i></b>
|
||||||
</pre>
|
```
|
||||||
|
|
||||||
The highlighted parts can be adjusted:
|
The highlighted parts can be adjusted:
|
||||||
|
|
||||||
- ***conan-generated***: directory (absolute or relative) where the generated files will appear. This value is used in CMake presets from VCMI, but you can actually use any directory and override it in your local CMake presets.
|
- ***conan-generated***: directory (absolute or relative) where the generated files will appear. This value is used in CMake presets from VCMI, but you can actually use any directory and override it in your local CMake presets.
|
||||||
- ***never***: use this value to avoid building any dependency from source. You can also use `missing` to build recipes, that are not present in your local cache, from source.
|
- ***never***: use this value to avoid building any dependency from source. You can also use `missing` to build recipes, that are not present in your local cache, from source.
|
||||||
- ***CI/conan/PROFILE***: if you want to consume our prebuilt binaries, ***PROFILE*** must be replaced with one of filenames from our [Conan profiles directory](../CI/conan) (determining the right file should be straight-forward). Otherwise, either select one of our profiles or replace ***CI/conan/PROFILE*** with `default` (your default profile).
|
- ***CI/conan/PROFILE***: if you want to consume our prebuilt binaries, ***PROFILE*** must be replaced with one of filenames from our [Conan profiles directory](../../CI/conan) (determining the right file should be straight-forward). Otherwise, either select one of our profiles or replace ***CI/conan/PROFILE*** with `default` (your default profile).
|
||||||
- ***note for Windows x86***: use profile mingw32-linux.jinja for building instead of mingw64-linux.jinja
|
|
||||||
|
|
||||||
If you use `--build=never` and this command fails, then it means that you can't use prebuilt binaries out of the box. For example, try using `--build=missing` instead.
|
If you use `--build=never` and this command fails, then it means that you can't use prebuilt binaries out of the box. For example, try using `--build=missing` instead.
|
||||||
|
|
||||||
@ -68,10 +59,6 @@ VCMI "recipe" also has some options that you can specify. For example, if you do
|
|||||||
|
|
||||||
_Note_: you can find full reference of this command [in the official documentation](https://docs.conan.io/en/latest/reference/commands/consumer/install.html) or by executing `conan help install`.
|
_Note_: you can find full reference of this command [in the official documentation](https://docs.conan.io/en/latest/reference/commands/consumer/install.html) or by executing `conan help install`.
|
||||||
|
|
||||||
### Using our prebuilt binaries for macOS/iOS
|
|
||||||
|
|
||||||
We use custom recipes for some libraries that are provided by the OS. You must additionally pass `-o with_apple_system_libs=True` for `conan install` to use them.
|
|
||||||
|
|
||||||
### Using prebuilt binaries from ConanCenter
|
### Using prebuilt binaries from ConanCenter
|
||||||
|
|
||||||
First, check if binaries for [your platform](https://github.com/conan-io/conan-center-index/blob/master/docs/supported_platforms_and_configurations.md) are produced.
|
First, check if binaries for [your platform](https://github.com/conan-io/conan-center-index/blob/master/docs/supported_platforms_and_configurations.md) are produced.
|
||||||
@ -81,25 +68,6 @@ You must adjust the above `conan install` command:
|
|||||||
1. Replace ***CI/conan/PROFILE*** with `default`.
|
1. Replace ***CI/conan/PROFILE*** with `default`.
|
||||||
2. Additionally pass `-o default_options_of_requirements=True`: this disables all custom options of our `conanfile.py` to match ConanCenter builds.
|
2. Additionally pass `-o default_options_of_requirements=True`: this disables all custom options of our `conanfile.py` to match ConanCenter builds.
|
||||||
|
|
||||||
### Building dependencies from source
|
|
||||||
|
|
||||||
This subsection describes platform specifics to build libraries from source properly.
|
|
||||||
|
|
||||||
#### Building for macOS/iOS
|
|
||||||
|
|
||||||
- To build Locale module of Boost in versions >= 1.81, you must use `compiler.cppstd=11` Conan setting (our profiles already contain it). To use it with another profile, either add this setting to your _host_ profile or pass `-s compiler.cppstd=11` on the command line.
|
|
||||||
- If you wish to build dependencies against system libraries (like our prebuilt ones do), follow [below instructions](#using-recipes-for-system-libraries) executing `conan create` for all directories. Don't forget to pass `-o with_apple_system_libs=True` to `conan install` afterwards.
|
|
||||||
|
|
||||||
#### Building for Android
|
|
||||||
|
|
||||||
Android has issues loading self-built shared Zlib library because binary name is identical to the system one, so we enforce using the OS-provided library. To achieve that, follow [below instructions](#using-recipes-for-system-libraries), you only need `zlib` directory.
|
|
||||||
|
|
||||||
##### Using recipes for system libraries
|
|
||||||
|
|
||||||
1. Clone/download https://github.com/kambala-decapitator/conan-system-libs
|
|
||||||
2. Execute `conan create PACKAGE vcmi/apple`, where `PACKAGE` is a directory path in that repository. Do it for each library you need.
|
|
||||||
3. Now you can execute `conan install` to build all dependencies.
|
|
||||||
|
|
||||||
## Configure project for building
|
## Configure project for building
|
||||||
|
|
||||||
You must pass the generated toolchain file to CMake invocation.
|
You must pass the generated toolchain file to CMake invocation.
|
||||||
@ -113,14 +81,13 @@ In these examples only the minimum required amount of options is passed to `cmak
|
|||||||
|
|
||||||
### Use our prebuilt binaries to build for macOS x86_64 with Xcode
|
### Use our prebuilt binaries to build for macOS x86_64 with Xcode
|
||||||
|
|
||||||
```
|
```sh
|
||||||
conan install . \
|
conan install . \
|
||||||
--install-folder=conan-generated \
|
--install-folder=conan-generated \
|
||||||
--no-imports \
|
--no-imports \
|
||||||
--build=never \
|
--build=never \
|
||||||
--profile:build=default \
|
--profile:build=default \
|
||||||
--profile:host=CI/conan/macos-intel \
|
--profile:host=CI/conan/macos-intel
|
||||||
-o with_apple_system_libs=True
|
|
||||||
|
|
||||||
cmake -S . -B build -G Xcode \
|
cmake -S . -B build -G Xcode \
|
||||||
--toolchain conan-generated/conan_toolchain.cmake
|
--toolchain conan-generated/conan_toolchain.cmake
|
||||||
@ -130,7 +97,7 @@ cmake -S . -B build -G Xcode \
|
|||||||
|
|
||||||
If you also want to build the missing binaries from source, use `--build=missing` instead of `--build=never`.
|
If you also want to build the missing binaries from source, use `--build=missing` instead of `--build=never`.
|
||||||
|
|
||||||
```
|
```sh
|
||||||
conan install . \
|
conan install . \
|
||||||
--install-folder=~/my-dir \
|
--install-folder=~/my-dir \
|
||||||
--no-imports \
|
--no-imports \
|
||||||
@ -145,14 +112,13 @@ cmake -S . -B build \
|
|||||||
|
|
||||||
### Use our prebuilt binaries to build for iOS arm64 device with custom preset
|
### Use our prebuilt binaries to build for iOS arm64 device with custom preset
|
||||||
|
|
||||||
```
|
```sh
|
||||||
conan install . \
|
conan install . \
|
||||||
--install-folder=~/my-dir \
|
--install-folder=~/my-dir \
|
||||||
--no-imports \
|
--no-imports \
|
||||||
--build=never \
|
--build=never \
|
||||||
--profile:build=default \
|
--profile:build=default \
|
||||||
--profile:host=CI/conan/ios-arm64 \
|
--profile:host=CI/conan/ios-arm64
|
||||||
-o with_apple_system_libs=True
|
|
||||||
|
|
||||||
cmake --preset ios-conan
|
cmake --preset ios-conan
|
||||||
```
|
```
|
||||||
@ -181,28 +147,3 @@ cmake --preset ios-conan
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Build VCMI with all deps for 32-bit windows in Ubuntu 22.04 WSL
|
|
||||||
```powershell
|
|
||||||
wsl --install
|
|
||||||
wsl --install -d Ubuntu
|
|
||||||
ubuntu
|
|
||||||
```
|
|
||||||
Next steps are identical both in WSL and in real Ubuntu 22.04
|
|
||||||
```bash
|
|
||||||
sudo pip3 install conan
|
|
||||||
sudo apt install cmake build-essential
|
|
||||||
sed -i 's/x86_64-w64-mingw32/i686-w64-mingw32/g' CI/mingw-ubuntu/before-install.sh
|
|
||||||
sed -i 's/x86-64/i686/g' CI/mingw-ubuntu/before-install.sh
|
|
||||||
sudo ./CI/mingw-ubuntu/before-install.sh
|
|
||||||
conan install . \
|
|
||||||
--install-folder=conan-generated \
|
|
||||||
--no-imports \
|
|
||||||
--build=missing \
|
|
||||||
--profile:build=default \
|
|
||||||
--profile:host=CI/conan/mingw32-linux \
|
|
||||||
-c tools.cmake.cmaketoolchain.presets:max_schema_version=2
|
|
||||||
cmake --preset windows-mingw-conan-linux
|
|
||||||
cmake --build --preset windows-mingw-conan-linux --target package
|
|
||||||
```
|
|
||||||
After that, you will have functional VCMI installer for 32-bit windows.
|
|
26
docs/developers/Development_with_Qt_Creator.md
Normal file
26
docs/developers/Development_with_Qt_Creator.md
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
< [Documentation](../Readme.md) / Development with Qt Creator
|
||||||
|
|
||||||
|
# Introduction to Qt Creator
|
||||||
|
|
||||||
|
Qt Creator is the recommended IDE for VCMI development on Linux distributions, but it may be used on other operating systems as well. It has the following advantages compared to other IDEs:
|
||||||
|
|
||||||
|
- Fast parser/indexer, stable.
|
||||||
|
- Almost no manual configuration when used with CMake. Project configuration is read from CMake text files,
|
||||||
|
- Easy to setup and use with multiple different compiler toolchains: GCC, Visual Studio, Clang
|
||||||
|
|
||||||
|
You can install Qt Creator from repository, but better to stick to latest version from Qt website: https://www.qt.io/download-qt-installer-oss
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
To open the project you have to click File -\> Open file or project... -\> Select /path/to/vcmi/src/CMakeLists.txt.
|
||||||
|
|
||||||
|
For the first time and for every CMake project configuration change you have to execute CMake. This step can be done when opening the project for the first time or alternatively via the left bar -\> Projects -\> Build Settings -\> Execute CMake. You have to specify CMake arguments and the build dir. CMake arguments can be the following: `-DCMAKE_BUILD_TYPE=Debug`
|
||||||
|
|
||||||
|
The build dir should be set to something like /trunk/build for the debug build and /trunk/buildrel for the release build. For cleaning the build dir a command like "make clean" may be not enough. Better way is to delete the build dir, re-create it and re-execute CMake. Steps for cleaning can be configured in the Projects tab as well.
|
||||||
|
|
||||||
|
## Debugging
|
||||||
|
|
||||||
|
There is a problem with QtCreator when debugging both vcmiclient and vcmiserver. If you debug the vcmiclient, start a game, attach the vcmiserver process to the gdb debugger(Debug \> Start Debugging \> Attach to Running External Application...) then breakpoints which are set for vcmiserver will be ignored. This looks like a bug, in any case it's not intuitively. Two workarounds are available luckily:
|
||||||
|
|
||||||
|
1. Run vcmiclient (no debug mode), then attach server process to the debugger
|
||||||
|
2. Open two instances of QtCreator and debug vcmiserver and vcmiclient separately(it works!)
|
163
docs/developers/Logging_API.md
Normal file
163
docs/developers/Logging_API.md
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
< [Documentation](../Readme.md) / Logging System
|
||||||
|
|
||||||
|
# Features
|
||||||
|
|
||||||
|
- A logger belongs to a "domain", this enables us to change log level settings more selectively
|
||||||
|
- The log format can be customized
|
||||||
|
- The color of a log entry can be customized based on logger domain and logger level
|
||||||
|
- Logger settings can be changed in the settings.json file
|
||||||
|
- No std::endl at the end of a log entry required
|
||||||
|
- Thread-safe
|
||||||
|
- Macros for tracing the application flow
|
||||||
|
- Provides stream-like and function-like logging
|
||||||
|
|
||||||
|
# Class diagram
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Some notes:
|
||||||
|
|
||||||
|
- There are two methods `configure` and `configureDefault` of the class `CBasicLogConfigurator` to initialize and setup the logging system. The latter one setups default logging and isn't dependent on VCMI's filesystem, whereas the first one setups logging based on the user's settings which can be configured in the settings.json.
|
||||||
|
- The methods `isDebugEnabled` and `isTraceEnabled` return true if a log record of level debug respectively trace will be logged. This can be useful if composing the log message is a expensive task and performance is important.
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
|
||||||
|
## Setup settings.json
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
{
|
||||||
|
"logging" : {
|
||||||
|
"console" : {
|
||||||
|
"threshold" : "debug",
|
||||||
|
"colorMapping" : [
|
||||||
|
{
|
||||||
|
"domain" : "network",
|
||||||
|
"level" : "trace",
|
||||||
|
"color" : "magenta"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"loggers" : [
|
||||||
|
{
|
||||||
|
"domain" : "global",
|
||||||
|
"level" : "debug"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"domain" : "ai",
|
||||||
|
"level" : "trace"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The above code is an example on how to configure logging. It sets the log level to debug globally and the log level of the domain ai to trace. In addition, it tells the console to log debug messages as well with the threshold attribute. Finally, it configures the console so that it logs network trace messages in magenta.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
The following code shows how the logging system can be configured:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
console = new CConsoleHandler;
|
||||||
|
CBasicLogConfigurator logConfig(VCMIDirs::get().localPath() + "/VCMI_Server_log.txt", console);
|
||||||
|
logConfig.configureDefault(); // Initialize default logging due to that the filesystem and settings are not available
|
||||||
|
preinitDLL(console); // Init filesystem
|
||||||
|
settings.init(); // Init settings
|
||||||
|
logConfig.configure(); // Now setup "real" logging system, overwrites default settings
|
||||||
|
```
|
||||||
|
|
||||||
|
If `configureDefault` or `configure` won't be called, then logs aren't written either to the console or to the file. The default logging setups a system like this:
|
||||||
|
|
||||||
|
**Console**
|
||||||
|
|
||||||
|
Format: %m
|
||||||
|
Threshold: info
|
||||||
|
coloredOutputEnabled: true
|
||||||
|
|
||||||
|
colorMapping: trace -\> gray, debug -\> white, info -\> green, warn -\> yellow, error -\> red
|
||||||
|
|
||||||
|
**File**
|
||||||
|
|
||||||
|
Format: %d %l %n \[%t\] - %m
|
||||||
|
|
||||||
|
**Loggers**
|
||||||
|
|
||||||
|
global -\> info
|
||||||
|
|
||||||
|
## How to get a logger
|
||||||
|
|
||||||
|
There exist only one logger object per domain. A logger object cannot be copied. You can get access to a logger object by using the globally defined ones like `logGlobal` or `logAi`, etc... or by getting one manually:
|
||||||
|
```cpp
|
||||||
|
Logger * logger = CLogger::getLogger(CLoggerDomain("rmg"));
|
||||||
|
```
|
||||||
|
|
||||||
|
## Logging
|
||||||
|
|
||||||
|
Logging can be done via two ways, stream-like or function-like.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
logGlobal->warnStream() << "Call to loadBitmap with void fname!";
|
||||||
|
logGlobal->warn("Call to loadBitmap with void fname!");
|
||||||
|
```
|
||||||
|
|
||||||
|
Don't include a '\n' or std::endl at the end of your log message, a new line will be appended automatically.
|
||||||
|
|
||||||
|
The following list shows several log levels from the highest one to the lowest one:
|
||||||
|
|
||||||
|
- error -\> for errors, e.g. if resource is not available, if a initialization fault has occured, if a exception has been thrown (can result in program termination)
|
||||||
|
- warn -\> for warnings, e.g. if sth. is wrong, but the program can continue execution "normally"
|
||||||
|
- info -\> informational messages, e.g. Filesystem initialized, Map loaded, Server started, etc...
|
||||||
|
- debug -\> for debugging, e.g. hero moved to (12,3,0), direction 3', 'following artifacts influence X: .. or pattern detected at pos (10,15,0), p-nr. 30, flip 1, repl. 'D'
|
||||||
|
- trace -\> for logging the control flow, the execution progress or fine-grained events, e.g. hero movement completed, entering CMapEditManager::updateTerrainViews: posx '10', posy '5', width '10', height '10', mapLevel '0',...
|
||||||
|
|
||||||
|
The following colors are available for console output:
|
||||||
|
|
||||||
|
- default
|
||||||
|
- green
|
||||||
|
- red
|
||||||
|
- magenta
|
||||||
|
- yellow
|
||||||
|
- white
|
||||||
|
- gray
|
||||||
|
- teal
|
||||||
|
|
||||||
|
## How to trace execution
|
||||||
|
|
||||||
|
The program execution can be traced by using the macros TRACE_BEGIN, TRACE_END and their \_PARAMS counterparts. This can be important if you want to analyze the operations/internal workings of the AI or the communication of the client-server. In addition, it can help you to find bugs on a foreign VCMI installation with a custom mod configuration.
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
int calculateMovementPointsForPath(int3 start, int3 end, CHero * hero) // This is just an example, the function is fictive
|
||||||
|
{
|
||||||
|
TRACE_BEGIN_PARAMS(logGlobal, "start '%s', end '%s', hero '%s'", start.toString() % end.toString() % hero.getName()); // toString is fictive as well and returns a string representation of the int3 pos, ....
|
||||||
|
int movPoints;
|
||||||
|
// Do some stuff
|
||||||
|
// ...
|
||||||
|
TRACE_END_PARAMS(logGlobal, "movPoints '%i'", movPoints);
|
||||||
|
return movPoints;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# Concepts
|
||||||
|
|
||||||
|
## Domain
|
||||||
|
|
||||||
|
A domain is a specific part of the software. In VCMI there exist several domains:
|
||||||
|
|
||||||
|
- network
|
||||||
|
- ai
|
||||||
|
- bonus
|
||||||
|
- network
|
||||||
|
|
||||||
|
In addition to these domains, there exist always a super domain called "global". Sub-domains can be created with "ai.battle" or "ai.adventure" for example. The dot between the "ai" and "battle" is important and notes the parent-child relationship of those two domains. A few examples how the log level will be inherited:
|
||||||
|
|
||||||
|
global, level=info
|
||||||
|
network, level=not set, effective level=info
|
||||||
|
|
||||||
|
global, level=warn
|
||||||
|
network, level=trace, effective level=trace
|
||||||
|
|
||||||
|
global, level=debug
|
||||||
|
ai, level=not set, effective level=debug
|
||||||
|
ai.battle, level=trace, effective level=trace
|
||||||
|
|
||||||
|
The same technique is applied to the console colors. If you want to have another debug color for the domain ai, you can explicitely set a color for that domain and level.
|
204
docs/developers/Lua_Scripting_System.md
Normal file
204
docs/developers/Lua_Scripting_System.md
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
< [Documentation](../Readme.md) / Lua Scripting System
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
{
|
||||||
|
//general purpose script, Lua or ERM, runs on server
|
||||||
|
"myScript":
|
||||||
|
{
|
||||||
|
"source":"path/to/script/with/ext",
|
||||||
|
"implements":"ANYTHING"
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
//custom battle spell effect, Lua only, runs on both client and server
|
||||||
|
//script ID will be used as effect 'type' (with mod prefix)
|
||||||
|
"mySpellEffect":
|
||||||
|
{
|
||||||
|
"source":"path/to/script/with/ext",
|
||||||
|
"implements":"BATTLE_EFFECT"
|
||||||
|
},
|
||||||
|
|
||||||
|
//TODO: object|building type
|
||||||
|
//custom map object or building, Lua only, runs on both client and server
|
||||||
|
//script ID will be used as 'handler' (with mod prefix)
|
||||||
|
"myObjectType":
|
||||||
|
{
|
||||||
|
"source":"path/to/script/with/ext",
|
||||||
|
"implements":"MAP_OBJECT"
|
||||||
|
},
|
||||||
|
//TODO: server query
|
||||||
|
//TODO: client query
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# Lua
|
||||||
|
|
||||||
|
## API Reference
|
||||||
|
|
||||||
|
TODO **In near future Lua API may change drastically several times. Information here may be outdated**
|
||||||
|
|
||||||
|
### Globals
|
||||||
|
|
||||||
|
- DATA - persistent table
|
||||||
|
- - DATA.ERM contains ERM state, anything else is free to use.
|
||||||
|
- GAME - IGameInfoCallback API
|
||||||
|
- BATTLE - IBattleInfoCallback API
|
||||||
|
- EVENT_BUS - opaque handle, for use with events API
|
||||||
|
- SERVICES - root "raw" access to all static game objects
|
||||||
|
- - SERVICES:artifacts()
|
||||||
|
- - SERVICES:creatures()
|
||||||
|
- - SERVICES:factions()
|
||||||
|
- - SERVICES:heroClasses()
|
||||||
|
- - SERVICES:heroTypes()
|
||||||
|
- - SERVICES:spells()
|
||||||
|
- - SERVICES:skills()
|
||||||
|
- require(URI)
|
||||||
|
- -works similar to usual Lua require
|
||||||
|
- -require("ClassName") - loads additional API and returns it as table (for C++ classes)
|
||||||
|
- -require("core:relative.path.to.module") - loads module from "SCRIPTS/LIB"
|
||||||
|
- -TODO require("modName:relative.path.to.module") - loads module from dependent mod
|
||||||
|
- -TODO require(":relative.path.to.module") - loads module from same mod
|
||||||
|
- logError(text) - backup error log function
|
||||||
|
|
||||||
|
### Low level events API
|
||||||
|
|
||||||
|
``` Lua
|
||||||
|
|
||||||
|
-- Each event type must be loaded first
|
||||||
|
local PlayerGotTurn = require("events.PlayerGotTurn")
|
||||||
|
|
||||||
|
-- in this example subscription handles made global, do so if there is no better place
|
||||||
|
-- !!! do not store them in local variables
|
||||||
|
sub1 = PlayerGotTurn.subscribeAfter(EVENT_BUS, function(event)
|
||||||
|
--do smth
|
||||||
|
end)
|
||||||
|
|
||||||
|
sub2 = PlayerGotTurn.subscribeBefore(EVENT_BUS, function(event)
|
||||||
|
--do smth
|
||||||
|
end)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Lua standard library
|
||||||
|
|
||||||
|
VCMI uses LuaJIT, which is Lua 5.1 API, see [upstream documentation](https://www.lua.org/manual/5.1/manual.html)
|
||||||
|
|
||||||
|
Following libraries are supported
|
||||||
|
|
||||||
|
- base
|
||||||
|
- table
|
||||||
|
- string
|
||||||
|
- math
|
||||||
|
- bit
|
||||||
|
|
||||||
|
# ERM
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- no strict limit on function/variable numbers (technical limit 32 bit integer except 0))
|
||||||
|
- TODO semi compare
|
||||||
|
- DONE macros
|
||||||
|
|
||||||
|
## Bugs
|
||||||
|
|
||||||
|
- TODO Broken XOR support (clashes with \`X\` option)
|
||||||
|
|
||||||
|
## Triggers
|
||||||
|
|
||||||
|
- TODO **!?AE** Equip/Unequip artifact
|
||||||
|
- WIP **!?BA** when any battle occurs
|
||||||
|
- WIP **!?BF** when a battlefield is prepared for a battle
|
||||||
|
- TODO **!?BG** at every action taken by any stack or by the hero
|
||||||
|
- TODO **!?BR** at every turn of a battle
|
||||||
|
- *!?CM (client only) click the mouse button.*
|
||||||
|
- TODO **!?CO** Commander triggers
|
||||||
|
- TODO **!?DL** Custom dialogs
|
||||||
|
- DONE **!?FU** function
|
||||||
|
- TODO **!?GE** "global" event
|
||||||
|
- TODO **!?GM** Saving/Loading
|
||||||
|
- TODO **!?HE** when the hero \# is attacked by an enemy hero or
|
||||||
|
visited by an allied hero
|
||||||
|
- TODO **!?HL** hero gains a level
|
||||||
|
- TODO **!?HM** every step a hero \# takes
|
||||||
|
- *!?IP Multiplayer support.*
|
||||||
|
- TODO **!?LE** (!$LE) An Event on the map
|
||||||
|
- WIP **!?MF** stack taking physical damage(before an action)
|
||||||
|
- TODO **!?MG** casting on the adventure map
|
||||||
|
- *!?MM scroll text during a battle*
|
||||||
|
- TODO **!?MR** Magic resistance
|
||||||
|
- TODO **!?MW** Wandering Monsters
|
||||||
|
- WIP **!?OB** (!$OB) visiting objects
|
||||||
|
- DONE **!?PI** Post Instruction.
|
||||||
|
- TODO **!?SN** Sound and ERA extensions
|
||||||
|
- *!?TH town hall*
|
||||||
|
- TODO **!?TL** Real-Time Timer
|
||||||
|
- TODO **!?TM** timed events
|
||||||
|
|
||||||
|
## Receivers
|
||||||
|
|
||||||
|
### VCMI
|
||||||
|
|
||||||
|
- **!!MC:S@varName@** - declare new "normal" variable (technically
|
||||||
|
v-var with string key)
|
||||||
|
- TODO Identifier resolver
|
||||||
|
- WIP Bonus system
|
||||||
|
|
||||||
|
### ERA
|
||||||
|
|
||||||
|
- DONE !!if !!el !!en
|
||||||
|
- TODO !!br !!co
|
||||||
|
- TODO !!SN:X
|
||||||
|
|
||||||
|
### WoG
|
||||||
|
|
||||||
|
- TODO !!AR Артефакт (ресурс) в определенной позиции
|
||||||
|
- TODO !!BA Битва
|
||||||
|
- !!BA:A$ return 1 for battle evaluation
|
||||||
|
- TODO !!BF Препятствия на поле боя
|
||||||
|
- TODO !!BG Действий монстров в бою
|
||||||
|
- TODO !!BH Действия героя в бою
|
||||||
|
- TODO !!BM Монстр в битве
|
||||||
|
- WIP !!BU Универсальные параметры битвы
|
||||||
|
- TODO !!CA Замок
|
||||||
|
- TODO !!CD Разрушения замков
|
||||||
|
- TODO !!CE События в замке
|
||||||
|
- TODO !!CM Клика мышью
|
||||||
|
- TODO !!DL Нестандартный диалог (только ТЕ или выше)
|
||||||
|
- TODO !!CO Командиры
|
||||||
|
- WIP !!DO Многократный вызов функции
|
||||||
|
- TODO !!EA Бонусы опыта существ
|
||||||
|
- TODO !!EX Опыт стека
|
||||||
|
- DONE !!FU Однократный вызов функции
|
||||||
|
- TODO !!GE Глобальное событие
|
||||||
|
- WIP !!HE Герой
|
||||||
|
- TODO !!HL Новый уровень героя
|
||||||
|
- TODO !!HO Взаимодействия героев
|
||||||
|
- TODO !!HT Подсказки по правому клику
|
||||||
|
- WIP !!IF Диалоги и флагов
|
||||||
|
- TODO !!IP Сетевой сервис битвы
|
||||||
|
- TODO !!LE Локальное события
|
||||||
|
- WIP !!MA Общие параметры монстров
|
||||||
|
- DONE !!MC Макросы
|
||||||
|
- WIP !!MF Получение физ. урона в бою
|
||||||
|
- TODO !!MM Текст в битве
|
||||||
|
- WIP !!MO Монстр в определенной позиции
|
||||||
|
- TODO !!MP Контроль MP3
|
||||||
|
- TODO !!MR Сопротивления магии
|
||||||
|
- TODO !!MW Бродячих монстров
|
||||||
|
- WIP !!OB Объект в определенной позиции
|
||||||
|
- TODO !!OW Параметры игрока
|
||||||
|
- TODO !!PM Пирамиды или новые объекты
|
||||||
|
- TODO !!PO Информация квадрата карты
|
||||||
|
- TODO (???) !!QW Журнала
|
||||||
|
- TODO !!SN Проигрываемые звуков
|
||||||
|
- TODO !!SS Настройка заклинаний (только ТЕ или выше)
|
||||||
|
- TODO !!TL Контроль времени хода (только ТЕ или выше)
|
||||||
|
- TODO !!TM Временный таймер
|
||||||
|
- TODO !!TR Квадрата карты (почва, проходимость, т.п.)
|
||||||
|
- TODO !!UN Универсальная команда
|
||||||
|
- *!#VC Контроль переменных*
|
||||||
|
- WIP !!VR Установка переменных
|
||||||
|
|
||||||
|
## Persistence
|
267
docs/developers/Serialization.md
Normal file
267
docs/developers/Serialization.md
Normal file
@ -0,0 +1,267 @@
|
|||||||
|
< [Documentation](../Readme.md) / Serialization System
|
||||||
|
|
||||||
|
# Introduction
|
||||||
|
|
||||||
|
The serializer translates between objects living in our code (like int or CGameState\*) and stream of bytes. Having objects represented as a stream of bytes is useful. Such bytes can send through the network connection (so client and server can communicate) or written to the disk (savegames).
|
||||||
|
|
||||||
|
VCMI uses binary format. The primitive types are simply copied from memory, more complex structures are represented as a sequence of primitives.
|
||||||
|
|
||||||
|
## Typical tasks
|
||||||
|
|
||||||
|
### Bumping a version number
|
||||||
|
|
||||||
|
Different major version of VCMI likely change the format of the save game. Every save game needs a version identifier, that loading can work properly. Backward compatibility isn't supported for now. The version identifier is a constant named version in Connection.h and should be updated every major VCMI version or development version if the format has been changed. Do not change this constant if it's not required as it leads to full rebuilds. Why should the version be updated? If VCMI cannot detect "invalid" save games the program behaviour is random and undefined. It mostly results in a crash. The reason can be anything from null pointer exceptions, index out of bounds exceptions(ok, they aren't available in c++, but you know what I mean:) or invalid objects loading(too much elements in a vector, etc...) This should be avoided at least for public VCMI releases.
|
||||||
|
|
||||||
|
### Adding a new class
|
||||||
|
|
||||||
|
If you want your class to be serializable (eg. being storable in a savegame) you need to define a serialize method template, as described in [#User types](#user-types)
|
||||||
|
|
||||||
|
Additionally, if your class is part of one of registered object hierarchies (basically: if it derives from CGObjectInstance, IPropagator, ILimiter, CBonusSystemNode, CPack) it needs to be registered. Just add an appropriate entry in the `RegisterTypes.h` file. See polymorphic serialization for more information.
|
||||||
|
|
||||||
|
# How does it work
|
||||||
|
|
||||||
|
## Primitive types
|
||||||
|
|
||||||
|
They are simply stored in a binary form, as in memory. Compatibility is ensued through the following means:
|
||||||
|
|
||||||
|
- VCMI uses internally types that have constant, defined size (like int32_t - has 32 bits on all platforms)
|
||||||
|
- serializer stores information about its endianess
|
||||||
|
|
||||||
|
It's not "really" portable, yet it works properly across all platforms we currently support.
|
||||||
|
|
||||||
|
## Dependant types
|
||||||
|
|
||||||
|
### Pointers
|
||||||
|
|
||||||
|
Storing pointers mechanics can be and almost always is customized. See [#Additional features](additional-features).
|
||||||
|
|
||||||
|
In the most basic form storing pointer simply sends the object state and loading pointer allocates an object (using "new" operator) and fills its state with the stored data.
|
||||||
|
|
||||||
|
### Arrays
|
||||||
|
|
||||||
|
Serializing array is simply serializing all its elements.
|
||||||
|
|
||||||
|
## Standard library types
|
||||||
|
|
||||||
|
### STL Containers
|
||||||
|
|
||||||
|
First the container size is stored, then every single contained element.
|
||||||
|
|
||||||
|
Supported STL types include:
|
||||||
|
|
||||||
|
`vector`
|
||||||
|
`array`
|
||||||
|
`set`
|
||||||
|
`unordered_set`
|
||||||
|
`list`
|
||||||
|
`string`
|
||||||
|
`pair`
|
||||||
|
`map`
|
||||||
|
|
||||||
|
### Smart pointers
|
||||||
|
|
||||||
|
Smart pointers at the moment are treated as the raw C-style pointers. This is very bad and dangerous for shared_ptr and is expected to be fixed somewhen in the future.
|
||||||
|
|
||||||
|
The list of supported data types from standard library:
|
||||||
|
|
||||||
|
`shared_ptr (partial!!!)`
|
||||||
|
`unique_ptr`
|
||||||
|
|
||||||
|
### Boost
|
||||||
|
|
||||||
|
Additionally, a few types for Boost are supported as well:
|
||||||
|
|
||||||
|
`variant`
|
||||||
|
`optional`
|
||||||
|
|
||||||
|
## User types
|
||||||
|
|
||||||
|
To make the user-defined type serializable, it has to provide a template method serialize. The first argument (typed as template parameter) is a reference to serializer. The second one is version number.
|
||||||
|
|
||||||
|
Serializer provides an operator& that is internally expanded to `<<` when serialziing or `>>` when deserializing.
|
||||||
|
|
||||||
|
Serializer provides a public bool field `saving`that set to true during serialziation and to false for deserialziation.
|
||||||
|
|
||||||
|
Typically, serializing class involves serializing all its members (given that they are serializable). Sample:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
/// The rumor struct consists of a rumor name and text.
|
||||||
|
struct DLL_LINKAGE Rumor
|
||||||
|
{
|
||||||
|
std::string name;
|
||||||
|
std::string text;
|
||||||
|
|
||||||
|
template <typename Handler>
|
||||||
|
void serialize(Handler & h, const int version)
|
||||||
|
{
|
||||||
|
h & name;
|
||||||
|
h & text;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Backwards compatibility
|
||||||
|
|
||||||
|
Serializer, before sending any data, stores its version number. It is passed as the parameter to the serialize method, so conditional code ensuring backwards compatibility can be added.
|
||||||
|
|
||||||
|
Yet, because of numerous changes to our game data structure, providing means of backwards compatibility is not feasible. The versioning feature is rarely used.
|
||||||
|
|
||||||
|
Sample:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
/// The rumor struct consists of a rumor name and text.
|
||||||
|
struct DLL_LINKAGE Rumor
|
||||||
|
{
|
||||||
|
std::string name; //introduced in version 1065
|
||||||
|
std::string text;
|
||||||
|
|
||||||
|
template <typename Handler>
|
||||||
|
void serialize(Handler & h, const int version)
|
||||||
|
{
|
||||||
|
if(version >= 1065)
|
||||||
|
h & name;
|
||||||
|
else //when loading old savegame
|
||||||
|
name = "no name"; //set name to a sane default value
|
||||||
|
|
||||||
|
h & text;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Serializer classes
|
||||||
|
|
||||||
|
### Common information
|
||||||
|
|
||||||
|
Serializer classes provide iostream-like interface with operator `<<` for serialization and operator `>>` for deserialization. Serializer upon creation will retrieve/store some metadata (version number, endianess), so even if no object is actually serialized, some data will be passed.
|
||||||
|
|
||||||
|
### Serialization to file
|
||||||
|
|
||||||
|
CLoadFile/CSaveFile classes allow to read data to file and store data to file. They take filename as the first parameter in constructor and, optionally, the minimum supported version number (default to the current version). If the construction fails (no file or wrong file) the exception is thrown.
|
||||||
|
|
||||||
|
### Networking
|
||||||
|
|
||||||
|
CConnection class provides support for sending data structures over TCP/IP protocol. It provides 3 constructors:
|
||||||
|
1. connect to given hostname at given port (host must be accepting connection)
|
||||||
|
2. accept connection (takes boost.asio acceptor and io_service)
|
||||||
|
3. adapt boost.asio socket with already established connection
|
||||||
|
|
||||||
|
All three constructors take as the last parameter the name that will be used to identify the peer.
|
||||||
|
|
||||||
|
## Additional features
|
||||||
|
|
||||||
|
Here is the list of additional custom features serialzier provides. Most of them can be turned on and off.
|
||||||
|
|
||||||
|
- Polymorphic serialization — no flag to control it, turned on by calls to registerType.
|
||||||
|
- Vectorized list member serialization — enabled by smartVectorMembersSerialization flag.
|
||||||
|
- Stack instance serialization — enabled by sendStackInstanceByIds flag.
|
||||||
|
- Smart pointer serialization — enabled by smartPointerSerialization flag.
|
||||||
|
|
||||||
|
### Polymorphic serialization
|
||||||
|
|
||||||
|
Serializer is to recognize the true type of object under the pointer if classes of that hierarchy were previously registered.
|
||||||
|
|
||||||
|
This means that following will work
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
Derived *d = new Derived();
|
||||||
|
Base *basePtr = d;
|
||||||
|
CSaveFile output("test.dat");
|
||||||
|
output << b;
|
||||||
|
//
|
||||||
|
Base *basePtr = nullptr;
|
||||||
|
CLoadFile input("test.dat");
|
||||||
|
input >> basePtr; //a new Derived object will be put under the pointer
|
||||||
|
```
|
||||||
|
|
||||||
|
Class hierarchies that are now registered to benefit from this feature are mostly adventure map object (CGObjectInstance) and network packs (CPack). See the RegisterTypes.h file for the full list.
|
||||||
|
|
||||||
|
It is crucial that classes are registered in the same order in the both serializers (storing and loading).
|
||||||
|
|
||||||
|
### Vectorized list member serialization
|
||||||
|
|
||||||
|
Both client and server store their own copies of game state and VLC (handlers with data from config). Many game logic objects are stored in the vectors and possess a unique id number that represent also their position in such vector.
|
||||||
|
|
||||||
|
The vectorised game objects are:
|
||||||
|
|
||||||
|
`CGObjectInstance`
|
||||||
|
`CGHeroInstance`
|
||||||
|
`CCreature`
|
||||||
|
`CArtifact`
|
||||||
|
`CArtifactInstance`
|
||||||
|
`CQuest`
|
||||||
|
|
||||||
|
For this to work, serializer needs an access to gamestate library classes. This is done by calling a method `CSerializer::addStdVecItems(CGameState *gs, LibClasses *lib)`.
|
||||||
|
|
||||||
|
When the game ends (or gamestate pointer is invaldiated for another reason) this feature needs to be turned off by toggling its flag.
|
||||||
|
|
||||||
|
When vectorized member serialization is turned on, serializing pointer to such object denotes not sending an object itself but rather its identity. For example:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
//Server code
|
||||||
|
CCreature *someCreature = ...;
|
||||||
|
connection << someCreature;
|
||||||
|
```
|
||||||
|
|
||||||
|
the last line is equivalent to
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
connection << someCreature->idNumber;
|
||||||
|
```
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
//Client code
|
||||||
|
CCreature *someCreature = nullptr;
|
||||||
|
connection >> someCreature;
|
||||||
|
```
|
||||||
|
|
||||||
|
the last line is equivalent to
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
CreatureID id;
|
||||||
|
connection >> id;
|
||||||
|
someCreature = VLC->creh->creatures[id.getNum()];
|
||||||
|
```
|
||||||
|
|
||||||
|
Important: this means that the object state is not serialized.
|
||||||
|
|
||||||
|
This feature makes sense only for server-client network communication.
|
||||||
|
|
||||||
|
### Stack instance serialization
|
||||||
|
|
||||||
|
This feature works very much like the vectorised object serialization. It is like its special case for stack instances that are not vectorised (each hero owns its map). When this option is turned on, sending CStackInstance\* will actually send an owning object (town, hero, garrison, etc) id and the stack slot position.
|
||||||
|
|
||||||
|
For this to work, obviously, both sides of the connection need to have exactly the same copies of an armed object and its stacks.
|
||||||
|
|
||||||
|
This feature depends on vectorised member serialization being turned on. (Sending owning object by id.)
|
||||||
|
|
||||||
|
### Smart pointer serialization
|
||||||
|
|
||||||
|
Note: name is unfortunate, this feature is not about smart pointers (like shared-ptr and unique_ptr). It is for raw C-style pointers, that happen to point to the same object.
|
||||||
|
|
||||||
|
This feature makes it that multiple pointers pointing to the same object are not stored twice.
|
||||||
|
|
||||||
|
Each time a pointer is stored, a unique id is given to it. If the same pointer is stored a second time, its contents is not serialized — serializer just stores a reference to the id.
|
||||||
|
|
||||||
|
For example:
|
||||||
|
|
||||||
|
``` cpp
|
||||||
|
Foo * a = new Foo();
|
||||||
|
Foo * b = b;
|
||||||
|
|
||||||
|
{
|
||||||
|
CSaveFile test("test.txt");
|
||||||
|
test << a << b;
|
||||||
|
}
|
||||||
|
|
||||||
|
Foo *loadedA, *loadedB;
|
||||||
|
{
|
||||||
|
CLoadFile test("test.txt");
|
||||||
|
test >> loadedA >> loadedB;
|
||||||
|
//now both pointers point to the same object
|
||||||
|
assert(loadedA == loadedB);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The feature recognizes pointers by addresses. Therefore it allows mixing pointers to base and derived classes. However, it does not allow serializing classes with multiple inheritance using a "non-first" base (other bases have a certain address offset from the actual object).
|
||||||
|
|
||||||
|
Pointer cycles are properly handled. This feature makes sense for savegames and is turned on for them.
|
136
docs/maintainers/Project_Infrastructure.md
Normal file
136
docs/maintainers/Project_Infrastructure.md
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
< [Documentation](../Readme.md) / Project Infrastructure
|
||||||
|
|
||||||
|
# Project Infrastructure
|
||||||
|
|
||||||
|
This section hold important information about project infrastructure for current and future contributors. At moment it's all maintained by me (SXX), but following information will be useful if someone going to replace me in future.
|
||||||
|
|
||||||
|
## Services and accounts
|
||||||
|
|
||||||
|
So far we using following services:
|
||||||
|
|
||||||
|
### Most important
|
||||||
|
|
||||||
|
- VCMI.eu domain paid until July of 2019.
|
||||||
|
- Owner: Tow
|
||||||
|
- Our main domain used by services.
|
||||||
|
- VCMI.download paid until November of 2026.
|
||||||
|
- Owner: SXX
|
||||||
|
- Intended to be used for all assets downloads.
|
||||||
|
- Domain registered on GANDI and **can be renewed by anyone without access to account**.
|
||||||
|
- [DigitalOcean](https://cloud.digitalocean.com/) team.
|
||||||
|
- Our hosting sponsor.
|
||||||
|
- Administrator access: SXX, Warmonger.
|
||||||
|
- User access: AVS, Tow.
|
||||||
|
- [CloudFlare](https://www.cloudflare.com/a/overview) account.
|
||||||
|
- Access through shared login / password.
|
||||||
|
- All of our infrastructure is behind CloudFlare and all our web. We manage our DNS there.
|
||||||
|
- [Google Apps (G Suite)](https://admin.google.com/) account.
|
||||||
|
- It's only for vcmi.eu domain and limited to 5 users. Each account has limit of 500 emails / day.
|
||||||
|
- One administrative email used for other services registration.
|
||||||
|
- "noreply" email used for outgoing mail on Wiki and Bug Tracker.
|
||||||
|
- "forum" email used for outgoing mail on Forums. Since we authenticate everyone through forum it's should be separate email.
|
||||||
|
- Administrator access: Tow, SXX.
|
||||||
|
- [Google Play Console](https://play.google.com/apps/publish/) account.
|
||||||
|
- Hold ownership over VCMI Android App.
|
||||||
|
- Owner: SXX
|
||||||
|
- Administrator access: Warmonger, AVS, Ivan.
|
||||||
|
- Release manager access: Fay.
|
||||||
|
|
||||||
|
Not all services let us safely share login credentials, but at least when possible at least two of core developers must have access to them in case of emergency.
|
||||||
|
|
||||||
|
### Public relations
|
||||||
|
|
||||||
|
We want to notify players about updates on as many social services as possible.
|
||||||
|
|
||||||
|
- Facebook page: <https://www.facebook.com/VCMIOfficial>
|
||||||
|
- Administrator access: SXX, Warmonger
|
||||||
|
- Twitter account: <https://twitter.com/VCMIOfficial>
|
||||||
|
- Administrator access: SXX.
|
||||||
|
- User access via TweetDeck:
|
||||||
|
- VK / VKontakte page: <https://vk.com/VCMIOfficial>
|
||||||
|
- Owner: SXX
|
||||||
|
- Administrator access: AVS
|
||||||
|
- Steam group: <https://steamcommunity.com/groups/VCMI>
|
||||||
|
- Administrator access: SXX
|
||||||
|
- Moderator access: Dydzio
|
||||||
|
- Reddit: <https://reddit.com/r/vcmi/>
|
||||||
|
- Administrator access: SXX
|
||||||
|
- ModDB entry: <http://www.moddb.com/engines/vcmi>
|
||||||
|
- Administrator access: SXX
|
||||||
|
|
||||||
|
### Communication channels
|
||||||
|
|
||||||
|
- Slack team: <https://h3vcmi.slack.com/>
|
||||||
|
- Owner: vmarkovtsev
|
||||||
|
- Administrator access: SXX, Warmonger, AVS...
|
||||||
|
- Trello team: <https://trello.com/vcmi/>
|
||||||
|
- Administrator access: SXX
|
||||||
|
- Discord:
|
||||||
|
- Owner: dydzio
|
||||||
|
- Administrator access: SXX, Warmonger, Ivan...
|
||||||
|
|
||||||
|
### Other services
|
||||||
|
|
||||||
|
- Launchpad PPA: <https://launchpad.net/~vcmi>
|
||||||
|
- Member access: AVS
|
||||||
|
- Administrator access: Ivan, SXX
|
||||||
|
- Snapcraft Dashboard: <https://dashboard.snapcraft.io/>
|
||||||
|
- Administrator access: SXX
|
||||||
|
- Coverity Scan page: <https://scan.coverity.com/projects/vcmi>
|
||||||
|
- Administrator access: SXX, Warmonger, AVS
|
||||||
|
- OpenHub page: <https://www.openhub.net/p/VCMI>
|
||||||
|
- Administrator access: Tow
|
||||||
|
- Docker Hub organization: <https://hub.docker.com/u/vcmi/>
|
||||||
|
- Administrator access: SXX
|
||||||
|
|
||||||
|
Reserve accounts for other code hosting services:
|
||||||
|
|
||||||
|
- GitLab organization: <https://gitlab.com/vcmi/>
|
||||||
|
- Administrator access: SXX
|
||||||
|
- BitBucket organization: <https://bitbucket.org/vcmi/>
|
||||||
|
- Administrator access: SXX
|
||||||
|
|
||||||
|
## What's to improve
|
||||||
|
|
||||||
|
1. Encourage Tow to transfer VCMI.eu to GANDI so it's can be also renewed without access.
|
||||||
|
2. Use 2FA on CloudFlare and just ask everyone to get FreeOTP and then use shared secret.
|
||||||
|
3. Centralized way to post news about game updates to all social media.
|
||||||
|
|
||||||
|
# Project Servers Configuration
|
||||||
|
|
||||||
|
This section dedicated to explain specific configurations of our servers for anyone who might need to improve it in future.
|
||||||
|
|
||||||
|
## Droplet configuration
|
||||||
|
|
||||||
|
### Droplet and hosted services
|
||||||
|
|
||||||
|
Currently we using two droplets:
|
||||||
|
|
||||||
|
- First one serve all of our web services:
|
||||||
|
- [Forum](https://forum.vcmi.eu/)
|
||||||
|
- [Bug tracker](https://bugs.vcmi.eu/)
|
||||||
|
- [Wiki](https://wiki.vcmi.eu/)
|
||||||
|
- [Slack invite page](https://slack.vcmi.eu/)
|
||||||
|
- Second serve downloads:
|
||||||
|
- [Legacy download page](http://download.vcmi.eu/)
|
||||||
|
- [Build download page](https://builds.vcmi.download/)
|
||||||
|
|
||||||
|
To keep everything secure we should always keep binary downloads separate from any web services.
|
||||||
|
|
||||||
|
### Rules to stick to
|
||||||
|
|
||||||
|
- SSH authentication by public key only.
|
||||||
|
- Incoming connections to all ports except SSH (22) must be blocked.
|
||||||
|
- Exception for HTTP(S) connection on ports 80 / 443 from [CloudFlare IP Ranges](https://www.cloudflare.com/ips/).
|
||||||
|
- No one except core developers should ever know real server IPs.
|
||||||
|
- Droplet hostname should never be valid host. Otherwise it's exposed in [reverse DNS](https://en.wikipedia.org/wiki/Reverse_DNS).
|
||||||
|
- If some non-web service need to listen for external connections then read below.
|
||||||
|
|
||||||
|
### Our publicly-facing server
|
||||||
|
|
||||||
|
We only expose floating IP that can be detached from droplet in case of emergency using [DO control panel](https://cloud.digitalocean.com/networking/floating_ips). This also allow us to easily move public services to dedicated droplet in future.
|
||||||
|
|
||||||
|
- Address: beholder.vcmi.eu (67.207.75.182)
|
||||||
|
- Port 22 serve SFTP for file uploads as well as CI artifacts uploads.
|
||||||
|
|
||||||
|
If new services added firewall rules can be adjusted in [DO control panel](https://cloud.digitalocean.com/networking/firewalls).
|
48
docs/maintainers/Release_Process.md
Normal file
48
docs/maintainers/Release_Process.md
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
< [Documentation](../Readme.md) / Release Process
|
||||||
|
|
||||||
|
## Branches
|
||||||
|
Our branching strategy is very similar to GitFlow
|
||||||
|
* `master` branch has release commits. One commit - one release. Each release commit should be tagged with version `maj.min.patch`
|
||||||
|
* `beta` branch is for stabilization of ongoing release. We don't merge new features into `beta` branch - only bug fixes are acceptable. Hotfixes for already released software should be delivered to this branch as well.
|
||||||
|
* `develop` branch is a main branch for ongoing development. Pull requests with new features should be targeted to this branch, `develop` version is one step ahead of 'beta`
|
||||||
|
|
||||||
|
## Release process step-by-step
|
||||||
|
Assuming that all features planned to be released are implemented in `develop` branch and next release version will be `1.x.0`
|
||||||
|
|
||||||
|
### Start of stabilization stage
|
||||||
|
Should be done several weeks before planned release date
|
||||||
|
|
||||||
|
- Create [milestone](https://github.com/vcmi/vcmi/milestones) named `Release 1.x`
|
||||||
|
- Specify new milestone for all regression bugs and major bugs related to new functionality
|
||||||
|
- Create `beta` branch from `develop`
|
||||||
|
- Bump vcmi version on `develop` branch
|
||||||
|
- Bump version for linux on `develop` branch
|
||||||
|
|
||||||
|
### Release preparation stage
|
||||||
|
Should be done several days before planned release date
|
||||||
|
|
||||||
|
- Make sure to announce codebase freeze deadline to all developers
|
||||||
|
- Update [release notes](https://github.com/vcmi/vcmi/blob/develop/ChangeLog.md)
|
||||||
|
- Update release date for Linux packaging. See [example](https://github.com/vcmi/vcmi/pull/1258)
|
||||||
|
- Update release date for Android packaging. See [example](https://github.com/vcmi/vcmi/pull/2090)
|
||||||
|
- Create draft release page, specify `1.x.0` as tag for `master` after publishing
|
||||||
|
- Prepare pull request with release update for web site https://github.com/vcmi/VCMI.eu
|
||||||
|
- Prepare pull request for [vcmi-updates](https://github.com/vcmi/vcmi-updates)
|
||||||
|
|
||||||
|
### Release publishing phase
|
||||||
|
Should be done on release date
|
||||||
|
|
||||||
|
- Check that all items from milestone `Release 1.x` completed
|
||||||
|
- Merge `beta` into `master`
|
||||||
|
- Check that artifacts for all platforms are available on `master` branch
|
||||||
|
- Trigger builds for new release on Ubuntu PPA
|
||||||
|
- Attach build artifacts for all platforms to release page
|
||||||
|
- Merge prepared pull requests
|
||||||
|
- Publish release page
|
||||||
|
|
||||||
|
### After release publish
|
||||||
|
|
||||||
|
- Close `Release 1.x` milestone
|
||||||
|
- Write announcements in social networks
|
||||||
|
- Merge `master` into `develop`
|
||||||
|
- Update downloads counter in readme.md. See [example](https://github.com/vcmi/vcmi/pull/2091)
|
44
docs/maintainers/Ubuntu_PPA.md
Normal file
44
docs/maintainers/Ubuntu_PPA.md
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
< [Documentation](../Readme.md) / Ubuntu PPA
|
||||||
|
|
||||||
|
## Main links
|
||||||
|
- [Team](https://launchpad.net/~vcmi)
|
||||||
|
- [Project](https://launchpad.net/vcmi)
|
||||||
|
- [Sources](https://code.launchpad.net/~vcmi/vcmi/+git/vcmi)
|
||||||
|
- [Recipes](https://code.launchpad.net/~vcmi/+recipes)
|
||||||
|
- - [Stable recipe](https://code.launchpad.net/~vcmi/+recipe/vcmi-stable)
|
||||||
|
- - [Daily recipe](https://code.launchpad.net/~vcmi/+recipe/vcmi-daily)
|
||||||
|
- PPA's
|
||||||
|
- - [Stable PPA](https://launchpad.net/~vcmi/+archive/ubuntu/ppa)
|
||||||
|
- - [Daily PPA](https://launchpad.net/~vcmi/+archive/ubuntu/vcmi-latest)
|
||||||
|
|
||||||
|
## Automatic daily builds process
|
||||||
|
|
||||||
|
### Code import
|
||||||
|
- Launchpad performs regular (once per few hours) clone of our git repository.
|
||||||
|
- This process can be observed on [Sources](https://code.launchpad.net/~vcmi/vcmi/+git/vcmi) page.
|
||||||
|
- If necessary, it is possible to trigger fresh clone immediately (Import Now button)
|
||||||
|
### Build dependencies
|
||||||
|
- All packages required for building of vcmi are defined in [debian/control](https://github.com/vcmi/vcmi/blob/develop/debian/control) file
|
||||||
|
- Launchpad will automatically install build dependencies during build
|
||||||
|
- Dependencies of output .deb package are defined implicitly as dependencies of packages required for build
|
||||||
|
### Recipe building
|
||||||
|
- Every 24 hours Launchpad triggers daily builds on all recipes that have build schedule enable. For vcmi this is [Daily recipe](https://code.launchpad.net/~vcmi/+recipe/vcmi-daily)
|
||||||
|
- Alternatively, builds can be triggered manually using "request build(s) link on recipe page. VCMI uses this for [Stable recipe](https://code.launchpad.net/~vcmi/+recipe/vcmi-stable)
|
||||||
|
### Recipe content (build settings)
|
||||||
|
- Version of resulting .deb package is set in recipe content, e.g `{debupstream}+git{revtime}` for daily builds
|
||||||
|
- Base version (referred as `debupstream` on Launchpad is taken from source code, [debian/changelog](https://github.com/vcmi/vcmi/blob/develop/debian/changelog) file
|
||||||
|
- CMake configuration settings are taken from source code, [debian/rules](https://github.com/vcmi/vcmi/blob/develop/debian/rules) file
|
||||||
|
- Branch which is used for build is specified in recipe content, e.g. `lp:vcmi master`
|
||||||
|
## Workflow for creating a release build
|
||||||
|
- if necessary, push all required changes including `debian/changelog` update to `vcmi/master` branch
|
||||||
|
- Go to [Sources](https://code.launchpad.net/~vcmi/vcmi/+git/vcmi) and run repository import.
|
||||||
|
- Wait for import to finish, which usually happens within a minute. Press F5 to actually see changes.
|
||||||
|
- Go to [Stable recipe](https://code.launchpad.net/~vcmi/+recipe/vcmi-stable) and request new builds
|
||||||
|
- Wait for builds to finish. This takes quite a while, usually - over a hour, even more for arm builds
|
||||||
|
- Once built, all successfully built packages are automatically copied to PPA linked to the recipe
|
||||||
|
- If any of builds have failed, open page with build info and check logs.
|
||||||
|
## People with access
|
||||||
|
- [alexvins](https://github.com/alexvins) (https://launchpad.net/~alexvins)
|
||||||
|
- [ArseniyShestakov](https://github.com/ArseniyShestakov) (https://launchpad.net/~sxx)
|
||||||
|
- [IvanSavenko](https://github.com/IvanSavenko) (https://launchpad.net/~saven-ivan)
|
||||||
|
- (Not member of VCMI, creator of PPA) (https://launchpad.net/~mantas)
|
208
docs/modders/Animation_Format.md
Normal file
208
docs/modders/Animation_Format.md
Normal file
@ -0,0 +1,208 @@
|
|||||||
|
< [Documentation](../Readme.md) / [Modding](Readme.md) / Animation Format
|
||||||
|
|
||||||
|
VCMI allows overriding HoMM3 .def files with .json replacement. Compared
|
||||||
|
to .def this format allows:
|
||||||
|
|
||||||
|
- Overriding individual frames from json file (e.g. icons)
|
||||||
|
- Modern graphics formats (targa, png - all formats supported by VCMI
|
||||||
|
image loader)
|
||||||
|
- Does not requires any special tools - all you need is text editor
|
||||||
|
and images.
|
||||||
|
|
||||||
|
# Format description
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
{
|
||||||
|
// Base path of all images in animation. Optional.
|
||||||
|
// Can be used to avoid using long path to images
|
||||||
|
"basepath" : "path/to/images/directory/",
|
||||||
|
|
||||||
|
// List of sequiences / groups in animation
|
||||||
|
// This will replace original group with specified list of files
|
||||||
|
// even if original animation is longer
|
||||||
|
"sequences" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
// Index of group, zero-based
|
||||||
|
"group" : 1,
|
||||||
|
|
||||||
|
// List of files in this group
|
||||||
|
"frames" :
|
||||||
|
[
|
||||||
|
"frame1.png",
|
||||||
|
"frame2.png"
|
||||||
|
...
|
||||||
|
]
|
||||||
|
},
|
||||||
|
...
|
||||||
|
],
|
||||||
|
|
||||||
|
// Allow overriding individual frames in file
|
||||||
|
"images" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
// Group of this image. Optional, default = 0
|
||||||
|
"group" : 0,
|
||||||
|
|
||||||
|
// Imdex of the image in group
|
||||||
|
"frame" : 0,
|
||||||
|
|
||||||
|
// Filename for this frame
|
||||||
|
"file" : "filename.png"
|
||||||
|
}.
|
||||||
|
...
|
||||||
|
]
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# Creature animation groups
|
||||||
|
|
||||||
|
Animation for creatures consist from multiple groups, with each group
|
||||||
|
representing specific one animation. VCMI uses groups as follows:
|
||||||
|
|
||||||
|
**Basic animations**
|
||||||
|
|
||||||
|
- \[0\] Movement: Used for creature movement
|
||||||
|
- \[1\] Mouse over: Used for random idle movements and when mouse is
|
||||||
|
moved on the creature
|
||||||
|
- \[2\] Idle: Basic animation that plays continuously when stack is
|
||||||
|
not acting
|
||||||
|
- \[3\] Hitted: Animation that plays whenever stack is hit
|
||||||
|
- \[4\] Defence: Alternative animation that plays when stack is
|
||||||
|
defending and was hit in melee
|
||||||
|
- \[5\] Death: Animation that plays when stack dies
|
||||||
|
- \[6\] Death (ranged): Alternative animation, plays when stack is
|
||||||
|
killed by ranged attack
|
||||||
|
|
||||||
|
**Rotation animations**
|
||||||
|
|
||||||
|
- \[7\] Turn left: Animation for rotating stack, only contains first
|
||||||
|
part of animation, with stack turning towards viewer
|
||||||
|
- \[8\] Turn right: Second part of animation for rotating stack
|
||||||
|
- \[9\] (unused in vcmi, present in H3 files)
|
||||||
|
- \[10\] (unused in vcmi, present in H3 files)
|
||||||
|
|
||||||
|
**Melee attack animations**
|
||||||
|
|
||||||
|
- \[11\] Attack (up): Attacking animation, stack facing upwards
|
||||||
|
- \[12\] Attack (front): Attacking animation, stack facing front
|
||||||
|
- \[13\] Attack (down): Attacking animation, stack facing downwards
|
||||||
|
|
||||||
|
**Ranged attack animations**
|
||||||
|
|
||||||
|
- \[14\] Shooting (up): Ranged attack animation, stack facing upwards
|
||||||
|
- \[15\] Shooting (front): Ranged attack animation, stack facing front
|
||||||
|
- \[16\] Shooting (down): Ranged attack animation, stack facing
|
||||||
|
downwards
|
||||||
|
|
||||||
|
**Special animations**
|
||||||
|
|
||||||
|
- \[17\] Special (up): Special animation, used if dedicated cast or
|
||||||
|
group attack animations were not found
|
||||||
|
- \[18\] Special (front): Special animation, used if dedicated cast or
|
||||||
|
group attack animations were not found
|
||||||
|
- \[19\] Special (down): Special animation, used if dedicated cast or
|
||||||
|
group attack animations were not found
|
||||||
|
|
||||||
|
**Additional H3 animations**
|
||||||
|
|
||||||
|
- \[20\] Movement start: Animation that plays before movement
|
||||||
|
animation starts.
|
||||||
|
- \[21\] Movement end: Animation that plays after movement animation
|
||||||
|
ends.
|
||||||
|
|
||||||
|
**Additional VCMI animations**
|
||||||
|
|
||||||
|
- \[22\] \[VCMI 1.0\] Dead: Animation that plays when creature is
|
||||||
|
dead. If not present, will consist from last frame from "Death"
|
||||||
|
group
|
||||||
|
- \[23\] \[VCMI 1.0\] Dead (ranged): Animation that plays when
|
||||||
|
creature is dead after ranged attack. If not present, will consist
|
||||||
|
from last frame from "Death (ranged)" group
|
||||||
|
- \[24\] \[VCMI 1.2\] Resurrection: Animation that plays when creature
|
||||||
|
is resurrected. If not present, will consist from reversed version
|
||||||
|
of "Death" animation
|
||||||
|
|
||||||
|
**Spellcasting animations**
|
||||||
|
|
||||||
|
- \[30\] \[VCMI 1.2\] Cast (up): Used when creature casts spell facing
|
||||||
|
upwards
|
||||||
|
- \[31\] \[VCMI 1.2\] Cast (front): Used when creature casts spell
|
||||||
|
facing front
|
||||||
|
- \[32\] \[VCMI 1.2\] Cast (down): Used when creature casts spell
|
||||||
|
facing downwards
|
||||||
|
|
||||||
|
**Group attack animations**
|
||||||
|
|
||||||
|
- \[40\] \[VCMI 1.2\] Group Attack (up): Used when creature attacks
|
||||||
|
multiple target, with primary target facing up (Dragon Breath
|
||||||
|
attack, or creatures like Hydra)
|
||||||
|
- \[41\] \[VCMI 1.2\] Group Attack (front): Used when creature attacks
|
||||||
|
multiple target, with primary target facing front (Dragon Breath
|
||||||
|
attack, or creatures like Hydra)
|
||||||
|
- \[42\] \[VCMI 1.2\] Group Attack (down): Used when creature attacks
|
||||||
|
multiple target, with primary target facing downwards (Dragon Breath
|
||||||
|
attack, or creatures like Hydra)
|
||||||
|
|
||||||
|
# Proposed format extensions
|
||||||
|
|
||||||
|
## Texture atlas format
|
||||||
|
|
||||||
|
**TODO**
|
||||||
|
|
||||||
|
- arbitrary texture coordinates
|
||||||
|
- margins
|
||||||
|
- grid-like layout
|
||||||
|
|
||||||
|
### Texture atlas format
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
{
|
||||||
|
// Base path of all images in animation. Optional.
|
||||||
|
// Can be used to avoid using long path to images
|
||||||
|
// If a path is a filename is is treated as single texture atlas
|
||||||
|
"basepath" : "path/to/images/atlas/bitmap.png",
|
||||||
|
|
||||||
|
// List of sequences / groups in animation
|
||||||
|
"sequences" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
// Index of group, zero-based
|
||||||
|
"group" : 1,
|
||||||
|
|
||||||
|
// List of files in this group
|
||||||
|
"frames" :
|
||||||
|
[
|
||||||
|
{"x":0, "y":0, "w": 64, "h": 64},
|
||||||
|
{"x":64, "y":0, "w": 64, "h": 64}
|
||||||
|
...
|
||||||
|
]
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Texture atlas grid format
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
{
|
||||||
|
// filename is is treated as single texture atlas
|
||||||
|
"basepath" : "path/to/images/atlas/bitmap.png",
|
||||||
|
|
||||||
|
//optional, atlas is a grid with same size images
|
||||||
|
//located left to right, top to bottom
|
||||||
|
//[columns, rows]
|
||||||
|
//default [1,1]
|
||||||
|
"gridCols":3,
|
||||||
|
"gridRows":3,
|
||||||
|
|
||||||
|
// List of sequences / groups in animation
|
||||||
|
// sequence index -> images count in sequence
|
||||||
|
"sequences" :
|
||||||
|
[
|
||||||
|
1,3,5
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
19
docs/modders/Bonus/Bonus_Duration_Types.md
Normal file
19
docs/modders/Bonus/Bonus_Duration_Types.md
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
< [Documentation](../../Readme.md) / [Modding](../Readme.md) / [Bonus Format](../Bonus_Format.md) / Bonus Duration Types
|
||||||
|
|
||||||
|
|
||||||
|
Bonus may have any of these durations. They acts in disjunction.
|
||||||
|
|
||||||
|
## List of all bonus duration types
|
||||||
|
|
||||||
|
- PERMANENT
|
||||||
|
- ONE_BATTLE //at the end of battle
|
||||||
|
- ONE_DAY //at the end of day
|
||||||
|
- ONE_WEEK //at the end of week (bonus lasts till the end of week,
|
||||||
|
thats NOT 7 days
|
||||||
|
- N_TURNS //used during battles, after battle bonus is always removed
|
||||||
|
- N_DAYS
|
||||||
|
- UNTIL_BEING_ATTACKED //removed after any damage-inflicting attack
|
||||||
|
- UNTIL_ATTACK //removed after attack and counterattacks are performed
|
||||||
|
- STACK_GETS_TURN //removed when stack gets its turn - used for
|
||||||
|
defensive stance
|
||||||
|
- COMMANDER_KILLED
|
107
docs/modders/Bonus/Bonus_Limiters.md
Normal file
107
docs/modders/Bonus/Bonus_Limiters.md
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
< [Documentation](../../Readme.md) / [Modding](../Readme.md) / [Bonus Format](../Bonus_Format.md) / Bonus Limiters
|
||||||
|
|
||||||
|
## Predefined Limiters
|
||||||
|
|
||||||
|
The limiters take no parameters:
|
||||||
|
|
||||||
|
- SHOOTER_ONLY
|
||||||
|
- DRAGON_NATURE
|
||||||
|
- IS_UNDEAD
|
||||||
|
- CREATURE_NATIVE_TERRAIN
|
||||||
|
- OPPOSITE_SIDE
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
"limiters" : [ "SHOOTER_ONLY" ]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Customizable Limiters
|
||||||
|
|
||||||
|
### HAS_ANOTHER_BONUS_LIMITER
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
- Bonus type
|
||||||
|
- (optional) bonus subtype
|
||||||
|
- (optional) bonus sourceType and sourceId in struct
|
||||||
|
- example: (from Adele's bless):
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
"limiters" : [
|
||||||
|
{
|
||||||
|
"type" : "HAS_ANOTHER_BONUS_LIMITER",
|
||||||
|
"parameters" : [
|
||||||
|
"GENERAL_DAMAGE_PREMY",
|
||||||
|
1,
|
||||||
|
{
|
||||||
|
"type" : "SPELL_EFFECT",
|
||||||
|
"id" : "spell.bless"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
### CREATURE_TYPE_LIMITER
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
- Creature id (string)
|
||||||
|
- (optional) include upgrades - default is false
|
||||||
|
|
||||||
|
### CREATURE_ALIGNMENT_LIMITER
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
- Alignment identifier
|
||||||
|
|
||||||
|
### CREATURE_FACTION_LIMITER
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
- Faction identifier
|
||||||
|
|
||||||
|
### CREATURE_TERRAIN_LIMITER
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
|
||||||
|
- Terrain identifier
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
"limiters": [ {
|
||||||
|
"type":"CREATURE_TYPE_LIMITER",
|
||||||
|
"parameters": [ "angel", true ]
|
||||||
|
} ],
|
||||||
|
```
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
"limiters" : [ {
|
||||||
|
"type" : "CREATURE_TERRAIN_LIMITER",
|
||||||
|
"parameters" : ["sand"]
|
||||||
|
} ]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Aggregate Limiters
|
||||||
|
|
||||||
|
The following limiters must be specified as the first element of a list,
|
||||||
|
and operate on the remaining limiters in that list:
|
||||||
|
|
||||||
|
- allOf (default when no aggregate limiter is specified)
|
||||||
|
- anyOf
|
||||||
|
- noneOf
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
"limiters" : [
|
||||||
|
"noneOf",
|
||||||
|
"IS_UNDEAD",
|
||||||
|
{
|
||||||
|
"type" : "HAS_ANOTHER_BONUS_LIMITER",
|
||||||
|
"parameters" : [ "SIEGE_WEAPON" ]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
27
docs/modders/Bonus/Bonus_Propagators.md
Normal file
27
docs/modders/Bonus/Bonus_Propagators.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
< [Documentation](../../Readme.md) / [Modding](../Readme.md) / [Bonus Format](../Bonus_Format.md) / Bonus Propagators
|
||||||
|
|
||||||
|
## Available propagators
|
||||||
|
|
||||||
|
- BATTLE_WIDE
|
||||||
|
|
||||||
|
Affects both sides during battle
|
||||||
|
|
||||||
|
- VISITED_TOWN_AND_VISITOR
|
||||||
|
|
||||||
|
Used with Legion artifacts (town visited by hero)
|
||||||
|
|
||||||
|
- PLAYER_PROPAGATOR
|
||||||
|
|
||||||
|
Bonus will affect all objects owned by player. Used by Statue of Legion.
|
||||||
|
|
||||||
|
- TEAM_PROPAGATOR
|
||||||
|
|
||||||
|
Bonus will affect all objects owned by player and his allies.
|
||||||
|
|
||||||
|
- HERO
|
||||||
|
|
||||||
|
Bonus will be transferred to hero (for example from stacks in his army).
|
||||||
|
|
||||||
|
- GLOBAL_EFFECT
|
||||||
|
|
||||||
|
This effect will influence all creatures, heroes and towns on the map.
|
22
docs/modders/Bonus/Bonus_Range_Types.md
Normal file
22
docs/modders/Bonus/Bonus_Range_Types.md
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
< [Documentation](../../Readme.md) / [Modding](../Readme.md) / [Bonus Format](../Bonus_Format.md) / Bonus Range Types
|
||||||
|
|
||||||
|
# List of all Bonus range types
|
||||||
|
|
||||||
|
- NO_LIMIT
|
||||||
|
- ONLY_DISTANCE_FIGHT
|
||||||
|
- ONLY_MELEE_FIGHT
|
||||||
|
- ONLY_ENEMY_ARMY (before 1.2)
|
||||||
|
|
||||||
|
TODO: in 0.91 ONLY_MELEE_FIGHT / ONLY_DISTANCE_FIGHT range types work
|
||||||
|
ONLY with creature attack, should be extended to all battle abilities.
|
||||||
|
|
||||||
|
(1.2+) For replacing ONLY_ENEMY_ARMY alias, you should use the following
|
||||||
|
parameters of bonus:
|
||||||
|
|
||||||
|
"propagator": "BATTLE_WIDE",
|
||||||
|
"propagationUpdater" : "BONUS_OWNER_UPDATER",
|
||||||
|
"limiters" : [ "OPPOSITE_SIDE" ]
|
||||||
|
|
||||||
|
If some propagators was set before, it was actually ignored and should
|
||||||
|
be replaced to code above. And OPPOSITE_SIDE limiter should be first, if
|
||||||
|
any other limiters exists.
|
23
docs/modders/Bonus/Bonus_Sources.md
Normal file
23
docs/modders/Bonus/Bonus_Sources.md
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
< [Documentation](../../Readme.md) / [Modding](../Readme.md) / [Bonus Format](../Bonus_Format.md) / Bonus Sources
|
||||||
|
|
||||||
|
# List of all possible bonus sources
|
||||||
|
|
||||||
|
- ARTIFACT
|
||||||
|
- ARTIFACT_INSTANCE
|
||||||
|
- OBJECT
|
||||||
|
- CREATURE_ABILITY
|
||||||
|
- TERRAIN_NATIVE
|
||||||
|
- TERRAIN_OVERLAY
|
||||||
|
- SPELL_EFFECT
|
||||||
|
- TOWN_STRUCTURE
|
||||||
|
- HERO_BASE_SKILL
|
||||||
|
- SECONDARY_SKILL
|
||||||
|
- HERO_SPECIAL
|
||||||
|
- ARMY
|
||||||
|
- CAMPAIGN_BONUS
|
||||||
|
- SPECIAL_WEEK
|
||||||
|
- STACK_EXPERIENCE
|
||||||
|
- COMMANDER
|
||||||
|
- GLOBAL_EFFECT (before 1.2)
|
||||||
|
- GLOBAL (after 1.2)
|
||||||
|
- OTHER
|
834
docs/modders/Bonus/Bonus_Types.md
Normal file
834
docs/modders/Bonus/Bonus_Types.md
Normal file
@ -0,0 +1,834 @@
|
|||||||
|
< [Documentation](../../Readme.md) / [Modding](../Readme.md) / [Bonus Format](../Bonus_Format.md) / Bonus Types
|
||||||
|
|
||||||
|
The bonuses were grouped according to their original purpose. The bonus
|
||||||
|
system allows them to propagate freely betwen the nodes, however they
|
||||||
|
may not be recognized properly beyond the scope of original use.
|
||||||
|
|
||||||
|
# General-purpose bonuses
|
||||||
|
|
||||||
|
### NONE
|
||||||
|
|
||||||
|
### MORALE, LUCK
|
||||||
|
|
||||||
|
- val = value
|
||||||
|
|
||||||
|
### MAGIC_SCHOOL_SKILL
|
||||||
|
|
||||||
|
eg. for magic plains terrain and for magic school secondary skills
|
||||||
|
|
||||||
|
- subtype: school of magic (0 - all, 1 - air, 2 - fire, 4 - water, 8 -
|
||||||
|
earth)
|
||||||
|
- val - level
|
||||||
|
|
||||||
|
### NO_TYPE
|
||||||
|
|
||||||
|
### DARKNESS
|
||||||
|
|
||||||
|
- val = radius
|
||||||
|
|
||||||
|
# Hero bonuses
|
||||||
|
|
||||||
|
### MOVEMENT
|
||||||
|
|
||||||
|
Before 1.2: both water / land After 1.2: subtype 0 - sea, subtype 1 -
|
||||||
|
land
|
||||||
|
|
||||||
|
- val = number of movement points (100 points for a tile)
|
||||||
|
|
||||||
|
### LAND_MOVEMENT, SEA_MOVEMENT (before 1.2)
|
||||||
|
|
||||||
|
- val = number of movement points (100 points for a tile)
|
||||||
|
|
||||||
|
### WATER_WALKING
|
||||||
|
|
||||||
|
- subtype: 1 - without penalty, 2 - with penalty
|
||||||
|
|
||||||
|
### FLYING_MOVEMENT
|
||||||
|
|
||||||
|
- subtype: 1 - without penalty, 2 - with penalty
|
||||||
|
|
||||||
|
### NO_TERRAIN_PENALTY (since 0.98f)
|
||||||
|
|
||||||
|
Hero does not get movement penalty on certain terrain type (Nomads
|
||||||
|
ability).
|
||||||
|
|
||||||
|
- subtype - type of terrain
|
||||||
|
|
||||||
|
### PRIMARY_SKILL
|
||||||
|
|
||||||
|
- uses subtype to pick skill
|
||||||
|
- additional info if set: 1 - only melee, 2 - only distance
|
||||||
|
|
||||||
|
### SIGHT_RADIOUS (before 1.2)
|
||||||
|
|
||||||
|
Additional bonus to range of sight (Used for Scouting secondary skill)
|
||||||
|
|
||||||
|
- val = distance in tiles
|
||||||
|
|
||||||
|
### SIGHT_RADIUS (after 1.2)
|
||||||
|
|
||||||
|
Sight radius of a hero. Used for base radius + Scouting secondary skill
|
||||||
|
|
||||||
|
- val = distance in tiles
|
||||||
|
|
||||||
|
### MANA_REGENERATION
|
||||||
|
|
||||||
|
Before 1.2: points per turn apart from normal (1 + mysticism) After 1.2:
|
||||||
|
points per turn (used for artifacts, global 1 point/turn regeneration
|
||||||
|
and mysticism secondary skill)
|
||||||
|
|
||||||
|
### FULL_MANA_REGENERATION
|
||||||
|
|
||||||
|
all mana points are replenished every day
|
||||||
|
|
||||||
|
### NONEVIL_ALIGNMENT_MIX
|
||||||
|
|
||||||
|
good and neutral creatures can be mixed without morale penalty
|
||||||
|
|
||||||
|
### SECONDARY_SKILL_PREMY (before 1.2)
|
||||||
|
|
||||||
|
%
|
||||||
|
|
||||||
|
### SURRENDER_DISCOUNT
|
||||||
|
|
||||||
|
%
|
||||||
|
|
||||||
|
### IMPROVED_NECROMANCY
|
||||||
|
|
||||||
|
Before 1.2: allows Necropolis units other than skeletons to be raised by
|
||||||
|
necromancy After 1.2: determine units which is raised by necromancy
|
||||||
|
skill.
|
||||||
|
|
||||||
|
- subtype: creature raised
|
||||||
|
- val: Necromancer power
|
||||||
|
- addInfo: limiter by Necromancer power
|
||||||
|
- Example (from Necromancy skill):
|
||||||
|
|
||||||
|
` "power" : {`
|
||||||
|
` "type" : "IMPROVED_NECROMANCY",`
|
||||||
|
` "subtype" : "creature.skeleton",`
|
||||||
|
` "addInfo" : 0`
|
||||||
|
` }`
|
||||||
|
|
||||||
|
### LEARN_BATTLE_SPELL_CHANCE (since 1.2)
|
||||||
|
|
||||||
|
- subtype: 0 - from enemy hero, 1 - from entire battlefield (not
|
||||||
|
implemented now).
|
||||||
|
- val: chance to learn spell after battle victory
|
||||||
|
|
||||||
|
Note: used for Eagle Eye skill
|
||||||
|
|
||||||
|
### LEARN_BATTLE_SPELL_LEVEL_LIMIT (since 1.2)
|
||||||
|
|
||||||
|
- subtype: school (-1 for all), others TODO
|
||||||
|
- val: maximum learning level
|
||||||
|
|
||||||
|
Note: used for Eagle Eye skill
|
||||||
|
|
||||||
|
### LEARN_MEETING_SPELL_LIMIT (since 1.2)
|
||||||
|
|
||||||
|
- subtype: school (-1 for all), others TODO
|
||||||
|
- val: maximum learning level for learning a spell during hero
|
||||||
|
exchange
|
||||||
|
|
||||||
|
Note: used for Scholar skill
|
||||||
|
|
||||||
|
### ROUGH_TERRAIN_DISCOUNT (since 1.2)
|
||||||
|
|
||||||
|
- val: Non-road terrain discount in movement points
|
||||||
|
|
||||||
|
Note: used for Pathfinding skill
|
||||||
|
|
||||||
|
### WANDERING_CREATURES_JOIN_BONUS (since 1.2)
|
||||||
|
|
||||||
|
- val: value than used as level of diplomacy inside joining
|
||||||
|
probability calculating
|
||||||
|
|
||||||
|
### BEFORE_BATTLE_REPOSITION (since 1.2)
|
||||||
|
|
||||||
|
- val: number of hexes - 1 than should be used as repositionable hexes
|
||||||
|
before battle (like H3 tactics skill)
|
||||||
|
|
||||||
|
### BEFORE_BATTLE_REPOSITION_BLOCK (since 1.2)
|
||||||
|
|
||||||
|
- val: value than block opposite tactics, if value of opposite tactics
|
||||||
|
is less than this value of your hero (for 1.2, double-side tactics
|
||||||
|
is not working).
|
||||||
|
|
||||||
|
### HERO_EXPERIENCE_GAIN_PERCENT (since 1.2)
|
||||||
|
|
||||||
|
- val: how many experience hero gains from any source. There is a
|
||||||
|
global effect which set it by 100 (global value) and it is used as
|
||||||
|
learning skill
|
||||||
|
|
||||||
|
### UNDEAD_RAISE_PERCENTAGE (since 1.2)
|
||||||
|
|
||||||
|
- val: Percentage of killed enemy creatures to be raised after battle
|
||||||
|
as undead.
|
||||||
|
|
||||||
|
Note: used for Necromancy secondary skill, Necromancy artifacts and town
|
||||||
|
buildings.
|
||||||
|
|
||||||
|
### MANA_PER_KNOWLEDGE (since 1.2)
|
||||||
|
|
||||||
|
- val: Percentage rate of translating 10 hero knowledge to mana, used
|
||||||
|
for intelligence and global bonus
|
||||||
|
|
||||||
|
### HERO_GRANTS_ATTACKS (since 1.2)
|
||||||
|
|
||||||
|
- subtype: creature to have additional attacks
|
||||||
|
- val: Number of attacks
|
||||||
|
|
||||||
|
Note: used for Artillery secondary skill
|
||||||
|
|
||||||
|
### BONUS_DAMAGE_PERCENTAGE (since 1.2)
|
||||||
|
|
||||||
|
- subtype: creature to have additional damage percentage
|
||||||
|
- val: percentage to be granted
|
||||||
|
|
||||||
|
Note: used for Artillery secondary skill
|
||||||
|
|
||||||
|
### BONUS_DAMAGE_CHANCE (since 1.2)
|
||||||
|
|
||||||
|
- subtype: creature to have additional damage chance (will have
|
||||||
|
BONUS_DAMAGE_PERCENTAGE applied before attack concluded)
|
||||||
|
- val: chance in percent
|
||||||
|
|
||||||
|
### MAX_LEARNABLE_SPELL_LEVEL (since 1.2)
|
||||||
|
|
||||||
|
- val: maximum level of spells than hero can learn from any source.
|
||||||
|
This bonus have priority above any other LEARN\_\*SPELL_LEVEL
|
||||||
|
bonuses.
|
||||||
|
|
||||||
|
Note: used as global effect and as wisdom secondary skill.
|
||||||
|
|
||||||
|
## Hero specialties
|
||||||
|
|
||||||
|
### SPECIAL_SPELL_LEV
|
||||||
|
|
||||||
|
- subtype = id
|
||||||
|
- additionalInfo = value per level in percent
|
||||||
|
|
||||||
|
### SPELL_DAMAGE
|
||||||
|
|
||||||
|
Since 1.2: used for Sorcery secondary skill
|
||||||
|
|
||||||
|
- val = value in percent
|
||||||
|
|
||||||
|
### SPECIFIC_SPELL_DAMAGE
|
||||||
|
|
||||||
|
- subtype = id of spell
|
||||||
|
- val = value in percent (Luna, Ciele)
|
||||||
|
|
||||||
|
### SPECIAL_BLESS_DAMAGE (before 1.2)
|
||||||
|
|
||||||
|
- subtype = spell (bless by default)
|
||||||
|
- val = value per level in percent
|
||||||
|
|
||||||
|
### MAXED_SPELL (before 1.2)
|
||||||
|
|
||||||
|
Spell always has expert effects but not expert range
|
||||||
|
|
||||||
|
- subtype = id
|
||||||
|
|
||||||
|
### SPECIAL_PECULIAR_ENCHANT
|
||||||
|
|
||||||
|
blesses and curses with id = val dependent on unit's level
|
||||||
|
|
||||||
|
- subtype = 0 or 1 for Coronius
|
||||||
|
|
||||||
|
### SPECIAL_UPGRADE
|
||||||
|
|
||||||
|
- subtype = base creature ID
|
||||||
|
- addInfo = target creature ID
|
||||||
|
|
||||||
|
# Artifact bonuses
|
||||||
|
|
||||||
|
### SPELL_DURATION
|
||||||
|
|
||||||
|
### AIR_SPELL_DMG_PREMY, EARTH_SPELL_DMG_PREMY, FIRE_SPELL_DMG_PREMY, WATER_SPELL_DMG_PREMY
|
||||||
|
|
||||||
|
Effect of original Orb artifacts.
|
||||||
|
|
||||||
|
- val - **percent** bonus to air / earth / fire / water spell damage.
|
||||||
|
|
||||||
|
### BLOCK_MORALE, BLOCK_LUCK (removed in 1.2)
|
||||||
|
|
||||||
|
### SPELL
|
||||||
|
|
||||||
|
Hero knows spell, even if this spell is banned in map options or set to
|
||||||
|
"special".
|
||||||
|
|
||||||
|
- subtype - spell id
|
||||||
|
- val - skill level (0 - 3)
|
||||||
|
|
||||||
|
### SPELLS_OF_LEVEL
|
||||||
|
|
||||||
|
hero knows all spells of given level
|
||||||
|
|
||||||
|
- subtype - level
|
||||||
|
- val - skill level
|
||||||
|
|
||||||
|
Does not grant spells banned in map options.
|
||||||
|
|
||||||
|
### FIRE_SPELLS, AIR_SPELLS, WATER_SPELLS, EARTH_SPELLS
|
||||||
|
|
||||||
|
All spells of this school are granted to hero, eg. by Tomes of Magic.
|
||||||
|
Does not grant spells banned in map options.
|
||||||
|
|
||||||
|
### GENERATE_RESOURCE
|
||||||
|
|
||||||
|
- subtype - resource
|
||||||
|
- val - daily income
|
||||||
|
|
||||||
|
### CREATURE_GROWTH
|
||||||
|
|
||||||
|
for legion artifacts
|
||||||
|
|
||||||
|
- value - weekly growth bonus,
|
||||||
|
- subtype - monster level if aplicable
|
||||||
|
|
||||||
|
### CREATURE_GROWTH_PERCENT
|
||||||
|
|
||||||
|
increases growth of all units in all towns,
|
||||||
|
|
||||||
|
- val - percentage
|
||||||
|
|
||||||
|
### BATTLE_NO_FLEEING
|
||||||
|
|
||||||
|
for Shackles of War
|
||||||
|
|
||||||
|
### NEGATE_ALL_NATURAL_IMMUNITIES
|
||||||
|
|
||||||
|
Orb of Vulnerability
|
||||||
|
|
||||||
|
### OPENING_BATTLE_SPELL
|
||||||
|
|
||||||
|
casts a spell at expert level at beginning of battle
|
||||||
|
|
||||||
|
- subtype - Spell ID
|
||||||
|
- val - spell power
|
||||||
|
|
||||||
|
### FREE_SHIP_BOARDING
|
||||||
|
|
||||||
|
movement points preserved with ship boarding and landing
|
||||||
|
|
||||||
|
### WHIRLPOOL_PROTECTION
|
||||||
|
|
||||||
|
hero won't lose army when teleporting through whirlpool
|
||||||
|
|
||||||
|
# Creature bonuses
|
||||||
|
|
||||||
|
### STACK_HEALTH
|
||||||
|
|
||||||
|
### STACKS_SPEED
|
||||||
|
|
||||||
|
- additional info - percent of speed bonus applied after direct
|
||||||
|
bonuses; \>0 - added, \<0 - subtracted to this part
|
||||||
|
|
||||||
|
### CREATURE_DAMAGE
|
||||||
|
|
||||||
|
- subtype: 0 = both, 1 = min, 2 = max
|
||||||
|
|
||||||
|
### SHOTS
|
||||||
|
|
||||||
|
### EXP_MULTIPLIER
|
||||||
|
|
||||||
|
- val - percent of additional exp gained by stack / commander (base
|
||||||
|
value 100)
|
||||||
|
|
||||||
|
# Creature abilities
|
||||||
|
|
||||||
|
## Static abilities and immunities
|
||||||
|
|
||||||
|
### NON_LIVING
|
||||||
|
|
||||||
|
eg. golems, elementals
|
||||||
|
|
||||||
|
### GARGOYLE
|
||||||
|
|
||||||
|
Gargoyle is special than NON_LIVING, cannot be rised or healed
|
||||||
|
|
||||||
|
### UNDEAD
|
||||||
|
|
||||||
|
### SIEGE_WEAPON
|
||||||
|
|
||||||
|
War machines have it. They cannot be raised or healed, have no morale
|
||||||
|
and don't move.
|
||||||
|
|
||||||
|
### DRAGON_NATURE
|
||||||
|
|
||||||
|
### KING1, KING2, KING3 (before 1.2)
|
||||||
|
|
||||||
|
Creatures take more damage from basic, advanced or expert Slayer effect.
|
||||||
|
|
||||||
|
### KING (after 1.2)
|
||||||
|
|
||||||
|
Creatures take more damage from Slayer effect than have greater or equal
|
||||||
|
value than KING bonus.
|
||||||
|
|
||||||
|
### FEARLESS
|
||||||
|
|
||||||
|
### NO_LUCK
|
||||||
|
|
||||||
|
eg. when fighting on cursed ground
|
||||||
|
|
||||||
|
### NO_MORALE
|
||||||
|
|
||||||
|
eg. when fighting on cursed ground
|
||||||
|
|
||||||
|
### SELF_MORALE (before 1.2)
|
||||||
|
|
||||||
|
eg. minotaur
|
||||||
|
|
||||||
|
### SELF_LUCK (before 1.2)
|
||||||
|
|
||||||
|
halfling
|
||||||
|
|
||||||
|
## Combat abilities
|
||||||
|
|
||||||
|
### FLYING
|
||||||
|
|
||||||
|
- subtype - 0 - regular, 1 - teleport
|
||||||
|
|
||||||
|
### SHOOTER
|
||||||
|
|
||||||
|
### CHARGE_IMMUNITY
|
||||||
|
|
||||||
|
### ADDITIONAL_ATTACK
|
||||||
|
|
||||||
|
### UNLIMITED_RETALIATIONS
|
||||||
|
|
||||||
|
### ADDITIONAL_RETALIATION
|
||||||
|
|
||||||
|
- value - number of additional retaliations
|
||||||
|
|
||||||
|
### JOUSTING
|
||||||
|
|
||||||
|
for champions
|
||||||
|
|
||||||
|
- val: percentage of charge
|
||||||
|
|
||||||
|
### HATE
|
||||||
|
|
||||||
|
eg. angels hate devils,
|
||||||
|
|
||||||
|
- subtype - ID of hated creature,
|
||||||
|
- val - damage bonus percent
|
||||||
|
|
||||||
|
### SPELL_LIKE_ATTACK
|
||||||
|
|
||||||
|
range is taken from spell, but damage from creature; eg. magog, lich
|
||||||
|
|
||||||
|
- subtype - spell,
|
||||||
|
- value - spell level
|
||||||
|
|
||||||
|
### THREE_HEADED_ATTACK
|
||||||
|
|
||||||
|
eg. cerberus
|
||||||
|
|
||||||
|
### ATTACKS_ALL_ADJACENT
|
||||||
|
|
||||||
|
eg. hydra
|
||||||
|
|
||||||
|
### TWO_HEX_ATTACK_BREATH
|
||||||
|
|
||||||
|
eg. dragons
|
||||||
|
|
||||||
|
### RETURN_AFTER_STRIKE
|
||||||
|
|
||||||
|
### ENEMY_DEFENCE_REDUCTION
|
||||||
|
|
||||||
|
in % (value) eg. behemots
|
||||||
|
|
||||||
|
### GENERAL_DAMAGE_REDUCTION
|
||||||
|
|
||||||
|
- subtype - 0 - shield (melee) , 1 - air shield effect (ranged), -1 -
|
||||||
|
armorer secondary skill (all, since 1.2)
|
||||||
|
|
||||||
|
### PERCENTAGE_DAMAGE_BOOST (since 1.2)
|
||||||
|
|
||||||
|
- subtype: -1 - any damage (not used), 0 - melee damage (offence), 1 -
|
||||||
|
ranged damage (archery)
|
||||||
|
|
||||||
|
### GENERAL_ATTACK_REDUCTION
|
||||||
|
|
||||||
|
eg. while stoned or blinded - in %
|
||||||
|
|
||||||
|
- subtype: -1 - any damage, 0 - melee damage, 1 - ranged damage
|
||||||
|
|
||||||
|
### DEFENSIVE_STANCE
|
||||||
|
|
||||||
|
WoG ability.
|
||||||
|
|
||||||
|
- val - bonus to defense while defending
|
||||||
|
|
||||||
|
### NO_DISTANCE_PENALTY
|
||||||
|
|
||||||
|
### NO_MELEE_PENALTY
|
||||||
|
|
||||||
|
Ranged stack does full damage in melee.
|
||||||
|
|
||||||
|
### NO_WALL_PENALTY
|
||||||
|
|
||||||
|
### FREE_SHOOTING
|
||||||
|
|
||||||
|
stacks can shoot even if otherwise blocked (sharpshooter's bow effect)
|
||||||
|
|
||||||
|
### BLOCKS_RETALIATION
|
||||||
|
|
||||||
|
eg. naga
|
||||||
|
|
||||||
|
### SOUL_STEAL
|
||||||
|
|
||||||
|
WoG ability. Gains new creatures for each enemy killed
|
||||||
|
|
||||||
|
- val: number of units gained per enemy killed
|
||||||
|
- subtype: 0 - gained units survive after battle, 1 - they do not
|
||||||
|
|
||||||
|
### TRANSMUTATION
|
||||||
|
|
||||||
|
WoG ability. % chance to transform attacked unit to other type
|
||||||
|
|
||||||
|
- val: chance to trigger in %
|
||||||
|
- subtype: 0 - resurrection based on HP, 1 - based on unit count
|
||||||
|
- addInfo: additional info - target creature ID (attacker default)
|
||||||
|
|
||||||
|
### SUMMON_GUARDIANS
|
||||||
|
|
||||||
|
WoG ability. Summon guardians surrounding desired stack
|
||||||
|
|
||||||
|
- val - amount in % of stack count
|
||||||
|
- subtype = creature ID
|
||||||
|
|
||||||
|
### RANGED_RETALIATION
|
||||||
|
|
||||||
|
Allows shooters to perform ranged retaliation
|
||||||
|
|
||||||
|
- no additional parameters
|
||||||
|
|
||||||
|
### BLOCKS_RANGED_RETALIATION
|
||||||
|
|
||||||
|
Disallows ranged retaliation for shooter unit, BLOCKS_RETALIATION bonus
|
||||||
|
is for melee retaliation only
|
||||||
|
|
||||||
|
- no additional parameters
|
||||||
|
|
||||||
|
### WIDE_BREATH
|
||||||
|
|
||||||
|
Dragon breath affecting multiple nearby hexes
|
||||||
|
|
||||||
|
- no additional parameters
|
||||||
|
|
||||||
|
### FIRST_STRIKE
|
||||||
|
|
||||||
|
First counterattack, then attack if possible
|
||||||
|
|
||||||
|
- no additional parameters
|
||||||
|
|
||||||
|
### SHOOTS_ALL_ADJACENT
|
||||||
|
|
||||||
|
H4 Cyclops-like shoot (attacks all hexes neighboring with target)
|
||||||
|
without spell-like mechanics
|
||||||
|
|
||||||
|
- no additional parameters
|
||||||
|
|
||||||
|
### DESTRUCTION
|
||||||
|
|
||||||
|
Kills extra units after hit
|
||||||
|
|
||||||
|
- subtype: 0 - kill percentage of units, 1 - kill amount
|
||||||
|
- val: chance in percent to trigger
|
||||||
|
- addInfo: amount/percentage to kill
|
||||||
|
|
||||||
|
### LIMITED_SHOOTING_RANGE (since VCMI 1.2)
|
||||||
|
|
||||||
|
Limits shooting range and/or changes long range penalty
|
||||||
|
|
||||||
|
- val: max shooting range in hexes
|
||||||
|
- addInfo: optional - sets range for "broken arrow" half damage
|
||||||
|
mechanic - default is 10
|
||||||
|
|
||||||
|
## Special abilities
|
||||||
|
|
||||||
|
### CATAPULT
|
||||||
|
|
||||||
|
- subtype: (since 1.2) ability to use when catapulting (usually it
|
||||||
|
contains ballistics parameters, ability for standard catapult and
|
||||||
|
affected by ballistics is core:spell.catapultShot)
|
||||||
|
|
||||||
|
### CATAPULT_EXTRA_SHOTS
|
||||||
|
|
||||||
|
- subtype: (since 1.2) ability to be affected. Ability of CATAPULT
|
||||||
|
bonus should match. Used for ballistics secondary skill with subtype
|
||||||
|
of core:spell.catapultShot.
|
||||||
|
- val: (since 1.2) ability level to be used with catapult. Additional
|
||||||
|
shots configured in ability level, not here.
|
||||||
|
- val: (before 1.2) number of additional shots, requires CATAPULT
|
||||||
|
bonus to work
|
||||||
|
|
||||||
|
### MANUAL_CONTROL
|
||||||
|
|
||||||
|
- manually control warmachine with
|
||||||
|
- id = subtype
|
||||||
|
- val = chance
|
||||||
|
|
||||||
|
### CHANGES_SPELL_COST_FOR_ALLY
|
||||||
|
|
||||||
|
eg. mage
|
||||||
|
|
||||||
|
- value - reduction in mana points
|
||||||
|
|
||||||
|
### CHANGES_SPELL_COST_FOR_ENEMY
|
||||||
|
|
||||||
|
eg. Silver Pegasus
|
||||||
|
|
||||||
|
- value - mana points penalty
|
||||||
|
|
||||||
|
### SPELL_RESISTANCE_AURA
|
||||||
|
|
||||||
|
eg. unicorns
|
||||||
|
|
||||||
|
- value - resistance bonus in % for adjacent creatures
|
||||||
|
|
||||||
|
### HP_REGENERATION
|
||||||
|
|
||||||
|
creature regenerates val HP every new round
|
||||||
|
|
||||||
|
- val: amount of HP regeneration per round
|
||||||
|
|
||||||
|
### MANA_DRAIN
|
||||||
|
|
||||||
|
value - spell points per turn
|
||||||
|
|
||||||
|
### MANA_CHANNELING
|
||||||
|
|
||||||
|
eg. familiar
|
||||||
|
|
||||||
|
- value in %
|
||||||
|
|
||||||
|
### LIFE_DRAIN
|
||||||
|
|
||||||
|
- val - precentage of life drained
|
||||||
|
|
||||||
|
### DOUBLE_DAMAGE_CHANCE
|
||||||
|
|
||||||
|
eg. dread knight
|
||||||
|
|
||||||
|
- value in %
|
||||||
|
|
||||||
|
### FEAR
|
||||||
|
|
||||||
|
### HEALER
|
||||||
|
|
||||||
|
First aid tent
|
||||||
|
|
||||||
|
- subtype: (since 1.2) ability used for healing.
|
||||||
|
|
||||||
|
### FIRE_SHIELD
|
||||||
|
|
||||||
|
### MAGIC_MIRROR
|
||||||
|
|
||||||
|
- value - chance of redirecting in %
|
||||||
|
|
||||||
|
### ACID_BREATH
|
||||||
|
|
||||||
|
- val - damage per creature after attack,
|
||||||
|
- additional info - chance in percent
|
||||||
|
|
||||||
|
### DEATH_STARE
|
||||||
|
|
||||||
|
- subtype: 0 - gorgon, 1 - commander
|
||||||
|
- val: if subtype is 0, its the (average) percentage of killed
|
||||||
|
creatures related to size of attacking stack
|
||||||
|
|
||||||
|
### SPECIAL_CRYSTAL_GENERATION
|
||||||
|
|
||||||
|
Crystal dragon crystal generation
|
||||||
|
|
||||||
|
### NO_SPELLCAST_BY_DEFAULT
|
||||||
|
|
||||||
|
Spellcast will not be default attack option for this creature
|
||||||
|
|
||||||
|
## Creature spellcasting and activated abilities
|
||||||
|
|
||||||
|
### SPELLCASTER
|
||||||
|
|
||||||
|
Creature gain activated ability to cast a spell. Example: Archangel,
|
||||||
|
Faerie Dragon
|
||||||
|
|
||||||
|
- subtype - spell id
|
||||||
|
- value - level of school
|
||||||
|
- additional info - weighted chance
|
||||||
|
|
||||||
|
use SPECIFIC_SPELL_POWER, CREATURE_SPELL_POWER or CREATURE_ENCHANT_POWER
|
||||||
|
for calculating the power (since 1.2 those bonuses can be used for
|
||||||
|
calculating CATAPULT and HEALER bonuses)
|
||||||
|
|
||||||
|
### ENCHANTER
|
||||||
|
|
||||||
|
for Enchanter spells
|
||||||
|
|
||||||
|
- val - skill level
|
||||||
|
- subtype - spell id
|
||||||
|
- additionalInfo - cooldown (number of turns)
|
||||||
|
|
||||||
|
### RANDOM_SPELLCASTER
|
||||||
|
|
||||||
|
eg. master genie
|
||||||
|
|
||||||
|
- val - spell mastery level
|
||||||
|
|
||||||
|
### SPELL_AFTER_ATTACK
|
||||||
|
|
||||||
|
- subtype - spell id
|
||||||
|
- value - chance %
|
||||||
|
- additional info - \[X, Y\]
|
||||||
|
- X - spell level
|
||||||
|
- Y = 0 - all attacks, 1 - shot only, 2 - melee only
|
||||||
|
|
||||||
|
### SPELL_BEFORE_ATTACK
|
||||||
|
|
||||||
|
- subtype - spell id
|
||||||
|
- value - chance %
|
||||||
|
- additional info - \[X, Y\]
|
||||||
|
- X - spell level
|
||||||
|
- Y = 0 - all attacks, 1 - shot only, 2 - melee only
|
||||||
|
|
||||||
|
### CASTS
|
||||||
|
|
||||||
|
how many times creature can cast activated spell
|
||||||
|
|
||||||
|
### SPECIFIC_SPELL_POWER
|
||||||
|
|
||||||
|
- value used for Thunderbolt and Resurrection casted by units, also
|
||||||
|
for Healing secondary skill (for core:spell.firstAid used by First
|
||||||
|
Aid tent)
|
||||||
|
- subtype - spell id
|
||||||
|
|
||||||
|
### CREATURE_SPELL_POWER
|
||||||
|
|
||||||
|
- value per unit, divided by 100 (so faerie Dragons have 500)
|
||||||
|
|
||||||
|
### CREATURE_ENCHANT_POWER
|
||||||
|
|
||||||
|
total duration of spells casted by creature
|
||||||
|
|
||||||
|
### REBIRTH
|
||||||
|
|
||||||
|
- val - percent of total stack HP restored
|
||||||
|
- subtype = 0 - regular, 1 - at least one unit (sacred Phoenix)
|
||||||
|
|
||||||
|
### ENCHANTED
|
||||||
|
|
||||||
|
Stack is permanently enchanted with spell subID of skill level = val, if
|
||||||
|
val \> 3 then spell is mass and has level of val-3. Enchantment is
|
||||||
|
refreshed every turn.
|
||||||
|
|
||||||
|
## Spell immunities
|
||||||
|
|
||||||
|
### LEVEL_SPELL_IMMUNITY
|
||||||
|
|
||||||
|
creature is immune to all spell with level below or equal to value of
|
||||||
|
this bonus
|
||||||
|
|
||||||
|
### MAGIC_RESISTANCE
|
||||||
|
|
||||||
|
- value - percent
|
||||||
|
|
||||||
|
### SPELL_DAMAGE_REDUCTION
|
||||||
|
|
||||||
|
eg. golems
|
||||||
|
|
||||||
|
- value - reduction in %
|
||||||
|
- subtype - spell school; -1 - all, 0 - air, 1 - fire, 2 - water, 3 -
|
||||||
|
earth
|
||||||
|
|
||||||
|
### MORE_DAMAGE_FROM_SPELL
|
||||||
|
|
||||||
|
- value - damage increase in %
|
||||||
|
- subtype - spell id
|
||||||
|
|
||||||
|
### FIRE_IMMUNITY,WATER_IMMUNITY, EARTH_IMMUNITY, AIR_IMMUNITY
|
||||||
|
|
||||||
|
- subtype 0 - all, 1 - all except positive, 2 - only damage spells
|
||||||
|
|
||||||
|
### MIND_IMMUNITY
|
||||||
|
|
||||||
|
Creature is immune to all mind spells.
|
||||||
|
|
||||||
|
### SPELL_IMMUNITY
|
||||||
|
|
||||||
|
- subtype - spell id
|
||||||
|
- ainfo - 0 - normal, 1 - absolute
|
||||||
|
|
||||||
|
### DIRECT_DAMAGE_IMMUNITY
|
||||||
|
|
||||||
|
WoG ability. Creature is completely immune to damage spells.
|
||||||
|
|
||||||
|
### RECEPTIVE
|
||||||
|
|
||||||
|
WoG ability. Creature accepts all friendly spells even though it would
|
||||||
|
be normally immune to it.
|
||||||
|
|
||||||
|
## Deprecated creature abilities
|
||||||
|
|
||||||
|
### DAEMON_SUMMONING
|
||||||
|
|
||||||
|
pit lord - removed in VCMI 1.2 as part of major battles refactoring
|
||||||
|
|
||||||
|
- subtype - type of creatures
|
||||||
|
- val - hp per unit
|
||||||
|
|
||||||
|
# Spell effects
|
||||||
|
|
||||||
|
### POISON
|
||||||
|
|
||||||
|
- val - max health penalty from poison possible
|
||||||
|
|
||||||
|
### SLAYER
|
||||||
|
|
||||||
|
- value - spell level
|
||||||
|
|
||||||
|
### BIND_EFFECT
|
||||||
|
|
||||||
|
doesn't do anything particular, works as a marker
|
||||||
|
|
||||||
|
### FORGETFULL
|
||||||
|
|
||||||
|
forgetfulness spell effect
|
||||||
|
|
||||||
|
- value - level
|
||||||
|
|
||||||
|
### NOT_ACTIVE
|
||||||
|
|
||||||
|
### ALWAYS_MINIMUM_DAMAGE
|
||||||
|
|
||||||
|
unit does its minimum damage from range
|
||||||
|
|
||||||
|
- subtype: -1 - any attack, 0 - melee, 1 - ranged
|
||||||
|
- value: additional damage penalty (it'll subtracted from dmg)
|
||||||
|
- additional info - multiplicative anti-bonus for dmg in % \[eg 20
|
||||||
|
means that creature will inflict 80% of normal minimal dmg\]
|
||||||
|
|
||||||
|
### ALWAYS_MAXIMUM_DAMAGE
|
||||||
|
|
||||||
|
eg. bless effect
|
||||||
|
|
||||||
|
- subtype: -1 - any attack, 0 - melee, 1 - ranged
|
||||||
|
- value: additional damage
|
||||||
|
- additional info - multiplicative bonus for dmg in %
|
||||||
|
|
||||||
|
### ATTACKS_NEAREST_CREATURE
|
||||||
|
|
||||||
|
while in berserk
|
||||||
|
|
||||||
|
### IN_FRENZY
|
||||||
|
|
||||||
|
- value - level
|
||||||
|
|
||||||
|
### HYPNOTIZED
|
||||||
|
|
||||||
|
### NO_RETALIATION
|
||||||
|
|
||||||
|
Eg. when blinded or paralyzed.
|
85
docs/modders/Bonus/Bonus_Updaters.md
Normal file
85
docs/modders/Bonus/Bonus_Updaters.md
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
< [Documentation](../../Readme.md) / [Modding](../Readme.md) / [Bonus Format](../Bonus_Format.md) / Bonus Updaters
|
||||||
|
|
||||||
|
# List of Bonus Updaters
|
||||||
|
|
||||||
|
Updaters come in two forms: simple and complex. Simple updaters take no
|
||||||
|
parameters and are specified as strings. Complex updaters do take
|
||||||
|
parameters (sometimes optional), and are specified as structs.
|
||||||
|
|
||||||
|
Check the files in *config/heroes/* for additional usage examples.
|
||||||
|
|
||||||
|
## GROWS_WITH_LEVEL
|
||||||
|
|
||||||
|
- Type: Complex
|
||||||
|
- Parameters: valPer20, stepSize=1
|
||||||
|
- Effect: Updates val to
|
||||||
|
|
||||||
|
` ceil(valPer20 * floor(heroLevel / stepSize) / 20)`
|
||||||
|
|
||||||
|
Example: The following updater will cause a bonus to grow by 6 for every
|
||||||
|
40 levels. At first level, rounding will cause the bonus to be 0.
|
||||||
|
|
||||||
|
` "updater" : {`
|
||||||
|
` "parameters" : [ 6, 2 ],`
|
||||||
|
` "type" : "GROWS_WITH_LEVEL"`
|
||||||
|
` }`
|
||||||
|
|
||||||
|
Example: The following updater will cause a bonus to grow by 3 for every
|
||||||
|
20 levels. At first level, rounding will cause the bonus to be 1.
|
||||||
|
|
||||||
|
` "updater" : {`
|
||||||
|
` "parameters" : [ 3 ],`
|
||||||
|
` "type" : "GROWS_WITH_LEVEL"`
|
||||||
|
` }`
|
||||||
|
|
||||||
|
Remarks:
|
||||||
|
|
||||||
|
- The rounding rules are designed to match the attack/defense bonus
|
||||||
|
progression for heroes with creature specialties in HMM3.
|
||||||
|
- There is no point in specifying val for a bonus with a
|
||||||
|
GROWS_WITH_LEVEL updater.
|
||||||
|
|
||||||
|
## TIMES_HERO_LEVEL
|
||||||
|
|
||||||
|
- Type: Simple
|
||||||
|
- Effect: Updates val to
|
||||||
|
|
||||||
|
` val * heroLevel`
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
` "updater" : "TIMES_HERO_LEVEL"`
|
||||||
|
|
||||||
|
Remark: This updater is redundant, in the sense that GROWS_WITH_LEVEL
|
||||||
|
can also express the desired scaling by setting valPer20 to 20\*val. It
|
||||||
|
has been added for convenience.
|
||||||
|
|
||||||
|
## TIMES_STACK_LEVEL
|
||||||
|
|
||||||
|
- Type: Simple
|
||||||
|
- Effect: Updates val to
|
||||||
|
|
||||||
|
` val * stackLevel`
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
|
||||||
|
` "updater" : "TIMES_STACK_LEVEL"`
|
||||||
|
|
||||||
|
Remark: The stack level for war machines is 0.
|
||||||
|
|
||||||
|
## ARMY_MOVEMENT
|
||||||
|
|
||||||
|
- Type: Complex
|
||||||
|
- Parameters: basePerSpeed, dividePerSpeed, additionalMultiplier,
|
||||||
|
maxValue
|
||||||
|
- Effect: Updates val to val+= max((floor(basePerSpeed /
|
||||||
|
dividePerSpeed)\* additionalMultiplier), maxValue)
|
||||||
|
- Remark: this updater is designed for MOVEMENT bonus to match H3 army
|
||||||
|
movement rules (in the example - actual movement updater, which
|
||||||
|
produces values same as in default movement.txt).
|
||||||
|
- Example:
|
||||||
|
|
||||||
|
` "updater" : {`
|
||||||
|
` "parameters" : [ 20, 3, 10, 700 ],`
|
||||||
|
` "type" : "ARMY_MOVEMENT"`
|
||||||
|
` }`
|
33
docs/modders/Bonus/Bonus_Value_Types.md
Normal file
33
docs/modders/Bonus/Bonus_Value_Types.md
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
< [Documentation](../../Readme.md) / [Modding](../Readme.md) / [Bonus Format](../Bonus_Format.md) / Bonus Value Types
|
||||||
|
|
||||||
|
Total value of Bonus is calculated using the following:
|
||||||
|
|
||||||
|
- For each bonus source type we calculate new source value (for all
|
||||||
|
bonus value types except PERCENT_TO_SOURCE and
|
||||||
|
PERCENT_TO_TARGET_TYPE) using the following:
|
||||||
|
|
||||||
|
` newVal = (val * (100 + PERCENT_TO_SOURCE) / 100))`
|
||||||
|
|
||||||
|
PERCENT_TO_TARGET_TYPE applies as PERCENT_TO_SOURCE to targetSourceType
|
||||||
|
of bonus.
|
||||||
|
|
||||||
|
- All bonus value types summarized and then used as subject of the
|
||||||
|
following formula:
|
||||||
|
|
||||||
|
` clamp(((BASE_NUMBER * (100 + PERCENT_TO_BASE) / 100) + ADDITIVE_VALUE) * (100 + PERCENT_TO_ALL) / 100), INDEPENDENT_MAX, INDEPENDENT_MIN)`
|
||||||
|
|
||||||
|
As for 1.2, semantics of INDEPENDENT_MAX and INDEPENDENT_MIN are
|
||||||
|
wrapped, and first means than bonus total value will be at least
|
||||||
|
INDEPENDENT_MAX, and second means than bonus value will be at most
|
||||||
|
INDEPENDENT_MIN.
|
||||||
|
|
||||||
|
# List of all bonus value types
|
||||||
|
|
||||||
|
- ADDITIVE_VALUE
|
||||||
|
- BASE_NUMBER
|
||||||
|
- PERCENT_TO_ALL
|
||||||
|
- PERCENT_TO_BASE
|
||||||
|
- INDEPENDENT_MAX
|
||||||
|
- INDEPENDENT_MIN
|
||||||
|
- PERCENT_TO_SOURCE (since 1.2)
|
||||||
|
- PERCENT_TO_TARGET_TYPE (since 1.2)
|
100
docs/modders/Bonus_Format.md
Normal file
100
docs/modders/Bonus_Format.md
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
< [Documentation](../Readme.md) / [Modding](Readme.md) / Bonus Format
|
||||||
|
|
||||||
|
## Full format
|
||||||
|
|
||||||
|
All parameters but type are optional.
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
{
|
||||||
|
"type": "BONUS_TYPE",
|
||||||
|
"subtype": 0,
|
||||||
|
"val" : 0,
|
||||||
|
"valueType": "VALUE_TYPE",
|
||||||
|
"addInfo" : 0, // or [1, 2, ...]
|
||||||
|
|
||||||
|
"duration" : "BONUS_DURATION", //or ["BONUS_DURATION1", "BONUS_DURATION2", ...]"
|
||||||
|
"turns" : 0,
|
||||||
|
|
||||||
|
"sourceType" : "SOURCE_TYPE",
|
||||||
|
"sourceID" : 0,
|
||||||
|
"effectRange" : "EFFECT_RANGE",
|
||||||
|
|
||||||
|
"limiters" : [
|
||||||
|
"PREDEFINED_LIMITER", optional_parameters (...), //whhich one is preferred?
|
||||||
|
{"type" : LIMITER_TYPE, "parameters" : [1,2,3]}
|
||||||
|
],
|
||||||
|
|
||||||
|
"propagator" : ["PROPAGATOR_TYPE", optional_parameters (...)],
|
||||||
|
"updater" : {Bonus Updater},
|
||||||
|
"propagationUpdater" : {Bonus Updater, but works during propagation},
|
||||||
|
"description" : "",
|
||||||
|
"stacking" : ""
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Supported bonus types
|
||||||
|
|
||||||
|
- [Bonus Duration Types](Bonus/Bonus_Duration_Types.md)
|
||||||
|
- [Bonus Sources](Bonus/Bonus_Sources.md)
|
||||||
|
- [Bonus Limiters](Bonus/Bonus_Limiters.md)
|
||||||
|
- [Bonus Types](Bonus/Bonus_Types.md)
|
||||||
|
- [Bonus Propagators](Bonus/Bonus_Propagators.md)
|
||||||
|
- [Bonus Updaters](Bonus/Bonus_Updaters.md)
|
||||||
|
- [Bonus Range Types](Bonus/Bonus_Range_Types.md)
|
||||||
|
- [Bonus Value Types](Bonus/Bonus_Value_Types.md)
|
||||||
|
|
||||||
|
## Subtype resolution
|
||||||
|
|
||||||
|
All string identifiers of items can be used in "subtype" field. This
|
||||||
|
allows cross-referencing between the mods and make config file more
|
||||||
|
readable.
|
||||||
|
|
||||||
|
### Available prefixes
|
||||||
|
|
||||||
|
- creature.
|
||||||
|
- artifact.
|
||||||
|
- skill:
|
||||||
|
``` javascript
|
||||||
|
"pathfinding", "archery", "logistics", "scouting", "diplomacy",
|
||||||
|
"navigation", "leadership", "wisdom", "mysticism", "luck",
|
||||||
|
"ballistics", "eagleEye", "necromancy", "estates", "fireMagic",
|
||||||
|
"airMagic", "waterMagic", "earthMagic", "scholar", "tactics",
|
||||||
|
"artillery", "learning", "offence", "armorer", "intelligence",
|
||||||
|
"sorcery", "resistance", "firstAid"
|
||||||
|
```
|
||||||
|
|
||||||
|
- resource:
|
||||||
|
``` javascript
|
||||||
|
"wood", "mercury", "ore", "sulfur", "crystal", "gems", "gold", "mithril"
|
||||||
|
```
|
||||||
|
|
||||||
|
- hero.
|
||||||
|
- faction.
|
||||||
|
- spell.
|
||||||
|
- primarySkill
|
||||||
|
``` javascript
|
||||||
|
"attack", "defence", "spellpower", "knowledge"
|
||||||
|
```
|
||||||
|
|
||||||
|
- terrain:
|
||||||
|
``` javascript
|
||||||
|
"dirt", "sand", "grass", "snow", "swamp", "rough", "subterra", "lava", "water", "rock"
|
||||||
|
```
|
||||||
|
|
||||||
|
- spellSchool
|
||||||
|
```javascript
|
||||||
|
"any", "fire", "air", "water", "earth"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
"bonus" :
|
||||||
|
{
|
||||||
|
"type" : "HATE",
|
||||||
|
"subtype" : "creature.enchanter",
|
||||||
|
"val" : 50
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This bonus makes creature do 50% more damage to Enchanters.
|
171
docs/modders/Building_Bonuses.md
Normal file
171
docs/modders/Building_Bonuses.md
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
< [Documentation](../Readme.md) / [Modding](Readme.md) / Building Bonuses
|
||||||
|
|
||||||
|
Work-in-progress page do describe all bonuses provided by town buildings
|
||||||
|
for future configuration.
|
||||||
|
|
||||||
|
## unique buildings
|
||||||
|
|
||||||
|
Hardcoded functionalities, selectable but not configurable. In future
|
||||||
|
should be moved to scripting.
|
||||||
|
|
||||||
|
Includes:
|
||||||
|
|
||||||
|
- mystic pond
|
||||||
|
- treasury
|
||||||
|
- god of fire
|
||||||
|
- castle gates
|
||||||
|
- cover of darkness
|
||||||
|
- portal of summoning
|
||||||
|
- escape tunnel
|
||||||
|
|
||||||
|
Function of all of these objects can be enabled by this:
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
"function" : "castleGates"
|
||||||
|
```
|
||||||
|
|
||||||
|
## trade-related
|
||||||
|
|
||||||
|
Hardcoded functionality for now due to complexity of these objects.
|
||||||
|
Temporary can be handles as unique buildings. Includes:
|
||||||
|
|
||||||
|
- resource - resource
|
||||||
|
- resource - player
|
||||||
|
- artifact - resource
|
||||||
|
- resource - artifact
|
||||||
|
- creature - resource
|
||||||
|
- resource - skills
|
||||||
|
- creature - skeleton
|
||||||
|
|
||||||
|
## hero visitables
|
||||||
|
|
||||||
|
Buildings that give one or another bonus to visiting hero. All should be
|
||||||
|
handled via configurable objects system.
|
||||||
|
|
||||||
|
Includes:
|
||||||
|
|
||||||
|
- gives mana points
|
||||||
|
- gives movement points
|
||||||
|
- give bonus to visitor
|
||||||
|
- permanent bonus to hero
|
||||||
|
|
||||||
|
## generic functions
|
||||||
|
|
||||||
|
Generic town-specific functions that can be implemented as part of
|
||||||
|
CBuilding class.
|
||||||
|
|
||||||
|
### unlock guild level
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
"guildLevels" : 1
|
||||||
|
```
|
||||||
|
|
||||||
|
### unlock hero recruitment
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
"allowsHeroPurchase" : true
|
||||||
|
```
|
||||||
|
|
||||||
|
### unlock ship purchase
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
"allowsShipPurchase" : true
|
||||||
|
```
|
||||||
|
|
||||||
|
### unlock building purchase
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
"allowsBuildingPurchase" : true
|
||||||
|
```
|
||||||
|
|
||||||
|
### unlocks creatures
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
"dwelling" : { "level" : 1, "creature" : "archer" }
|
||||||
|
```
|
||||||
|
|
||||||
|
### creature growth bonus
|
||||||
|
|
||||||
|
Turn into town bonus? What about creature-specific bonuses from hordes?
|
||||||
|
|
||||||
|
### gives resources
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
"provides" : { "gold" : 500 }
|
||||||
|
```
|
||||||
|
|
||||||
|
### gives guild spells
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
"guildSpells" : [5, 0, 0, 0, 0]
|
||||||
|
```
|
||||||
|
|
||||||
|
### gives thieves guild
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
"thievesGuildLevels" : 1
|
||||||
|
```
|
||||||
|
|
||||||
|
### gives fortifications
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
"fortificationLevels" : 1
|
||||||
|
```
|
||||||
|
|
||||||
|
### gives war machine
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
"warMachine" : "ballista"
|
||||||
|
```
|
||||||
|
|
||||||
|
## simple bonuses
|
||||||
|
|
||||||
|
Bonuses that can be made part of CBuilding. Note that due to how bonus
|
||||||
|
system works this bonuses won't be stackable.
|
||||||
|
|
||||||
|
TODO: how to handle stackable bonuses like Necromancy Amplifier?
|
||||||
|
|
||||||
|
Includes:
|
||||||
|
|
||||||
|
- bonus to defender
|
||||||
|
- bonus to alliance
|
||||||
|
- bonus to scouting range
|
||||||
|
- bonus to player
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
"bonuses" :
|
||||||
|
{
|
||||||
|
"moraleToDefenders" :
|
||||||
|
{
|
||||||
|
"type": "MORALE",
|
||||||
|
"val" : 1,
|
||||||
|
"propagator" : ["VISITED_TOWN_AND_VISITOR"]
|
||||||
|
},
|
||||||
|
"luckToTeam" :
|
||||||
|
{
|
||||||
|
"type" : "LUCK",
|
||||||
|
"val" : 2,
|
||||||
|
"propagator" : [ "TEAM_PROPAGATOR" ]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## misc
|
||||||
|
|
||||||
|
Some other properties of town building that does not fall under "bonus"
|
||||||
|
category.
|
||||||
|
|
||||||
|
### unique building
|
||||||
|
|
||||||
|
Possible issue - with removing of fixed ID's buildings in different town
|
||||||
|
may no longer share same ID. However Capitol must be unique across all
|
||||||
|
town. Should be fixed somehow.
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
"onePerPlayer" : true
|
||||||
|
```
|
||||||
|
|
||||||
|
### chance to be built on start
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
"prebuiltChance" : 75
|
||||||
|
```
|
215
docs/modders/Campaign_Format.md
Normal file
215
docs/modders/Campaign_Format.md
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
< [Documentation](../Readme.md) / [Modding](Readme.md) / Campaign Format
|
||||||
|
|
||||||
|
# Introduction
|
||||||
|
|
||||||
|
Starting from version 1.3, VCMI supports its own campaign format.
|
||||||
|
Campaigns have *.vcmp file format and it consists from campaign json and set of scenarios (can be both *.vmap and *.h3m)
|
||||||
|
|
||||||
|
To start making campaign, create file named `00.json`. See also [Packing campaign](#packing-campaign)
|
||||||
|
|
||||||
|
Basic structure of this file is here, each section is described in details below
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
"version" : 1,
|
||||||
|
|
||||||
|
<header properties>
|
||||||
|
|
||||||
|
"scenarios" : [
|
||||||
|
{
|
||||||
|
//scenario 1
|
||||||
|
<scenario properties>
|
||||||
|
},
|
||||||
|
{
|
||||||
|
//scenario 2
|
||||||
|
<scenario properties>
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`"version"` defines version of campaign file. Larger versions should have more features and flexibility, but may not be supported by older VCMI engines. See [compatibility table](#compatibility-table)
|
||||||
|
|
||||||
|
# Header properties
|
||||||
|
|
||||||
|
In header are parameters describing campaign properties
|
||||||
|
```js
|
||||||
|
...
|
||||||
|
"regions": {...},
|
||||||
|
"name": "Campaign name",
|
||||||
|
"description": "Campaign description",
|
||||||
|
"allowDifficultySelection": true,
|
||||||
|
```
|
||||||
|
|
||||||
|
- `"regions"` contains information about background and regions. See section [campaign regions](#regions-description) for more information
|
||||||
|
- `"name"` is a human readable title of campaign
|
||||||
|
- `"description"` is a human readable description of campaign
|
||||||
|
- `"allowDifficultySelection"` is a boolean field (`true`/`false`) which allows or disallows to choose difficulty before scenario start
|
||||||
|
|
||||||
|
# Scenario description
|
||||||
|
|
||||||
|
Scenario description looks like follow:
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
"map": "maps/SomeMap",
|
||||||
|
"preconditions": [],
|
||||||
|
"color": 0,
|
||||||
|
"difficulty": 2,
|
||||||
|
"regionText": "",
|
||||||
|
"prolog": {},
|
||||||
|
"epilog": {},
|
||||||
|
"heroKeeps": [],
|
||||||
|
"keepCreatures": [],
|
||||||
|
"startOptions": "none",
|
||||||
|
"playerColor": 0,
|
||||||
|
"bonuses": [ <see bonus description> ]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `"map"` map name without extension but with relative path. Both *.h3m and *.vmap maps are supported. If you will pack scenarios inside campaign, numerical map name should be used, see details in [packing campaign](#packing-campaign)
|
||||||
|
- `"preconditions"` enumerate scenarios indexes which must be completed to unlock this scenario. For example, if you want to make sequential missions, you should specify `"preconditions": []` for first scenario, but for second scenario it should be `"preconditions": [0]` and for third `"preconditions": [0, 1]`. But you can allow non-linear conquering using this parameter
|
||||||
|
- `"color"` defines color id for the region. Possible values are `0: red, 1: blue, tan: 2, green: 3, orange: 4, purple: 5, teal: 6, pink: 7`
|
||||||
|
- `"difficulty"` sets initial difficulty for this scenario. If `"allowDifficultySelection"`is defined for campaign, difficulty may be changed by player. Possible values are `0: pawn, 1: knight, 2: rook, 3: queen, 4: king`
|
||||||
|
- `"regionText"` is a text which will be shown if player holds right button over region
|
||||||
|
- `"prolog"`/`"epilog"` optional, defines prolog/epilog for scenario. See [prolog/epilog](#prologepilog) section for more information
|
||||||
|
- `"heroKeeps"` defines what hero will carry to the next scenario. Can be specified one or several attributes from list `"experience", "primarySkills", "secondarySkills", "spells", "artifacts"`
|
||||||
|
- `"keepCreatures"` array of creature types which hero will carry to the next scenario. Game identifiers are used to specify creature type.
|
||||||
|
- `"startOptions"` defines what type of bonuses player may have. Possible values are `"none", "bonus", "crossover", "hero"`
|
||||||
|
- `none`: player starts scenario without bonuses. [Description](#none-start-option)
|
||||||
|
- `bonus`: player chooses one of the predefined bonuses. [Description](#bonus-start-option)
|
||||||
|
- `crossover`: player will start with hero from previous scenario. [Description](#crossover-start-option)
|
||||||
|
- `hero` : player will start scenario with specified hero. [Description](#hero-start-option)
|
||||||
|
- `"playerColor"` defines color id of flag which player will play for. Possible values are `0: red, 1: blue, tan: 2, green: 3, orange: 4, purple: 5, teal: 6, pink: 7`
|
||||||
|
- "bonuses" array of possible bonus objects, format depends on `"startOptions"` parameter
|
||||||
|
|
||||||
|
## Prolog/Epilog
|
||||||
|
|
||||||
|
Prolog and epilog properties are optional
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
"video": "NEUTRALA.smk", //video to show
|
||||||
|
"music": "musicFile.ogg", //music to play, should be located in music directory
|
||||||
|
"text": "some long text" //text to be shown
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Start options and bonuses
|
||||||
|
|
||||||
|
### None start option
|
||||||
|
|
||||||
|
If `startOptions` is `none`, `bonuses` field will be ignored
|
||||||
|
|
||||||
|
### Bonus start option
|
||||||
|
|
||||||
|
If `startOptions` is `bonus`, bonus format may vary depending on its type.
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
"what": "",
|
||||||
|
|
||||||
|
<attributes>
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
- `"what"` field defines bonus type. Possible values are: `spell, creature, building, artifact, scroll, primarySkill, secondarySkill, resource`
|
||||||
|
- `"spell"` has following attributes (fields):
|
||||||
|
- `"hero"`: hero who will get spell (see below)
|
||||||
|
- `"type"`: spell type, string, e.g. "firewall"
|
||||||
|
- `"creature"` has following attributes (fields):
|
||||||
|
- `"hero"`: hero who will get spell (see below)
|
||||||
|
- `"type"`: creature type, string, e.g. "pikeman"
|
||||||
|
- `"amount"`: amount of creatures
|
||||||
|
- `"building"` has following attributes (fields):
|
||||||
|
- `"type"`: building type (string), e.g. "citadel" or "dwellingLvl1"
|
||||||
|
- `"artifact"` has following attributes (fields):
|
||||||
|
- `"hero"`: hero who will get spell (see below)
|
||||||
|
- `"type"`: artifact type, string, e.g. "spellBook"
|
||||||
|
- `"scroll"` has following attributes (fields):
|
||||||
|
- `"hero"`: hero who will get spell (see below)
|
||||||
|
- `"type"`: spell type in the scroll, string, e.g. "firewall"
|
||||||
|
- `"primarySkill"` has following attributes (fields):
|
||||||
|
- `"hero"`: hero who will get spell (see below)
|
||||||
|
- `"attack"`: amount of attack gained
|
||||||
|
- `"defence"`: amount of defence gained
|
||||||
|
- `"spellpower"`: amount of spellpower gained
|
||||||
|
- `"knowledge"`: amount of knowledge gained
|
||||||
|
- `"secondarySkill"` has following attributes (fields):
|
||||||
|
- `"hero"`: hero who will get spell (see below)
|
||||||
|
- `"type"`: skill type, string, e.g. "logistics"
|
||||||
|
- `"amount"`: skill level, `1: beginner, 2: advanced, 3: expert`
|
||||||
|
- `"resource"` has following attributes (fields):
|
||||||
|
- `"type"`: resource type, one of `wood, ore, mercury, sulfur, crystal, gems, gold, common, rare`, where `common` is both wood and ore, `rare` means that bonus gives each rare resource
|
||||||
|
- `"amount"`: amount of resources
|
||||||
|
- `"hero"` can be specified as explicit hero name and as one of keywords: `strongest`, `generated`
|
||||||
|
|
||||||
|
### Crossover start option
|
||||||
|
|
||||||
|
If `startOptions` is `crossover`, heroes from specific scenario will be moved to this scenario. Bonus format is following
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
"playerColor": 0,
|
||||||
|
"scenario": 0
|
||||||
|
},
|
||||||
|
```
|
||||||
|
- `"playerColor"` from what player color heroes shall be taken. Possible values are `0: red, 1: blue, tan: 2, green: 3, orange: 4, purple: 5, teal: 6, pink: 7`
|
||||||
|
- `"scenario"` from which scenario heroes shall be taken. 0 means first scenario
|
||||||
|
|
||||||
|
### Hero start option
|
||||||
|
|
||||||
|
If `startOptions` is `hero`, hero can be chosen as a starting bonus. Bonus format is following
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
"playerColor": 0,
|
||||||
|
"hero": "random"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `"playerColor"` from what player color heroes shall be taken. Possible values are `0: red, 1: blue, tan: 2, green: 3, orange: 4, purple: 5, teal: 6, pink: 7`
|
||||||
|
- `"hero"` can be specified as explicit hero name and as one of keywords: `random`
|
||||||
|
|
||||||
|
## Regions description
|
||||||
|
|
||||||
|
Predefined campaign regions are located in file `campaign_regions.json`
|
||||||
|
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
"prefix": "G3",
|
||||||
|
"color_suffix_length": 1,
|
||||||
|
"desc": [
|
||||||
|
{ "infix": "A", "x": 289, "y": 376 },
|
||||||
|
{ "infix": "B", "x": 60, "y": 147 },
|
||||||
|
{ "infix": "C", "x": 131, "y": 202 }
|
||||||
|
]
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
- `"prefix"` used to identify all images related to campaign. In this example, background picture will be `G3_BG`
|
||||||
|
- `"inflix"` ised to identify all images related to region. In this example, it will be pictures starting from `G3A_..., G3B_..., G3C_..."`
|
||||||
|
- `"color_suffix_length"` identifies suffix length for region colourful frames. 1 is used for `R, B, N, G, O, V, T, P`, value 2 is used for `Re, Bl, Br, Gr, Or, Vi, Te, Pi`
|
||||||
|
|
||||||
|
# Packing campaign
|
||||||
|
|
||||||
|
After campaign scenarios and campaign description are ready, you should pack them into *.vcmp file.
|
||||||
|
This file is basically headless gz archive.
|
||||||
|
|
||||||
|
Your campaign should be stored in some folder with json describing campaign information.
|
||||||
|
Place all your scenarios inside same folder and enumerate their filenames, e.g `01.vmap`, '02.vmap', etc.
|
||||||
|
```
|
||||||
|
my-campaign/
|
||||||
|
|-- 00.json
|
||||||
|
|-- 01.vmap
|
||||||
|
|-- 02.vmap
|
||||||
|
|-- 03.vmap
|
||||||
|
```
|
||||||
|
|
||||||
|
If you use unix system, execute this command to pack your campaign:
|
||||||
|
```
|
||||||
|
gzip -c -n ./* >> my-campaign.vcmp
|
||||||
|
```
|
||||||
|
|
||||||
|
If you are using Windows system, try this https://gnuwin32.sourceforge.net/packages/gzip.htm
|
||||||
|
|
||||||
|
# Compatibility table
|
||||||
|
| Version | Min VCMI | Max VCMI | Description |
|
||||||
|
|---------|----------|----------|-------------|
|
||||||
|
| 1 | 1.3 | | Initial release |
|
835
docs/modders/Configurable_Widgets.md
Normal file
835
docs/modders/Configurable_Widgets.md
Normal file
@ -0,0 +1,835 @@
|
|||||||
|
< [Documentation](../Readme.md) / [Modding](Readme.md) / Configurable Widgets
|
||||||
|
|
||||||
|
# Table of contents
|
||||||
|
|
||||||
|
- [Introduction](#introduction)
|
||||||
|
- [Tutorial](#tutorial)
|
||||||
|
- [Documentation](#documentation)
|
||||||
|
- [Types](#types)
|
||||||
|
- [Configurable objects](#configurable-objects)
|
||||||
|
- [Basic widgets](#basic-widgets)
|
||||||
|
- [High-level widgets](#high-level-widgets)
|
||||||
|
- [Custom widgets](#custom-widgets)
|
||||||
|
- [For developers](#for-developers)
|
||||||
|
|
||||||
|
# Introduction
|
||||||
|
|
||||||
|
VCMI has capabilities to change some UI elements in your mods beyond only replacing one image with another. Not all UI elements are possible to modify currently, but development team is expanding them.
|
||||||
|
|
||||||
|
Elements possible to modify are located in `config/widgets`.
|
||||||
|
|
||||||
|
# Tutorial
|
||||||
|
|
||||||
|
Let's take `extendedLobby` mod from `vcmi-extras` as an example for VCMI-1.4. [Example sources](https://github.com/vcmi-mods/vcmi-extras/tree/vcmi-1.4/Mods/extendedLobby).
|
||||||
|
|
||||||
|
**You can take all assets from this tutorial from sources.**
|
||||||
|
|
||||||
|
This submod offers extended options while player creates new game.
|
||||||
|
For random map tab it defines UI to select RMG template, select map size bigger than XL, configure teams and roads.
|
||||||
|
For options tab it introduces UI for chess timers.
|
||||||
|
|
||||||
|
In this tutorial we will recreate options tab to support chess timers UI.
|
||||||
|
|
||||||
|
## Creating mod structure
|
||||||
|
|
||||||
|
To start making mod, create following folders structure;
|
||||||
|
```
|
||||||
|
extendedLobby/
|
||||||
|
|- content/
|
||||||
|
| |- sprites/
|
||||||
|
| |- config/
|
||||||
|
| | |- widgets/
|
||||||
|
|- mod.json
|
||||||
|
```
|
||||||
|
|
||||||
|
File `mod.json` is generic and could look like this:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name" : "Configurable UI tutorial mod",
|
||||||
|
"description" : "See tutorial here https://github.com/vcmi/vcmi/wiki/Configurable-UI-widgets",
|
||||||
|
"version" : "0.1",
|
||||||
|
"modType" : "Interface",
|
||||||
|
"compatibility":
|
||||||
|
{
|
||||||
|
"min" : "1.4.0"
|
||||||
|
},
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
After that you can copy `extendedLobby/ folder to `mods/` folder and your mod will immediately appear in launcher but it does nothing for now.
|
||||||
|
|
||||||
|
## Making layout for timer
|
||||||
|
|
||||||
|
Let's copy `config/widgets/optionsTab.json` file from VCMI folder to `content/config/widgets/` folder from our mod.
|
||||||
|
It defines UI for options tab as it designed in original game, we will keep everything related to player settings and will modify only timer area.
|
||||||
|
|
||||||
|
**It's important, that when you are modifying `optionsTab.json`, game restart is not needed! When you updated file, it's enough to go back to main menu and then open lobby and options again. However, when you add new assets (images), you have to restart game to make possible find them.**
|
||||||
|
|
||||||
|
It looks like on image below and has 3 elements: label with "Player Turn Duration", label with timer duration ("Unlimited" on picture) and slider to control timer.
|
||||||
|
|
||||||
|
<img width="350" alt="Снимок экрана 2023-08-30 в 14 53 49" src="https://github.com/vcmi/vcmi/assets/9308612/a34be309-29fc-412a-9d54-e40a634b56f9">
|
||||||
|
|
||||||
|
So we need to modify turn duration label and add combo box with timer types
|
||||||
|
|
||||||
|
<img width="345" alt="Снимок экрана 2023-08-30 в 14 53 02" src="https://github.com/vcmi/vcmi/assets/9308612/717b21e6-4ac9-4e27-b90b-b68b0ce65db2">
|
||||||
|
|
||||||
|
Open `optionsTab.json` and scroll it until you see comment `timer`. Three elements after this comment are related to timer.
|
||||||
|
|
||||||
|
Let's find first element, which is label
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"items"
|
||||||
|
[
|
||||||
|
...
|
||||||
|
// timer
|
||||||
|
{
|
||||||
|
"type": "label",
|
||||||
|
"font": "small",
|
||||||
|
"alignment": "center",
|
||||||
|
"color": "yellow",
|
||||||
|
"text": "core.genrltxt.521",
|
||||||
|
"position": {"x": 222, "y": 544}
|
||||||
|
},
|
||||||
|
...
|
||||||
|
],
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
And modify it a bit
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "labelTimer", //add name, only for convenience
|
||||||
|
"type": "label",
|
||||||
|
"font": "small",
|
||||||
|
"alignment": "center",
|
||||||
|
"color": "yellow",
|
||||||
|
"text": "vcmi.optionsTab.widgets.labelTimer", //replace text
|
||||||
|
"position": {"x": 104, "y": 542} //move to the left
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
But we also need proper background image for this label. Add image widget BEFORE labelTimer widget:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "picture",
|
||||||
|
"image": "RmgTTBk",
|
||||||
|
"position": {"x": 54, "y": 532}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "labelTimer", //add name, only for convenience
|
||||||
|
...
|
||||||
|
},
|
||||||
|
```
|
||||||
|
In order to make it work, add file `RmgTTBk.bmp` to `content/sprites/`
|
||||||
|
|
||||||
|
Elements named `labelTurnDurationValue` and `sliderTurnDuration` we will keep without change - they are needed to configure classic timer.
|
||||||
|
|
||||||
|
## Adding combo box
|
||||||
|
|
||||||
|
Now, let's add combo box.
|
||||||
|
|
||||||
|
Copy image `DrDoCoBk.bmp` to `content/sprites/`. Button objects use animated images to show different button states.
|
||||||
|
For normal, pressed, blocked and highlighted. Our combo box inherits this behavior, so let's convert image to animation.
|
||||||
|
In order to do it, we need to create file `DrDoCoBk.json` in same folder `content/sprites/` with following content:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"sequences" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"group" : 0,
|
||||||
|
"frames" :
|
||||||
|
[
|
||||||
|
"DrDoCoBk.bmp"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Thus we created file with animation, containing single frame which can be used for combo box.
|
||||||
|
|
||||||
|
Let's add one more element after `//timer` comment:
|
||||||
|
|
||||||
|
```json
|
||||||
|
...
|
||||||
|
//timer
|
||||||
|
{
|
||||||
|
"name": "timerModeSwitch", //this is important to name it timerModeSwitch, because VCMI binds behavior to element called this way
|
||||||
|
"type": "comboBox",
|
||||||
|
"image": "DrDoCoBk",
|
||||||
|
"position": {"x": 158, "y": 532},
|
||||||
|
"imageOrder": [0, 0, 0, 0],
|
||||||
|
"dropDown": {}, //here will be defined elements to be shown in drop down list
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
`imageOrder` helps VCMI to understand, which frame from animation to use in normal, pressed, blocked and highlighted states. In our case they will be same and we use 0 frame from `DrDoCoBk` animation.
|
||||||
|
|
||||||
|
We also want to have label on the top of this combo box showing which element is selected. You need to add `items` array, where additional elements can be specified, label in our case:
|
||||||
|
|
||||||
|
```json
|
||||||
|
...
|
||||||
|
//timer
|
||||||
|
{
|
||||||
|
"name": "timerModeSwitch",
|
||||||
|
"type": "comboBox",
|
||||||
|
"image": "DrDoCoBk",
|
||||||
|
"position": {"x": 158, "y": 532},
|
||||||
|
"imageOrder": [0, 0, 0, 0],
|
||||||
|
"dropDown": {}, //here will be defined elements to be shown in drop down list
|
||||||
|
"items":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "timer",
|
||||||
|
"type": "label",
|
||||||
|
"font": "small",
|
||||||
|
"alignment": "left",
|
||||||
|
"color": "yellow",
|
||||||
|
"text": "vcmi.optionsTab.widgets.timerModeSwitch.classic" //default value for timer label
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
With that we already have desired layout with all elements shown by default, but we also need to add elements with timer modes into drop-down list:
|
||||||
|
|
||||||
|
<img width="236" alt="Снимок экрана 2023-08-30 в 15 34 47" src="https://github.com/vcmi/vcmi/assets/9308612/f515f54e-94e1-4650-88e4-721e00c22e0d">
|
||||||
|
|
||||||
|
First of all, add images to `content/sprites/` folder: `List2Bk.bmp` for drop-down background and `List10Sl.bmp` for element highlighting.
|
||||||
|
|
||||||
|
Now specify items inside `dropDown` field
|
||||||
|
|
||||||
|
```json
|
||||||
|
"dropDown":
|
||||||
|
{
|
||||||
|
"items":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "background",
|
||||||
|
"type": "picture",
|
||||||
|
"image": "List2Bk",
|
||||||
|
"position": {"x": 0, "y": -52} //negative value because our drop-down shall open in the top direction
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "slider", //let's add slider if we have more elements in future
|
||||||
|
"type": "slider",
|
||||||
|
"position": {"x": 212, "y": -52},
|
||||||
|
"size": 52,
|
||||||
|
"style": "blue",
|
||||||
|
"itemsVisible": 2, //we show only two elements
|
||||||
|
"itemsTotal": 0,
|
||||||
|
"selected": 0,
|
||||||
|
"orientation": "vertical",
|
||||||
|
"callback": "sliderMove" //callback predefined for drop-down menu to control which elements to show
|
||||||
|
},
|
||||||
|
|
||||||
|
//now list elements
|
||||||
|
{ //classic timer
|
||||||
|
"type": "item", //this is special type for drop-down elements
|
||||||
|
"position": {"x": 0, "y": -52},
|
||||||
|
"items": //each element may have several elements
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"type": "label",
|
||||||
|
"name": "labelName",
|
||||||
|
"font": "small",
|
||||||
|
"alignment": "left",
|
||||||
|
"color": "white",
|
||||||
|
"position": {"x": 4, "y": 0},
|
||||||
|
"text": "vcmi.optionsTab.widgets.timerModeSwitch.classic"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "picture",
|
||||||
|
"name": "hoverImage", //"hoverImage" is a key word, helping VCMI to understand which element to show when cursor hovers element
|
||||||
|
"visible": false, //invisible by default
|
||||||
|
"image": "List10Sl"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{ //chess timer
|
||||||
|
"type": "item",
|
||||||
|
"position": {"x": 0, "y": -27},
|
||||||
|
"items":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"type": "label",
|
||||||
|
"name": "labelName",
|
||||||
|
"font": "small",
|
||||||
|
"alignment": "left",
|
||||||
|
"color": "white",
|
||||||
|
"position": {"x": 4, "y": 0},
|
||||||
|
"text": "vcmi.optionsTab.widgets.timerModeSwitch.chess"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "picture",
|
||||||
|
"name": "hoverImage",
|
||||||
|
"visible": false,
|
||||||
|
"image": "List10Sl"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
Now we can press drop-down menu and even select elements.
|
||||||
|
|
||||||
|
## Switching timer modes
|
||||||
|
|
||||||
|
After view part is done, let's make behavioural part.
|
||||||
|
Let's hide elements, related to classic timer when chess timer is selected and show them back if classic selected.
|
||||||
|
|
||||||
|
To do that, find `"variables"` part inside `optionsTab.json` and add there `"timers"` array, containing 2 elements:
|
||||||
|
```json
|
||||||
|
"variables":
|
||||||
|
{
|
||||||
|
"timers":
|
||||||
|
[
|
||||||
|
{ //variables used if first element is chosen
|
||||||
|
"text": "vcmi.optionsTab.widgets.timerModeSwitch.classic",
|
||||||
|
"showWidgets": ["labelTurnDurationValue", "sliderTurnDuration"],
|
||||||
|
"hideWidgets": [],
|
||||||
|
},
|
||||||
|
|
||||||
|
{ //variables used if second element is chosen
|
||||||
|
"text": "vcmi.optionsTab.widgets.timerModeSwitch.chess",
|
||||||
|
"showWidgets": [],
|
||||||
|
"hideWidgets": ["labelTurnDurationValue", "sliderTurnDuration"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"timerPresets" :
|
||||||
|
[
|
||||||
|
...
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Now we show and hide elements, but visually you still can some "artifacts":
|
||||||
|
|
||||||
|
<img width="341" alt="Снимок экрана 2023-08-30 в 15 51 22" src="https://github.com/vcmi/vcmi/assets/9308612/8a4eecdf-2c44-4f38-a7a0-aff6b9254fe6">
|
||||||
|
|
||||||
|
It's because options tab background image we use has those elements drawn. Let's hide them with overlay image `timchebk.bmp`.
|
||||||
|
It should be drawn before all other timer elements:
|
||||||
|
|
||||||
|
```json
|
||||||
|
...
|
||||||
|
// timer
|
||||||
|
{
|
||||||
|
"name": "timerBackground",
|
||||||
|
"type": "picture",
|
||||||
|
"image": "timchebk",
|
||||||
|
"position": {"x": 0, "y": 530}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"name": "timerModeSwitch",
|
||||||
|
...
|
||||||
|
},
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
This background must be visible for chess timer and hidden for classic timer. Just put its name `"timerBackground"` into `"hideWidgets"` and `"showWidgets"` for corresponding elements.
|
||||||
|
|
||||||
|
It works and can switch elements, the only missing part is chess timer configuration.
|
||||||
|
|
||||||
|
## Chess timer configuration
|
||||||
|
|
||||||
|
We should add text input fields, to specify different timers. We will use background for them `timerField.bmp`, copy it to `content/sprites/` folder of your mod.
|
||||||
|
|
||||||
|
There are 4 different timers: base, turn, battle and creature. Read about them here: https://github.com/vcmi/vcmi/issues/1364
|
||||||
|
We can add editors for them into items list, their format will be following:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "chessFieldBase",
|
||||||
|
"type": "textInput",
|
||||||
|
"background": "timerField",
|
||||||
|
"alignment": "center",
|
||||||
|
"text": "00:00", //default text
|
||||||
|
"rect": {"x": 54, "y": 557, "w": 84, "h": 25},
|
||||||
|
"offset": {"x": 0, "y": 0},
|
||||||
|
"callback": "parseAndSetTimer_base", //callback to specify base timer value from string
|
||||||
|
"help": "vcmi.optionsTab.widgets.chessFieldBase.help"
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
Add three remaining elements for different timers by yourself. You can play with all settings, except callback. There are 4 predefined callbacks to setup timers:
|
||||||
|
- `parseAndSetTimer_base`
|
||||||
|
- `parseAndSetTimer_turn`
|
||||||
|
- `parseAndSetTimer_battle`
|
||||||
|
- `parseAndSetTimer_creature`
|
||||||
|
|
||||||
|
And what we want to do is to hide/show those fields when classic/chess times is selected. Just add names of those elements into corresponding variables `"showWidgets"`, `"hideWidgets".
|
||||||
|
|
||||||
|
We are done! You can find more information about configurable UI elements in documentation section.
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
|
||||||
|
## Types
|
||||||
|
|
||||||
|
All fields have format `"key": value`
|
||||||
|
There are different basic types, which can be used as value.
|
||||||
|
|
||||||
|
### Primitive types
|
||||||
|
|
||||||
|
Read JSON documentation for primitive types description: https://www.json.org/json-en.html
|
||||||
|
|
||||||
|
### Text
|
||||||
|
|
||||||
|
Load predefined text which can be localised, examples:
|
||||||
|
`"vcmi.otherOptions.availableCreaturesAsDwellingLabel"`
|
||||||
|
`"core.genrltxt.738"`
|
||||||
|
|
||||||
|
### Position
|
||||||
|
|
||||||
|
Point with two coordinates, example:
|
||||||
|
`{ "x": 43, "y": -28 }`
|
||||||
|
|
||||||
|
### Rect
|
||||||
|
|
||||||
|
Rectangle ares, example:
|
||||||
|
`{ "x": 28, "y": 220, "w": 108, "h": 50 }`
|
||||||
|
|
||||||
|
### Text alignment
|
||||||
|
|
||||||
|
Defines text alignment, can be one of values:
|
||||||
|
`"center"`, `"left"`, `"right"`
|
||||||
|
|
||||||
|
### Color
|
||||||
|
|
||||||
|
Predefined colors:
|
||||||
|
`"yellow"`, `"white"`, `"gold"`, `"green"`, `"orange"`, `"bright-yellow"`
|
||||||
|
|
||||||
|
To have custom color make an array of four elements in RGBA notation:
|
||||||
|
`[255, 128, 0, 255]`
|
||||||
|
|
||||||
|
### Font
|
||||||
|
|
||||||
|
Predefined fonts:
|
||||||
|
`"big"`, `"medium"`, `"small"`, `"tiny"`, `"calisto"`
|
||||||
|
|
||||||
|
### Hint text
|
||||||
|
|
||||||
|
Hint text is a pair of strings, one is usually shown in status bar when cursor hovers element, another hint while right button pressed.
|
||||||
|
Each of elements is a [Text](#text)
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"hover": "Text",
|
||||||
|
"help": "Text
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If one string specified, it will be applied for both hover and help.
|
||||||
|
|
||||||
|
`"text"`
|
||||||
|
|
||||||
|
### Shortcut
|
||||||
|
|
||||||
|
String value defines shortcut. Some examples of shortcuts:
|
||||||
|
`"globalAccept", "globalCancel", "globalReturn","globalFullscreen", "globalOptions", "globalBackspace", "globalMoveFocus"`
|
||||||
|
|
||||||
|
Full list is TBD
|
||||||
|
|
||||||
|
### [VCMI-1.4] Player color
|
||||||
|
|
||||||
|
One of predefined values:
|
||||||
|
`"red"`, `"blue"`, `"tan"`, `"green"`, `"orange"`, `"purple"`, `"teal"`, `"pink"`
|
||||||
|
|
||||||
|
## Configurable objects
|
||||||
|
|
||||||
|
Configurable object has following structure:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"items": [],
|
||||||
|
"variables": {}, //optional
|
||||||
|
"customTypes": {}, //optional
|
||||||
|
"library": {} //optional
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`items` - array of widgets to be created. Widgets are created in sequentially in same order as they described.
|
||||||
|
|
||||||
|
`variables` - variables, which can be used by object. Meaningful variable names are predefined for each object
|
||||||
|
|
||||||
|
`customTypes` - description of custom widgets, which can be used for this object, see [Custom widgets](#custom-widgets)
|
||||||
|
|
||||||
|
`library` - same as above, but custom widgets are described in separate json, this parameter should contain path to library json is specified
|
||||||
|
|
||||||
|
## Basic widgets
|
||||||
|
|
||||||
|
### Label
|
||||||
|
|
||||||
|
`"type": "label"`
|
||||||
|
|
||||||
|
`"name": "string"` optional, object name
|
||||||
|
|
||||||
|
`"font"`: [font](#font)
|
||||||
|
|
||||||
|
`"alignment"`: [alignment](#text-alignment),
|
||||||
|
|
||||||
|
`"color"`: [color](#color),
|
||||||
|
|
||||||
|
`"text"`: [text](#text),
|
||||||
|
|
||||||
|
`"position"`: [position](#position)
|
||||||
|
|
||||||
|
### [VCMI-1.4] Multi-line label
|
||||||
|
|
||||||
|
`"type": "multiLineLabel"`
|
||||||
|
|
||||||
|
`"name": "string"` optional, object name
|
||||||
|
|
||||||
|
`"font"`: [font](#font)
|
||||||
|
|
||||||
|
`"alignment"`: [alignment](#text-alignment),
|
||||||
|
|
||||||
|
`"color"`: [color](#color),
|
||||||
|
|
||||||
|
`"text"`: [text](#text),
|
||||||
|
|
||||||
|
`"position"`: [position](#position)
|
||||||
|
|
||||||
|
`"rect"`: [rect](#rect) //text area
|
||||||
|
|
||||||
|
`"adoptHeight": bool` //if true, text area height will be adopted automatically based on content
|
||||||
|
|
||||||
|
### Label group
|
||||||
|
|
||||||
|
`"type": "labelGroup"`
|
||||||
|
|
||||||
|
`"name": "string"` optional, object name
|
||||||
|
|
||||||
|
`"font"`: [font](#font)
|
||||||
|
|
||||||
|
`"alignment"`: [alignment](#text-alignment),
|
||||||
|
|
||||||
|
`"color"`: [color](#color),
|
||||||
|
|
||||||
|
`"items": []` array of elements
|
||||||
|
|
||||||
|
**Label group item**
|
||||||
|
|
||||||
|
`"position"`: [position](#position)
|
||||||
|
|
||||||
|
`"text"`: [text](#text),
|
||||||
|
|
||||||
|
### Picture
|
||||||
|
|
||||||
|
`"type": "picture"`
|
||||||
|
|
||||||
|
`"name": "string"` optional, object name
|
||||||
|
|
||||||
|
`"position"`: [position](#position)
|
||||||
|
|
||||||
|
`"image": string`, specify filename
|
||||||
|
|
||||||
|
`"visible": bool`, optional
|
||||||
|
|
||||||
|
`"playerColored", bool`, optional, if true will be colorised to current player
|
||||||
|
|
||||||
|
### Image
|
||||||
|
|
||||||
|
Use to show single frame from animation
|
||||||
|
|
||||||
|
`"type": "image"`
|
||||||
|
|
||||||
|
`"name": "string"` optional, object name
|
||||||
|
|
||||||
|
`"position"`: [position](#position)
|
||||||
|
|
||||||
|
`"image": string`, specify filename, animation only (def, json)
|
||||||
|
|
||||||
|
`"group": integer` optional, specify animation group
|
||||||
|
|
||||||
|
`"frame": integer` optional, specify animation frame
|
||||||
|
|
||||||
|
### Texture
|
||||||
|
|
||||||
|
Filling area with texture
|
||||||
|
|
||||||
|
`"type": "texture"`
|
||||||
|
|
||||||
|
`"name": "string"` optional, object name
|
||||||
|
|
||||||
|
`"image": string`, specify filename
|
||||||
|
|
||||||
|
`"rect"`: [rect](#rect)
|
||||||
|
|
||||||
|
### Animation
|
||||||
|
|
||||||
|
`"type": "animation"`
|
||||||
|
|
||||||
|
`"name": "string"` optional, object name
|
||||||
|
|
||||||
|
`"position"`: [position](#position)
|
||||||
|
|
||||||
|
`"image": string`, specify filename, animation only (def, json)
|
||||||
|
|
||||||
|
`"repeat": bool`, play only once or repeat animation
|
||||||
|
|
||||||
|
`"group": integer` optional, specify animation group
|
||||||
|
|
||||||
|
`"alpha": integer` optional, specify alpha opacity
|
||||||
|
|
||||||
|
`"callback": string` optional, callback to be called after animation complete
|
||||||
|
|
||||||
|
`"frames": []` optional, array of frame ranges to show
|
||||||
|
|
||||||
|
**Frame range**
|
||||||
|
|
||||||
|
`"start": integer`, first frame
|
||||||
|
|
||||||
|
`"end": integer`, last frame
|
||||||
|
|
||||||
|
### [VCMI-1.4] Text input
|
||||||
|
|
||||||
|
`"type": "textInput"`
|
||||||
|
|
||||||
|
`"name": "string"` optional, object name
|
||||||
|
|
||||||
|
`"rect"`: [rect](#rect)
|
||||||
|
|
||||||
|
`"backgroundOffset": [position](#position)
|
||||||
|
|
||||||
|
`"background": string`, specify filename
|
||||||
|
|
||||||
|
`"font"`: [font](#font)
|
||||||
|
|
||||||
|
`"alignment"`: [alignment](#text-alignment),
|
||||||
|
|
||||||
|
`"color"`: [color](#color),
|
||||||
|
|
||||||
|
`"text": string` optional, default text. Translations are not supported
|
||||||
|
|
||||||
|
`"position"`: [position](#position)
|
||||||
|
|
||||||
|
`"help"`: [hint](#hint-text)
|
||||||
|
|
||||||
|
`"callback": string` optional, callback to be called on text changed. Input text is passed to callback function as an argument.
|
||||||
|
|
||||||
|
### Button
|
||||||
|
|
||||||
|
`"type": "button"`
|
||||||
|
|
||||||
|
`"name": "string"` optional, object name
|
||||||
|
|
||||||
|
`"position"`: [position](#position)
|
||||||
|
|
||||||
|
`"image": string`, specify filename, animation only (def, json)
|
||||||
|
|
||||||
|
`"help"`: [hint](#hint-text)
|
||||||
|
|
||||||
|
`"imageOrder": []` array of 4 integers, each is responsible for frame to be shown in different states: normal, pressed, blocked and highlighted
|
||||||
|
|
||||||
|
`"borderColor"`: [color](#color), optional
|
||||||
|
|
||||||
|
`"hotkey"`: [shortcut](#shortcut), optional
|
||||||
|
|
||||||
|
`"callback": string` optional, callback to be called on press. No arguments are passed to callback function.
|
||||||
|
|
||||||
|
`"items": []` array of widgets to be shown as overlay (caption [label](#label), for example)
|
||||||
|
|
||||||
|
### Toggle button
|
||||||
|
|
||||||
|
`"type": "toggleButton"`
|
||||||
|
|
||||||
|
`"name": "string"` optional, object name
|
||||||
|
|
||||||
|
`"position"`: [position](#position)
|
||||||
|
|
||||||
|
`"image": string`, specify filename, animation only (def, json)
|
||||||
|
|
||||||
|
`"help"`: [hint](#hint-text)
|
||||||
|
|
||||||
|
`"imageOrder": []` array of 4 integers, each is responsible for frame to be shown in different states: normal, pressed, blocked and highlighted
|
||||||
|
|
||||||
|
`"callback": string` optional, callback to be called on selection. Toggle identifier is passed to callback function as an argument.
|
||||||
|
|
||||||
|
`"selected": bool`, optional, is selected by default
|
||||||
|
|
||||||
|
`"items": []` array of widgets to be shown as overlay (caption [label](#label), for example)
|
||||||
|
|
||||||
|
### Toggle group
|
||||||
|
|
||||||
|
Group of [toggle buttons](#toggle-button), when one is selected, other will be de-selected
|
||||||
|
|
||||||
|
`"type": "toggleGroup"`
|
||||||
|
|
||||||
|
`"name": "string"` optional, object name
|
||||||
|
|
||||||
|
`"position"`: [position](#position)
|
||||||
|
|
||||||
|
`"callback": string` optional, callback to be called when one of toggles is selected
|
||||||
|
|
||||||
|
`"items": []` array of [toggle buttons](#toggle-button)
|
||||||
|
|
||||||
|
### Slider
|
||||||
|
|
||||||
|
`"type": "slider"`
|
||||||
|
|
||||||
|
`"name": "string"` optional, object name
|
||||||
|
|
||||||
|
`"position"`: [position](#position)
|
||||||
|
|
||||||
|
`"size": integer` size in pixels
|
||||||
|
|
||||||
|
`"style": string`, can be `"brown"` or `"blue"`
|
||||||
|
|
||||||
|
`"itemsVisible": integer`, how many items are visible
|
||||||
|
|
||||||
|
`"itemsTotal": integer`, how many items in total
|
||||||
|
|
||||||
|
`"selected": integer`, current state for slider
|
||||||
|
|
||||||
|
`"orientation" string`, can be `"horizontal"` or `"vertical"`
|
||||||
|
|
||||||
|
`"callback": string` callback to be called on state change. Slider position is passed to callback function as an argument.
|
||||||
|
|
||||||
|
`"scrollBounds":` [rect](#rect), optional
|
||||||
|
|
||||||
|
`"panningStep": integer`, optional
|
||||||
|
|
||||||
|
### Combo box
|
||||||
|
|
||||||
|
`"type": "comboBox"`
|
||||||
|
|
||||||
|
`"name": "string"` optional, object name
|
||||||
|
|
||||||
|
`"position"`: [position](#position)
|
||||||
|
|
||||||
|
`"image": string`, specify filename, animation only (def, json)
|
||||||
|
|
||||||
|
`"help"`: [hint](#hint-text)
|
||||||
|
|
||||||
|
`"imageOrder": []` array of 4 integers, each is responsible for frame to be shown in different states: normal, pressed, blocked and highlighted
|
||||||
|
|
||||||
|
`"borderColor"`: [color](#color), optional
|
||||||
|
|
||||||
|
`"hotkey"`: [shortcut](#shortcut), optional
|
||||||
|
|
||||||
|
`"items": []` array of widgets to be shown as overlay, for example, [label](#label)
|
||||||
|
|
||||||
|
`"dropDown" : {}` description of [drop down](#drop-down) menu widget
|
||||||
|
|
||||||
|
### Drop down
|
||||||
|
|
||||||
|
Used only as special object for [combo box](#combo-box)
|
||||||
|
|
||||||
|
`"items": []` array of widgets to be built. Usually contains background [picture](#picture), [slider](#slider) and item elements.
|
||||||
|
|
||||||
|
**Item elements**
|
||||||
|
|
||||||
|
`"type": "item"`
|
||||||
|
|
||||||
|
`"name": "string"` optional, object name
|
||||||
|
|
||||||
|
`"position"`: [position](#position)
|
||||||
|
|
||||||
|
`"items": []` array of overlay widgets with certain types and names:
|
||||||
|
- `"name": "hoverImage"`, `"type": ` [picture](#picture) - image to be shown when cursor hovers elements
|
||||||
|
- `"name": "labelName"`, `"type": ` [label](#label) - element caption
|
||||||
|
|
||||||
|
**Callbacks**
|
||||||
|
- `sliderMove` connect to slider callback to correctly navigate over elements
|
||||||
|
|
||||||
|
### Layout
|
||||||
|
|
||||||
|
`"type": "layout"`
|
||||||
|
|
||||||
|
`"name": "string"` optional, object name
|
||||||
|
|
||||||
|
## High-level widgets
|
||||||
|
|
||||||
|
## Custom widgets
|
||||||
|
|
||||||
|
# For developers
|
||||||
|
|
||||||
|
While designing a new element, you can make it configurable to reuse all functionality described above. It will provide flexibility to further changes as well as modding capabilities.
|
||||||
|
|
||||||
|
Class should inherit `InterfaceObjectConfigurable`.
|
||||||
|
```C++
|
||||||
|
#include "gui/InterfaceObjectConfigurable.h" //assuming we are in client folder
|
||||||
|
|
||||||
|
class MyYesNoDialog: public InterfaceObjectConfigurable
|
||||||
|
{
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`InterfaceObjectConfigurable` doesn't have default constructor, but has possibility to specify arguments to be passed to `CIntObject`.
|
||||||
|
|
||||||
|
To make new object work, it's sufficient to define constructor, which receives const reference to `JsonNode`.
|
||||||
|
|
||||||
|
```C++
|
||||||
|
MyYesNoDialog::MyYesNoDialog(const JsonNode & config):
|
||||||
|
InterfaceObjectConfigurable(), //you can pass arguments same as for CIntObject
|
||||||
|
{
|
||||||
|
//register custom builders
|
||||||
|
REGISTER_BUILDER("MyItem", &MyYesNoDialog::buildMyItem);
|
||||||
|
|
||||||
|
//add callbacks which can be used by widgets
|
||||||
|
addCallback("okPressed", std::bind(&MyYesNoDialog::onOk, this, std::placeholders::_1));
|
||||||
|
addCallback("cancelPressed", std::bind(&MyYesNoDialog::onCancel, this, std::placeholders::_1));
|
||||||
|
|
||||||
|
build(config); //after this point all widgets are built and accessible
|
||||||
|
|
||||||
|
//access widgets by name
|
||||||
|
if(auto w = widget<CButton>("cancel"))
|
||||||
|
{
|
||||||
|
//now you can do something with button
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Callbacks
|
||||||
|
|
||||||
|
## Custom widgets
|
||||||
|
|
||||||
|
You can build custom widgets, related to your UI element specifically. Like in example above, there is Item widget, which can be also used on JSON config.
|
||||||
|
|
||||||
|
```C++
|
||||||
|
REGISTER_BUILDER("myItem", &MyYesNoDialog::buildMyItem);
|
||||||
|
```
|
||||||
|
|
||||||
|
You have to define function, which takes JsonNode as an argument and return pointer to built widget
|
||||||
|
|
||||||
|
```C++
|
||||||
|
std::shared_ptr<MyYesNoDialog::Item> MyYesNoDialog::buildMyItem(const JsonNode & config)
|
||||||
|
{
|
||||||
|
auto position = readPosition(config["position"]);
|
||||||
|
return std::make_shared<MyYesNoDialog::Item>(*this, position); //define Item object as you want
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
After that, if your JSON file has items with type "MyItem", the new Item element will be constructed.
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"items":
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"type": "myItem",
|
||||||
|
"position": {"x": 100, "y": 50}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Variables
|
||||||
|
|
||||||
|
After calling `build(config)` variables defined in config JSON file become available. You can interpret them and use in callbacks or in element code
|
||||||
|
|
||||||
|
```C++
|
||||||
|
build(config);
|
||||||
|
|
||||||
|
if(variables["colorfulText"].Bool())
|
||||||
|
{
|
||||||
|
if(auto w = widget<CLabel>("text"))
|
||||||
|
{
|
||||||
|
w->setColor(getMyPlayerColor()); //for reference only, getMyPlayerColor is not defined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
65
docs/modders/Entities_Format/Artifact_Format.md
Normal file
65
docs/modders/Entities_Format/Artifact_Format.md
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
< [Documentation](../../Readme.md) / [Modding](../Readme.md) / Entities Format / Artifact Format
|
||||||
|
|
||||||
|
Artifact bonuses use [Bonus Format](../Bonus_Format.md)
|
||||||
|
|
||||||
|
TODO:
|
||||||
|
|
||||||
|
- Artifacts growing with Commander level
|
||||||
|
|
||||||
|
## Required data
|
||||||
|
|
||||||
|
In order to make functional artifact you also need:
|
||||||
|
|
||||||
|
- Icon for hero inventory (1 image)
|
||||||
|
- Icon for popup windows (1 image, optional)
|
||||||
|
- Animation for adventure map (1 animation)
|
||||||
|
|
||||||
|
## Format
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
{
|
||||||
|
//what kind of bearer can use this artifact
|
||||||
|
"type": ["HERO", "CREATURE", "COMMANDER"]
|
||||||
|
|
||||||
|
//TREASURE, MINOR, MAJOR, RELIC, SPECIAL
|
||||||
|
"class": "TREASURE",
|
||||||
|
|
||||||
|
//SHOULDERS, NECK, RIGHT_HAND, LEFT_HAND, TORSO, RIGHT_RING, LEFT_RING, FEET, MISC1, MISC2, MISC3, MISC4,
|
||||||
|
//MACH1, MACH2, MACH3, MACH4, SPELLBOOK, MISC5
|
||||||
|
//also possible MISC, RING
|
||||||
|
"slot": "HEAD",
|
||||||
|
|
||||||
|
//based on ARTRAITS.txt
|
||||||
|
"value": 12000,
|
||||||
|
|
||||||
|
"text":
|
||||||
|
{
|
||||||
|
"name": "Big Sword",
|
||||||
|
"description": "Big sword gived +10 attack to hero",
|
||||||
|
"event": "On your travel, you stumble upon big sword. You dust it off and stick in your backpack"
|
||||||
|
},
|
||||||
|
"graphics":
|
||||||
|
{
|
||||||
|
"image": "BigSword.png",
|
||||||
|
"large": "BigSword_large.png",
|
||||||
|
//def file for adventure map
|
||||||
|
"map": "BigSword.def"
|
||||||
|
},
|
||||||
|
"bonuses":
|
||||||
|
{
|
||||||
|
Bonus_1,
|
||||||
|
Bonus_2
|
||||||
|
},
|
||||||
|
|
||||||
|
//optional, for combined artifacts only
|
||||||
|
"components":
|
||||||
|
[
|
||||||
|
"artifact1",
|
||||||
|
"artifact2",
|
||||||
|
"artifact3"
|
||||||
|
],
|
||||||
|
|
||||||
|
//if set with artifact works like war machine
|
||||||
|
"warMachine" : "some.creature"
|
||||||
|
}
|
||||||
|
```
|
3
docs/modders/Entities_Format/Battle_Obstacle_Format.md
Normal file
3
docs/modders/Entities_Format/Battle_Obstacle_Format.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
< [Documentation](../../Readme.md) / [Modding](../Readme.md) / Entities Format / Battle Obstacle Format
|
||||||
|
|
||||||
|
TODO
|
3
docs/modders/Entities_Format/Battlefield_Format.md
Normal file
3
docs/modders/Entities_Format/Battlefield_Format.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
< [Documentation](../../Readme.md) / [Modding](../Readme.md) / Entities Format / Battlefield Format
|
||||||
|
|
||||||
|
TODO
|
195
docs/modders/Entities_Format/Creature_Format.md
Normal file
195
docs/modders/Entities_Format/Creature_Format.md
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
< [Documentation](../../Readme.md) / [Modding](../Readme.md) / Entities Format / Creature Format
|
||||||
|
|
||||||
|
## Required data
|
||||||
|
|
||||||
|
In order to make functional creature you also need:
|
||||||
|
|
||||||
|
### Animation
|
||||||
|
|
||||||
|
- Battle animation (1 def file)
|
||||||
|
- Set of rendered projectiles (1 def files, shooters only)
|
||||||
|
- Adventure map animation (1 def file)
|
||||||
|
|
||||||
|
### Images
|
||||||
|
|
||||||
|
- Small portrait for hero exchange window (1 image)
|
||||||
|
- Large portrait for hero window (1 image)
|
||||||
|
|
||||||
|
### Sounds
|
||||||
|
|
||||||
|
- Set of sounds (up to 8 sounds)
|
||||||
|
|
||||||
|
## Format
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
// camelCase unique creature identifier
|
||||||
|
"creatureName" :
|
||||||
|
{
|
||||||
|
// translatable names
|
||||||
|
"name" :
|
||||||
|
{
|
||||||
|
"singular" : "Creature",
|
||||||
|
"plural" : "Creatures"
|
||||||
|
},
|
||||||
|
"level" : 0,
|
||||||
|
|
||||||
|
// if set to true creature will not appear in-game randomly (e.g. as neutral creature)
|
||||||
|
"special" : true,
|
||||||
|
|
||||||
|
// config name of faction. Examples: castle, rampart
|
||||||
|
"faction" : "",
|
||||||
|
// cost to recruit, zero values can be omitted.
|
||||||
|
"cost" :
|
||||||
|
{
|
||||||
|
"wood" : 0,
|
||||||
|
"mercury" : 0,
|
||||||
|
"ore" : 0,
|
||||||
|
"sulfur" : 0,
|
||||||
|
"crystal" : 0,
|
||||||
|
"gems" : 0,
|
||||||
|
"gold" : 0
|
||||||
|
},
|
||||||
|
// "value" of creature, used to determine for example army strength
|
||||||
|
"fightValue" : 0,
|
||||||
|
|
||||||
|
// "ai value" - how valuable this creature should be for AI
|
||||||
|
"aiValue" : 0,
|
||||||
|
|
||||||
|
// normal growth in town or external dwellings
|
||||||
|
"growth" : 0,
|
||||||
|
|
||||||
|
// growth bonus from horde building
|
||||||
|
// TODO: reconsider need of this field after configurable buildings support
|
||||||
|
"hordeGrowth" : 0,
|
||||||
|
|
||||||
|
// Creature stats in battle
|
||||||
|
"attack" : 0,
|
||||||
|
"defense" : 0,
|
||||||
|
"hitPoints" : 0,
|
||||||
|
"shots" : 0,
|
||||||
|
"speed" : 0,
|
||||||
|
"damage" :
|
||||||
|
{
|
||||||
|
"min" : 0,
|
||||||
|
"max" : 0
|
||||||
|
},
|
||||||
|
// spellpoints this creature has, how many times creature may cast its spells
|
||||||
|
"spellPoints" : 0,
|
||||||
|
// initial size of creature army on adventure map
|
||||||
|
"advMapAmount" :
|
||||||
|
{
|
||||||
|
"min" : 0,
|
||||||
|
"max" : 0
|
||||||
|
},
|
||||||
|
|
||||||
|
// Creature to which this creature can be upgraded
|
||||||
|
// Note that only one upgrade can be available from UI
|
||||||
|
"upgrades" :
|
||||||
|
[
|
||||||
|
"anotherCreature"
|
||||||
|
],
|
||||||
|
|
||||||
|
// Creature is 2-tiles in size on the battlefield
|
||||||
|
"doubleWide" : false,
|
||||||
|
|
||||||
|
// All creature abilities, using bonus format
|
||||||
|
"abilities" :
|
||||||
|
[
|
||||||
|
"someName1" : Bonus Format,
|
||||||
|
"someName2" : Bonus Format
|
||||||
|
],
|
||||||
|
|
||||||
|
"hasDoubleWeek": true,
|
||||||
|
|
||||||
|
"graphics" :
|
||||||
|
{
|
||||||
|
// name of file with creature battle animation
|
||||||
|
"animation" : "",
|
||||||
|
// adventure map animation def
|
||||||
|
"map" : "",
|
||||||
|
// path to small icon for tooltips & hero exchange window
|
||||||
|
"iconSmall" : "",
|
||||||
|
// path to large icon, used on town screen and in hero screen
|
||||||
|
"iconLarge" : "",
|
||||||
|
|
||||||
|
// animation parameters
|
||||||
|
|
||||||
|
// how often creature should play idle animation
|
||||||
|
"timeBetweenFidgets" : 1.00,
|
||||||
|
// unused H3 property
|
||||||
|
"troopCountLocationOffset" : 0,
|
||||||
|
"animationTime" :
|
||||||
|
{
|
||||||
|
// movement animation time.
|
||||||
|
"walk" : 1.00,
|
||||||
|
|
||||||
|
// idle animation time. For H3 creatures this value is always 10
|
||||||
|
"idle" : 10.00,
|
||||||
|
|
||||||
|
// ranged attack animation time. Applicable to shooting and casting animation
|
||||||
|
// NOTE: does NOT affects melee attacks
|
||||||
|
// This is H3 behaviour, for proper synchronization of attack/defense animations
|
||||||
|
"attack" : 1.00,
|
||||||
|
|
||||||
|
// How far flying creature should move during one "round" of movement animation
|
||||||
|
// This is multiplier to base value (200 pixels)
|
||||||
|
"flight" : 1.00
|
||||||
|
},
|
||||||
|
"missile" :
|
||||||
|
{
|
||||||
|
// name of file for missile
|
||||||
|
"animation" : "",
|
||||||
|
|
||||||
|
// (VCMI 1.1 or later only) indicates that creature uses ray animation for ranged attacks instead of missile image (e.g. Evil Eye)
|
||||||
|
"ray" :
|
||||||
|
[
|
||||||
|
{ // definition of first (top-most) line in the ray
|
||||||
|
"start" : [ 160, 192, 0, 255 ], // color (RGBA components) of ray at starting point
|
||||||
|
"end" : [ 160, 192, 0, 64 ] // color (RGBA components) of ray at finishing point
|
||||||
|
},
|
||||||
|
{}, // definition of second from top line in the ray, identical format
|
||||||
|
... // definitions of remaining lines, till desired width of the ray
|
||||||
|
],
|
||||||
|
// Frame at which shooter shoots his projectile (e.g. releases arrow)
|
||||||
|
"attackClimaxFrame" : 0,
|
||||||
|
|
||||||
|
// offsets between position of shooter and position where projectile should appear
|
||||||
|
"offset" :
|
||||||
|
{
|
||||||
|
"upperX" : 0,
|
||||||
|
"upperY" : 0,
|
||||||
|
"middleX" : 0,
|
||||||
|
"middleY" : 0,
|
||||||
|
"lowerX" : 0,
|
||||||
|
"lowerY" : 0
|
||||||
|
},
|
||||||
|
// angles from which frames in .def file were rendered, -90...90 range
|
||||||
|
// Example below will work for file that contains following frames:
|
||||||
|
// 1) facing top, 2) facing top-right, 3)facing right,
|
||||||
|
// 4) facing bottom-right 5) facing bottom.
|
||||||
|
"frameAngles" : [ -90, -45, 0, 45, 90]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// names of sound files
|
||||||
|
"sound" :
|
||||||
|
{
|
||||||
|
// Creature attack enemy in melee (counter-)attack
|
||||||
|
"attack": "",
|
||||||
|
// Creature in "defend mode" is attacked
|
||||||
|
"defend": "",
|
||||||
|
// Creature killed
|
||||||
|
"killed": "",
|
||||||
|
// Plays in loop during creature movement
|
||||||
|
"move": "",
|
||||||
|
// Shooters only, creature shoots
|
||||||
|
"shoot" : "",
|
||||||
|
// Creature not in "defend mode" is under attack
|
||||||
|
"wince": "",
|
||||||
|
|
||||||
|
// Creature start/end movement or teleports
|
||||||
|
"startMoving" : "",
|
||||||
|
"endMoving" : ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
390
docs/modders/Entities_Format/Faction_Format.md
Normal file
390
docs/modders/Entities_Format/Faction_Format.md
Normal file
@ -0,0 +1,390 @@
|
|||||||
|
< [Documentation](../../Readme.md) / [Modding](../Readme.md) / Entities Format / Faction Format
|
||||||
|
|
||||||
|
## Required data
|
||||||
|
|
||||||
|
In order to make functional town you also need:
|
||||||
|
|
||||||
|
### Images
|
||||||
|
|
||||||
|
- Creature backgrounds images, 120x100 and 130x100 versions (2 images)
|
||||||
|
- Set of puzzle map pieces (48 images)
|
||||||
|
- Background scenery (1 image)
|
||||||
|
- Mage guild window view (1 image)
|
||||||
|
- Town hall background (1 image)
|
||||||
|
|
||||||
|
<!-- -->
|
||||||
|
|
||||||
|
- Set of town icons, consists from all possible combinations of: (8
|
||||||
|
images total)
|
||||||
|
- small and big icons
|
||||||
|
- village and fort icons
|
||||||
|
- built and normal icons
|
||||||
|
|
||||||
|
<!-- -->
|
||||||
|
|
||||||
|
- Set for castle siege screen, consists from:
|
||||||
|
- Background (1 image)
|
||||||
|
- Destructible towers (3 parts, 3 images each)
|
||||||
|
- Destructible walls (4 parts, 3 images each)
|
||||||
|
- Static walls (3 images)
|
||||||
|
- Town gates (5 images)
|
||||||
|
- Moat (2 images)
|
||||||
|
|
||||||
|
### Animation
|
||||||
|
|
||||||
|
- Adventure map images for village, town and capitol (3 def files)
|
||||||
|
|
||||||
|
### Music
|
||||||
|
|
||||||
|
- Town theme music track (1 music file)
|
||||||
|
|
||||||
|
### Buildings
|
||||||
|
|
||||||
|
Each town requires a set of buildings (Around 30-45 buildings)
|
||||||
|
|
||||||
|
- Town animation file (1 animation file)
|
||||||
|
- Selection highlight (1 image)
|
||||||
|
- Selection area (1 image)
|
||||||
|
- Town hall icon (1 image)
|
||||||
|
|
||||||
|
## Faction node (root entry for town configuration)
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
// Unique faction identifier. Should be unique.
|
||||||
|
"myTown" :
|
||||||
|
{
|
||||||
|
// Main part of town description, see below
|
||||||
|
// Optional but it should be present for playable faction
|
||||||
|
"town" : { ... },
|
||||||
|
|
||||||
|
// Native terrain for this town. See config/terrains.json for identifiers
|
||||||
|
"nativeTerrain" : "grass",
|
||||||
|
|
||||||
|
// Localizable town name, e.g. "Rampart"
|
||||||
|
"name" : "",
|
||||||
|
|
||||||
|
// Faction alignment. Can be good, neutral (default) or evil.
|
||||||
|
"alignment" : "",
|
||||||
|
|
||||||
|
// Backgrounds for creature screen, two versions: 120px-height and 130-px height
|
||||||
|
"creatureBackground"
|
||||||
|
{
|
||||||
|
// Paths to background images
|
||||||
|
"120px" : "",
|
||||||
|
"130px" : ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Town puzzle map
|
||||||
|
"puzzleMap" :
|
||||||
|
{
|
||||||
|
// Prefix for image names, e.g. "PUZCAS" for name "PUZCAS12.png"
|
||||||
|
"prefix" : "",
|
||||||
|
// List of map pieces. First image will have name <prefix>00, second - <prefix>01 and so on
|
||||||
|
"pieces" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
// Position of image on screen
|
||||||
|
"x" : 0
|
||||||
|
"y" : 0
|
||||||
|
|
||||||
|
//indicates order in which this image will be opened
|
||||||
|
"index" : 0
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Town node
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
{
|
||||||
|
// DEPRECATED, see "mapObject" field below | Path to images of object on adventure map
|
||||||
|
"adventureMap" :
|
||||||
|
{
|
||||||
|
"village": "", // village without built fort
|
||||||
|
"castle" : "", // town with built fort
|
||||||
|
"capitol": "" // town with capitol (usually have some additional flags)
|
||||||
|
},
|
||||||
|
|
||||||
|
// field that describes behavior of map object part of town. Town-specific part of object format
|
||||||
|
"mapObject" :
|
||||||
|
{
|
||||||
|
// Optional, controls what template will be used to display this object.
|
||||||
|
// Whenever player builds a building in town game will test all applicable templates using
|
||||||
|
// tests with matching name and on success - set such template as active.
|
||||||
|
// There are 3 predefined filters: "village", "fort" and "capitol" that emulate H3 behavior
|
||||||
|
"filter" : {
|
||||||
|
"capitol" : [ "anyOf", [ "capitol" ], [ "castle" ] ]
|
||||||
|
},
|
||||||
|
|
||||||
|
// List of templates that represent this object. For towns only animation is required
|
||||||
|
// See object template description for other fields that can be used.
|
||||||
|
"templates" : {
|
||||||
|
"village" : { "animation" : "" },
|
||||||
|
"castle" : { "animation" : "" },
|
||||||
|
"capitol" : { "animation" : "" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
//icons, small and big. Built versions indicate constructed during this turn building.
|
||||||
|
"icons" :
|
||||||
|
{
|
||||||
|
"village" : {
|
||||||
|
"normal" : {
|
||||||
|
"small" : "modname/icons/hall-small.bmp",
|
||||||
|
"large" : "modname/icons/hall-big.bmp"
|
||||||
|
},
|
||||||
|
"built" : {
|
||||||
|
"small" : "modname/icons/hall-builded-small.bmp",
|
||||||
|
"large" : "modname/icons/hall-builded-big.bmp"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fort" : {
|
||||||
|
"normal" : {
|
||||||
|
"small" : "modname/icons/fort-small.bmp",
|
||||||
|
"large" : "modname/icons/fort-big.bmp"
|
||||||
|
},
|
||||||
|
"built" : {
|
||||||
|
"small" : "modname/icons/fort-builded-small.bmp",
|
||||||
|
"large" : "modname/icons/fort-builded-big.bmp"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// Path to town music theme, e.g. "music/castleTheme"
|
||||||
|
"musicTheme" : "",
|
||||||
|
|
||||||
|
// List of structures which represents visible graphical objects on town screen.
|
||||||
|
// See detailed description below
|
||||||
|
"structures" :
|
||||||
|
{
|
||||||
|
"building1" : { ... },
|
||||||
|
...
|
||||||
|
"building9" : { ... }
|
||||||
|
},
|
||||||
|
|
||||||
|
// List of names for towns on adventure map e.g. "Dunwall", "Whitestone"
|
||||||
|
// Does not have any size limitations
|
||||||
|
"names" : [ "", ""],
|
||||||
|
|
||||||
|
// Background scenery for town screen, size must be 800x374
|
||||||
|
"townBackground": "",
|
||||||
|
|
||||||
|
// Small scenery for window in mage guild screen
|
||||||
|
"guildWindow": "",
|
||||||
|
|
||||||
|
// Background image for window in mage guild screen - since 0.95b
|
||||||
|
"guildBackground" : "",
|
||||||
|
|
||||||
|
// Video for tavern window - since 0.95b
|
||||||
|
"tavernVideo" : "",
|
||||||
|
|
||||||
|
// Building icons for town hall
|
||||||
|
"buildingsIcons": "HALLCSTL.DEF",
|
||||||
|
|
||||||
|
// Background image for town hall window
|
||||||
|
"hallBackground": "",
|
||||||
|
|
||||||
|
// List of buildings available in each slot of town hall window
|
||||||
|
// As in most cases there is no hard limit on number of columns, rows
|
||||||
|
// or items in any of them, but size of gui is limited to 5 rows and 4 columns
|
||||||
|
"hallSlots":
|
||||||
|
[
|
||||||
|
[ [ "buildingID1" ], [ "buildingID2", "buildingID3" ] ],
|
||||||
|
...
|
||||||
|
],
|
||||||
|
// List of creatures available on each tier. Number of creatures on each tier
|
||||||
|
// is not hardcoded but it should match with number of dwelling for each level.
|
||||||
|
// For example structure below would need buildings with these id's:
|
||||||
|
// first tier: 30 and 37, second tier: 31, third tier: 32, 39, 46
|
||||||
|
"creatures" :
|
||||||
|
[
|
||||||
|
["centaur", "captainCentaur"],
|
||||||
|
["dwarf"],
|
||||||
|
["elf", "grandElf", "sharpshooter"],
|
||||||
|
...
|
||||||
|
],
|
||||||
|
|
||||||
|
// Buildings, objects in town that affect mechanics. See detailed description below
|
||||||
|
"buildings" :
|
||||||
|
{
|
||||||
|
"building1" : { ... },
|
||||||
|
...
|
||||||
|
"building9" : { ... }
|
||||||
|
},
|
||||||
|
// Description of siege screen, see below
|
||||||
|
"siege" : { ... },
|
||||||
|
|
||||||
|
// Chance for a hero class to appear in this town, creates pair with same field in class format
|
||||||
|
// Used for situations where chance was not set in "tavern" field, chance will be determined as:
|
||||||
|
// square root( town tavern chance * hero class tavern chance )
|
||||||
|
"defaultTavern" : 5,
|
||||||
|
|
||||||
|
// Chance of specific hero class to appear in this town
|
||||||
|
// Mirrored version of field "tavern" from hero class format
|
||||||
|
"tavern" :
|
||||||
|
{
|
||||||
|
"knight" : 5,
|
||||||
|
"druid" : 6
|
||||||
|
},
|
||||||
|
|
||||||
|
// Chance of specific spell to appear in mages guild of this town
|
||||||
|
// If spell is missing or set to 0 it will not appear unless set as "always present" in editor
|
||||||
|
// Spells from unavailable levels are not required to be in this list
|
||||||
|
// TODO: Mirrored version of field "guildSpells" from spell format
|
||||||
|
"guildSpells" :
|
||||||
|
{
|
||||||
|
"magicArrow" : 30,
|
||||||
|
"bless" : 10
|
||||||
|
},
|
||||||
|
|
||||||
|
// TODO: Entries below should be replaced with autodetection
|
||||||
|
|
||||||
|
// Which tiers in this town have creature hordes. Set to -1 to disable horde(s)
|
||||||
|
"horde" : [ 2, -1 ],
|
||||||
|
|
||||||
|
// Resource given by starting bonus, if not set silo will produce wood + ore
|
||||||
|
"primaryResource" : "gems",
|
||||||
|
|
||||||
|
// maximum level of mage guild
|
||||||
|
"mageGuild" : 4,
|
||||||
|
|
||||||
|
// war machine produced in town
|
||||||
|
"warMachine" : "ballista"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Siege node
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
// Describes town siege screen
|
||||||
|
// Comments in the end of each graphic position indicate specify required suffix for image
|
||||||
|
// Note: one not included image is battlefield background with suffix "BACK"
|
||||||
|
{
|
||||||
|
// shooter creature name
|
||||||
|
"shooter" : "archer",
|
||||||
|
|
||||||
|
// (VCMI 1.1 or later) Large icon of towers, for use in battle queue
|
||||||
|
"towerIconLarge" : "",
|
||||||
|
|
||||||
|
// (VCMI 1.1 or later) Small icon of towers, for use in battle queue
|
||||||
|
"towerIconSmall" : "",
|
||||||
|
|
||||||
|
// prefix for all siege images. Final name will be composed as <prefix><suffix>
|
||||||
|
"imagePrefix" : "SGCS",
|
||||||
|
|
||||||
|
// Descriptions for towers. Each tower consist from 3 parts:
|
||||||
|
// tower itself - two images with untouched and destroyed towers
|
||||||
|
// battlement or creature cover - section displayed on top of creature
|
||||||
|
// creature using type from "shooter" field above
|
||||||
|
"towers":
|
||||||
|
{
|
||||||
|
// Top tower description
|
||||||
|
"top" :
|
||||||
|
{
|
||||||
|
"tower" : { "x": 0, "y": 0}, // "TW21" ... "TW22"
|
||||||
|
"battlement" : { "x": 0, "y": 0}, // "TW2C"
|
||||||
|
"creature" : { "x": 0, "y": 0}
|
||||||
|
},
|
||||||
|
// Central keep description
|
||||||
|
"keep" :
|
||||||
|
{
|
||||||
|
"tower" : { "x": 0, "y": 0}, // "MAN1" ... "MAN2"
|
||||||
|
"battlement" : { "x": 0, "y": 0}, // "MANC"
|
||||||
|
"creature" : { "x": 0, "y": 0}
|
||||||
|
},
|
||||||
|
// Bottom tower description
|
||||||
|
"bottom" :
|
||||||
|
{
|
||||||
|
"tower" : { "x": 0, "y": 0}, // "TW11" ... "TW12"
|
||||||
|
"battlement" : { "x": 0, "y": 0}, // "TW1C"
|
||||||
|
"creature" : { "x": 0, "y": 0}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
//Two parts of gate: gate itself and arch above it
|
||||||
|
"gate" :
|
||||||
|
{
|
||||||
|
"gate" : { "x": 0, "y": 0}, // "DRW1" ... "DRW3" and "DRWC" (rope)
|
||||||
|
"arch" : { "x": 0, "y": 0} // "ARCH"
|
||||||
|
},
|
||||||
|
// Destructible walls. In this example they are ordered from top to bottom
|
||||||
|
// Each of them consist from 3 files: undestroyed, damaged, destroyed
|
||||||
|
"walls" :
|
||||||
|
{
|
||||||
|
"upper" : { "x": 0, "y": 0}, // "WA61" ... "WA63"
|
||||||
|
"upperMid" : { "x": 0, "y": 0}, // "WA41" ... "WA43"
|
||||||
|
"bottomMid" : { "x": 0, "y": 0}, // "WA31" ... "WA33"
|
||||||
|
"bottom" : { "x": 0, "y": 0} // "WA11" ... "WA13"
|
||||||
|
},
|
||||||
|
// Two pieces for moat: moat itself and shore
|
||||||
|
"moat" : { "x": 0, "y": 0}, // moat: "MOAT", shore: "MLIP"
|
||||||
|
|
||||||
|
// Static non-destructible walls. All of them have only one piece
|
||||||
|
"static" :
|
||||||
|
{
|
||||||
|
// Section between two bottom destructible walls
|
||||||
|
"bottom" : { "x": 0, "y": 0}, // "WA2"
|
||||||
|
|
||||||
|
// Section between two top destructible walls
|
||||||
|
"top" : { "x": 0, "y": 0}, // "WA5"
|
||||||
|
|
||||||
|
// Topmost wall located behind hero
|
||||||
|
"background" : { "x": 0, "y": 0} // "TPWL"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Building node
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
{
|
||||||
|
"id" : 0,
|
||||||
|
"name" : "",
|
||||||
|
"description" : "",
|
||||||
|
"upgrades" : "baseBuilding", // optional, which building can be upgraded by this one
|
||||||
|
"requires" : [ "allOf", [ "mageGuild1" ], [ "tavern" ] ], // building requirements, H3-style. See below for full format.
|
||||||
|
"cost" : { ... }, //resources needed to buy building
|
||||||
|
"produce" : { ... }, //resources produced each day by building - since 0.95b
|
||||||
|
|
||||||
|
//determine how this building can be built. Possible values are:
|
||||||
|
// normal - default value. Fulfill requirements, use resources, spend one day
|
||||||
|
// auto - building appears when all requirements are built
|
||||||
|
// special - building can not be built manually
|
||||||
|
// grail - building reqires grail to be built
|
||||||
|
"mode" : "auto"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Building requirements can be described using logical expressions:
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
"requires" :
|
||||||
|
[
|
||||||
|
"allOf", // Normal H3 "build all" mode
|
||||||
|
[ "mageGuild1" ],
|
||||||
|
[
|
||||||
|
"noneOf", // available only when none of these building are built
|
||||||
|
[ "dwelling5A" ],
|
||||||
|
[ "dwelling5AUpgrade" ]
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"anyOf", // any non-zero number of these buildings must be built
|
||||||
|
[ "tavern" ],
|
||||||
|
[ "blacksmith" ]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Structure node
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
{
|
||||||
|
"animation" : "", // def file with animation
|
||||||
|
"x" : 0,
|
||||||
|
"y" : 0,
|
||||||
|
"z" : 0, // used for blit order. Higher value places structure close to screen
|
||||||
|
"border" : "", // selection highlight
|
||||||
|
"area" : "" // used to detect building selection
|
||||||
|
}
|
||||||
|
```
|
111
docs/modders/Entities_Format/Hero_Class_Format.md
Normal file
111
docs/modders/Entities_Format/Hero_Class_Format.md
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
< [Documentation](../../Readme.md) / [Modding](../Readme.md) / Entities Format / Hero Class Format
|
||||||
|
|
||||||
|
## Required data
|
||||||
|
|
||||||
|
In order to make functional hero class you also need:
|
||||||
|
|
||||||
|
- Adventure animation (1 def file)
|
||||||
|
- Battle animation, male and female version (2 def files)
|
||||||
|
|
||||||
|
## Format
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
// Unique identifier of hero class, camelCase
|
||||||
|
"myClassName" :
|
||||||
|
{
|
||||||
|
// Various hero animations
|
||||||
|
"animation"
|
||||||
|
{
|
||||||
|
"battle" :
|
||||||
|
{
|
||||||
|
// Battle animation for female heroes
|
||||||
|
"female" : "myMod/battle/heroFemale",
|
||||||
|
|
||||||
|
// Battle animation for male heroes, can be same as female
|
||||||
|
"male" : "myMod/battle/heroMale"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Description of map object representing this hero class. See map template format for details
|
||||||
|
"mapObject" : {
|
||||||
|
// Optional, hero ID-base filter, using same rules as building requirements
|
||||||
|
"filters" : {
|
||||||
|
"mutare" : [ "anyOf", [ "mutare" ], [ "mutareDrake" ]]
|
||||||
|
},
|
||||||
|
|
||||||
|
// List of templates used for this object, normally - only one is needed
|
||||||
|
"templates" : {
|
||||||
|
"normal" : { "animation" : "AH00_.def" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Translatable name of hero class
|
||||||
|
"name" : "My hero class",
|
||||||
|
|
||||||
|
// Identifier of faction this class belongs to
|
||||||
|
"faction" : "myFaction",
|
||||||
|
|
||||||
|
// Identifier of creature that should be used as commander for this hero class
|
||||||
|
// Can be a regular creature that has shooting animation
|
||||||
|
"commander" : "mage",
|
||||||
|
|
||||||
|
// Affinity of this class, might or magic
|
||||||
|
"affinity" : "might",
|
||||||
|
|
||||||
|
// Initial primary skills of heroes
|
||||||
|
"primarySkills" :
|
||||||
|
{
|
||||||
|
"attack" : 2,
|
||||||
|
"defence" : 0,
|
||||||
|
"spellpower" : 1,
|
||||||
|
"knowledge" : 2
|
||||||
|
},
|
||||||
|
|
||||||
|
// Chance to get specific primary skill on level-up
|
||||||
|
// This set specifies chances for levels 2-9
|
||||||
|
"lowLevelChance" :
|
||||||
|
{
|
||||||
|
"attack" : 15,
|
||||||
|
"defence" : 10,
|
||||||
|
"spellpower" : 50,
|
||||||
|
"knowledge" : 25
|
||||||
|
},
|
||||||
|
|
||||||
|
// Chance to get specific primary skill on level-up
|
||||||
|
// This set specifies chances for levels starting from 10
|
||||||
|
"highLevelChance" :
|
||||||
|
{
|
||||||
|
"attack" : 25,
|
||||||
|
"defence" : 5,
|
||||||
|
"spellpower" : 45,
|
||||||
|
"knowledge" : 25
|
||||||
|
},
|
||||||
|
|
||||||
|
// Chance to get specific secondary skill on level-up
|
||||||
|
// Skills not listed here will be considered as unavailable, including universities
|
||||||
|
"secondarySkills" :
|
||||||
|
{
|
||||||
|
"pathfinding" : 3.
|
||||||
|
"archery" : 6.
|
||||||
|
...
|
||||||
|
"resistance" : 5,
|
||||||
|
"firstAid" : 4
|
||||||
|
},
|
||||||
|
|
||||||
|
// Chance for a this hero class to appear in a town, creates pair with same field in town format
|
||||||
|
// Used for situations where chance was not set in "tavern" field, chance will be determined as:
|
||||||
|
// square root( town tavern chance * hero class tavern chance )
|
||||||
|
"defaultTavern" : 5,
|
||||||
|
|
||||||
|
// Chance for this hero to appear in tavern of this factions.
|
||||||
|
// Reversed version of field "tavern" from town format
|
||||||
|
// If faction-class pair is not listed in any of them
|
||||||
|
// chance set to 0 and the class won't appear in tavern of this town
|
||||||
|
"tavern" :
|
||||||
|
{
|
||||||
|
"castle" : 4,
|
||||||
|
...
|
||||||
|
"conflux" : 6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
128
docs/modders/Entities_Format/Hero_Type_Format.md
Normal file
128
docs/modders/Entities_Format/Hero_Type_Format.md
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
< [Documentation](../../Readme.md) / [Modding](../Readme.md) / Entities Format / Hero Type Format
|
||||||
|
|
||||||
|
## Required data
|
||||||
|
|
||||||
|
In order to make functional hero you also need:
|
||||||
|
|
||||||
|
- Portraits, small and big versions (2 images)
|
||||||
|
- Specialty icons, small and big versions (2 images)
|
||||||
|
|
||||||
|
## Format
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
"myHeroName" :
|
||||||
|
{
|
||||||
|
// Identifier of class. Usually camelCase version of human-readable name
|
||||||
|
"class" : "wizard",
|
||||||
|
|
||||||
|
// List of starting spells, if available. Will also grant spellbook
|
||||||
|
"spellbook" :
|
||||||
|
[
|
||||||
|
"magicArrow"
|
||||||
|
],
|
||||||
|
|
||||||
|
// Set to true if the hero is female by default (can be changed in map editor)
|
||||||
|
"female" : true,
|
||||||
|
|
||||||
|
// If set to true hero will be unavailable on start and won't appear in taverns (campaign heroes)
|
||||||
|
"special" : true,
|
||||||
|
|
||||||
|
// All translatable texts related to hero
|
||||||
|
"texts" :
|
||||||
|
{
|
||||||
|
"name" : "My Hero",
|
||||||
|
"biography" : "This is a long story...",
|
||||||
|
|
||||||
|
"specialty" :
|
||||||
|
{
|
||||||
|
// Description visible when hovering over specialty icon
|
||||||
|
"description" : "Spell mastery: Magic Arrow",
|
||||||
|
|
||||||
|
// Tooltip visible on clicking icon. Can use {} symbols to change title to yellow
|
||||||
|
// as well as escape sequences "\n" to add line breaks
|
||||||
|
"tooltip" : "{Magic Arrow}\n\nCasts powerfull magic arrows",
|
||||||
|
|
||||||
|
// Name of your specialty
|
||||||
|
"name" : "Magic Arrow"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// Graphics used by hero
|
||||||
|
"images" :
|
||||||
|
{
|
||||||
|
// Small 32px speciality icon
|
||||||
|
"specialtySmall" : "myMod/myHero/specSmall.png",
|
||||||
|
|
||||||
|
// Large 44px speciality icon
|
||||||
|
"specialtyLarge" : "myMod/myHero/specLarge.png",
|
||||||
|
|
||||||
|
// Large 58x64px portrait
|
||||||
|
"large" : "myMod/myHero/large.png",
|
||||||
|
|
||||||
|
// Small 48x32px portrait
|
||||||
|
"small" : "myMod/myHero/small.png"
|
||||||
|
|
||||||
|
// Class-independent animation in battle
|
||||||
|
"small" : "myMod/myHero/battle.def"
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
// Initial hero army when recruited in tavern
|
||||||
|
// Must have 1-3 elements
|
||||||
|
"army" :
|
||||||
|
[
|
||||||
|
// First always available stack
|
||||||
|
{
|
||||||
|
// Identifier of creature in this stack
|
||||||
|
"creature" : "mage",
|
||||||
|
|
||||||
|
// Minimal and maximum size of stack. Size will be
|
||||||
|
// determined randomly at the start of the game
|
||||||
|
"max" : 2,
|
||||||
|
"min" : 1
|
||||||
|
},
|
||||||
|
// Second stack has 90 % chance to appear
|
||||||
|
{
|
||||||
|
"creature" : "archmage",
|
||||||
|
"max" : 1,
|
||||||
|
"min" : 1
|
||||||
|
},
|
||||||
|
// Third stack with just 20 % chance to appear
|
||||||
|
{
|
||||||
|
"creature" : "mage",
|
||||||
|
"max" : 2,
|
||||||
|
"min" : 1
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
// List of skills received by hero
|
||||||
|
// Not limited by size - you can add as many skills as you wish
|
||||||
|
"skills" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
// Skill level, basic, advanced or expert
|
||||||
|
"level" : "basic",
|
||||||
|
|
||||||
|
// Skill identifier, camelCase version of name
|
||||||
|
"skill" : "wisdom"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"level" : "basic",
|
||||||
|
"skill" : "waterMagic"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
// Description of specialty mechanics using bonuses (with updaters)
|
||||||
|
"specialty" : {
|
||||||
|
// to be merged with all bonuses, use for specialties with multiple similar bonuses (optional)
|
||||||
|
"base" : {common bonus properties},
|
||||||
|
"bonuses" : {
|
||||||
|
// use updaters for bonuses that grow with level
|
||||||
|
"someBonus" : {Bonus Format},
|
||||||
|
"anotherOne" : {Bonus Format}
|
||||||
|
},
|
||||||
|
// adds creature specialty following the HMM3 default formula
|
||||||
|
"creature" : "griffin"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
3
docs/modders/Entities_Format/River_Format.md
Normal file
3
docs/modders/Entities_Format/River_Format.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
< [Documentation](../../Readme.md) / [Modding](../Readme.md) / Entities Format / River Format
|
||||||
|
|
||||||
|
TODO
|
3
docs/modders/Entities_Format/Road_Format.md
Normal file
3
docs/modders/Entities_Format/Road_Format.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
< [Documentation](../../Readme.md) / [Modding](../Readme.md) / Entities Format / Road Format
|
||||||
|
|
||||||
|
TODO
|
88
docs/modders/Entities_Format/Secondary_Skill_Format.md
Normal file
88
docs/modders/Entities_Format/Secondary_Skill_Format.md
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
< [Documentation](../../Readme.md) / [Modding](../Readme.md) / Entities Format / Secondary Skill Format
|
||||||
|
|
||||||
|
## Main format
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
{
|
||||||
|
"skillName":
|
||||||
|
{
|
||||||
|
//numeric id of skill required only for original skills, prohibited for new skills
|
||||||
|
"index": 0,
|
||||||
|
//Mandatory
|
||||||
|
"name": "Localizable name",
|
||||||
|
//optional base format, will be merged with basic/advanced/expert
|
||||||
|
"base": {Skill level base format},
|
||||||
|
//configuration for different skill levels
|
||||||
|
"basic": {Skill level format},
|
||||||
|
"advanced": {Skill level format},
|
||||||
|
"expert": {Skill level format}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Skill level base format
|
||||||
|
|
||||||
|
Json object with data common for all levels can be put here. These
|
||||||
|
configuration parameters will be default for all levels. All mandatory
|
||||||
|
level fields become optional if they equal "base" configuration.
|
||||||
|
|
||||||
|
## Skill level format
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
{
|
||||||
|
//Optional, localizable description
|
||||||
|
//Use {xxx} for formatting
|
||||||
|
"description": "",
|
||||||
|
//Bonuses provided by skill at given level
|
||||||
|
//If different levels provide same bonus with different val, only the highest applies
|
||||||
|
"effects":
|
||||||
|
{
|
||||||
|
"firstEffect": {bonus format},
|
||||||
|
"secondEffect": {bonus format}
|
||||||
|
//...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
The following modifies the tactics skill to grant an additional speed
|
||||||
|
boost at advanced and expert levels.
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
"core:tactics" : {
|
||||||
|
"base" : {
|
||||||
|
"effects" : {
|
||||||
|
"main" : {
|
||||||
|
"subtype" : "skill.tactics",
|
||||||
|
"type" : "SECONDARY_SKILL_PREMY",
|
||||||
|
"valueType" : "BASE_NUMBER"
|
||||||
|
},
|
||||||
|
"xtra" : {
|
||||||
|
"type" : "STACKS_SPEED",
|
||||||
|
"valueType" : "BASE_NUMBER"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"basic" : {
|
||||||
|
"effects" : {
|
||||||
|
"main" : { "val" : 3 },
|
||||||
|
"xtra" : { "val" : 0 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"advanced" : {
|
||||||
|
"description" : "{Advanced Tactics}\n\nAllows you to rearrange troups within 5 hex rows, and increases their speed by 1.",
|
||||||
|
"effects" : {
|
||||||
|
"main" : { "val" : 5 },
|
||||||
|
"xtra" : { "val" : 1 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"expert" : {
|
||||||
|
"description" : "{Expert Tactics}\n\nAllows you to rearrange troups within 7 hex rows, and increases their speed by 2.",
|
||||||
|
"effects" : {
|
||||||
|
"main" : { "val" : 7 },
|
||||||
|
"xtra" : { "val" : 2 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
383
docs/modders/Entities_Format/Spell_Format.md
Normal file
383
docs/modders/Entities_Format/Spell_Format.md
Normal file
@ -0,0 +1,383 @@
|
|||||||
|
< [Documentation](../../Readme.md) / [Modding](../Readme.md) / Entities Format / Spell Format
|
||||||
|
|
||||||
|
# Main format
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
{
|
||||||
|
"spellName":
|
||||||
|
{ //numeric id of spell required only for original spells, prohibited for new spells
|
||||||
|
"index": 0,
|
||||||
|
//Original Heroes 3 info
|
||||||
|
//Mandatory, spell type
|
||||||
|
"type": "adventure",//"adventure", "combat", "ability"
|
||||||
|
|
||||||
|
//Mandatory, spell target type
|
||||||
|
"targetType":"NO_TARGET",//"CREATURE","OBSTACLE"."LOCATION"
|
||||||
|
|
||||||
|
//Mandatory
|
||||||
|
"name": "Localizable name",
|
||||||
|
//Mandatory, flags structure of school names, Spell schools this spell belongs to
|
||||||
|
"school": {"air":true, "earth":true, "fire":true, "water":true},
|
||||||
|
//number, mandatory, Spell level, value in range 1-5
|
||||||
|
"level": 1,
|
||||||
|
//Mandatory, base power
|
||||||
|
"power": 10,
|
||||||
|
//Mandatory, default chance for this spell to appear in Mage Guilds
|
||||||
|
//Used only if chance for a faction is not set in gainChance field
|
||||||
|
"defaultGainChance": 0,
|
||||||
|
//Optional, chance for it to appear in Mage Guild of a specific faction
|
||||||
|
//NOTE: this field is linker with faction configuration
|
||||||
|
"gainChance":
|
||||||
|
{
|
||||||
|
"factionName": 3
|
||||||
|
},
|
||||||
|
//VCMI info
|
||||||
|
|
||||||
|
"animation":{<Animation format>},
|
||||||
|
|
||||||
|
//countering spells, flags structure of spell ids (spell. prefix is required)
|
||||||
|
"counters": {"spell.spellID1":true, ...}
|
||||||
|
|
||||||
|
//Mandatory,flags structure:
|
||||||
|
// indifferent, negative, positive - Positiveness of spell for target (required)
|
||||||
|
// damage - spell does damage (direct or indirect)
|
||||||
|
// offensive - direct damage (implicitly sets damage and negative)
|
||||||
|
// rising - rising spell (implicitly sets positive)
|
||||||
|
// summoning //todo:
|
||||||
|
// special - can be obtained only with bonus::SPELL
|
||||||
|
|
||||||
|
"flags" : {"flag1": true, "flag2": true},
|
||||||
|
|
||||||
|
//DEPRECATED | optional| no default | flags structure of bonus names,any one of these bonus grants immunity. Negatable by the Orb.
|
||||||
|
"immunity": {"BONUS_NAME":true, ...},
|
||||||
|
|
||||||
|
//DEPRECATED | optional| no default | flags structure of bonus names
|
||||||
|
//any one of these bonus grants immunity, cant be negated
|
||||||
|
"absoluteImmunity": {"BONUS_NAME": true, ...},
|
||||||
|
|
||||||
|
//DEPRECATED | optional| no default | flags structure of bonus names, presence of all bonuses required to be affected by. Negatable by the Orb.
|
||||||
|
"limit": {"BONUS_NAME": true, ...},
|
||||||
|
|
||||||
|
//DEPRECATED | optional| no default | flags structure of bonus names, presence of all bonuses required to be affected by. Cant be negated
|
||||||
|
"absoluteLimit": {"BONUS_NAME": true, ...},
|
||||||
|
|
||||||
|
//[WIP] optional | default no limit no immunity
|
||||||
|
//
|
||||||
|
"targetCondition" {
|
||||||
|
//at least one required to be affected
|
||||||
|
"anyOf" : {
|
||||||
|
//generic format
|
||||||
|
"mod:metaClassName.typeName":"absolute",//"normal", null or empty ignored - use for overrides
|
||||||
|
},
|
||||||
|
//all required to be affected (like [absolute]limit)
|
||||||
|
"allOf" : {
|
||||||
|
//bonus type format
|
||||||
|
"bonus.BONUS_TYPE":"absolute"//"normal" Short bonus type format
|
||||||
|
"modId:bonus.bonusTypeName":"absolute"//"normal" Future bonus format for configurable bonuses
|
||||||
|
},
|
||||||
|
//at least one grants immunity (like [absolute]immunity)
|
||||||
|
"noneOf": {
|
||||||
|
//some more examples
|
||||||
|
"core:creature.imp":"absolute", //[to be in initial version] this creature explicitly absolutely immune
|
||||||
|
"core:bonus.MIND_IMMUITY":"normal", // [to be in initial version] new format of existing mind spell immunity
|
||||||
|
"core:artifact.armorOfWonder":"absolute", //[possible future extension] this artifact on target itself (!) explicitly grant absolute immune
|
||||||
|
"core:luck":["absolute", 3], // [possible future extension] lack value of at least 3 grant absolute immunity from this horrible spell
|
||||||
|
"core:custom":[<script>] // [possible future extension] script lines for arbitrary condition
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//graphics; mandatory; object;
|
||||||
|
"graphics":
|
||||||
|
{
|
||||||
|
// ! will be moved to bonus type config in next bonus config version
|
||||||
|
// iconImmune - OPTIONAL; string;
|
||||||
|
//resource path of icon for SPELL_IMMUNITY bonus (relative to DATA or SPRITES)
|
||||||
|
"iconImmune":"ZVS/LIB1.RES/E_SPMET",
|
||||||
|
|
||||||
|
|
||||||
|
// iconScenarioBonus- mandatory, string, image resource path
|
||||||
|
//resource path of icon for scenario bonus
|
||||||
|
"iconScenarioBonus": "MYSPELL_B",
|
||||||
|
|
||||||
|
// iconEffect- mandatory, string, image resource path
|
||||||
|
//resource path of icon for spell effects during battle
|
||||||
|
"iconEffect": "MYSPELL_E",
|
||||||
|
|
||||||
|
// iconBook- mandatory, string, image resource path
|
||||||
|
//resource path of icon for spellbook
|
||||||
|
"iconBook": "MYSPELL_E",
|
||||||
|
|
||||||
|
// iconScroll- mandatory, string, image resource path
|
||||||
|
//resource path of icon for spell scrolls
|
||||||
|
"iconScroll": "MYSPELL_E"
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
//OPTIONAL; object; TODO
|
||||||
|
"sounds":
|
||||||
|
{
|
||||||
|
//OPTIONAL; resourse path, casting sound
|
||||||
|
"cast":"LIGHTBLT"
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
//Mandatory structure
|
||||||
|
//configuration for no skill, basic, adv, expert
|
||||||
|
"levels":{
|
||||||
|
"base": {Spell level base format},
|
||||||
|
"none": {Spell level format},
|
||||||
|
"basic":{Spell level format},
|
||||||
|
"advanced":{Spell level format},
|
||||||
|
"expert":{Spell level format}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# Animation format
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
|
||||||
|
{
|
||||||
|
"projectile": [
|
||||||
|
{"minimumAngle": 0 ,"defName":"C20SPX4"},
|
||||||
|
{"minimumAngle": 0.60 ,"defName":"C20SPX3"},
|
||||||
|
{"minimumAngle": 0.90 ,"defName":"C20SPX2"},
|
||||||
|
{"minimumAngle": 1.20 ,"defName":"C20SPX1"},
|
||||||
|
{"minimumAngle": 1.50 ,"defName":"C20SPX0"}
|
||||||
|
],
|
||||||
|
"hit":["C20SPX"],
|
||||||
|
"affect":[{"defName":"C03SPA0", "verticalPosition":"bottom"}, "C11SPA1"]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# Spell level base format
|
||||||
|
|
||||||
|
Json object with data common for all levels can be put here. These configuration parameters will be default for all levels. All mandatory level fields become optional if they equal "base" configuration.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
This will make spell affect single target on all levels except expert, where it is massive spell.
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
|
||||||
|
"base":{
|
||||||
|
|
||||||
|
"range": 0
|
||||||
|
},
|
||||||
|
"expert":{
|
||||||
|
"range": "X"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# Spell level format
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
|
||||||
|
{
|
||||||
|
//Mandatory, localizable description
|
||||||
|
//Use {xxx} for formatting
|
||||||
|
"description": "",
|
||||||
|
|
||||||
|
|
||||||
|
//Mandatory, number,
|
||||||
|
//cost in mana points
|
||||||
|
"cost": 1,
|
||||||
|
|
||||||
|
//Mandatory, number
|
||||||
|
"power": 10,
|
||||||
|
|
||||||
|
//Mandatory, number
|
||||||
|
"aiValue": 20,
|
||||||
|
|
||||||
|
//Mandatory, flags structure //TODO
|
||||||
|
// modifiers make sense for creature target
|
||||||
|
//
|
||||||
|
//
|
||||||
|
"targetModifier":
|
||||||
|
{
|
||||||
|
"smart": false, //true: friendly/hostile based on positiveness; false: all targets
|
||||||
|
"clearTarget": false,
|
||||||
|
"clearAffected": false,
|
||||||
|
}
|
||||||
|
//Mandatory
|
||||||
|
//spell range description in SRSL
|
||||||
|
// range "X" + smart modifier = enchanter casting, expert massive spells
|
||||||
|
// range "X" + no smart modifier = armageddon, death ripple, destroy undead
|
||||||
|
|
||||||
|
"range": "X",
|
||||||
|
|
||||||
|
//DEPRECATED, Optional, arbitrary name - bonus format map
|
||||||
|
//timed effects, overriding by name
|
||||||
|
"effects":
|
||||||
|
{
|
||||||
|
"firstEffect": {[bonus format]},
|
||||||
|
"secondEffect": {[bonus format]}
|
||||||
|
//...
|
||||||
|
|
||||||
|
|
||||||
|
},
|
||||||
|
//DEPRECATED, cumulative effects that stack while active
|
||||||
|
"cumulativeEffects":
|
||||||
|
{
|
||||||
|
"firstCumulativeEffect": {[bonus format]}
|
||||||
|
//...
|
||||||
|
|
||||||
|
},
|
||||||
|
"battleEffects":
|
||||||
|
{
|
||||||
|
"mod:firstEffect": {[effect format]},
|
||||||
|
"mod:secondEffect": {[effect format]}
|
||||||
|
//...
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# Configurable battle effects
|
||||||
|
|
||||||
|
**If spell have at least one special effect it become configurable spell and spell configuration processed different way**
|
||||||
|
|
||||||
|
## Configurable spell
|
||||||
|
|
||||||
|
Configurable spells ignore *offensive* flag, *effects* and *cumulativeEffects*. For backward compatibility *offensive* flag define Damage effect, *effects* and *cumulativeEffects* define Timed effect.
|
||||||
|
|
||||||
|
## Special effect common format
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
|
||||||
|
"mod:effectId":{
|
||||||
|
|
||||||
|
"type":"mod:effectType", //identifier of effect type
|
||||||
|
"indirect": false, // effect will be deferred (f.e. land mine damage)
|
||||||
|
"optional": false // you can cast spell even if this effect in not applicable
|
||||||
|
|
||||||
|
//for unit target effects
|
||||||
|
"ignoreImmunity" : false,
|
||||||
|
"chainFactor" : 0.5,
|
||||||
|
"chainLength" : 4
|
||||||
|
|
||||||
|
//other fields depending on type
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## catapult
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
|
||||||
|
"mod:effectId":{
|
||||||
|
|
||||||
|
"type": "core:catapult"
|
||||||
|
"targetsToAttack": 1, //How many targets will be attacked by this
|
||||||
|
"chanceToHitKeep" : 5, //If it is a targeted spell, chances to hit keep
|
||||||
|
"chanceToHitGate" : 25, //If it is a targeted spell, chances to hit gate
|
||||||
|
"chanceToHitTower" : 10, //If it is a targeted spell, chances to hit tower
|
||||||
|
"chanceToHitWall" : 50, //If it is a targeted spell, chances to hit wall
|
||||||
|
"chanceToNormalHit" : 60, //Chance to have 1 damage to wall, used for both targeted and massive
|
||||||
|
"chanceToCrit" : 30 //Chance to have 2 damage to wall, used for both targeted and massive
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Clone
|
||||||
|
|
||||||
|
Configurable version of Clone spell.
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
|
||||||
|
"mod:effectId":{
|
||||||
|
|
||||||
|
"type": "core:clone"
|
||||||
|
|
||||||
|
"maxTier" : 3//unit tier
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Damage effect
|
||||||
|
|
||||||
|
If effect is automatic, spell behave like offensive spell (uses power, levelPower etc)
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
|
||||||
|
"mod:effectId":{
|
||||||
|
|
||||||
|
"type": "core:damage",
|
||||||
|
"killByCount": false, //if true works like Death Stare
|
||||||
|
"killByPercentage" : false, //if true works like DESTRUCTION ability
|
||||||
|
|
||||||
|
//TODO: options override
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Dispel
|
||||||
|
|
||||||
|
documetation
|
||||||
|
|
||||||
|
## Heal
|
||||||
|
|
||||||
|
documetation
|
||||||
|
|
||||||
|
## Obstacle
|
||||||
|
|
||||||
|
documetation
|
||||||
|
|
||||||
|
## Remove obstacle
|
||||||
|
|
||||||
|
documetation
|
||||||
|
|
||||||
|
## Sacrifice
|
||||||
|
|
||||||
|
documetation
|
||||||
|
|
||||||
|
## Summon
|
||||||
|
|
||||||
|
documetation
|
||||||
|
|
||||||
|
## Teleport
|
||||||
|
|
||||||
|
documetation
|
||||||
|
|
||||||
|
## Timed
|
||||||
|
|
||||||
|
If effect is automatic, spell behave like \[de\]buff spell (effect and
|
||||||
|
cumulativeEffects ignored)
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
|
||||||
|
"mod:effectId":{
|
||||||
|
|
||||||
|
"type": "core:timed",
|
||||||
|
"cumulative": false
|
||||||
|
"bonus":
|
||||||
|
{
|
||||||
|
"firstBonus":{[bonus format]}
|
||||||
|
//...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# Additional documentation
|
||||||
|
|
||||||
|
## Targets, ranges, modifiers
|
||||||
|
|
||||||
|
- CREATURE target (only battle spells)
|
||||||
|
- range 0: smart assumed single creature target
|
||||||
|
- range "X" + smart modifier = enchanter casting, expert massive spells
|
||||||
|
- range "X" + no smart modifier = armageddon, death ripple, destroy undead
|
||||||
|
- any other range (including chain effect)
|
||||||
|
- smart modifier: smth like cloud of confusion in H4 (if I remember correctly :) )
|
||||||
|
- no smart modifier: like inferno, fireball etc. but target only creature
|
||||||
|
|
||||||
|
- NO_TARGET
|
||||||
|
- no target selection,(abilities, most adventure spells)
|
||||||
|
|
||||||
|
- LOCATION
|
||||||
|
- any tile on map/battlefield (inferno, fireball etc.), DD also here but with special handling
|
||||||
|
- clearTarget - destination hex must be clear (unused so far)
|
||||||
|
- clearAfffected - all affected hexes must be clear (forceField, fireWall)
|
||||||
|
|
||||||
|
- OBSTACLE target
|
||||||
|
- range 0: any single obstacle
|
||||||
|
- range X: all obstacles
|
3
docs/modders/Entities_Format/Terrain_Format.md
Normal file
3
docs/modders/Entities_Format/Terrain_Format.md
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
< [Documentation](../../Readme.md) / [Modding](../Readme.md) / Entities Format / Terrain Format
|
||||||
|
|
||||||
|
TODO
|
236
docs/modders/Map_Editor.md
Normal file
236
docs/modders/Map_Editor.md
Normal file
@ -0,0 +1,236 @@
|
|||||||
|
< [Documentation](../Readme.md) / [Modding](Readme.md) / Map Editor
|
||||||
|
|
||||||
|
# Interface
|
||||||
|
|
||||||
|
<img width="738" src="https://user-images.githubusercontent.com/9308612/188775648-8551107d-9f0b-4743-8980-56c2c1c58bbc.png">
|
||||||
|
|
||||||
|
# Create the map
|
||||||
|
|
||||||
|
<img width="145" src="https://user-images.githubusercontent.com/9308612/188782248-b7895eb1-86a9-4f06-9309-43c6b3a3a728.png">
|
||||||
|
|
||||||
|
## New map
|
||||||
|
|
||||||
|
Create the new map by pressing **New** button from the toolbar
|
||||||
|
|
||||||
|
### Empty map
|
||||||
|
|
||||||
|
To create empty map, define its size by choosing option from drop-down list or enter required size manually in the text fields and press Ok button. Check **Two level map** option to create map with underground.
|
||||||
|
`Note: there are no limits on map size but be careful with sizes larger predefined XL size. It will be processed quite long to create even empty map. Also, it will be difficult to work with the huge maps because of possible performance issues`
|
||||||
|
|
||||||
|
Other parameters won't be used for empty map.
|
||||||
|
|
||||||
|
<img width="413" src="https://user-images.githubusercontent.com/9308612/188782588-c9f1a164-df1e-46bc-a6d3-24ff1e5396c2.png">
|
||||||
|
|
||||||
|
### Random map
|
||||||
|
|
||||||
|
To generate random map, check the **Random map** option and configure map parameters. You can select template from the drop-down list.
|
||||||
|
|
||||||
|
<img width="439" src="https://user-images.githubusercontent.com/9308612/188783256-7e498238-14a0-4377-8c09-d702d54ee7d9.png">
|
||||||
|
|
||||||
|
Templates are dynamically filtered depending on parameters you choose.
|
||||||
|
|
||||||
|
* [Default] template means that template will be randomly chosen
|
||||||
|
* If you see empty list it means that there are no templates fit your settings. It could be related to the settings chosen or it can mean that there are no templates install.
|
||||||
|
|
||||||
|
<img width="412" src="https://user-images.githubusercontent.com/9308612/188783360-1c042782-328d-4692-952f-58fa5110d0d0.png">
|
||||||
|
|
||||||
|
## Map load & save
|
||||||
|
|
||||||
|
To load the map, press open and select map file from the browser.
|
||||||
|
|
||||||
|
You can load both *.h3m and *.vmap formats but for saving *.vmap is allowed only.
|
||||||
|
|
||||||
|
# Views
|
||||||
|
|
||||||
|
There are 3 buttons switching views <img width="131" alt="Снимок экрана 2022-09-07 в 06 48 08" src="https://user-images.githubusercontent.com/9308612/188777527-b7106146-0d8c-4f14-b78d-f13512bc7bad.png">
|
||||||
|
|
||||||
|
### Ground/underground
|
||||||
|
|
||||||
|
**"U/G"** switches you between ground and underground
|
||||||
|
|
||||||
|
### Grid view
|
||||||
|
|
||||||
|
**Grid** show/hide grid
|
||||||
|
|
||||||
|
<img width="153" src="https://user-images.githubusercontent.com/9308612/188777723-934d693b-247d-42a6-815c-aecd0d34f653.png">
|
||||||
|
|
||||||
|
### Passability view
|
||||||
|
|
||||||
|
**Pass** show/hide passability map
|
||||||
|
|
||||||
|
<img width="190" src="https://user-images.githubusercontent.com/9308612/188778010-a1d45d59-7333-4432-b83f-57190fbe09f4.png">
|
||||||
|
|
||||||
|
# Setup terrain
|
||||||
|
|
||||||
|
1. Select brush you want
|
||||||
|
<img width="124" src="https://user-images.githubusercontent.com/9308612/188776299-fd688696-a98d-4f89-8bef-e81c90d3724b.png">
|
||||||
|
|
||||||
|
2. Select area you'd like to change
|
||||||
|
|
||||||
|
`Note: left mouse button selects tiles, right button removes selection`
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
3. Press terrain you want
|
||||||
|
|
||||||
|
<img width="116" src="https://user-images.githubusercontent.com/9308612/188777176-1167561a-f23c-400a-a57b-be7fc90accae.png">
|
||||||
|
|
||||||
|
### Drawing roads and rivers
|
||||||
|
|
||||||
|
Actually, the process to draw rivers or roads is exactly the same as for terrains. You need to select tiles and then choose road/river type from the panel.
|
||||||
|
|
||||||
|
<img width="232" src="https://user-images.githubusercontent.com/9308612/189968965-7adbd76c-9ffc-46e5-aeb7-9a79214cc506.png">
|
||||||
|
|
||||||
|
To erase roads or rivers, you need to select tiles to be cleaned and press empty button.
|
||||||
|
|
||||||
|
<img width="130" src="https://user-images.githubusercontent.com/9308612/189969309-87ff7818-2915-4b38-b9db-ec4a616d18e7.png">
|
||||||
|
|
||||||
|
_Erasing works either for roads or for rivers, e.g. empty button from the roads tab erases roads only, but not rivers. You also can safely select bigger area, because it won't erase anything on tiles without roads/rivers accordingly_
|
||||||
|
|
||||||
|
## About brushes
|
||||||
|
* Buttons "1", "2", "4" - 1x1, 2x2, 4x4 brush sizes accordingly
|
||||||
|
* Button "[]" - non-additive rectangle selection
|
||||||
|
* Button "O" - lasso brush (not implemented yet)
|
||||||
|
* Button "E" - object erase, not a brush
|
||||||
|
|
||||||
|
## Fill obstacles
|
||||||
|
|
||||||
|
Map editor supports automatic obstacle placement.
|
||||||
|
Obstacle types are automatically selected for appropriate terrain types
|
||||||
|
|
||||||
|
To do that, select area (see Setup terrains) and press **Fill** button from the toolbar
|
||||||
|
<img width="222" src="https://user-images.githubusercontent.com/9308612/188778572-f80b3706-1713-40c7-a5aa-e4c3b9fc6649.png">
|
||||||
|
|
||||||
|
<img width="335" src="https://user-images.githubusercontent.com/9308612/188778694-507009a1-4bb0-4f37-afc7-4aa26a6f3eeb.png">
|
||||||
|
|
||||||
|
<img width="350" src="https://user-images.githubusercontent.com/9308612/188778728-f66adcbe-9cf2-41f2-8947-f60b38901317.png">
|
||||||
|
|
||||||
|
`Note: obstacle placer may occupy few neighbour tiles outside of selected area`
|
||||||
|
|
||||||
|
# Manipulating objects
|
||||||
|
|
||||||
|
## Adding new objects
|
||||||
|
|
||||||
|
1. Find the object you'd like to place in the object browser
|
||||||
|
|
||||||
|
<img width="188" src="https://user-images.githubusercontent.com/9308612/188779107-dc2ab212-9ed2-48ee-ba0d-7856b94a87b1.png">
|
||||||
|
|
||||||
|
2. You can also see selected object in preview area in the left part of application window
|
||||||
|
|
||||||
|
<img width="130" src="https://user-images.githubusercontent.com/9308612/188779263-a78577f7-8278-4927-a44e-18a7d85e2f64.png">
|
||||||
|
|
||||||
|
3. Hold mouse at object you want to place and move it to the map. You will see transparent object. Release object at point to confirm its creation
|
||||||
|
|
||||||
|
<img width="181" src="https://user-images.githubusercontent.com/9308612/188779350-653bad29-c54f-471b-93aa-90096da6d98c.png">
|
||||||
|
|
||||||
|
4. Press somewhere on the map to locate object.
|
||||||
|
|
||||||
|
**Right click over the scene - cancel object placement**
|
||||||
|
|
||||||
|
## Removing objects
|
||||||
|
|
||||||
|
1. **Make sure that no one terrain brush is selected.** To de-select brush click on selected brush again.
|
||||||
|
|
||||||
|
2. Select object you'd like to remove by simple clicking on it. You can also select multiple objects by moving mouse while left button is pressed
|
||||||
|
<img width="170" src="https://user-images.githubusercontent.com/9308612/188780096-6aefcad5-e092-44c6-8647-975e95f9a8a3.png">
|
||||||
|
|
||||||
|
3. Press **"E"** button from the brush panel or press **delete** on keyboard
|
||||||
|
|
||||||
|
## Changing object's properties
|
||||||
|
|
||||||
|
1. **Make sure that no one terrain brush is selected.** To de-select brush click on selected brush again.
|
||||||
|
|
||||||
|
2. Select object you'd like to remove by simple clicking on it. **You cannot review and modify properties for several objects, multiple selection is not supported.**
|
||||||
|
|
||||||
|
3. Go to the **inspector** tab. You will see object's properties
|
||||||
|
|
||||||
|
<img width="197" src="https://user-images.githubusercontent.com/9308612/188780504-40713019-3cdd-4077-9e2f-e3417c960efe.png">
|
||||||
|
|
||||||
|
4. You are able to modify properties which are not gray
|
||||||
|
`Note: sometimes there are empty editable fields`
|
||||||
|
|
||||||
|
### Assigning player to the object
|
||||||
|
|
||||||
|
Objects with flags can be assigned to the player. Find Owner property in the inspector for selected object, press twice to modify right cell. Type player number from **0 to 7 or type NEUTRAL** for neutral objects.
|
||||||
|
|
||||||
|
# Set up the map
|
||||||
|
|
||||||
|
You can modify general properties of the map
|
||||||
|
|
||||||
|
## Map name and description
|
||||||
|
|
||||||
|
1. Open **Map** menu on the top and select **General**
|
||||||
|
|
||||||
|
<img width="145" src="https://user-images.githubusercontent.com/9308612/188780943-70578b79-001b-45a2-bdfd-94577db40a6b.png">
|
||||||
|
|
||||||
|
2. You will see a new window with text fields to edit map name and description
|
||||||
|
|
||||||
|
3. Pressing **Ok** will save the changes, closing the window will discard the changes
|
||||||
|
|
||||||
|
<img width="307" src="https://user-images.githubusercontent.com/9308612/188781063-50ce65f8-aab4-43c3-a308-22acafa7d0a2.png">
|
||||||
|
|
||||||
|
# Player settings
|
||||||
|
|
||||||
|
Open **Map** menu on the top and select **Player settings"
|
||||||
|
|
||||||
|
<img width="141" src="https://user-images.githubusercontent.com/9308612/188781357-4a6091cf-f175-4649-a000-620f306d2c46.png">
|
||||||
|
|
||||||
|
You will see a window with player settings. Combobox players defines amount of players on the map. To review settings for particular player scroll the internal window. There are bunch on settings for each player you can change.
|
||||||
|
|
||||||
|
`Important: at least one player must be controlled as Human/CPU. Maps without human players won't be started in the game at most cases`
|
||||||
|
|
||||||
|
<img width="641" src="https://user-images.githubusercontent.com/9308612/188781400-7d5ba463-4f82-4dba-83ff-56210995e2c7.png">
|
||||||
|
|
||||||
|
# Compatibility questions
|
||||||
|
|
||||||
|
## Platform compatibility
|
||||||
|
|
||||||
|
vcmieditor is a cross-platform application, so in general can support all platforms, supported by VCMI.
|
||||||
|
|
||||||
|
However, currently it doesn't support mobile platforms.
|
||||||
|
|
||||||
|
## Engine compatibility
|
||||||
|
|
||||||
|
vcmieditor is independent application so potentially it can be installed just in the folder with existing stable vcmi. However, on the initial stages of development compatibility was not preserved because major changes were needed to introduce into vcmi library. So it's recommended to download full package to use editor.
|
||||||
|
|
||||||
|
## Map compatibility
|
||||||
|
|
||||||
|
vcmieditor haven't introduced any change into map format yet, so all maps made by vcmieditor can be easily played with any version of vcmi. At the same time, those maps can be open and read in the old map editor and vice verse - maps from old editor can be imported in the new editor. So, full compatibility is ensured here.
|
||||||
|
|
||||||
|
## Mod compatibilty
|
||||||
|
|
||||||
|
vcmieditor loads set of mods using exactly same mechanism as game uses and mod manipulations can be done using vcmilaucnher application, just enable or disable mods you want and open editor to use content from those mods. In regards on compatibility, of course you need to play maps with same set of mods as you used in the editor. Good part is that is maps don't use content from the mods (even mods were enabled), it can be played on vcmi without mods as well
|
||||||
|
|
||||||
|
# Working With Mods
|
||||||
|
|
||||||
|
## Enabling and disabling mods
|
||||||
|
|
||||||
|
The mods mechanism used in map editor is the same as in game.
|
||||||
|
|
||||||
|
To enable or disable mods
|
||||||
|
* Start launcher, activate or deactivate mods you want
|
||||||
|
* Close launcher
|
||||||
|
* Run map editor
|
||||||
|
|
||||||
|
There is no button to start map editor directly from launcher, however you may use this approach to control active mods from any version of vcmi.
|
||||||
|
|
||||||
|
## Placing objects from mods
|
||||||
|
|
||||||
|
* All objects from mods will be automatically added into objects Browser. You can type mod name into filter field to find them.
|
||||||
|
|
||||||
|
<img width="269" src="https://user-images.githubusercontent.com/9308612/189965141-62ee0d2c-2c3e-483c-98fe-63517ed51912.png">
|
||||||
|
|
||||||
|
* Objects from mods related to new terrains (if mod adds any) should not be filtered this way, instead choose terrain from terrains filter on the top of objects browser
|
||||||
|
|
||||||
|
<img width="271" src="https://user-images.githubusercontent.com/9308612/189965836-de1fd196-2f6d-4996-a62a-e2fcb52b8d74.png">
|
||||||
|
|
||||||
|
## Playing maps with mods
|
||||||
|
|
||||||
|
If you place any kind of objects from the mods, obviously, you need those mods to be installed to play the map.
|
||||||
|
Also, you need to activate them.
|
||||||
|
|
||||||
|
You also may have other mods being activated in addition to what was used during map designing.
|
||||||
|
|
||||||
|
### Mod versions
|
||||||
|
|
||||||
|
In the future, the will be support of mods versioning so map will contain information about mods used and game can automatically search and activate required mods or let user know which are required. However, it's not implemented yet
|
158
docs/modders/Map_Object_Format.md
Normal file
158
docs/modders/Map_Object_Format.md
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
< [Documentation](../Readme.md) / [Modding](Readme.md) / Map Object Format
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
Full object consists from 3 parts:
|
||||||
|
|
||||||
|
- Object group - set of objects that have similar behavior and share
|
||||||
|
same identifier in H3 (towns, heroes, mines, etc)
|
||||||
|
- Object type - object with fixed behavior but without fixed
|
||||||
|
appearance. Multiple objects types may share same group
|
||||||
|
- Object template - defines appearance of an object - image used to
|
||||||
|
display it, its size & blockmap. These entries only describe
|
||||||
|
templates that will be used when object is placed via map editor or
|
||||||
|
generated by the game. When new object is created its starting
|
||||||
|
appearance will be copied from template
|
||||||
|
|
||||||
|
### Object types
|
||||||
|
|
||||||
|
- [Rewardable](Map_Objects/Rewardable.md) - Visitable object which grants all kinds of rewards (gold, experience, Bonuses etc...)
|
||||||
|
- [Creature Bank](Map_Objects/Creature_Bank.md) - Object that grants award on defeating guardians
|
||||||
|
- [Dwelling](Map_Objects/Dwelling.md) - Object that allows recruitments of units outside of towns
|
||||||
|
- [Market](Map_Objects/Market.md) - Trading resources, artifacts, creatures and such
|
||||||
|
- [Boat](Map_Objects/Boat.md) - Object to move across different terrains, such as water
|
||||||
|
|
||||||
|
## Object group format
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
|
||||||
|
{
|
||||||
|
"myCoolObjectGroup":
|
||||||
|
{
|
||||||
|
//numeric ID, mandatory for h3/wog objects, shall be unique if not defined
|
||||||
|
//used only for H3 objects, mods can not be used by mods
|
||||||
|
"index":123,
|
||||||
|
|
||||||
|
//Mandatory for new objects,
|
||||||
|
// human readable name, localized
|
||||||
|
//default for original objects from "OBJNAMES.TXT"
|
||||||
|
"name": "My cool object",
|
||||||
|
|
||||||
|
//defines C++/script class name that handles behavior of this object
|
||||||
|
"handler" : "mine",
|
||||||
|
|
||||||
|
// default values, will be merged with each type during loading
|
||||||
|
"base" : { <object type format> },
|
||||||
|
|
||||||
|
"types" : {
|
||||||
|
<list of object types, see below>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Object type format
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
|
||||||
|
{
|
||||||
|
"myCoolObject":
|
||||||
|
{
|
||||||
|
//numeric sub ID, mandatory for h3/wog objects, shall be unique if set
|
||||||
|
//used only for H3 objects, can not be used by mods
|
||||||
|
"index":123,
|
||||||
|
|
||||||
|
// parameters that will be passed over to class that controls behavior of the object
|
||||||
|
"producedResources" : "gold",
|
||||||
|
"producedValue" : 1000
|
||||||
|
|
||||||
|
// TODO: allow better selection of template for object, instead of just terrain
|
||||||
|
// field describes how object template will be selected if there are multiple possiblities
|
||||||
|
// exact behavior and format depends on object type
|
||||||
|
"filter" : { ... },
|
||||||
|
|
||||||
|
// Data for random map generator that describes how object should be placed.
|
||||||
|
// If this entry is missing object will not be placed by RMG
|
||||||
|
"rmg" : {
|
||||||
|
// How valuable this object is, 1k = worthless, 20k = relic level
|
||||||
|
"value" : 5000,
|
||||||
|
|
||||||
|
// Optional, how many of such objects can be placed on map
|
||||||
|
"mapLimit" : 25,
|
||||||
|
|
||||||
|
// Optional, how many of such objects can be placed in one zone
|
||||||
|
"zoneLimit" : 4,
|
||||||
|
|
||||||
|
// Rarity of object, 10 = rare, 100 = common
|
||||||
|
"rarity" : 50
|
||||||
|
}
|
||||||
|
|
||||||
|
// default values, will be merged with each template during loading
|
||||||
|
// mostly needed to avoid redefining whole template to change 1-2 fields
|
||||||
|
"base" : { <template format> },
|
||||||
|
|
||||||
|
"templates" : {
|
||||||
|
<templates description, see below>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Object template format
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
{
|
||||||
|
"myCoolObjectTemplate" :
|
||||||
|
{
|
||||||
|
// resource ID of animation, relative to SPRITES directory (def file or json file)
|
||||||
|
"animation":"DEFNAME.def",
|
||||||
|
|
||||||
|
// resource ID of animation for mapeditor, relative to SPRITES directory (def file or json file)
|
||||||
|
//0.98c+
|
||||||
|
"editorAnimation":"DEFNAME.def",
|
||||||
|
|
||||||
|
// directions from which hero can visit this object.
|
||||||
|
// "+" means that object can be visited from that direction, or "-" othervice
|
||||||
|
// default not visitable
|
||||||
|
"visitableFrom" : [
|
||||||
|
"---",
|
||||||
|
"+++",
|
||||||
|
"+++"
|
||||||
|
],
|
||||||
|
|
||||||
|
// passability of the object
|
||||||
|
// 0=not visible, passable. Space symbol ' ' can be used as well
|
||||||
|
// V=visible, passable
|
||||||
|
// B=blocked, visible
|
||||||
|
// H=hidden - blocked, not visible tile
|
||||||
|
// A=activable, visible, passable depending on visitableFrom field
|
||||||
|
// T=trigger - visiting the tile will trigger the object, tile is not visible (e.g. event)
|
||||||
|
//top and left leading zeros are optional and in fact ignored
|
||||||
|
//bottom, right corner of mask = bottom right corner of animation frame
|
||||||
|
//animation can not be larger than size of mask
|
||||||
|
"mask":[
|
||||||
|
"00000000",
|
||||||
|
"00000000",
|
||||||
|
"00000000",
|
||||||
|
"0000VVVV",
|
||||||
|
"0000HBBB",
|
||||||
|
"0000HHAT"
|
||||||
|
],
|
||||||
|
|
||||||
|
// optional; default or if explicitly set to null: all terrains except rock
|
||||||
|
// allowed terrain types to place object too. Affects also RMG.
|
||||||
|
// Note that map editor will still allow to place object on other terrains
|
||||||
|
// allowed terrain types: "dirt", "sand", "grass", "snow", "swamp", "rough", "subterra", "lava", "water", "rock"
|
||||||
|
"allowedTerrains":["dirt", "sand"],
|
||||||
|
|
||||||
|
// TODO, default - empty
|
||||||
|
// tags from object type are always present (???)
|
||||||
|
// List of tags that can be used to locate object in map editor
|
||||||
|
"tags":["dirt", "sand", "mine"],
|
||||||
|
|
||||||
|
//zindex, defines order in which objects on same tile will be blit. optional, default is 0
|
||||||
|
//NOTE: legacy overlay objects has zindex = 100
|
||||||
|
"zIndex": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
1
docs/modders/Map_Objects/Boat.md
Normal file
1
docs/modders/Map_Objects/Boat.md
Normal file
@ -0,0 +1 @@
|
|||||||
|
TODO
|
65
docs/modders/Map_Objects/Creature_Bank.md
Normal file
65
docs/modders/Map_Objects/Creature_Bank.md
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
< [Documentation](../../Readme.md) / [Modding](../Readme.md) / [Map Object Format](../Map_Object_Format.md) / Creature Bank
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
{
|
||||||
|
/// List of levels of this bank. On map loading, one of them will be randomly assigned to bank.
|
||||||
|
"levels": [
|
||||||
|
{
|
||||||
|
/// Chance for this level to be active
|
||||||
|
"chance": 30,
|
||||||
|
|
||||||
|
/// Description of guards, stacks will be ordered
|
||||||
|
/// on battlefield according to this scheme:
|
||||||
|
/// 4 7 1
|
||||||
|
///
|
||||||
|
/// 6 5
|
||||||
|
///
|
||||||
|
/// 3 2
|
||||||
|
/// Possible fields:
|
||||||
|
/// amount - size of stack
|
||||||
|
/// type - string ID of creature for this stack
|
||||||
|
/// upgradeChance - chance (in percent) for this stack to be upgraded
|
||||||
|
"guards": [
|
||||||
|
{ "amount": 4, "type": "cyclop" },
|
||||||
|
{ "amount": 4, "type": "cyclop" },
|
||||||
|
{ "amount": 4, "type": "cyclop", "upgradeChance": 50 },
|
||||||
|
{ "amount": 4, "type": "cyclop" },
|
||||||
|
{ "amount": 4, "type": "cyclop" }
|
||||||
|
],
|
||||||
|
|
||||||
|
// How hard are guards of this level. Unused?
|
||||||
|
"combat_value": 506,
|
||||||
|
|
||||||
|
/// Description of rewards granted for clearing bank
|
||||||
|
"reward" : {
|
||||||
|
|
||||||
|
/// Approximate value of reward, known to AI. Unused?
|
||||||
|
"value": 10000,
|
||||||
|
|
||||||
|
/// Granted resources
|
||||||
|
"resources": {
|
||||||
|
"wood" : 4,
|
||||||
|
"mercury" : 4,
|
||||||
|
"ore" : 4,
|
||||||
|
"sulfur" : 4,
|
||||||
|
"crystal" : 4,
|
||||||
|
"gems" : 4,
|
||||||
|
"gold" : 0
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Granted creatures, same format as guards
|
||||||
|
"creatures" : [
|
||||||
|
{ "amount": 4, "type": "wyvern" }
|
||||||
|
],
|
||||||
|
|
||||||
|
/// List of random artifacts
|
||||||
|
"artifacts": [ { "class" : "TREASURE" } ]
|
||||||
|
|
||||||
|
/// List of spells
|
||||||
|
"spells" : [ { "level" : 5 } ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
21
docs/modders/Map_Objects/Dwelling.md
Normal file
21
docs/modders/Map_Objects/Dwelling.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
< [Documentation](../../Readme.md) / [Modding](../Readme.md) / [Map Object Format](../Map_Object_Format.md) / Dwelling
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
{
|
||||||
|
/// List of creatures in this bank. Each list represents one "level" of bank
|
||||||
|
/// Creatures on the same level will have shared growth and available number (similar to towns)
|
||||||
|
/// Note that due to GUI limitation it is not recommended to have more than 4 creatures at once
|
||||||
|
"creatures" : [
|
||||||
|
[ "airElemental", "stormElemental" ],
|
||||||
|
[ "waterElemental" ]
|
||||||
|
],
|
||||||
|
|
||||||
|
/// List of guards for this dwelling. Can have two possible values:
|
||||||
|
/// Boolean true/false - If set to "true", guards will be generated using H3 formula:
|
||||||
|
/// 3 week growth of first available creatures
|
||||||
|
/// List of objects - custom guards, each entry represent one stack in defender army
|
||||||
|
"guards" : [
|
||||||
|
{ "amount" : 12, "type" : "earthElemental" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
102
docs/modders/Map_Objects/Market.md
Normal file
102
docs/modders/Map_Objects/Market.md
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
< [Documentation](../../Readme.md) / [Modding](../Readme.md) / [Map Object Format](../Map_Object_Format.md) / Market
|
||||||
|
|
||||||
|
# Market schema
|
||||||
|
|
||||||
|
Since VCMI-1.3 it's possible to create customizable markets on adventure map.
|
||||||
|
Markets can be added as any other object with special handler called "market".
|
||||||
|
|
||||||
|
Here is schema describing such object
|
||||||
|
|
||||||
|
```js
|
||||||
|
"seafaringAcademy" : //object name
|
||||||
|
{
|
||||||
|
"handler" : "market", //market handler
|
||||||
|
"name" : "Seafaring Academy",
|
||||||
|
... //describe any other regular parameters, such as sounds
|
||||||
|
"types" : {
|
||||||
|
"object" : { //object here is a type name
|
||||||
|
... //describe any other regular parameters, such as aiValue or rmg
|
||||||
|
"modes": ["resource-skill"], //modes available for market
|
||||||
|
"offer": ["navigation"], //optional parameter - specific items, must be presented on market
|
||||||
|
"title": "Seafaring Academy", //optional parameter - title for market window
|
||||||
|
"efficiency": 5, //market exchange rate, equivalent to amount of markets of certain type owning by player
|
||||||
|
"speech": "", //optional parameter - extra message showing on market
|
||||||
|
|
||||||
|
"templates" : {
|
||||||
|
... //describe templates in a common way
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# Modes
|
||||||
|
|
||||||
|
Mode parameter defines a way to exchange different entities. Multiple modes can be specified to support several types of exchange.
|
||||||
|
Following options are supported:
|
||||||
|
* `"resource-resource"` - regular resource exchange, like trading post
|
||||||
|
* `"resource-player"` - allows to send resources to another player
|
||||||
|
* `"creature-resource"` - acts like freelance guild
|
||||||
|
* `"resource-artifact"` - black market
|
||||||
|
* `"artifact-resource"` - allows to sell artifacts for resources
|
||||||
|
* `"artifact-experience"` - acts like altar of sacrifice for good factions
|
||||||
|
* `"creature-experience"` - acts like altar of sacrifice for evil factions
|
||||||
|
* `"creature-undead"` - acts like skeleton transformer
|
||||||
|
* `"resource-skill"` - acts like university, where skills can be learned
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
### Trading post
|
||||||
|
|
||||||
|
Trading post allows to exchange resources and send resources to another player, so it shall be configured this way:
|
||||||
|
```json
|
||||||
|
"modes" : ["resource-resource", "resource-player"]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Black market
|
||||||
|
|
||||||
|
```json
|
||||||
|
"modes" : ["resource-artifact"]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Freelance guild
|
||||||
|
|
||||||
|
```json
|
||||||
|
"modes" : ["creature-resource"]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Altar of sacrifice
|
||||||
|
|
||||||
|
Altar of sacrifice allows exchange creatures for experience for evil factions and artifacts for experience for good factions.
|
||||||
|
So both modes shall be available in the market.
|
||||||
|
Game logic prohibits using modes unavailable for faction
|
||||||
|
|
||||||
|
```json
|
||||||
|
"modes" : ["creature-experience", "artifact-experience"]
|
||||||
|
```
|
||||||
|
|
||||||
|
# Offer
|
||||||
|
|
||||||
|
This field allows to configure specific items available in the market.
|
||||||
|
In VCMI-1.3 it can be used only for `resource-skill` mode
|
||||||
|
|
||||||
|
See [Secondary skills](Rewardable.md#secondary-skills) description for more details
|
||||||
|
|
||||||
|
### Example for University of magic (e.g conflux building)
|
||||||
|
|
||||||
|
```js
|
||||||
|
"modes" : ["resource-skill"],
|
||||||
|
"offer" : ["airMagic", "waterMagic", "earthMagic", "fireMagic"]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example for regular University
|
||||||
|
|
||||||
|
```js
|
||||||
|
"modes" : ["resource-skill"],
|
||||||
|
"offer" : [ //4 random skills except necromancy
|
||||||
|
{ "noneOf" : ["necromancy"] },
|
||||||
|
{ "noneOf" : ["necromancy"] },
|
||||||
|
{ "noneOf" : ["necromancy"] },
|
||||||
|
{ "noneOf" : ["necromancy"] }
|
||||||
|
]
|
||||||
|
```
|
472
docs/modders/Map_Objects/Rewardable.md
Normal file
472
docs/modders/Map_Objects/Rewardable.md
Normal file
@ -0,0 +1,472 @@
|
|||||||
|
< [Documentation](../../Readme.md) / [Modding](../Readme.md) / [Map Object Format](../Map_Object_Format.md) / Rewardable
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
- [Base object definition](#base-object-definition)
|
||||||
|
- [Configurable object definition](#configurable-object-definition)
|
||||||
|
- [Base object definition](#base-object-definition)
|
||||||
|
- [Reset Parameters definition](#reset-parameters-definition)
|
||||||
|
- [Appear Chance definition](#appear-chance-definition)
|
||||||
|
- [Configurable Properties](#configurable-properties)
|
||||||
|
- - [Current Day](#current-day)
|
||||||
|
- - [Resource](#resource)
|
||||||
|
- - [Experience](#experience)
|
||||||
|
- - [Hero Level](#hero-level)
|
||||||
|
- - [Mana Points](#mana-points)
|
||||||
|
- - [Mana Percentage](#mana-percentage)
|
||||||
|
- - [Movement Points](#movement-points)
|
||||||
|
- - [Movement Percentage](#movement-percentage)
|
||||||
|
- - [Primary Skills](#primary-skills)
|
||||||
|
- - [Secondary Skills](#secondary-skills)
|
||||||
|
- - [Bonus System](#bonus-system)
|
||||||
|
- - [Artifacts](#artifacts)
|
||||||
|
- - [Spells](#spells)
|
||||||
|
- - [Creatures](#creatures)
|
||||||
|
- - [Creatures Change](#creatures-change)
|
||||||
|
- - [Spell cast](#spell-cast)
|
||||||
|
|
||||||
|
## Base object definition
|
||||||
|
Rewardable object is defined similarly to other objects, with key difference being `handler`. This field must be set to `"handler" : "configurable"` in order for vcmi to use this mode.
|
||||||
|
```js
|
||||||
|
{
|
||||||
|
"baseObjectName" : {
|
||||||
|
"name" : "Object name",
|
||||||
|
"handler" : "configurable",
|
||||||
|
"types" : {
|
||||||
|
"objectName" :
|
||||||
|
{
|
||||||
|
"rmg" : {
|
||||||
|
"value" : 2500,
|
||||||
|
"rarity" : 25,
|
||||||
|
"zoneLimit" : 1
|
||||||
|
},
|
||||||
|
|
||||||
|
// Standard definition of object templates
|
||||||
|
"templates" : {
|
||||||
|
"avwrhscr" : {
|
||||||
|
"animation" : "warehouses/avwrhscr",
|
||||||
|
"visitableFrom" : [ "---", "-++", "+++" ],
|
||||||
|
"mask" : ["VVV","VVV","VBA"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// See Configurable object definition section
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configurable object definition
|
||||||
|
```js
|
||||||
|
// List of potential rewards
|
||||||
|
"rewards" : [
|
||||||
|
{
|
||||||
|
// see Appear Chance definition section
|
||||||
|
"appearChance" : {
|
||||||
|
},
|
||||||
|
|
||||||
|
// Conditions to receive reward. Hero can only see this reward if he fulfills limiter
|
||||||
|
"limiter" : {
|
||||||
|
|
||||||
|
// additional list of conditions. Limiter will be valid if any of these conditions are true
|
||||||
|
"anyOf" : [
|
||||||
|
{
|
||||||
|
// See "Configurable Properties" section for additiona parameters
|
||||||
|
<additional properties>
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
// additional list of conditions. Limiter will be valid only if none of these conditions are true
|
||||||
|
"noneOf" : [
|
||||||
|
{
|
||||||
|
// See "Configurable Properties" section for additiona parameters
|
||||||
|
<additional properties>
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
// See "Configurable Properties" section for additiona parameters
|
||||||
|
<additional properties>
|
||||||
|
}
|
||||||
|
|
||||||
|
// message that will be shown if this is the only available award
|
||||||
|
"message": "{Warehouse of Crystal}"
|
||||||
|
|
||||||
|
// (VCMI 1.2) object will be disappeared after taking reward is set to true
|
||||||
|
"removeObject": false
|
||||||
|
|
||||||
|
// See "Configurable Properties" section for additiona parameters
|
||||||
|
<additional properties>
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
// (VCMI 1.2) If true, hero can not move to visitable tile of the object and will access this object from adjacent tile (e.g. Treasure Chest)
|
||||||
|
"blockedVisitable" : true,
|
||||||
|
|
||||||
|
// Message that will be shown if there are no applicable awards
|
||||||
|
"onEmptyMessage": "",
|
||||||
|
|
||||||
|
// Alternatively, rewards for empty state:
|
||||||
|
// Format is identical to "rewards" section, allowing to fine-tune behavior in this case, including giving awards or different messages to explain why object is "empty". For example, Tree of Knowledge will give different messages depending on whether it asks for gold or crystals
|
||||||
|
"onEmpty" : [
|
||||||
|
]
|
||||||
|
|
||||||
|
// Message that will be shown if there are multiple selectable awards to choose from
|
||||||
|
"onSelectMessage" : "",
|
||||||
|
|
||||||
|
// Message that will be shown if this object has been already visited before
|
||||||
|
"onVisitedMessage" : "{Warehouse of Crystal}\r\n\r\nThe owner of the storage is apologising: 'I am sorry Milord, no crystal here. Please, return next week!'",
|
||||||
|
|
||||||
|
// Alternatively, rewards for visited state:
|
||||||
|
// Format is identical to "rewards" section, allowing to fine-tune behavior of already visited object, including potentially giving bonuses to player, e.g. Warrior's Tomb give -3 morale for visiting such object.
|
||||||
|
"onVisited" : [
|
||||||
|
]
|
||||||
|
|
||||||
|
// if true, then player can refuse from reward and don't select anything
|
||||||
|
// Note that in this case object will not become "visited" and can still be revisited later
|
||||||
|
"canRefuse": true,
|
||||||
|
|
||||||
|
// object reset period. Note that period is counted from game start and not from hero visit
|
||||||
|
// reset duration of 7 will always reset object on new week & duration of 28 will reset on new month
|
||||||
|
// if field is not present or set to 0 object will never reset
|
||||||
|
// (VCMI 1.2) This property has been removed in favor of more detailed "resetParameters" property
|
||||||
|
"resetDuration" : 7,
|
||||||
|
|
||||||
|
// (VCMI 1.2) see Reset Parameters definition section
|
||||||
|
"resetParameters" : {
|
||||||
|
}
|
||||||
|
|
||||||
|
// determines who can revisit object before reset
|
||||||
|
// "once", - object can only be visited once. First visitor takes it all.
|
||||||
|
// "hero", - object can be visited if this hero has not visited it before
|
||||||
|
// "player", - object can be visited if this player has not visited it before
|
||||||
|
// "bonus" - object can be visited if hero no longer has bonus from this object (including any other object of the same type)
|
||||||
|
// "unlimited" - no restriction on revisiting.
|
||||||
|
"visitMode" : "unlimited",
|
||||||
|
|
||||||
|
//determines way to select granted rewards if multiple options are available
|
||||||
|
// "selectFirst", - first reward which passes "limiter" will be granted to player
|
||||||
|
// "selectPlayer", - player will be allowed to choose between rewards (e.g. treasure chest)
|
||||||
|
"selectMode" : "selectFirst", "selectPlayer"
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Reset Parameters definition
|
||||||
|
(VCMI 1.2 only)
|
||||||
|
|
||||||
|
This property describes how object state should be reset. Objects without this field will never reset its state.
|
||||||
|
- Period describes interval between object resets in day. Periods are counted from game start and not from hero visit, so reset duration of 7 will always reset object on new week & duration of 28 will always reset on new month.
|
||||||
|
- If `visitors` is set to true, game will reset list of visitors (heroes and players) on start of new period, allowing revisits of objects with `visitMode` set to `once`, `hero`, or `player`. Objects with visit mode set to `bonus` are not affected. In order to allow revisit such objects use appropriate bonus duration (e.g. `ONE_DAY` or `ONE_WEEK`) instead.
|
||||||
|
- If `rewards` is set to true, object will re-randomize its provided rewards, similar to such H3 objects as "Fountain of Fortune" or "Windmill"
|
||||||
|
|
||||||
|
```js
|
||||||
|
"resetParameters" : {
|
||||||
|
"period" : 7,
|
||||||
|
"visitors" : true,
|
||||||
|
"rewards" : true
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Appear Chance definition
|
||||||
|
This property describes chance for reward to be selected.
|
||||||
|
When object is initialized on map load, game will roll a "dice" - random number in range 0-99, and pick all awards that have appear chance within selected number
|
||||||
|
|
||||||
|
```js
|
||||||
|
"appearChance":
|
||||||
|
{
|
||||||
|
// (Advanced) rewards with different dice number will get different dice number
|
||||||
|
// This allows (for example) choosing two rewards randomly, independent from each other
|
||||||
|
// For H3 objects, this is generally not needed and this field can be omitted
|
||||||
|
"dice": 1,
|
||||||
|
|
||||||
|
// reward will be selected only if random roll value is greater or equal than this
|
||||||
|
"min" : 33,
|
||||||
|
|
||||||
|
// reward will be selected only if random roll value is lower than this
|
||||||
|
"max" : 66
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configurable Properties
|
||||||
|
Unless stated othervice, all numbers in this section can be replaced with random values, e.g.
|
||||||
|
```js
|
||||||
|
"minLevel" : { "min" : 5, "max" : 10 } // select random number between 5-10, including both 5 & 10
|
||||||
|
"minLevel" : [ 2, 4, 6, 8, 10] // (VCMI 1.2) select random number out of provided list, with equal chance for each
|
||||||
|
```
|
||||||
|
|
||||||
|
In this case, actual value for minLevel will be picked randomly.
|
||||||
|
(VCMI 1.2) Keep in mind, that all randomization is performed on map load and on reset (only if `rewards` field in `resetParameter` was set).
|
||||||
|
|
||||||
|
### Current Day
|
||||||
|
- Can only be used as limiter. To pass, current day of week should be equal to this value. 1 = first day of the week, 7 = last day
|
||||||
|
|
||||||
|
```js
|
||||||
|
"dayOfWeek" : 0
|
||||||
|
```
|
||||||
|
|
||||||
|
- (VCMI 1.2) Can only be used as limiter. To pass, number of days since game started must be at equal or greater than this value
|
||||||
|
|
||||||
|
```js
|
||||||
|
"daysPassed" : 8
|
||||||
|
```
|
||||||
|
|
||||||
|
### Resource
|
||||||
|
- Can be used as limiter. To pass, player needs to have specified resources. Note that limiter will NOT take resources.
|
||||||
|
- Can be used as reward to grant resources to player
|
||||||
|
- If negative value is used as reward, it will be used as cost and take resources from player
|
||||||
|
|
||||||
|
```js
|
||||||
|
"resources": {
|
||||||
|
"crystal" : 6,
|
||||||
|
"gold" : -1000,
|
||||||
|
},
|
||||||
|
```
|
||||||
|
- (VCMI 1.2) Alternative format that allows random selection of a resource type
|
||||||
|
|
||||||
|
```js
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"list" : [ "wood", "ore" ],
|
||||||
|
"amount" : 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type" : "gold",
|
||||||
|
"amount" : 1000
|
||||||
|
}
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
### Experience
|
||||||
|
- (VCMI 1.2) Can be used as limiter
|
||||||
|
- Can be used as reward to grant experience to hero
|
||||||
|
|
||||||
|
```js
|
||||||
|
"heroExperience" : 1000,
|
||||||
|
```
|
||||||
|
|
||||||
|
### Hero Level
|
||||||
|
- Can be used as limiter. Hero requires to have at least specified level
|
||||||
|
- (VCMI 1.2) Can be used as reward, will grant hero experience amount equal to the difference between the hero's next level and current level (Tree of Knowledge)
|
||||||
|
|
||||||
|
```js
|
||||||
|
"heroLevel" : 1,
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mana Points
|
||||||
|
- (VCMI 1.2) Can be used as limiter. Hero must have at least specific mana amount
|
||||||
|
- Can be used as reward, to give mana points to hero. Mana points may go above mana pool limit.
|
||||||
|
- If negative value is used as reward, it will be used as cost and take mana from player
|
||||||
|
|
||||||
|
```js
|
||||||
|
"manaPoints": -10,
|
||||||
|
```
|
||||||
|
|
||||||
|
- (VCMI 1.2) if giving mana points puts hero above mana pool limit, any overflow will be multiplied by specified percentage. If set to 0, mana will not go above mana pool limit.
|
||||||
|
|
||||||
|
```js
|
||||||
|
"manaOverflowFactor" : 50,
|
||||||
|
```
|
||||||
|
|
||||||
|
### Mana Percentage
|
||||||
|
- (VCMI 1.2) Can be used as limiter. Hero must have at least specific mana percentage
|
||||||
|
- Can be used to set hero mana level to specified percentage value, not restricted to mana pool limit (Magic Well, Mana Spring)
|
||||||
|
|
||||||
|
```js
|
||||||
|
"manaPercentage": 200,
|
||||||
|
```
|
||||||
|
|
||||||
|
### Movement Points
|
||||||
|
- Can NOT be used as limiter
|
||||||
|
- Can be used as reward, to give movement points to hero. Movement points may go above mana pool limit.
|
||||||
|
|
||||||
|
```js
|
||||||
|
"movePoints": 200,
|
||||||
|
```
|
||||||
|
|
||||||
|
### Movement Percentage
|
||||||
|
- Can NOT be used as limiter
|
||||||
|
- Can be used to set hero movement points level to specified percentage value. Value of 0 will take away any remaining movement points
|
||||||
|
|
||||||
|
```js
|
||||||
|
"movePercentage": 50,
|
||||||
|
```
|
||||||
|
|
||||||
|
### Primary Skills
|
||||||
|
- Can be used as limiter, hero must have primary skill at least at specified level
|
||||||
|
- Can be used as reward, to increase hero primary skills by selected value
|
||||||
|
- If reward value is negative, value will be used as cost, decreasing primary skill
|
||||||
|
- (VCMI 1.3) Each primary skill can be explicitly specified or randomly selected
|
||||||
|
```js
|
||||||
|
"primary": [
|
||||||
|
{
|
||||||
|
// Specific primary skill
|
||||||
|
"type" : "defence",
|
||||||
|
"amount" : 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Primary skill will be selected randomly from the list
|
||||||
|
"anyOf" : ["attack", "defence],
|
||||||
|
"min" : 1,
|
||||||
|
"max" : 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Primary skill will be selected randomly, expect those
|
||||||
|
"noneOf" : ["knowledge"],
|
||||||
|
"amount" : 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Primary skill will be selected randomly
|
||||||
|
"amount" : 3
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
- Possible values: `"attack", "defence", "spellpower", "knowledge"`
|
||||||
|
- (VCMI 1.2) Deprecated format
|
||||||
|
```js
|
||||||
|
"primary": {
|
||||||
|
"attack" : 1,
|
||||||
|
"spellpower": -1
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
### Secondary Skills
|
||||||
|
- Can be used as limiter, hero must have secondary skill at least at specified level
|
||||||
|
- Can be used as reward, to grant secondary skills to hero
|
||||||
|
- If hero already has specified skill, the skills will be leveled up specified number of times
|
||||||
|
- If hero does not have selected skill and have free skill slots, he will receive skill at specified level
|
||||||
|
- Possible values: 1 (basic), 2 (advanced), 3 (expert)
|
||||||
|
- (VCMI 1.3) Each secondary skill can be explicitly specified or randomly selected
|
||||||
|
```js
|
||||||
|
"secondary": [
|
||||||
|
{
|
||||||
|
// Specific skill
|
||||||
|
"type" : "wisdom",
|
||||||
|
"amount" : 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Skill will be selected randomly from the list
|
||||||
|
"anyOf" : ["airMagic", "waterMagic", "earthMagic", "fireMagic"],
|
||||||
|
"min" : 1,
|
||||||
|
"max" : 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Skill will be selected randomly from all allowed, expect those
|
||||||
|
"noneOf" : ["necromancy", "leadership"],
|
||||||
|
"amount" : 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// Skill will be selected randomly from all allowed
|
||||||
|
"amount" : 3
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
- (VCMI 1.2) deprecated format
|
||||||
|
```js
|
||||||
|
"secondary": {
|
||||||
|
"wisdom" : 1
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
### Bonus System
|
||||||
|
- (VCMI 1.2) Can be used as reward, to grant bonus to player
|
||||||
|
- (VCMI 1.2) if present, MORALE and LUCK bonus will add corresponding image component to UI.
|
||||||
|
- (VCMI 1.2) Note that unlike most values, parameter of bonuses can NOT be randomized
|
||||||
|
- (VCMI 1.X) Description can be string or number of corresponding string from `arraytxt.txt`
|
||||||
|
|
||||||
|
```js
|
||||||
|
"bonuses" : [
|
||||||
|
{
|
||||||
|
"type" : "MORALE",
|
||||||
|
"val" : 1,
|
||||||
|
"duration" : "ONE_BATTLE",
|
||||||
|
"desription" : 94
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Artifacts
|
||||||
|
- Can be used as limiter, hero must have artifact either equipped or in backpack
|
||||||
|
- Can be used as reward, to give new artifact to a hero
|
||||||
|
- (VCMI 1.2) Artifacts added as reward will be used for text substitution. First `%s` in text string will be replaced with name of an artifact
|
||||||
|
|
||||||
|
```js
|
||||||
|
"artifacts": [
|
||||||
|
"ribCage"
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
- Alternative format, random artifact generation.
|
||||||
|
- For artifact class possible values are "TREASURE", "MINOR", "MAJOR", "RELIC"
|
||||||
|
- Artifact value range can be specified with min value and max value
|
||||||
|
|
||||||
|
```js
|
||||||
|
"artifacts": [
|
||||||
|
{
|
||||||
|
"class" : "TREASURE",
|
||||||
|
"minValue" : 5000,
|
||||||
|
"maxValue" : 10000
|
||||||
|
}
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
### Spells
|
||||||
|
- (VCMI 1.2) Can be used as limiter
|
||||||
|
- Can be used as reward, to give new spell to a hero
|
||||||
|
- (VCMI 1.2) Spells added as reward will be used for text substitution. First `%s` in text string will be replaced with spell name
|
||||||
|
|
||||||
|
```js
|
||||||
|
"spells": [
|
||||||
|
"magicArrow"
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
- Alternative format, random spell selection
|
||||||
|
- (VCMI 1.X) Spell can be selected from specifically selected school
|
||||||
|
|
||||||
|
```js
|
||||||
|
"spells": [
|
||||||
|
{
|
||||||
|
"level" : 1,
|
||||||
|
"school" : "fire",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
### Creatures
|
||||||
|
- Can be used as limiter
|
||||||
|
- Can be used as reward, to give new creatures to a hero
|
||||||
|
- If hero does not have enough free slots, game will show selection dialog to pick troops to keep
|
||||||
|
- It is possible to specify probabilty to receive upgraded creature
|
||||||
|
```js
|
||||||
|
"creatures" : [
|
||||||
|
{
|
||||||
|
"creature" : "archer",
|
||||||
|
"upgradeChance" : 30,
|
||||||
|
"amount" : 20,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
```
|
||||||
|
|
||||||
|
### Creatures Change
|
||||||
|
- (VCMI 1.2) Can NOT be used as limiter
|
||||||
|
- (VCMI 1.2) Can be used as reward, to replace creatures in hero army. It is possible to use this parameter both for upgrades of creatures as well as for changing them into completely unrelated creature, e.g. similar to Skeleton Transformer
|
||||||
|
- (VCMI 1.2) This parameter will not change creatures given by `creatures` parameter on the same visit
|
||||||
|
|
||||||
|
```js
|
||||||
|
"changeCreatures" : {
|
||||||
|
"cavalier" : "champion"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Spell cast
|
||||||
|
- (VCMI 1.3) Can NOT be used as limiter
|
||||||
|
- (VCMI 1.3) As reward, instantly casts adventure map spell for visiting hero. All checks for spell book, wisdom or presence of mana will be ignored. It's possible to specify school level at which spell will be casted. If it's necessary to reduce player's mana or do some checks, they shall be introduced as limiters and other rewards
|
||||||
|
- School level possible values: 1 (basic), 2 (advanced), 3 (expert)
|
||||||
|
|
||||||
|
```js
|
||||||
|
"spellCast" : {
|
||||||
|
"spell" : "townPortal",
|
||||||
|
"schoolLevel": 3
|
||||||
|
}
|
||||||
|
```
|
140
docs/modders/Mod_File_Format.md
Normal file
140
docs/modders/Mod_File_Format.md
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
< [Documentation](../Readme.md) / [Modding](Readme.md) / Mod File Format
|
||||||
|
|
||||||
|
## Fields with description of mod
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
|
||||||
|
{
|
||||||
|
// Name of your mod. While it does not have hard length limit
|
||||||
|
// it should not be longer than ~30 symbols to fit into allowed space
|
||||||
|
"name" : "My test mod",
|
||||||
|
|
||||||
|
// More lengthy description of mod. No hard limit. This text will be visible in launcher.
|
||||||
|
// This field can use small subset of HTML, see link at the bottom of this page.
|
||||||
|
"description" : "My test mod that add a lot of useless stuff into the game",
|
||||||
|
|
||||||
|
// Author of mod. Can be nickname, real name or name of team
|
||||||
|
"author" : "Anonymous",
|
||||||
|
|
||||||
|
// Full name of license used by mod. Should be set only if you're author of mod
|
||||||
|
// or received permission to use such license from original author
|
||||||
|
"licenseName" : "Creative Commons Attribution-ShareAlike",
|
||||||
|
|
||||||
|
// URL which user can use to see license terms and text
|
||||||
|
"licenseURL" : "https://creativecommons.org/licenses/by-sa/4.0/",
|
||||||
|
|
||||||
|
|
||||||
|
// Home page of mod or link to forum thread to contact the author
|
||||||
|
"contact" : "http://example.com",
|
||||||
|
|
||||||
|
// Type of mod, list of all possible values:
|
||||||
|
// "Translation", "Town", "Test", "Templates", "Spells", "Music", "Sounds", "Skills", "Other", "Objects",
|
||||||
|
// "Mechanics", "Interface", "Heroes", "Graphical", "Expansion", "Creatures", "Artifacts", "AI"
|
||||||
|
"modType" : "Graphical",
|
||||||
|
|
||||||
|
// List of mods that are required to run this one
|
||||||
|
"depends" :
|
||||||
|
[
|
||||||
|
"baseMod"
|
||||||
|
],
|
||||||
|
|
||||||
|
// List of mods that can't be enabled in the same time as this one
|
||||||
|
"conflicts" :
|
||||||
|
[
|
||||||
|
"badMod"
|
||||||
|
],
|
||||||
|
|
||||||
|
//List of changes/new features in each version
|
||||||
|
"changelog" :
|
||||||
|
{
|
||||||
|
"1.0" : [ "initial release" ],
|
||||||
|
"1.0.1" : [ "change 1", "change 2" ],
|
||||||
|
"1.1" : [ "change 3", "change 4" ]
|
||||||
|
},
|
||||||
|
|
||||||
|
// If set to true, mod will not be enabled automatically on install
|
||||||
|
"keepDisabled" : false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Fields with description of mod content
|
||||||
|
|
||||||
|
These are fields that are present only in local mod.json file
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
|
||||||
|
{
|
||||||
|
// Following section describes configuration files with content added by mod
|
||||||
|
// It can be split into several files in any way you want but recommended organization is
|
||||||
|
// to keep one file per object (creature/hero/etc) and, if applicable, add separate file
|
||||||
|
// with translatable strings for each type of content
|
||||||
|
// See "additional links" at the bottom of page for descriptions of each of these formats
|
||||||
|
|
||||||
|
// list of factions/towns configuration files
|
||||||
|
"factions" :
|
||||||
|
[
|
||||||
|
"config/myMod/faction.json"
|
||||||
|
]
|
||||||
|
|
||||||
|
// List of hero classes configuration files
|
||||||
|
"heroClasses" :
|
||||||
|
[
|
||||||
|
"config/myMod/heroClasses.json"
|
||||||
|
],
|
||||||
|
|
||||||
|
// List of heroes configuration files
|
||||||
|
"heroes" :
|
||||||
|
[
|
||||||
|
"config/myMod/heroes.json"
|
||||||
|
],
|
||||||
|
|
||||||
|
// list of creature configuration files
|
||||||
|
"creatures" :
|
||||||
|
[
|
||||||
|
"config/myMod/creatures.json"
|
||||||
|
],
|
||||||
|
|
||||||
|
// List of artifacts configuration files
|
||||||
|
"artifacts" :
|
||||||
|
[
|
||||||
|
"config/myMod/artifacts.json"
|
||||||
|
],
|
||||||
|
|
||||||
|
// List of objects defined in this mod
|
||||||
|
"objects" :
|
||||||
|
[
|
||||||
|
"config/myMod/objects.json"
|
||||||
|
],
|
||||||
|
|
||||||
|
// List of spells defined in this mod
|
||||||
|
"spells" :
|
||||||
|
[
|
||||||
|
"config/myMod/spells.json"
|
||||||
|
],
|
||||||
|
|
||||||
|
// List of RMG templates defined in this mod
|
||||||
|
"templates" :
|
||||||
|
[
|
||||||
|
"config/myMod/templates.json"
|
||||||
|
],
|
||||||
|
|
||||||
|
// Optional, description on how files are organized in your mod
|
||||||
|
// In most cases you do not need to use this field
|
||||||
|
// Needed mostly to port any existing mods to vcmi (e.g. WoG distributed with Era)
|
||||||
|
// Example below is default value, which is "Content" directory that acts as H3 root directory
|
||||||
|
"filesystem":
|
||||||
|
{
|
||||||
|
"":
|
||||||
|
[
|
||||||
|
{"type" : "dir", "path" : "/Content"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notes
|
||||||
|
|
||||||
|
For mod description it is possible to use certain subset of HTML as
|
||||||
|
described here:
|
||||||
|
|
||||||
|
<http://qt-project.org/doc/qt-5.0/qtgui/richtext-html-subset.html>
|
92
docs/modders/Random_Map_Template.md
Normal file
92
docs/modders/Random_Map_Template.md
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
< [Documentation](../Readme.md) / [Modding](Readme.md) / Random Map Template Format
|
||||||
|
|
||||||
|
## Template format
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
/// Unique template name
|
||||||
|
"Triangle" :
|
||||||
|
{
|
||||||
|
//optional name - useful to have several template variations with same name (since 0.99)
|
||||||
|
"name" : "Custom template name",
|
||||||
|
"description" : "Brief description of template, recommended setting or rules".
|
||||||
|
|
||||||
|
/// Minimal and maximal size of the map. Possible formats:
|
||||||
|
/// Size code: s, m, l or xl for size with optional suffix "+u" for underground
|
||||||
|
/// Numeric size, e.g. 120x120x1 (width x height x depth). Note that right now depth can only be 0 or 1
|
||||||
|
"minSize" : "m",
|
||||||
|
"maxSize" : "xl+u",
|
||||||
|
|
||||||
|
/// Number of players that will be present on map (human or AI)
|
||||||
|
"players" : "2-4",
|
||||||
|
|
||||||
|
/// Number of AI-only players
|
||||||
|
"cpu" : "2",
|
||||||
|
|
||||||
|
///Optional parameter allowing to prohibit some water modes. All modes are allowed if parameter is not specified
|
||||||
|
"allowedWaterContent" : ["none", "normal", "islands"]
|
||||||
|
|
||||||
|
/// List of named zones, see below for format description
|
||||||
|
"zones" :
|
||||||
|
{
|
||||||
|
"zoneA" : { ... },
|
||||||
|
"zoneB" : { ... },
|
||||||
|
"zoneC" : { ... }
|
||||||
|
},
|
||||||
|
"connections" :
|
||||||
|
[
|
||||||
|
{ "a" : "zoneA", "b" : "zoneB", "guard" : 5000, "road" : "false" },
|
||||||
|
{ "a" : "zoneA", "b" : "zoneC", "guard" : 5000, "road" : "random" },
|
||||||
|
{ "a" : "zoneB", "b" : "zoneC", "type" : "wide" }
|
||||||
|
//"type" can be "guarded" (default), "wide", "fictive" or "repulsive"
|
||||||
|
//"wide" connections have no border, or guard. "fictive" and "repulsive" connections are virtual -
|
||||||
|
//they do not create actual path, but only attract or repulse zones, respectively
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Zone format
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
{
|
||||||
|
"type" : "playerStart", //"cpuStart" "treasure" "junction"
|
||||||
|
"size" : 2, //relative size of zone
|
||||||
|
"owner" : 1, //player owned this zone
|
||||||
|
"playerTowns" : {
|
||||||
|
"castles" : 1
|
||||||
|
//"towns" : 1
|
||||||
|
},
|
||||||
|
"neutralTowns" : {
|
||||||
|
//"castles" : 1
|
||||||
|
"towns" : 1
|
||||||
|
},
|
||||||
|
"townsAreSameType" : true,
|
||||||
|
"monsters" : "normal", //"weak" "strong", "none" - All treasures will be unguarded
|
||||||
|
|
||||||
|
"terrainTypes" : [ "sand" ], //possible terrain types. All terrains will be available if not specified
|
||||||
|
"bannedTerrains" : ["lava", "asphalt"] //optional
|
||||||
|
|
||||||
|
"matchTerrainToTown" : false, //if true, terrain for this zone will match native terrain of player faction
|
||||||
|
"minesLikeZone" : 1,
|
||||||
|
"treasureLikeZone" : 1
|
||||||
|
"terrainTypeLikeZone" : 3
|
||||||
|
|
||||||
|
"allowedMonsters" : ["inferno", "necropolis"] //factions of monsters allowed on this zone
|
||||||
|
"bannedMonsters" : ["fortress", "stronghold", "conflux"] //These monsers will never appear in the zone
|
||||||
|
"allowedTowns" : ["castle", "tower", "rampart"] //towns allowed on this terrain
|
||||||
|
"bannedTowns" : ["necropolis"] //towns will never spawn on this terrain
|
||||||
|
|
||||||
|
"mines" : {
|
||||||
|
"wood" : 1,
|
||||||
|
"ore" : 1,
|
||||||
|
},
|
||||||
|
|
||||||
|
"treasure" : [
|
||||||
|
{
|
||||||
|
"min" : 2100,
|
||||||
|
"max": 3000,
|
||||||
|
"density" : 5
|
||||||
|
}
|
||||||
|
...
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
215
docs/modders/Readme.md
Normal file
215
docs/modders/Readme.md
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
< [Documentation](../Readme.md) / Modding
|
||||||
|
|
||||||
|
# Creating mod
|
||||||
|
|
||||||
|
To make your own mod you need to create subdirectory in **<data dir>/Mods/** with name that will be used as identifier for your mod.
|
||||||
|
Main mod is file called **mod.json** and should be placed into main folder of your mod, e.g. **Mods/myMod/mod.json**
|
||||||
|
All content of your mod should go into **Content** directory, e.g. **Mods/myMod/Content/**. Alternatively, it is possible to replace this directory with single .zip archive.
|
||||||
|
|
||||||
|
Example of how directory structure of your mod may look like:
|
||||||
|
|
||||||
|
```
|
||||||
|
Mods/
|
||||||
|
myMod/
|
||||||
|
mod.json
|
||||||
|
Content/
|
||||||
|
config/ - json configuration files
|
||||||
|
data/ - unorganized files, mostly bitmap images (.bmp, .png, .pcx)
|
||||||
|
maps/ - h3m maps added or modified by mod
|
||||||
|
music/ - music files. Mp3 and ogg/vorbis are supported
|
||||||
|
sounds/ - sound files, in wav format.
|
||||||
|
sprites/ - animation, image sets (H3 .def files or VCMI .json files)
|
||||||
|
video/ - video files, .bik or .smk
|
||||||
|
```
|
||||||
|
|
||||||
|
## Creating mod file
|
||||||
|
|
||||||
|
All VCMI configuration files use [JSON format](http://en.wikipedia.org/wiki/Json) so you may want to familiarize yourself with it first.
|
||||||
|
Mod.json is main file in your mod and must be present in any mod. This file contains basic description of your mod, dependencies or conflicting mods (if present), list of new content and so on.
|
||||||
|
Minimalistic version of this file:
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
{
|
||||||
|
"name" : "My test mod",
|
||||||
|
"description" : "My test mod that add a lot of useless stuff into the game"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
See [Mod file Format](Mod_File_Format.md) for its full description.
|
||||||
|
|
||||||
|
## Creation of new objects
|
||||||
|
|
||||||
|
In order to create new object use following steps:
|
||||||
|
1. Create json file with definition of new object. See list of supported object types below.
|
||||||
|
2. Add any resources needed for this object, such as images, animations or sounds.
|
||||||
|
2. Add reference to new object in corresponding section of mod.json file
|
||||||
|
|
||||||
|
### List of supported new object types
|
||||||
|
|
||||||
|
Random Map Generator:
|
||||||
|
- [Random Map Template](Random_Map_Template.md)
|
||||||
|
|
||||||
|
Game Entities:
|
||||||
|
- [Artifact](Entities_Format/Artifact_Format.md)
|
||||||
|
- [Creature](Entities_Format/Creature_Format.md)
|
||||||
|
- [Faction](Entities_Format/Faction_Format.md)
|
||||||
|
- [Hero Class](Entities_Format/Hero_Class_Format.md)
|
||||||
|
- [Hero Type](Entities_Format/Hero_Type_Format.md)
|
||||||
|
- [Spell](Entities_Format/Spell_Format.md)
|
||||||
|
- [Secondary Skill](Entities_Format/Secondary_Skill_Format.md)
|
||||||
|
|
||||||
|
Map objects:
|
||||||
|
- [Map Objects](Map_Object_Format.md)
|
||||||
|
- - [Rewardable](Map_Objects/Rewardable.md)
|
||||||
|
- - [Creature Bank](Map_Objects/Creature_Bank.md)
|
||||||
|
- - [Dwelling](Map_Objects/Dwelling.md)
|
||||||
|
- - [Market](Map_Objects/Markets.md)
|
||||||
|
- - [Boat](Map_Objects/Boat.md)
|
||||||
|
|
||||||
|
Other:
|
||||||
|
- [Terrain](Entities_Format/Terrain_Format.md)
|
||||||
|
- [River](Entities_Format/River_Format.md)
|
||||||
|
- [Road](Entities_Format/Road_Format.md)
|
||||||
|
- [Battlefield](Entities_Format/Battlefield_Format.md)
|
||||||
|
- [Battle Obstacle](Entities_Format/Battle_Obstacle_Format.md)
|
||||||
|
|
||||||
|
## Game Identifiers system
|
||||||
|
|
||||||
|
VCMI uses strings to reference objects. Examples:
|
||||||
|
|
||||||
|
- Referencing H3 objects: `"nativeTerrain" : "sand"`. All mods can freely access any existing objects from H3 data.
|
||||||
|
|
||||||
|
- Referencing object from another mod: `"nativeTerrain" : "asphalt"`. Mods can only reference object from mods that are marked as dependencies
|
||||||
|
|
||||||
|
- Referencing objects in bonus system: `"subtype" : "creature.archer"`. Bonus system requires explicit definition of object type since different bonuses may require different identifier class.
|
||||||
|
|
||||||
|
- Referencing object from specific mod: `"nativeTerrain" : "hota.cove:sorceress"`. In some cases, for example to resolve conflicts when multiple mods use same object name you might need to explicitly specify mod in which game needs to look up an identifier. Alternatively, you can use this form for clarity if you want to clearly specify that object comes from another mod.
|
||||||
|
|
||||||
|
### Modifying existing objects
|
||||||
|
|
||||||
|
Alternatively to creating new objects, you can edit existing objects. Normally, when creating new objects you specify object name as:
|
||||||
|
``` javascript
|
||||||
|
"newCreature" : {
|
||||||
|
// creature parameters
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
In order to access and modify existing object you need to specify mod that you wish to edit:
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
/// "core" specifier refers to objects that exist in H3
|
||||||
|
"core:archer" : {
|
||||||
|
/// This will set health of Archer to 10
|
||||||
|
"hitPoints" : 10,
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Modifying object named "jumpSoldier" in mod "forge"
|
||||||
|
"forge:jumpSoldier" : {
|
||||||
|
/// Set attack of Jump Soldiers to 20
|
||||||
|
"attack": 20
|
||||||
|
},
|
||||||
|
|
||||||
|
/// Modifying object named "sorceress" in submod "cove" of mod "hota"
|
||||||
|
"hota.cove:sorceress" : {
|
||||||
|
/// Set speed of Sorceresses to 10
|
||||||
|
"speed" : 10
|
||||||
|
},
|
||||||
|
```
|
||||||
|
Note that modification of existing objects does not requires a dependency on edited mod. Such definitions will only be used by game if corresponding mod is installed and active.
|
||||||
|
|
||||||
|
This allows using objects editing not just for rebalancing mods but also to provide compatibility between two different mods or to add interaction between two mods.
|
||||||
|
|
||||||
|
## Overriding graphical files from Heroes III
|
||||||
|
|
||||||
|
Any graphical replacer mods fall under this category. In VCMI directory **<mod name>/Content** acts as mod-specific game root directory. So for example file **<mod name>/Content/Data/AISHIELD.PNG** will replace file with same name from **H3Bitmap.lod** game archive.
|
||||||
|
Any other files can be replaced in exactly same way.
|
||||||
|
Note that replacing files from archives requires placing them into specific location:
|
||||||
|
- H3Bitmap.lod -> Data
|
||||||
|
- H3Sprite.lod -> Sprites
|
||||||
|
- Heroes3.snd -> Sounds
|
||||||
|
- Video.vid -> Video
|
||||||
|
|
||||||
|
This includes archives added by expansions (e.g. **H3ab_bmp.lod** uses same rules as **H3Bitmap.lod**)
|
||||||
|
|
||||||
|
- **Warning:** overriding graphical files from other mods is discouraged and may be removed in future versions of vcmi. Please use modification of existing objects instead.
|
||||||
|
|
||||||
|
### Replacing .def animation files
|
||||||
|
|
||||||
|
Heroes III uses custom format for storing animation: def files. These files are used to store all in-game animations as well as for some GUI elements like buttons and for icon sets.
|
||||||
|
These files can be replaced by another def file but in some cases original format can't be used. This includes but not limited to:
|
||||||
|
- Replacing one (or several) icons in set
|
||||||
|
- Replacing animation with fully-colored 32-bit images
|
||||||
|
In VCMI these animation files can also be replaced by json description of their content. See [Animation Format](Animation_Format.md) for full description of this format.
|
||||||
|
Example: replacing single icon
|
||||||
|
|
||||||
|
``` javascript
|
||||||
|
{
|
||||||
|
// List of replaced images
|
||||||
|
"images" :
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"frame" : 0, // Index of replaced frame
|
||||||
|
"file" : "HPS000KN.bmp" //name of file that will be used as replacement
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
# Publishing mods in VCMI Repository
|
||||||
|
|
||||||
|
This will allow players to install mods directly from VCMI Launcher without visiting any 3rd-party sites.
|
||||||
|
|
||||||
|
## Where files are hosted
|
||||||
|
|
||||||
|
Mods list hosted under main VCMI organization: [vcmi-mods-repository](https://github.com/vcmi/vcmi-mods-repository).
|
||||||
|
Each mod hosted in it's own repository under separate organization [vcmi-mods](https://github.com/vcmi-mods). This way if engine become more popular in future we can create separate teams for each mod and accept as many people as needed.
|
||||||
|
|
||||||
|
## Why Git / GitHub?
|
||||||
|
|
||||||
|
It's solve a lot of problems:
|
||||||
|
|
||||||
|
- Engine developers get control over all mods and can easily update them without adding extra burden for modders / mod maintainers.
|
||||||
|
- With tools such as [GitHub Desktop](https://desktop.github.com/) it's easy for non-programmers to contribute.
|
||||||
|
- Forward and backward compatibility. Stable releases of game use compatible version of mods while users of daily builds will be able to test mods supporting bleeding edge features.
|
||||||
|
- Tracking of changes for repository and mods. It's not big deal now, but once we have scripting it's will be important to keep control over what code included in mods.
|
||||||
|
- GitHub also create ZIP archives for us so mods will be stored uncompressed and version can be identified by commit hash.
|
||||||
|
|
||||||
|
## On backward compatibility
|
||||||
|
|
||||||
|
Our mod list in vcmi-mods-repository had "develop" as primary branch. Daily builds of VCMI use mod list file from this branch.
|
||||||
|
Once VCMI get stable release there will be branching into "1.0.0", "1.1.0", etc. Launcher of released version will request mod list for particular version.
|
||||||
|
Same way we can also create special stable branch for every mod under "vcmi-mods" organization umbrella once new stable version is released. So this way it's will be easier to maintain two versions of same mod: for stable and latest version.
|
||||||
|
|
||||||
|
## Getting into vcmi-mods organization
|
||||||
|
|
||||||
|
Before your mod can be accepted into official mod list you need to get it into repository under "vcmi-mods" organization umbrella. To do this contact one of mod repository maintainers. If needed you can get own team within "vcmi-mods" organization.
|
||||||
|
Link to our mod will looks like that: https://github.com/vcmi-mods/adventure-ai-trace
|
||||||
|
|
||||||
|
## Rules of repository
|
||||||
|
|
||||||
|
### Allowed name for mod identifier
|
||||||
|
|
||||||
|
For sanity reasons mod identifier must only contain lower-case English characters, numbers and hyphens.
|
||||||
|
|
||||||
|
my-mod-name
|
||||||
|
2000-new-maps
|
||||||
|
|
||||||
|
Sub-mods can be named as you like, but we strongly encourage everyone to use proper identifiers for them as well.
|
||||||
|
|
||||||
|
### Rewriting History
|
||||||
|
|
||||||
|
Once you submitted certain commit into official mod list you are not allowed to rewrite history before that commit. This way we can make sure that VCMI launcher will always be able to download older version of any mod.
|
||||||
|
Branches such as "develop" or stable branches like "1.0.0" should be marked as protected on GitHub.
|
||||||
|
|
||||||
|
## Submitting mods to repository
|
||||||
|
|
||||||
|
Once mod ready for general public maintainer to make PR to [vcmi-mods-repository](https://github.com/vcmi/vcmi-mods-repository).
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
Right now main requirements for a mod to be accepted into VCMI mods list are:
|
||||||
|
|
||||||
|
- Mod must be complete. For work-in-progress mods it is better to use other way of distribution.
|
||||||
|
- Mod must met some basic quality requirements. Having high-quality content is always preferable.
|
||||||
|
- Mod must not contain any errors detectable by validation (console message you may see during loading)
|
||||||
|
- Music files must be in Ogg/Vorbis format (\*.ogg extension)
|
64
docs/modders/Translations.md
Normal file
64
docs/modders/Translations.md
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
< [Documentation](../Readme.md) / [Modding](Readme.md) / Translations
|
||||||
|
|
||||||
|
## For translators
|
||||||
|
### Adding new languages
|
||||||
|
New languages require minor changes in the source code. Please contact someone from vcmi team if you wish to translate game into a new language
|
||||||
|
|
||||||
|
### Translation of Launcher and Map Editor
|
||||||
|
TODO: write me
|
||||||
|
|
||||||
|
### Translation of game content
|
||||||
|
TODO: write me
|
||||||
|
|
||||||
|
## For modders
|
||||||
|
|
||||||
|
### Adding new translation to mod
|
||||||
|
TODO: write me
|
||||||
|
|
||||||
|
### Translation of mod information
|
||||||
|
In order to display information in Launcher in language selected by user add following block into your mod.json:
|
||||||
|
```
|
||||||
|
"<language>" : {
|
||||||
|
"name" : "<translated name>",
|
||||||
|
"description" : "<translated description>",
|
||||||
|
"author" : "<translated author>",
|
||||||
|
"modType" : "<translated mod type>",
|
||||||
|
},
|
||||||
|
```
|
||||||
|
List of currently supported values for language parameter:
|
||||||
|
- english
|
||||||
|
- german
|
||||||
|
- polish
|
||||||
|
- russian
|
||||||
|
- ukrainian
|
||||||
|
|
||||||
|
However, normally you don't need to use block for English. Instead, English text should remain in root section of your mod.json file, to be used when game can not find translated version.
|
||||||
|
|
||||||
|
### Translation of mod content
|
||||||
|
TODO: write me
|
||||||
|
|
||||||
|
### Searching for missing translation strings
|
||||||
|
TODO: write me
|
||||||
|
|
||||||
|
## For developers
|
||||||
|
### Adding new languages
|
||||||
|
In order to add new language it needs to be added in multiple locations in source code:
|
||||||
|
- Generate new .ts files for launcher and map editor, either by running `lupdate` with name of new .ts or by copying english.ts and editing language tag in the header.
|
||||||
|
- Add new language into Launcher UI drop-down selector and name new string using such format:
|
||||||
|
`"<native name for language> (<english name for language>)"`
|
||||||
|
- Add new language into array of possible values for said selector
|
||||||
|
|
||||||
|
Also, make full search for a name of an existing language to ensure that there are not other places not referenced here
|
||||||
|
### Updating translation of Launcher and Map Editor to include new strings
|
||||||
|
At the moment, build system will generate binary translation files (.qs) that can be opened by Qt.
|
||||||
|
However, any new or changed lines will not be added into existing .ts files.
|
||||||
|
In order to update .ts files manually, open command line shell in `mapeditor` or `launcher` source directories and execute command
|
||||||
|
```
|
||||||
|
lupdate -no-obsolete * -ts translation/*.ts
|
||||||
|
```
|
||||||
|
This will remove any no longer existing lines from translation and add any new lines for all translations.
|
||||||
|
There *may* be a way to do the same via QtCreator UI or via CMake, if you find one feel free to update this information.
|
||||||
|
### Updating translation of Launcher and Map Editor using new .ts file from translators
|
||||||
|
Generally, this should be as simple as overwriting old files. Things that may be necessary if translation update is not visible in executable:
|
||||||
|
- Rebuild subproject (map editor/launcher).
|
||||||
|
- Regenerate translations via `lupdate -no-obsolete * -ts translation/*.ts`
|
34
docs/players/Bug_Reporting_Guidelines.md
Normal file
34
docs/players/Bug_Reporting_Guidelines.md
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
< [Documentation](../Readme.md) / Bug Reporting Guidelines
|
||||||
|
|
||||||
|
First of all, thanks for your support! If you report a bug we can fix it. But keep in mind that reporting your bugs appropriately makes our (developers') lifes easier. Here are a few guidelines that will help you write good bug reports.
|
||||||
|
|
||||||
|
# Github bugtracker
|
||||||
|
|
||||||
|
The main place for managing and reporting bugs is [our bugtracker](https://github.com/vcmi/vcmi/issues). When you are not logged in, you can only browse already reported bugs. To be able to report bugs you need to make an account there.
|
||||||
|
|
||||||
|
## What should be reported
|
||||||
|
|
||||||
|
Certainly the most important bugs we would like to know about are crashes and game hangs. Game should not crash nor hang under any conditions. But bugs are not restricted to those extreme cases. Graphical glitches, significant differences in game mechanics and serious performance drops should be reported too.
|
||||||
|
|
||||||
|
## What to focus on while testing
|
||||||
|
|
||||||
|
There are no specific guidelines on this. Every part of the game needs some attention while testing. Usually newly added features should be tested more. Sometimes bugs occur only when loading from savegame, so you shouldn't always begin a new game.
|
||||||
|
|
||||||
|
## General guidelines
|
||||||
|
|
||||||
|
First of all, if you encounter a crash, don't re-run VCMI immediately to see if you can reproduce it. Firstly take a screenshot or copy console output (those mostly green letters on black background). Then back up following files (if you won't be able to reproduce the issue you should upload them with issue report):
|
||||||
|
|
||||||
|
- VCMI_Client_log.txt
|
||||||
|
- VCMI_Server_log.txt
|
||||||
|
|
||||||
|
By default, log files are written to:
|
||||||
|
|
||||||
|
- Windows: Documents\My Games\vcmi\\
|
||||||
|
- Linux: ~/.cache/vcmi/
|
||||||
|
- Android: Android/data/is.xyz.vcmi/files/vcmi-data/cache/
|
||||||
|
|
||||||
|
Now you should try to reproduce encountered issue. It's best when you write how to reproduce the issue by starting a new game and taking some steps (e.g. start Arrogance map as red player and attack monster Y with hero X). If you have troubles with reproducing it this way but you can do it from a savegame - that's good too. Finally, when you are not able to reproduce the issue at all, just upload the files mentioned above. To sum up, this is a list of what's the most desired for a developer:
|
||||||
|
|
||||||
|
1. (most desired) a map with list of steps needed to reproduce the bug
|
||||||
|
2. savegame with list of steps to reproduce the bug
|
||||||
|
3. (least desired) VCMI_Client_log.txt and VCMI_Server_log.txt (but then remember to back logs up before trying to reproduce it).
|
136
docs/players/Cheat_Codes.md
Normal file
136
docs/players/Cheat_Codes.md
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
< [Documentation](../Readme.md) / Cheat Codes
|
||||||
|
|
||||||
|
# Cheat Codes
|
||||||
|
|
||||||
|
Similar to H3, VCMI provides cheat codes to make testing game more convenient.
|
||||||
|
|
||||||
|
To use cheat code, press `Tab` key or click/tap on status bar to open game chat and enter code. Most cheat codes have several alternative names, including name of this cheat code in H3:SoD
|
||||||
|
|
||||||
|
## List of Cheat Codes
|
||||||
|
|
||||||
|
### Spells
|
||||||
|
|
||||||
|
`nwcthereisnospoon` or `vcmiistari` or `vcmispells` - give a spell book, all spells and 999 mana to currently selected hero
|
||||||
|
|
||||||
|
### Army
|
||||||
|
|
||||||
|
`nwctrinity` or `vcmiainur` or `vcmiarchangel` - give 5 Archangels in every empty slot (to currently selected hero)
|
||||||
|
`nwcagents` or `vcmiangband` or `vcmiblackknight` - give 10 black knight in every empty slot
|
||||||
|
`vcmiglaurung` or `vcmicrystal` - give 5000 crystal dragons in every empty slot
|
||||||
|
`vcmiazure` - give 5000 azure dragons in every empty slot
|
||||||
|
`vcmifaerie` - give 5000 faerie dragons in every empty slot
|
||||||
|
|
||||||
|
Alternative usage: `vcmiarmy <creatureID> <amount>`
|
||||||
|
Gives specific creature in every slot, with optional amount. Examples:
|
||||||
|
`vcmiarmy imp` - give 5, 50, 500... 500k imps in every free slot
|
||||||
|
`vcmiarmy grandElf 100` - gives 100 grand elves in every free slot
|
||||||
|
|
||||||
|
### Town buildings
|
||||||
|
|
||||||
|
`nwczion` or `vcmiarmenelos` or `vcmibuild` - build all buildings in currently selected town
|
||||||
|
|
||||||
|
### Artifacts
|
||||||
|
|
||||||
|
`nwclotsofguns` or `vcminoldor` or `vcmimachines` - give ballista, ammo cart and first aid tent
|
||||||
|
`vcmiforgeofnoldorking` or `vcmiartifacts` - give all artifacts, except spell book, spell scrolls and war machines. Artifacts added via mods included
|
||||||
|
|
||||||
|
### Movement points
|
||||||
|
|
||||||
|
`nwcnebuchadnezzar` or `vcminahar` or `vcmimove` - give 1000000 movement points and free ship boarding for 1 day
|
||||||
|
Alternative usage: `vcmimove <amount>` - gives specified amount of movement points
|
||||||
|
|
||||||
|
### Resources
|
||||||
|
|
||||||
|
`nwctheconstruct` or `vcmiformenos` or `vcmiresources` - give resources (100000 gold, 100 of wood, ore and rare resources)
|
||||||
|
Alternative usage: `vcmiresources <amount>` - gives specified amount of all resources and x1000 of gold
|
||||||
|
|
||||||
|
### Fog of War
|
||||||
|
|
||||||
|
`nwcwhatisthematrix` or `vcmieagles` or `vcmimap` - reveal Fog of War
|
||||||
|
`nwcignoranceisbliss` or `vcmiungoliant` or `vcmihidemap` - conceal Fog of War
|
||||||
|
|
||||||
|
### Experience
|
||||||
|
|
||||||
|
`nwcneo` or `vcmiglorfindel` or `vcmilevel` - advances currently selected hero to the next level
|
||||||
|
Alternative usage: `vcmilevel <amount>` - advances hero by specified number of levels
|
||||||
|
|
||||||
|
- `vcmiolorin` or `vcmiexp` - gives selected hero 10000 experience
|
||||||
|
Alternative usage: `vcmiexp <amount>` - gives selected hero specified amount of experience
|
||||||
|
|
||||||
|
### Finishing the game
|
||||||
|
|
||||||
|
`nwcredpill` or `vcmisilmaril` or `vcmiwin` - player wins
|
||||||
|
`nwcbluepill` or `vcmimelkor` or `vcmilose` - player loses
|
||||||
|
|
||||||
|
## Using cheat codes on other players
|
||||||
|
By default, all cheat codes apply to current player. Alternatively, it is possible to specify player that you want to target:
|
||||||
|
|
||||||
|
- Specific players: `red`/`blue`/`green`...
|
||||||
|
- Only AI players: `ai`
|
||||||
|
- All players: `all`
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
`vcmieagles blue` - reveal FoW only for blue player
|
||||||
|
`vcmieagles ai` - reveal FoW only for AI players
|
||||||
|
`vcmieagles all` - reveal FoW for all players on map
|
||||||
|
`vcminahar ai` - give 1000000 movement points to each hero of every AI player
|
||||||
|
|
||||||
|
## Multiplayer chat commands
|
||||||
|
Note: These commands are not a cheats, and can be used in multiplayer by host player to control the session
|
||||||
|
|
||||||
|
- `game exit/quit/end` - finish the game
|
||||||
|
- `game save <filename>` - save the game into the specified file
|
||||||
|
- `game kick red/blue/tan/green/orange/purple/teal/pink` - kick player of specified color from the game
|
||||||
|
- `game kick 0/1/2/3/4/5/6/7/8` - kick player of specified ID from the game (_zero indexed!_) (`0: red, 1: blue, tan: 2, green: 3, orange: 4, purple: 5, teal: 6, pink: 7`)
|
||||||
|
|
||||||
|
|
||||||
|
# Client Commands
|
||||||
|
|
||||||
|
Client commands are set of predefined commands that are supported by VCMI, but unlike cheats they perform utility actions that do not alter state of the gameplay. As of release 1.2 client commands can work by typing them in-game like cheats, preceded by symbol / (for example `/controlai blue`)
|
||||||
|
|
||||||
|
Alternative way, the only one working for older releases is typing them in console:
|
||||||
|
Console is separated from game window on desktop versions of VCMI Client.
|
||||||
|
Windows builds of VCMI run separate console window by default, on other platforms you can access it by running VCMI Client from command line.
|
||||||
|
|
||||||
|
Below a list of supported commands, with their arguments wrapped in `<>`
|
||||||
|
|
||||||
|
#### Game Commands
|
||||||
|
`die, fool` - quits game
|
||||||
|
`save <filename>` - saves game in given file (at the moment doesn't work)
|
||||||
|
`mp` - on adventure map with a hero selected, shows heroes current movement points, max movement points on land and on water
|
||||||
|
`bonuses` - shows bonuses of currently selected adventure map object
|
||||||
|
|
||||||
|
#### Extract commands
|
||||||
|
`convert txt` - save game texts into json files
|
||||||
|
`get config` - save game objects data into json files
|
||||||
|
`get scripts` - dumps lua script stuff into files (currently inactive due to scripting disabled for default builds)
|
||||||
|
`get txt` - save game texts into .txt files matching original heroes 3 files
|
||||||
|
`def2bmp <.def file name>` - extract .def animation as BMP files
|
||||||
|
`extract <relative file path>` - export file into directory used by other extraction commands
|
||||||
|
|
||||||
|
#### AI commands
|
||||||
|
`setBattleAI <ai name>` - change battle AI used by neutral creatures to the one specified, persists through game quit
|
||||||
|
`gosolo` - AI takes over until the end of turn (unlike original H3 currently causes AI to take over until typed again)
|
||||||
|
`controlai <[red][blue][tan][green][orange][purple][teal][pink]>` - gives you control over specified AI player. If none is specified gives you control over all AI players
|
||||||
|
`autoskip` - Toggles autoskip mode on and off. In this mode, player turns are automatically skipped and only AI moves. However, GUI is still present and allows to observe AI moves. After this option is activated, you need to end first turn manually. Press `[Shift]` before your turn starts to not skip it
|
||||||
|
|
||||||
|
#### Settings
|
||||||
|
`set <command> <on/off>` - sets special temporary settings that reset on game quit. Below some of the most notable commands:
|
||||||
|
-`autoskip` - identical to `autoskip` option
|
||||||
|
-`onlyAI` - run without human player, all players will be _default AI_
|
||||||
|
-`headless` - run without GUI, implies `onlyAI` is set
|
||||||
|
-`showGrid` - display a square grid overlay on top of adventure map
|
||||||
|
-`showBlocked` - show blocked tiles on map
|
||||||
|
-`showVisitable` - show visitable tiles on map
|
||||||
|
-`hideSystemMessages` - suppress server messages in chat
|
||||||
|
|
||||||
|
#### Developer Commands
|
||||||
|
`crash` - force a game crash. It is sometimes useful to generate memory dump file in certain situations, for example game freeze
|
||||||
|
`gui` - displays tree view of currently present VCMI common GUI elements
|
||||||
|
`activate <0/1/2>` - activate game windows (no current use, apparently broken long ago)
|
||||||
|
`redraw` - force full graphical redraw
|
||||||
|
`screen` - show value of screenBuf variable, which prints "screen" when adventure map has current focus, "screen2" otherwise, and dumps values of both screen surfaces to .bmp files
|
||||||
|
`unlock pim` - unlocks specific mutex known in VCMI code as "pim"
|
||||||
|
`not dialog` - set the state indicating if dialog box is active to "no"
|
||||||
|
`tell hs <hero ID> <artifact slot ID>` - write what artifact is present on artifact slot with specified ID for hero with specified ID. (must be called during gameplay)
|
47
docs/players/Game_Mechanics.md
Normal file
47
docs/players/Game_Mechanics.md
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
< [Documentation](../Readme.md) / Game Mechanics
|
||||||
|
|
||||||
|
# List of features added in VCMI
|
||||||
|
|
||||||
|
Some of game features have already been extended in comparison to Shadow of Death:
|
||||||
|
|
||||||
|
- Support for 32-bit graphics with alpha channel. Supported formats are .def, .bmp, .png and .tga
|
||||||
|
- Support for maps of any size, including rectangular shapes
|
||||||
|
- No limit of number of map objects, such as dwellings and stat boosters
|
||||||
|
- Hero experience capacity currently at 2^64, which equals 199 levels with typical progression
|
||||||
|
- Heroes can have primary stats up to 2^16
|
||||||
|
- Unlimited backpack
|
||||||
|
- Support for Stack Experience
|
||||||
|
|
||||||
|
The list of implemented cheat codes and console commands is [here](Cheat_codes.md).
|
||||||
|
|
||||||
|
# List of bugs fixed in VCMI
|
||||||
|
|
||||||
|
These bugs were present in original Shadow of Death game, however the team decided to fix them to bring back desired behaviour:
|
||||||
|
|
||||||
|
# List of game mechanics changes
|
||||||
|
|
||||||
|
Some of H3 mechanics can't be straight considered as bug, but default VCMI behaviour is different:
|
||||||
|
|
||||||
|
- Pathfinding. Hero can't grab artifact while flying when all tiles around it are guarded without triggering attack from guard.
|
||||||
|
- Battles. Hero that won battle, but only have temporary summoned creatures alive going to appear in tavern like if he retreated.
|
||||||
|
- Battles. Spells from artifacts like AOTD are autocasted on beginning of the battle, not beginning of turn.
|
||||||
|
- Spells. Dimension Door spell doesn't allow to teleport to unexplored tiles.
|
||||||
|
|
||||||
|
# List of extended game functionality
|
||||||
|
|
||||||
|
## Quick Army Management
|
||||||
|
|
||||||
|
- [LShift] + LClick – splits a half units from the selected stack into an empty slot.
|
||||||
|
- [LCtrl] + LClick – splits a single unit from the selected stack into an empty slot.
|
||||||
|
- [LCtrl] + [LShift] + LClick – split single units from the selected stack into all empty hero/garrison slots
|
||||||
|
- [Alt] + LClick – merge all splitted single units into one stack
|
||||||
|
- [Alt] + [LCtrl] + LClick - move all units of selected stack to the city's garrison or to the met hero
|
||||||
|
- [Alt] + [LShift] + LClick - dismiss selected stack`
|
||||||
|
|
||||||
|
## Quick Recruitment
|
||||||
|
|
||||||
|
Mouse click on castle icon in the town screen open quick recruitment window, where we can purhase in fast way units.
|
||||||
|
|
||||||
|
# Manuals and guides
|
||||||
|
|
||||||
|
- https://heroes.thelazy.net//index.php/Main_Page Wiki that aims to be a complete reference to Heroes of Might and Magic III.
|
42
docs/players/Installation_Android.md
Normal file
42
docs/players/Installation_Android.md
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
< [Documentation](../Readme.md) / Installation on Android
|
||||||
|
|
||||||
|
## Step 1: Download and install VCMI
|
||||||
|
|
||||||
|
**This app requires original heroes 3 sod / complete files to operate, they are not supplied with this installer. it is recommended to purchase version from gog.com. Heroes 3 "hd edition" (steam version) files are not supported !!!**
|
||||||
|
Installation is a two step process, at first you need to install game, then you need to upload Heroes3 original data files into your android device.
|
||||||
|
|
||||||
|
- Latest release on Google Play (recommended): <https://play.google.com/store/apps/details?id=is.xyz.vcmi>
|
||||||
|
- Latest release as .apk file: <https://github.com/vcmi/vcmi/releases/latest>
|
||||||
|
- Daily builds (unstable): <https://builds.vcmi.download/branch/develop/Android/>
|
||||||
|
|
||||||
|
## Step 2: Installing Heroes III data files
|
||||||
|
|
||||||
|
- Install Heroes III on your PC or extract Heroes III data files from gog installer
|
||||||
|
- Connect your device to PC and enable file transfer.
|
||||||
|
- Copy "Data", "Maps" and "Mp3" from Heroes III to any folder on mobile device, then open VCMI, select Heroes III data import option, then select the folder where you copied Heroes III data.
|
||||||
|
|
||||||
|
## Troubleshooting / known issues
|
||||||
|
|
||||||
|
### The game crashes on start
|
||||||
|
|
||||||
|
**Please double check that you copied original SoD/Complete game files into your Android Device**
|
||||||
|
|
||||||
|
### I imported game data files, but music in game is missing
|
||||||
|
|
||||||
|
**Solution:** Try to run data import again or copy Mp3 folder from Heroes III manually to Android/data/is.xyz.vcmi/files/vcmi-data/Mp3
|
||||||
|
|
||||||
|
### I installed google play version, but have a problem while installing daily builds
|
||||||
|
|
||||||
|
**Solution:** Uninstall google play version first, before installing daily build version.
|
||||||
|
|
||||||
|
### I installed play version, but the screen is flashing / blank on its edges
|
||||||
|
|
||||||
|
**Solution:** Update app to latest version
|
||||||
|
|
||||||
|
### The game always starts in 800x600 resolution, cannot effectively change it, also there is a lot of blank space on my widescreen device
|
||||||
|
|
||||||
|
**Solution:** Update app to latest version
|
||||||
|
|
||||||
|
## Other problems
|
||||||
|
|
||||||
|
Please report about gameplay problem: [Github](https://github.com/vcmi/vcmi/issues), [Help & Bugs](https://forum.vcmi.eu/c/international-board/help-bugs) or [Discord](https://discord.gg/chBT42V). Make sure to specify your device and used version of Android.
|
121
docs/players/Installation_Linux.md
Normal file
121
docs/players/Installation_Linux.md
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
< [Documentation](../Readme.md) / Installation on Linux
|
||||||
|
|
||||||
|
VCMI requires data from original Heroes 3: Shadow of Death or Complete editions. Data from native Linux version made by LOKI will not work.
|
||||||
|
|
||||||
|
# Step 1: Binaries installation
|
||||||
|
|
||||||
|
## Ubuntu
|
||||||
|
|
||||||
|
### Latest stable build from PPA (recommended)
|
||||||
|
|
||||||
|
Up-to-date releases can be found in our PPA here: <https://launchpad.net/~vcmi/+archive/ubuntu/ppa>
|
||||||
|
|
||||||
|
To install VCMI from PPA use:
|
||||||
|
```
|
||||||
|
sudo apt-add-repository ppa:vcmi/ppa
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install vcmi
|
||||||
|
```
|
||||||
|
|
||||||
|
### Unstable testing build from PPA
|
||||||
|
|
||||||
|
We also provide latest, unstable builds mostly suitable for testing here: <https://launchpad.net/~vcmi/+archive/ubuntu/vcmi-latest>
|
||||||
|
|
||||||
|
In order to install from this PPA use:
|
||||||
|
```
|
||||||
|
sudo add-apt-repository ppa:vcmi/vcmi-latest
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install vcmi
|
||||||
|
```
|
||||||
|
### From Ubuntu repository
|
||||||
|
|
||||||
|
VCMI stable builds available in "multiverse" repository. Learn how to enable it in [Ubuntu wiki](https://help.ubuntu.com/community/Repositories/Ubuntu).
|
||||||
|
Once enabled, you can install VCMI using Ubuntu Store or in terminal using following commands:
|
||||||
|
```
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install vcmi
|
||||||
|
```
|
||||||
|
Note that version available in Ubuntu is outdated. Install via PPA is preferred.
|
||||||
|
|
||||||
|
## Debian
|
||||||
|
|
||||||
|
Stable VCMI version is available in "contrib" repository. Learn how to enable it in [Debian wiki](https://wiki.debian.org/SourcesList).
|
||||||
|
To install VCMI from repository:
|
||||||
|
```
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install vcmi
|
||||||
|
```
|
||||||
|
## Flatpak (distribution-agnostic)
|
||||||
|
|
||||||
|
Latest public release build can be installed via Flatpak.
|
||||||
|
|
||||||
|
Depending on your distribution, you may need to install flatpak itself. You can find guide for your distribution here: <https://www.flatpak.org/setup/>
|
||||||
|
Once you have flatpak, you can install VCMI package which can be found here: <https://flathub.org/apps/details/eu.vcmi.VCMI>
|
||||||
|
|
||||||
|
## Other distributions
|
||||||
|
|
||||||
|
For other distributions, VCMI can be installed from 3rd-party repositories listed below. Note that these repositories are not supported by vcmi team and may not be up to date.
|
||||||
|
|
||||||
|
- Archlinux [vcmi](https://aur.archlinux.org/packages/vcmi/) [vcmi-git](https://aur.archlinux.org/packages/vcmi-git/)
|
||||||
|
- openSUSE [1 Click Install](https://software.opensuse.org/download.html?project=games&package=vcmi)
|
||||||
|
|
||||||
|
If you are interested in providing builds for other distributions, please let us know.
|
||||||
|
|
||||||
|
## Compiling from source
|
||||||
|
|
||||||
|
Please check following developer guide: [How to build VCMI (Linux)]((../developers/Building_Linux.md))
|
||||||
|
|
||||||
|
# Step 2: Installing Heroes III data files
|
||||||
|
|
||||||
|
To install VCMI you will need Heroes III: Shadow of Death or Complete edition.
|
||||||
|
|
||||||
|
## Install data using vcmibuilder script
|
||||||
|
|
||||||
|
Recommended for non-Flatpak installs.
|
||||||
|
|
||||||
|
To install Heroes 3 data using automated script you need any of:
|
||||||
|
|
||||||
|
- Offline Installer downloaded from gog.com (both .exe and .bin files are required)
|
||||||
|
- Directory with preinstalled game
|
||||||
|
- One or two CD's or CD images
|
||||||
|
|
||||||
|
Run the script using options appropriate to your input files:
|
||||||
|
```
|
||||||
|
vcmibuilder --cd1 /path/to/iso/or/cd --cd2 /path/to/second/cd
|
||||||
|
vcmibuilder --gog /path/to/gog.com/installer.exe
|
||||||
|
vcmibuilder --data /path/to/h3/data
|
||||||
|
```
|
||||||
|
You should use only one of these commands.
|
||||||
|
|
||||||
|
On flatpak install, it's also possible to run the script, but any path seems to be interpreted from within the Flatpak sandbox:
|
||||||
|
|
||||||
|
```
|
||||||
|
flatpak run --command=vcmibuilder eu.vcmi.VCMI --data /path/to/h3/data`
|
||||||
|
```
|
||||||
|
|
||||||
|
## Install data using gog.com offline installer
|
||||||
|
|
||||||
|
Download both files for the "offline backup game installers" and extract them using innoextract tool
|
||||||
|
```
|
||||||
|
innoextract --output-dir=~/Downloads/HoMM3 "setup_heroes_of_might_and_magic_3_complete_4.0_(28740).exe"
|
||||||
|
```
|
||||||
|
(note that installer file name might be different)
|
||||||
|
|
||||||
|
Once innoextract completes, start VCMI Launcher and choose to copy existing files. Select the ~/Downloads/HoMM3 directory. Once copy is complete, you can delete both offline installer files as well as ~/Downloads/HoMM3.
|
||||||
|
|
||||||
|
## Install manually using existing Heroes III data
|
||||||
|
|
||||||
|
Copy "Data", "Maps" and "Mp3" from Heroes III to `$HOME/.local/share/vcmi/`
|
||||||
|
Or, in case of flatpak install to `$HOME/.var/app/eu.vcmi.VCMI/data/vcmi/`
|
||||||
|
On some distributions $XDG_DATA_HOME could differ so instead you may need to use: `$XDG_DATA_HOME/vcmi/`
|
||||||
|
|
||||||
|
# Step 3: Launching game
|
||||||
|
|
||||||
|
VCMI should be available via desktop environment menu or launcher (Games/Strategy/VCMI)
|
||||||
|
|
||||||
|
To start the game type in console: `vcmilauncher`
|
||||||
|
Or, to start game directly avoiding Launcher: `vcmiclient`
|
||||||
|
|
||||||
|
# Reporting bugs
|
||||||
|
|
||||||
|
Please report any issues with packages according to [Bug Reporting Guidelines](Bug_Reporting_Guidelines.md)
|
27
docs/players/Installation_Windows.md
Normal file
27
docs/players/Installation_Windows.md
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
< [Documentation](../Readme.md) / Installation on Windows
|
||||||
|
|
||||||
|
# Prerequisites
|
||||||
|
|
||||||
|
As of VCMI 1.2 and newer Windows 10 or newer is required since our automated system uses elements incompatible with older Windows.
|
||||||
|
|
||||||
|
# Step 1: Download and install VCMI
|
||||||
|
|
||||||
|
Install one of following into new folder, same as when installing new game:
|
||||||
|
|
||||||
|
- Latest release (recommended): <https://github.com/vcmi/vcmi/releases/latest>
|
||||||
|
- Daily builds (unstable): <https://builds.vcmi.download/branch/develop/Windows/>
|
||||||
|
- Please report about problems on GitHub: [Bug Tracker](https://github.com/vcmi/vcmi/issues)
|
||||||
|
|
||||||
|
# Step 2: Installing Heroes III data files
|
||||||
|
|
||||||
|
**Since VCMI 1.2 you can skip this step, just run VCMI launcher and it will help you with importing H3 data. For older releases you can follow this step.**
|
||||||
|
|
||||||
|
- Install Heroes III from disk or using GOG installer.
|
||||||
|
- Copy "Data", "Maps" and "Mp3" from Heroes III to: `Documents\My Games\vcmi\`
|
||||||
|
|
||||||
|
Create this folder if it doesnt exist yet
|
||||||
|
|
||||||
|
# Step 3: connect to the mod repository
|
||||||
|
|
||||||
|
- If that's your first installation, connection to the mod repository will be configured automatically, you'll see mods available to install from VCMI launcher -
|
||||||
|
- We recommend you to install VCMI extras to support various helpful UI tweaks
|
58
docs/players/Installation_iOS.md
Normal file
58
docs/players/Installation_iOS.md
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
< [Documentation](../Readme.md) / Installation on iOS
|
||||||
|
|
||||||
|
You can run VCMI on iOS 12.0 and later, all devices are supported. If you wish to run on iOS 10 or 11, you should build from source, see [How to build VCMI (iOS)](../developers/Building_iOS.md).
|
||||||
|
|
||||||
|
## Step 1: Download and install VCMI
|
||||||
|
|
||||||
|
- The latest release (recommended): <https://github.com/vcmi/vcmi/releases/latest>
|
||||||
|
- Daily builds: <https://builds.vcmi.download/branch/develop/iOS/>
|
||||||
|
|
||||||
|
To run on a non-jailbroken device you need to sign the IPA file, you
|
||||||
|
have the following options:
|
||||||
|
|
||||||
|
- (Easiest way) [AltStore](https://altstore.io/) or [Sideloadly](https://sideloadly.io/) - can be installed on Windows or macOS, don't require dealing with signing on your own
|
||||||
|
- if you're on iOS 14.0-15.4.1, you can try <https://github.com/opa334/TrollStore>
|
||||||
|
- Get signer tool [here](https://dantheman827.github.io/ios-app-signer/) and a guide [here](https://forum.kodi.tv/showthread.php?tid=245978) (it's for Kodi, but the logic is the same). Signing with this app can only be done on macOS.
|
||||||
|
- [Create signing assets on macOS from terminal](https://github.com/kambala-decapitator/xcode-auto-signing-assets). In the command replace `your.bundle.id` with something like `com.MY-NAME.vcmi`. After that use the above signer tool.
|
||||||
|
- [Sign from any OS](https://github.com/indygreg/PyOxidizer/tree/main/tugger-code-signing). You'd still need to find a way to create signing assets (private key and provisioning profile) though.
|
||||||
|
|
||||||
|
## Step 2: Installing Heroes III data files
|
||||||
|
|
||||||
|
Note: if you don't need in-game videos, you can omit downloading/copying file VIDEO.VID from data folder - it will save your time and space. The same applies to the Mp3 directory.
|
||||||
|
|
||||||
|
### Step 2.a: Installing data files with Finder or Windows explorer
|
||||||
|
|
||||||
|
To play the game, you need to upload HoMM3 data files - **Data**, **Maps** and **Mp3** directories - to the device. Use Finder (or iTunes, if you're on Windows or your macOS is 10.14 or earlier) for that. You can also add various mods by uploading **Mods** directory. Follow [official Apple guide](https://support.apple.com/en-us/HT210598) and place files into VCMI app. Unfortunately, Finder doesn't display copy progress, give it about 10 minutes to finish.
|
||||||
|
|
||||||
|
### Step 2.b: Installing data files using iOS device only
|
||||||
|
|
||||||
|
If you have data somewhere on device or in shared folder or you have downloaded it, you can copy it directly on your iPhone/iPad using Files application.
|
||||||
|
|
||||||
|
Move or copy **Data**, **Maps** and **Mp3** folders into vcmi application - it will be visible in Files along with other applications' folders.
|
||||||
|
|
||||||
|
### Step 2.c: Installing data files with Xcode on macOS
|
||||||
|
|
||||||
|
You can also upload files with Xcode. You need to prepare "container" for that.
|
||||||
|
|
||||||
|
1. Connect your device to your Mac
|
||||||
|
2. Start Xcode
|
||||||
|
3. Open Devices and Simulators window: Cmd+Shift+2 or Menu - Window - Devices and Simulators
|
||||||
|
4. Select your device
|
||||||
|
5. Select VCMI
|
||||||
|
6. In the bottom find "three dots" or "cogwheel" button (it should be next to + - buttons) - click it - select Download Container...
|
||||||
|
7. Place the game directories inside the downloaded container - AppData - Documents
|
||||||
|
8. Click the "three dots" / "cogwheel" button in Xcode again - Replace Container... - select the downloaded container
|
||||||
|
9. Wait until Xcode finishes copying, progress is visible (although it might be "indefinite")
|
||||||
|
|
||||||
|
## Game controls
|
||||||
|
|
||||||
|
- Tap: left click
|
||||||
|
- Tap and hold (long press): right click
|
||||||
|
- Tap in the bottom area (status bar): activate chat/console in the game
|
||||||
|
|
||||||
|
You can start game directly (avoiding the launcher) by changing setting in iOS Settings app - VCMI.
|
||||||
|
|
||||||
|
## Reporting bugs
|
||||||
|
|
||||||
|
- Please report about gameplay problem on forums: [Help & Bugs](https://forum.vcmi.eu/c/international-board/help-bugs)
|
||||||
|
- Please report iOS-specific issues in [this forum thread](https://forum.vcmi.eu/t/ios-port/820) or (better) at [GitHub](https://github.com/vcmi/vcmi/issues) with **iOS** label
|
19
docs/players/Installation_macOS.md
Normal file
19
docs/players/Installation_macOS.md
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
< [Documentation](../Readme.md) / Installation on macOS
|
||||||
|
|
||||||
|
**For iOS installation look here: (Installation on iOS)[Installation_iOS.md]
|
||||||
|
|
||||||
|
# Step 1: Download and install VCMI
|
||||||
|
|
||||||
|
- The latest release (recommended): <https://github.com/vcmi/vcmi/releases/latest>
|
||||||
|
- Daily builds (might be unstable)
|
||||||
|
- Intel (x86_64) builds: <https://builds.vcmi.download/branch/develop/macOS/intel>
|
||||||
|
- Apple Silicon (arm64) builds: <https://builds.vcmi.download/branch/develop/macOS/arm>
|
||||||
|
|
||||||
|
If the app doesn't open, right-click the app bundle - select *Open* menu item - press *Open* button.
|
||||||
|
|
||||||
|
Please report about gameplay problem on forums: [Help & Bugs](https://forum.vcmi.eu/c/international-board/help-bugs) Make sure to specify what hardware and macOS version you use.
|
||||||
|
|
||||||
|
# Step 2: Installing Heroes III data files
|
||||||
|
|
||||||
|
1. Find a way to unpack Windows Heroes III or GOG installer. For example, use `vcmibuilder` script inside app bundle or install the game with [CrossOver](https://www.codeweavers.com/crossover) or [Wineskin](https://github.com/Gcenx/WineskinServer).
|
||||||
|
2. Copy (or symlink) **Data**, **Maps** and **Mp3** directories from Heroes III to:`~/Library/Application\ Support/vcmi/`
|
168
docs/players/Manual.md
Normal file
168
docs/players/Manual.md
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
< [Documentation](../Readme.md) / Manual
|
||||||
|
|
||||||
|
# Introduction
|
||||||
|
|
||||||
|
The purpose of VCMI project is to rewrite entire HoMM3: WoG engine from scratch, giving it new and extended possibilities. We are hoping to support mods and new towns already made by fans, but abandoned because of game code limitations.
|
||||||
|
VCMI is a fan-made open-source project in progress. We already allow support for maps of any sizes, higher resolutions and extended engine limits. However, although working, the game is not finished. There are still many features and functionalities to add, both old and brand new.
|
||||||
|
|
||||||
|
# Installation
|
||||||
|
|
||||||
|
VCMI requires Heroes of Might & Magic 3 complete installation and will not run properly without their files.
|
||||||
|
|
||||||
|
## Windows
|
||||||
|
|
||||||
|
To install VCMI, simply unzip downloaded archive to main HoMM3 directory. To launch it, click `VCMI_client` icon. Server mode is inactive yet.
|
||||||
|
|
||||||
|
## Linux
|
||||||
|
|
||||||
|
Visit [Installation on Linux](Installation_Linux.md) for Linux packages and installation guidelines.
|
||||||
|
|
||||||
|
# New features
|
||||||
|
|
||||||
|
A number of enchancements had been introduced thorough new versions of VCMI. In this section you can learn about all of them.
|
||||||
|
|
||||||
|
## High resolutions
|
||||||
|
|
||||||
|
VCMI supports resolutions higher than original 800x600.
|
||||||
|
Switching resolution may not only change visible area of map, but also alters some interface features such as [Stack Queue.](#Stack_Queue)
|
||||||
|
To change resolution or full screen mode use System Options menu when in game. Fullscreen mode can be toggled anytime using F4 hotkey.
|
||||||
|
|
||||||
|
## Stack Experience
|
||||||
|
|
||||||
|
In 0.85, new stack experience interface has been merged with regular creature window. Among old functionalities, it includes new useful info:
|
||||||
|
|
||||||
|
- Click experience icon to see detailed info about creature rank and experience needed for next level. This window works only if stack experience module is enabled (true by default).
|
||||||
|
- Stack Artifact. As yet creature artifacts are not handled, so this place is unused. You can choose enabled artifact with arrow buttons. There is also additional button below to pass currently selected artifact back to hero.
|
||||||
|
- Abilities description contain information about actual values and types of bonuses received by creature - be it default ability, stack experience, artifact or other effect. These descriptions use custom text files which have not been translated.
|
||||||
|
|
||||||
|
## Commanders
|
||||||
|
|
||||||
|
VCMI offers native support for Commanders. By default, they resemble original WoG behaviour with basic "Commanders" script enabled.
|
||||||
|
|
||||||
|
## Stack Queue
|
||||||
|
|
||||||
|
Stack queue is a feature coming straight from HoMM5, which allows you to see order of stacks on the battlefield, sorted from left to right. To toggle in on/off, press 'Q' during the battle. There is smaller and bigger version of it, the second one is available only in higher resolutions.
|
||||||
|
|
||||||
|
## Pathfinder
|
||||||
|
|
||||||
|
VCMI introduces improved pathfinder, which may find the way on adventure map using ships and subterranean gates. Simply click your destination on another island or level and the proposed path will be displayed.
|
||||||
|
|
||||||
|
## Quest log
|
||||||
|
|
||||||
|
In 0.9 new quest log was introduced. It can display info about Seer Hut or Quest Guard mission, but also handle Borderguard and Border Gate missions. When you choose a quest from the list on the left, it's description is shown. Additionally, on inner minimap you can see small icons indicating locations of quest object. Clicking these objects immediately centers adventure map on desired location.
|
||||||
|
|
||||||
|
## Attack range
|
||||||
|
|
||||||
|
In combat, some creatures, such as Dragon or Cerberi, may attack enemies on multiple hexes. All such attacked stacks will be highlighted if the attack cursor is hovered over correct destination tile. Whenever battle stack is hovered, its movement range is highlighted in darker shade. This can help when you try to avoid attacks of melee units.
|
||||||
|
|
||||||
|
## Power rating
|
||||||
|
|
||||||
|
When hovering cursor over neutral stack on adventure map, you may notice additional info about relative threat this stack poses to selected hero. This feature has been introduced in Heroes of Might and Magic V and is planned to be extended to all kinds of armed objects.
|
||||||
|
|
||||||
|
## FPS counter
|
||||||
|
|
||||||
|
VCMI 0.85 introduces new feature for testing, the FPS counter.
|
||||||
|
|
||||||
|
## Minor improvements
|
||||||
|
|
||||||
|
## New controls
|
||||||
|
|
||||||
|
VCMI introduces several minor improvements and new keybinds in user
|
||||||
|
interface.
|
||||||
|
|
||||||
|
### Pregame - Scenario / Saved Game list
|
||||||
|
|
||||||
|
- Mouse wheel - scroll through the Scenario list.
|
||||||
|
- Home - move to the top of the list.
|
||||||
|
- End - move to the bottom of the list.
|
||||||
|
- NumPad keys can be used in the Save Game screen (they didn't work in H3).
|
||||||
|
|
||||||
|
### Adventure Map
|
||||||
|
|
||||||
|
- CTRL + R - Quick restart of current scenario.
|
||||||
|
- CTRL + Arrows - scrolls Adventure Map behind an open window.
|
||||||
|
- CTRL pressed blocks Adventure Map scrolling (it allows us to leave the application window without losing current focus).
|
||||||
|
- NumPad 5 - centers view on selected hero.
|
||||||
|
- NumPad Enter functions same as normal Enter in the game (it didn't in H3).
|
||||||
|
|
||||||
|
### Miscellaneous
|
||||||
|
|
||||||
|
- Numbers for components in selection window - for example Treasure Chest, skill choice dialog and more yet to come.
|
||||||
|
- Type numbers in the Split Stack screen (for example 25 will split the stacks as such that there are 25 creatures in the second stack).
|
||||||
|
- 'Q' - Toggles the [Stack Queue](#Stack_Queue) display (so it can be enabled/disabled with single key press).
|
||||||
|
- During Tactics phase, click on any of your stack to instantly activate it. No need to scroll trough entire army anymore.
|
||||||
|
|
||||||
|
## Cheat codes
|
||||||
|
|
||||||
|
Following cheat codes have been implemented in VCMI. Type them in console:
|
||||||
|
|
||||||
|
- `vcmiistari` - Gives all spells and 999 mana to currently selected hero
|
||||||
|
- `vcmiainur` - Gives 5 Archangels to every empty slot of currently selected hero
|
||||||
|
- `vcmiangband` - Gives 10 Black Knights into each slot
|
||||||
|
- `vcmiarmenelos` - Build all structures in currently selected town
|
||||||
|
- `vcminoldor` - All war machines
|
||||||
|
- `vcminahar` - 1000000 movement points
|
||||||
|
- `vcmiformenos` - Give resources (100 wood, ore and rare resources and 20000 gold)
|
||||||
|
- `vcmieagles` - Reveals fog of war
|
||||||
|
- `vcmiglorfindel` - Advances currently selected hero to the next level
|
||||||
|
- `vcmisilmaril` - Player wins
|
||||||
|
- `vcmimelkor` - Player loses
|
||||||
|
- `vcmiforgeofnoldorking` - Hero gets all artifacts except spell book, spell scrolls and war machines
|
||||||
|
|
||||||
|
# Feedback
|
||||||
|
|
||||||
|
Our project is open and its sources are available for everyone to browse and download. We do our best to inform community of Heroes fans with all the details and development progress. We also look forward to your comments, support and advice.\
|
||||||
|
A good place to start is [VCMI Documentation](../Readme.md) which contains all necessary information for developers, testers and the people who would like to get familiar with our project. If you want to report a bug, use [Mantis Bugtracker](http://bugs.vcmi.eu/bug_report_advanced_page.php).
|
||||||
|
Make sure the issue is not already mentioned on [the list](http://bugs.vcmi.eu/view_all_bug_page.php) unless you can provide additional details for it. Please do not report as bugs features not yet implemented. For proposing new ideas and requests, visit [our board](http://forum.vcmi.eu/index.php).
|
||||||
|
VCMI comes with its own bug handlers: the console which prints game log `(server_log, VCMI_Client_log, VCMI_Server_log)` and memory dump file (`.dmp`) created on crash on Windows systems. These may be very helpful when the nature of bug is not obvious, please attach them if necessary.
|
||||||
|
To resolve an issue, we must be able to reproduce it on our computers. Please put down all circumstances in which a bug occurred and what did you do before, especially if it happens rarely or is not clearly visible. The better report, the better chance to track the bug quickly.
|
||||||
|
|
||||||
|
# FAQ
|
||||||
|
|
||||||
|
### What does "VCMI" stand for?
|
||||||
|
|
||||||
|
VCMI is an acronym of the [Quenya](https://en.wikipedia.org/wiki/Quenya) phrase "Vinyar Callor Meletya Ingole", meaning "New Heroes of Might and Magic". ([Source](https://forum.vcmi.eu/t/what-vcmi-stands-for/297/4))
|
||||||
|
|
||||||
|
## How to turn off creature queue panel in battles?
|
||||||
|
|
||||||
|
Hotkey to switch this panel is "Q"
|
||||||
|
|
||||||
|
### Is it possible to add town X to vcmi?
|
||||||
|
|
||||||
|
This depends on town authors or anyone else willing to port it to vcmi. Aim of VCMI is to provide *support* for such features.
|
||||||
|
|
||||||
|
## When will the final version be released?
|
||||||
|
|
||||||
|
When it is finished, which is another year at least. Exact date is impossible to predict. Development tempo depends mostly on free time of active programmers and community members, there is no exact shedule. You may expect new version every three months. Of course, joining the project will speed things up.
|
||||||
|
|
||||||
|
## Are you going to add / change X?
|
||||||
|
|
||||||
|
VCMI recreates basic H3:SoD engine and does not add new content or modify original mechanics by default. Only engine and interface improvements are likely to be supported now. If you want something specific to be done, please present detailed project on [our board](http://forum.vcmi.eu/index.php). Of course you are free to contribute with anything you can do.
|
||||||
|
|
||||||
|
## Will it be possible to do Y?
|
||||||
|
|
||||||
|
Removing engine restrictions and allowing flexible modding of game is the main aim of the project. As yet modification of game is not supported.
|
||||||
|
|
||||||
|
## The game is not working, it crashes and I get strange console messages.
|
||||||
|
|
||||||
|
Report your bug. Details are described [here](#Feedback). The sooner you tell the team about the problem, the sooner it will be resolved. Many problems come just from improper installation or system settings.
|
||||||
|
|
||||||
|
## What is the current status of the project?
|
||||||
|
|
||||||
|
Check [Documentation](../Readme.md), [release notes](http://forum.vcmi.eu/viewforum.php?f=1) or [changelog](https://github.com/vcmi/vcmi/blob/develop/ChangeLog). The best place to watch current changes as they are committed to the develop branch is the [Github commits page](https://github.com/vcmi/vcmi/commits/develop). The game is quite playable by now, although many important features are missing.
|
||||||
|
|
||||||
|
## I have a great idea!
|
||||||
|
|
||||||
|
Share it on [VCMI forum](http://forum.vcmi.eu/index.php) so all team members can see it and share their thoughts. Remember, brainstorming is good for your health.
|
||||||
|
|
||||||
|
## Are you going to support Horn of The Abyss / Wog 3.59 / Grove Town etc.?
|
||||||
|
|
||||||
|
Yes, of course. VCMI is designed as a base for any further mods and uses own executables, so the compatibility is not an issue. The team is not going to compete, but to cooperate with the community of creative modders.
|
||||||
|
|
||||||
|
## Can I help VCMI Project in any way?
|
||||||
|
|
||||||
|
If you are C++ programmer, graphican, tester or just have tons of ideas, do not hesistate - your help is needed. The game is huge and many different ares of activity are still waiting for someone like you.
|
||||||
|
|
||||||
|
## I would like to join development team.
|
||||||
|
|
||||||
|
You are always welcome. Contact the core team via [our board](http://forum.vcmi.eu/index.php). The usual way to join the team is to post your patch for review on our board. If the patch is positively rated by core team members, you will be given access to SVN repository.
|
16
docs/players/Privacy_Policy.md
Normal file
16
docs/players/Privacy_Policy.md
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
< [Documentation](../Readme.md) / Privacy Policy
|
||||||
|
|
||||||
|
**Last Updated: 24th December, 2022**
|
||||||
|
|
||||||
|
### Glossary
|
||||||
|
|
||||||
|
* VCMI team - a community of VCMI developers, mod makers and testers. It is not some officially registered organization.
|
||||||
|
* VCMI app - an application provided by VCMI team.
|
||||||
|
|
||||||
|
### Single player
|
||||||
|
|
||||||
|
VCMI team does not collect any data produced by VCMI app. All game files, logs, saves, mods are stored in app's internal directory and will be removed upon app uninstallation. It should be possible to backup this data by standard ways provided by your device.
|
||||||
|
|
||||||
|
### Multiplayer
|
||||||
|
|
||||||
|
If you decide to play with other users via Internet there are two roles. The host is the one who provides the game server. The clients are the other players who connect to the host. The host provides to the client its IP address in order to establish connections. The clients and the host during the gameplay exchange their usernames, messages and other game activity. All this data is collected and stored by the host. VCMI team does not collect and store any multiplayer data.
|
@ -37,8 +37,8 @@
|
|||||||
<url type="homepage">https://vcmi.eu/</url>
|
<url type="homepage">https://vcmi.eu/</url>
|
||||||
<url type="bugtracker">https://github.com/vcmi/vcmi/issues</url>
|
<url type="bugtracker">https://github.com/vcmi/vcmi/issues</url>
|
||||||
<url type="faq">https://vcmi.eu/faq/</url>
|
<url type="faq">https://vcmi.eu/faq/</url>
|
||||||
<url type="help">https://wiki.vcmi.eu/Main_Page</url>
|
<url type="help">https://github.com/vcmi/vcmi/blob/master/docs/Readme.md</url>
|
||||||
<url type="translate">https://github.com/vcmi/vcmi/wiki/Translations</url>
|
<url type="translate">https://github.com/vcmi/vcmi/blob/master/docs/modders/Translations.md</url>
|
||||||
<url type="contact">https://slack.vcmi.eu/</url>
|
<url type="contact">https://slack.vcmi.eu/</url>
|
||||||
<url type="vcs-browser">https://github.com/vcmi/vcmi</url>
|
<url type="vcs-browser">https://github.com/vcmi/vcmi</url>
|
||||||
<recommends>
|
<recommends>
|
||||||
|
@ -91,7 +91,7 @@ void FirstLaunchView::on_pushButtonDataCopy_clicked()
|
|||||||
|
|
||||||
void FirstLaunchView::on_pushButtonDataHelp_clicked()
|
void FirstLaunchView::on_pushButtonDataHelp_clicked()
|
||||||
{
|
{
|
||||||
static const QUrl vcmibuilderWiki("https://wiki.vcmi.eu/Using_vcmibuilder");
|
static const QUrl vcmibuilderWiki("https://github.com/vcmi/vcmi/blob/master/docs/players/Installation_Linux.md#install-data-using-vcmibuilder-script");
|
||||||
QDesktopServices::openUrl(vcmibuilderWiki);
|
QDesktopServices::openUrl(vcmibuilderWiki);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
209
vcmimanual.tex
209
vcmimanual.tex
@ -1,209 +0,0 @@
|
|||||||
\documentclass[a4size,final]{article}
|
|
||||||
\usepackage{fullpage}
|
|
||||||
%\usepackage{graphicx}
|
|
||||||
\usepackage[usenames,dvipsnames]{color}
|
|
||||||
\usepackage{hyperref}
|
|
||||||
\hypersetup{
|
|
||||||
colorlinks,
|
|
||||||
citecolor=black,
|
|
||||||
filecolor=black,
|
|
||||||
linkcolor=ForestGreen,
|
|
||||||
urlcolor=blue
|
|
||||||
}
|
|
||||||
\begin{document}
|
|
||||||
\normalsize
|
|
||||||
\pagestyle{plain}
|
|
||||||
\setcounter{secnumdepth}{1}
|
|
||||||
\title{\Huge VCMI 0.90 player manual}
|
|
||||||
\author{The Team}
|
|
||||||
\maketitle
|
|
||||||
\section{Introduction}
|
|
||||||
The purpose of VCMI project is to rewrite entire HoMM3: WoG engine from scratch, giving it new and extended possibilities. We are hoping to support mods and new towns already made by fans, but abandoned because of game code limitations.\\
|
|
||||||
VCMI is a fan-made open-source project in progress. We already allow support for maps of any sizes, higher resolutions and extended engine limits. However, although working, the game is not finished. There are still many features and functionalities to add, both old and brand new.\smallskip\\
|
|
||||||
Learn more about VCMI Project at \href{http://wiki.vcmi.eu/index.php?title=VCMI}{Wiki}.\\
|
|
||||||
Check \href{http://spreadsheets.google.com/ccc?key=pRhYM0YkAF9lIpLe4raNAWA&hl=pl}{google docs} for the list of already implemented objects, spells and artifacts.
|
|
||||||
\section{Installation}
|
|
||||||
VCMI requires Heroes of Might \& Magic 3 complete + WoG 3.58f installation and will not run properly without their files. We strongly recommend using English version, other languages may cause unexpected errors or bizarre font glitches.\\
|
|
||||||
If you don't have Wake of Gods 3.58f yet, click \href{http://www.maps4heroes.com/heroes3/files/allinone_358f.zip}{here}.\\
|
|
||||||
For English language files, extract \href{http://download.vcmi.eu/dataEN.7z}{this package} to your \texttt{Data} folder.\bigskip\\
|
|
||||||
Starting from 0.90, VCMI can be also installed on H3 + ERA setups.
|
|
||||||
\subsection{Windows}
|
|
||||||
To install VCMI, simply unzip downloaded archive to main HoMM3 directory. To launch it, click \texttt{VCMI\_client} icon. Server mode is inactive yet.\medskip\\
|
|
||||||
\subsection{Linux}
|
|
||||||
Visit \href{http://wiki.vcmi.eu/index.php?title=Installation_on_Linux}{Wiki article} for Linux packages and installation guidelines.\\
|
|
||||||
\newpage
|
|
||||||
\section{New features}
|
|
||||||
A number of enchancements had been introduced thorough new versions of VCMI. In this section you can learn about all of them.
|
|
||||||
\subsection{High resolutions}
|
|
||||||
VCMI supports resolutions higher than original 800x600. Namely these are:
|
|
||||||
\begin{itemize}
|
|
||||||
\item 1024x600
|
|
||||||
\item 1024x768
|
|
||||||
\item 1280x960
|
|
||||||
\item 1280x1024
|
|
||||||
\item 1366x768 %\footnote{May cause bugs on old video cards}
|
|
||||||
\item 1440x900
|
|
||||||
\item 1600x1050
|
|
||||||
\item 1600x1200
|
|
||||||
\item 1920x1080
|
|
||||||
\end{itemize}
|
|
||||||
Switching resolution may not only change visible area of map, but also alters some interface features such as \hyperref[Stack_Queue]{Stack Queue.}\\
|
|
||||||
To change resolution or full screen mode use System Options menu when in game. Changes in resolution will take place when you restart VCMI. \\
|
|
||||||
Fullscreen mode can be toggled anytime using F4 hotkey.
|
|
||||||
%\end{itemize}
|
|
||||||
\label{Mods}
|
|
||||||
\subsection{Game modification}
|
|
||||||
Since 0.9, there is a possibility to edit gameplay settings with config file. You may turn some options on/off or adjust certain values in \texttt{config/defaultMods.json} file. This file is read at game launch and the settings are stored in savegame file, so editing config won't break existing games.\\
|
|
||||||
Files placed in \texttt{Mods} subfolders will override all default files and settings.
|
|
||||||
\label{Stack_Experience}
|
|
||||||
\subsection{New creature info window}
|
|
||||||
In 0.85, new stack experience interface has been merged with regular creature window. Among old functionalities, it includes new useful info:
|
|
||||||
\begin{itemize}
|
|
||||||
\item Click experience icon to see detailed info about creature rank and experience needed for next level. This window works only if stack experience module is enabled (true by default).
|
|
||||||
\item Stack Artifact. As yet creature artifacts are not handled, so this place is unused. You can choose enabled artifact with arrow buttons. There is also additional button below to pass currently selected artifact back to hero.
|
|
||||||
\item Abilities description contain information about actual values and types of bonuses received by creature - be it default ability, stack experience, artifact or other effect. These descriptions use custom text files which have not been translated.
|
|
||||||
\end{itemize}
|
|
||||||
By default new window is used. In order to switch back to original creature window, use system setting dialog or type \texttt{switchCreWin} in console\\
|
|
||||||
\label{Commanders}
|
|
||||||
\subsection{Commanders}
|
|
||||||
VCMI offers native support for Commanders. By default, they resemble original WoG behaviour with basic "Commanders: script enabled.
|
|
||||||
\label{Stack_Artifacts}
|
|
||||||
\subsection{Stack artifacts}
|
|
||||||
The possibility to equip creatures with artifacts has been extended - now a number of artifacts can be potentially equipped. By default, there artifacts are not possible to use by hero itself. Drag them from backpack onto Stack portrait to equip.\\
|
|
||||||
Current list of Stack Artifacts available for testing:
|
|
||||||
\begin{itemize}
|
|
||||||
\item Warlord's banner
|
|
||||||
\item Magic Wand
|
|
||||||
\item Gold Tower Arrow
|
|
||||||
\item Monster's Power
|
|
||||||
\end{itemize}
|
|
||||||
\label{Stack_Queue}
|
|
||||||
\subsection{Stack Queue}
|
|
||||||
Stack queue is a feature coming straight from HoMM5, which allows you to see order of stacks on the battlefield, sorted from left to right. To toggle in on/off, press `Q' during the battle.\\
|
|
||||||
There is smaller and bigger version of it, the second one is available only in higher resolutions.
|
|
||||||
\subsection{Pathfinder}
|
|
||||||
VCMI introduces improved pathfinder, which may find the way on adventure map using ships and subterranean gates. Simply click your destination on another island or level and the proposed path will be displayed.
|
|
||||||
\label{Quest_Log}
|
|
||||||
\subsection{Quest log}
|
|
||||||
In 0.9 new quest log was introduced. It can display info about Seer Hut or Quest Guard mission, but also handle Borderguard and Border Gate missions. When you choose a quest from the list on the left, it's description is shown. Additionally, on inner minimap you can see small icons indicating locations of quest object. Clicking these objects immediately centers adventure map on desired location.
|
|
||||||
\subsection{Attack range}
|
|
||||||
In combat, some creatures, such as Dragon or Cerberi, may attack enemies on multiple hexes. All such attacked stacks will be highlighted if the attack cursor is hovered over correct destination tile.\\
|
|
||||||
Whenever battle stack is hovered, its movement range is highlighted in darker shade. This can help when you try to avoid attacks of melee units.
|
|
||||||
\subsection{Power rating}
|
|
||||||
When hovering cursor over neutral stack on adventure map, you may notice additional info about relative threat this stack poses to selected hero. This feature has been introduced in Heroes of Might and Magic V and is planned to be extended to all kinds of armed objects.\\
|
|
||||||
Custom text file is in use, so using localized version of data files will not change text in your game. It is not a bug, but lack of new translated files.
|
|
||||||
\subsection{FPS counter}
|
|
||||||
VCMI 0.85 introduces new feature for testing, the FPS counter. To enable it, edit this line in config/settings.txt file:\\
|
|
||||||
\colorbox{SpringGreen}{\texttt{showFPS=0;}}\\
|
|
||||||
Value of 1 enables simple FPS counter which may be useful to test graphical performance on mobile platforms.
|
|
||||||
\subsection{Custom menu graphics}
|
|
||||||
Since 0.9, it is possible to use any background graphics in main menu. Open \texttt{config/mainmenu.json} file for that reason and edit this line:\\
|
|
||||||
\colorbox{SpringGreen}{\texttt{"background" : "background-file-name"}}\\
|
|
||||||
Place the background file in \texttt{Data} folder.
|
|
||||||
\subsection{Minor improvements}
|
|
||||||
\subsubsection{Linux directory}
|
|
||||||
In Linux-based sysems, files placed in \texttt{$\sim$/.vcmi} directory will override data files with the same name.
|
|
||||||
\subsection{New controls}
|
|
||||||
VCMI introduces several minor improvements and new keybinds in user interface.
|
|
||||||
\subsubsection{Pregame - Scenario / Saved Game list}
|
|
||||||
\begin{itemize}
|
|
||||||
\item Mouse wheel - scroll through the Scenario list.
|
|
||||||
\item Home - move to the top of the list.
|
|
||||||
\item End - move to the bottom of the list.
|
|
||||||
\item NumPad keys can be used in the Save Game screen (they didn't work in H3).
|
|
||||||
\end{itemize}
|
|
||||||
\subsubsection{Adventure Map}
|
|
||||||
\begin{itemize}
|
|
||||||
\item CTRL + R - Quick restart of current scenario.
|
|
||||||
\item CTRL + Arrows - scrolls Adventure Map behind an open window.
|
|
||||||
\item CTRL pressed blocks Adventure Map scrolling (it allows us to leave the application window without losing current focus).
|
|
||||||
\item NumPad 5 - centers view on selected hero.
|
|
||||||
\item NumPad Enter functions same as normal Enter in the game (it didn't in H3).
|
|
||||||
\end{itemize}
|
|
||||||
\subsubsection{Spellbook}
|
|
||||||
\begin{itemize}
|
|
||||||
\item ALT + 1-10 or `-' or `=' on main pad - cast 1st to 12th visible spell
|
|
||||||
\item ALT + 1-10 or `-' or `+' on NumPad - cast 1st to 12th spell
|
|
||||||
\end{itemize}
|
|
||||||
\subsubsection{Miscellaneous}
|
|
||||||
\begin{itemize}
|
|
||||||
\item Numbers for components in selection window - for example Treasure Chest, skill choice dialog and more yet to come.
|
|
||||||
\item Type numbers in the Split Stack screen (for example 25 will split the stacks as such that there are 25 creatures in the second stack).
|
|
||||||
\item `Q' - Toggles the \hyperref[Stack_Queue]{Stack Queue} display (so it can be enabled/disabled with single key press).
|
|
||||||
\item During Tactics phase, click on any of your stack to instantly activate it. No need to scroll trough entire army anymore.
|
|
||||||
\end{itemize}
|
|
||||||
\subsection{Cheat codes}
|
|
||||||
Following cheat codes have been implemented in VCMI. Type them in console:
|
|
||||||
\begin{itemize}
|
|
||||||
\item \texttt{vcmiistari} - Gives all spells and 999 mana to currently selected hero
|
|
||||||
\item \texttt{vcmiainur} - Gives 5 Archangels to every empty slot of currently selected hero
|
|
||||||
\item \texttt{vcmiangband} - Gives 10 Black Knights into each slot
|
|
||||||
\item \texttt{vcmiarmenelos} - Build all structures in currently selected town
|
|
||||||
\item \texttt{vcminoldor} - All war machines
|
|
||||||
\item \texttt{vcminahar} - 1000000 movement points
|
|
||||||
\item \texttt{vcmiformenos} - Give resources (100 wood, ore and rare resources and 20000 gold)
|
|
||||||
\item \texttt{vcmieagles} - Reveals fog of war
|
|
||||||
\item \texttt{vcmiglorfindel} - Advances currently selected hero to the next level
|
|
||||||
\item \texttt{vcmisilmaril} - Player wins
|
|
||||||
\item \texttt{vcmimelkor} - Player loses
|
|
||||||
\item \texttt{vcmiforgeofnoldorking} - Hero gets all artifacts except spell book, spell scrolls and war machines
|
|
||||||
\end{itemize}
|
|
||||||
\subsection{Command line}
|
|
||||||
It is possible to save a starting configuration (such as map and options) in pregame by typing "\texttt{sinfo} filename". Then VCMI can be started with option \texttt{-i --start=fname} and it will automatically start the game.\\
|
|
||||||
\texttt{--onlyAI} command line option allows to run AI-on-AI game (without GUI). Also, typing \texttt{onlyai} in pregame triggers that mode.
|
|
||||||
\newpage
|
|
||||||
\section{Release notes}
|
|
||||||
\begin{itemize}
|
|
||||||
\item In 0.89 \hyperref[Commanders]{Commanders} and \hyperref[Stack_Artifacts]{Stack Artifacts} were implemented and enabled by default. There are four Stack Artifacts available. Their behaviour has been altered for testing purpose only.
|
|
||||||
\item \hyperref[Stack_Experience]{Stack Experience} is enabled by default. It's an optional feature, but needs complex tesing. Mechanics and tables from original WoG 3.58f were used for this purpose. Note that not all of WoG creature abilities are handled.
|
|
||||||
\item Online game, random map generator as well as some other parts of the game are not yet implemented. Do not worry if nothing happens when you click them, please report only actual bugs and game crashes.
|
|
||||||
\item It is possible to start the campaign, although heroes will not carry over to subsequent scenarios.
|
|
||||||
\end{itemize}
|
|
||||||
\subsection{Android port}
|
|
||||||
Android port, despite some rumours, is not complete and may crash at random. The port is work of a Peyla - volunteer outside of VCMI team, who abandoned it. Any Android support is beyond our scope.
|
|
||||||
\label{Feedback}
|
|
||||||
\section{Feedback}
|
|
||||||
Our project is open and its sources are available for everyone to browse and download. We do our best to inform community of Heroes fans with all the details and development progress. We also look forward to your comments, support and advice.\medskip\\
|
|
||||||
A good place to start is \href{http://wiki.vcmi.eu/index.php?title=Main_Page}{VCMI Wiki} which contains all necessary information for developers, testers and the people who would like to get familiar with our project.
|
|
||||||
If you want to report a bug, use \href{http://bugs.vcmi.eu/bug_report_advanced_page.php}{Mantis Bugtracker}.\\
|
|
||||||
Make sure the issue is not already mentioned on \href{http://bugs.vcmi.eu/view_all_bug_page.php}{the list} unless you can provide additional details for it.\\
|
|
||||||
Please do not report as bugs features not yet implemented. For proposing new ideas and requests, visit \href{http://forum.vcmi.eu/index.php}{our board}.\medskip\\
|
|
||||||
VCMI comes with its own bug handlers: the console which prints game log \texttt{(server\_log, VCMI\_Client\_log, VCMI\_Server\_log)} and memory dump file (\texttt{.dmp}) created on crash on Windows systems. These may be very helpful when the nature of bug is not obvious, please attach them if necessary.\medskip\\
|
|
||||||
To resolve an issue, we must be able to reproduce it on our computers. Please put down all circumstances in which a bug occurred and what did you do before, especially if it happens rarely or is not clearly visible. The better report, the better chance to track the bug quickly.
|
|
||||||
\subsubsection{Linux notes}
|
|
||||||
On *nix-like systems logs can be found in \texttt{$\sim$/.vcmi} directory. \\
|
|
||||||
When reporting compilation issues please specify name and version of your distribution.
|
|
||||||
\section{FAQ}
|
|
||||||
\subsection{When will the final version be released?}
|
|
||||||
When it is finished, which is another year at least. Exact date is impossible to predict.\\
|
|
||||||
Development tempo depends mostly on free time of active programmers and community members, there is no exact shedule. You may expect new version every three months. Of course, joining the project will speed things up.
|
|
||||||
\subsection{Are you going to add / change X?}
|
|
||||||
VCMI recreates basic H3:TSoD + WoG engine and does not add new content or modify original mechanics by default. Only engine and interface improvements are likely to be supported now. The list of possible features is placed on \href{http://wiki.vcmi.eu/index.php?title=TODO_list}{Wiki TODO list}.
|
|
||||||
If you want something specific to be done, please present detailed project on \href{http://forum.vcmi.eu/index.php}{our board}. Of course you are free to contribute with anything you can do.
|
|
||||||
\subsection{Will it be possible to do Y?}
|
|
||||||
Removing engine restrictions and allowing flexible modding of game is the main aim of the project.\\
|
|
||||||
As yet modification of game is not supported.
|
|
||||||
\subsection{The game is not working, it crashes and I get strange console messages.}
|
|
||||||
Report your bug. Details are described \hyperref[Feedback]{here}. The sooner you tell the team about the problem, the sooner it will be resolved. Many problems come just from improper installation or system settings.
|
|
||||||
\subsection{What is the current status of the project?}
|
|
||||||
Check \href{http://wiki.vcmi.eu/index.php?title=VCMI}{Wiki}, \href{http://forum.vcmi.eu/viewforum.php?f=1}{release notes} or \href{https://github.com/vcmi/vcmi/blob/develop/ChangeLog}{changelog}. The best place to watch current changes as they are committed to the develop branch is the \href{https://github.com/vcmi/vcmi/commits/develop}{Github commits page}. The game is quite playable by now, although many important features are missing.
|
|
||||||
\subsection{I have a great idea!}
|
|
||||||
Share it on \href{http://forum.vcmi.eu/index.php}{VCMI forum} so all team members can see it and share their thoughts. Remember, brainstorming is good for your health.
|
|
||||||
\subsection{Are you going to support Horn of The Abyss / Wog 3.59 / Grove Town etc.?}
|
|
||||||
Yes, of course. VCMI is designed as a base for any further mods and uses own executables, so the compatibility is not an issue. The team is not going to compete, but to cooperate with the community of creative modders.
|
|
||||||
\subsection{I don't like Wake of Gods at all. Can I disable it?}
|
|
||||||
Most WoG features already implemented are just for testing purposes and can be disabled in \hyperref[Mods]{mod settings}.
|
|
||||||
\subsection{Can I help VCMI Project in any way?}
|
|
||||||
If you are C++ programmer, graphican, tester or just have tons of ideas, do not hesistate - your help is needed. The game is huge and many different ares of activity are still waiting for someone like you. See \href{http://wiki.vcmi.eu/index.php?title=TODO_list}{Wiki TODO list} for more info.
|
|
||||||
\subsection{I would like to join development team.}
|
|
||||||
You are always welcome. Contact the core team via \href{http://forum.vcmi.eu/index.php}{our board}. In the meantime, read `building VCMI' guide at \href{http://wiki.vcmi.eu/index.php?title=Main_Page}{Wiki}.\\
|
|
||||||
The usual way to join the team is to post your patch for review on our board. If the patch is positively rated by core team members, you will be given access to SVN repository.
|
|
||||||
\section{Credits}
|
|
||||||
Visit
|
|
||||||
\href{http://forum.vcmi.eu/index.php}{VCMI board}
|
|
||||||
for additional support.
|
|
||||||
\bigskip\\
|
|
||||||
\begin{center}
|
|
||||||
This manual will be updated with every new release.
|
|
||||||
\end{center}
|
|
||||||
\end{document}
|
|
Reference in New Issue
Block a user