1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-10 00:43:59 +02:00

Merge pull request #5011 from IvanSavenko/markdown_lint

Added markdownlint to Github CI
This commit is contained in:
Ivan Savenko 2024-12-02 13:14:03 +02:00 committed by GitHub
commit 38e0b08b34
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
78 changed files with 2304 additions and 1472 deletions

View File

@ -15,6 +15,7 @@ Please attach game logs: `VCMI_client.txt`, `VCMI_server.txt` etc.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
@ -33,6 +34,7 @@ If this something which worked well some time ago, please let us know about vers
If applicable, add screenshots to help explain your problem.
**Version**
- OS: [e.g. Windows, macOS Intel, macOS ARM, Android, Linux, iOS]
- Version: [VCMI version]

View File

@ -402,3 +402,9 @@ jobs:
run: |
sudo apt install python3-jstyleson
python3 CI/validate_json.py
- name: Validate Markdown
uses: DavidAnson/markdownlint-cli2-action@v18
with:
config: 'CI/example.markdownlint-cli2.jsonc'
globs: '**/*.md'

View File

@ -0,0 +1,280 @@
{
"config" : {
"default" : true,
// MD001/heading-increment : Heading levels should only increment by one level at a time : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md001.md
"MD001": false,
// MD003/heading-style : Heading style : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md003.md
"MD003": {
"style": "atx"
},
// MD004/ul-style : Unordered list style : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md004.md
"MD004": false,
// FIXME: enable and consider fixing
//{
// "style": "consistent"
//},
// MD005/list-indent : Inconsistent indentation for list items at the same level : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md005.md
"MD005": true,
// MD007/ul-indent : Unordered list indentation : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md007.md
"MD007": {
// Spaces for indent
"indent": 2,
// Whether to indent the first level of the list
"start_indented": false,
// Spaces for first level indent (when start_indented is set)
"start_indent": 0
},
// MD009/no-trailing-spaces : Trailing spaces : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md009.md
"MD009": {
// Spaces for line break
"br_spaces": 2,
// Allow spaces for empty lines in list items
"list_item_empty_lines": false,
// Include unnecessary breaks
"strict": false
},
// MD010/no-hard-tabs : Hard tabs : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md010.md
"MD010": {
// Include code blocks
"code_blocks": false,
// Fenced code languages to ignore
"ignore_code_languages": [],
// Number of spaces for each hard tab
"spaces_per_tab": 4
},
// MD011/no-reversed-links : Reversed link syntax : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md011.md
"MD011": true,
// MD012/no-multiple-blanks : Multiple consecutive blank lines : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md012.md
"MD012": {
// Consecutive blank lines
"maximum": 1
},
// MD013/line-length : Line length : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md013.md
"MD013": false,
// MD014/commands-show-output : Dollar signs used before commands without showing output : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md014.md
"MD014": true,
// MD018/no-missing-space-atx : No space after hash on atx style heading : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md018.md
"MD018": true,
// MD019/no-multiple-space-atx : Multiple spaces after hash on atx style heading : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md019.md
"MD019": true,
// MD020/no-missing-space-closed-atx : No space inside hashes on closed atx style heading : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md020.md
"MD020": true,
// MD021/no-multiple-space-closed-atx : Multiple spaces inside hashes on closed atx style heading : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md021.md
"MD021": true,
// MD022/blanks-around-headings : Headings should be surrounded by blank lines : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md022.md
"MD022": {
// Blank lines above heading
"lines_above": 1,
// Blank lines below heading
"lines_below": 1
},
// MD023/heading-start-left : Headings must start at the beginning of the line : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md023.md
"MD023": true,
// MD024/no-duplicate-heading : Multiple headings with the same content : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md024.md
"MD024": false,
// FIXME: false positives?
//{
// // Only check sibling headings
// "allow_different_nesting": true,
// // Only check sibling headings
// "siblings_only": true
//},
// MD025/single-title/single-h1 : Multiple top-level headings in the same document : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md025.md
"MD025": {
// Heading level
"level": 1,
// RegExp for matching title in front matter
"front_matter_title": "^\\s*title\\s*[:=]"
},
// MD026/no-trailing-punctuation : Trailing punctuation in heading : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md026.md
"MD026": {
// Punctuation characters
"punctuation": ".,;:!。,;:!"
},
// MD027/no-multiple-space-blockquote : Multiple spaces after blockquote symbol : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md027.md
"MD027": true,
// MD028/no-blanks-blockquote : Blank line inside blockquote : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md028.md
"MD028": true,
// MD029/ol-prefix : Ordered list item prefix : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md029.md
"MD029": false,
// FIXME: false positives or broken formatting
//{
// // List style
// "style": "ordered"
//},
// MD030/list-marker-space : Spaces after list markers : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md030.md
"MD030": {
// Spaces for single-line unordered list items
"ul_single": 1,
// Spaces for single-line ordered list items
"ol_single": 1,
// Spaces for multi-line unordered list items
"ul_multi": 1,
// Spaces for multi-line ordered list items
"ol_multi": 1
},
// MD031/blanks-around-fences : Fenced code blocks should be surrounded by blank lines : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md031.md
"MD031": {
// Include list items
"list_items": false
},
// MD032/blanks-around-lists : Lists should be surrounded by blank lines : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md032.md
"MD032": true,
// MD033/no-inline-html : Inline HTML : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md033.md
"MD033": false,
// FIXME: enable and consider fixing
//{
// // Allowed elements
// "allowed_elements": []
//},
// MD034/no-bare-urls : Bare URL used : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md034.md
"MD034": true,
// MD035/hr-style : Horizontal rule style : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md035.md
"MD035": {
// Horizontal rule style
"style": "consistent"
},
// MD036/no-emphasis-as-heading : Emphasis used instead of a heading : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md036.md
"MD036": false,
// FIXME: enable and consider fixing
// {
// // Punctuation characters
// "punctuation": ".,;:!?。,;:!?"
// },
// MD037/no-space-in-emphasis : Spaces inside emphasis markers : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md037.md
"MD037": true,
// MD038/no-space-in-code : Spaces inside code span elements : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md038.md
"MD038": true,
// MD039/no-space-in-links : Spaces inside link text : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md039.md
"MD039": true,
// MD040/fenced-code-language : Fenced code blocks should have a language specified : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md040.md
"MD040": false,
// FIXME: enable and consider fixing
//{
//// List of languages
// "allowed_languages": [ "cpp", "json5", "sh" ],
//// Require language only
// "language_only": true
//},
// MD041/first-line-heading/first-line-h1 : First line in a file should be a top-level heading : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md041.md
"MD041": {
// Heading level
"level": 1,
// RegExp for matching title in front matter
"front_matter_title": "^\\s*title\\s*[:=]"
},
// MD042/no-empty-links : No empty links : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md042.md
"MD042": true,
// MD043/required-headings : Required heading structure : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md043.md
"MD043": false,
// MD044/proper-names : Proper names should have the correct capitalization : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md044.md
"MD044": false,
// MD045/no-alt-text : Images should have alternate text (alt text) : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md045.md
"MD045": false,
// MD046/code-block-style : Code block style : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md046.md
"MD046": {
// Block style
"style": "fenced"
},
// MD047/single-trailing-newline : Files should end with a single newline character : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md047.md
"MD047": true,
// MD048/code-fence-style : Code fence style : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md048.md
"MD048": {
// Code fence style
"style": "backtick"
},
// MD049/emphasis-style : Emphasis style : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md049.md
"MD049": {
// Emphasis style
"style": "asterisk"
},
// MD050/strong-style : Strong style : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md050.md
"MD050": {
// Strong style
"style": "asterisk"
},
// MD051/link-fragments : Link fragments should be valid : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md051.md
"MD051": true,
// MD052/reference-links-images : Reference links and images should use a label that is defined : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md052.md
"MD052": {
// Include shortcut syntax
"shortcut_syntax": false
},
// MD053/link-image-reference-definitions : Link and image reference definitions should be needed : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md053.md
"MD053": {
// Ignored definitions
"ignored_definitions": [
"//"
]
},
// MD054/link-image-style : Link and image style : https://github.com/DavidAnson/markdownlint/blob/v0.32.1/doc/md054.md
"MD054": {
// Allow autolinks
"autolink": true,
// Allow inline links and images
"inline": true,
// Allow full reference links and images
"full": true,
// Allow collapsed reference links and images
"collapsed": true,
// Allow shortcut reference links and images
"shortcut": true,
// Allow URLs as inline links
"url_inline": true
},
// MD058 - Tables should be surrounded by blank lines
"MD058" : true
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,11 @@
# VCMI Project
[![VCMI](https://github.com/vcmi/vcmi/actions/workflows/github.yml/badge.svg?branch=develop&event=push)](https://github.com/vcmi/vcmi/actions/workflows/github.yml?query=branch%3Adevelop+event%3Apush)
[![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/1.5.0/total)](https://github.com/vcmi/vcmi/releases/tag/1.5.0)
[![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/1.5.6/total)](https://github.com/vcmi/vcmi/releases/tag/1.5.6)
[![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/1.5.7/total)](https://github.com/vcmi/vcmi/releases/tag/1.5.7)
[![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/total)](https://github.com/vcmi/vcmi/releases)
# VCMI Project
VCMI is an open-source recreation of Heroes of Might & Magic III engine, giving it new and extended possibilities.
<p>
@ -15,14 +15,13 @@ VCMI is an open-source recreation of Heroes of Might & Magic III engine, giving
<img src="https://github.com/vcmi/VCMI.eu/blob/master/static/img/screenshots/1.4.0/Quick%20Hero%20Select%20Bastion.jpg?raw=true" alt="New widget for Hero selection, featuring Pavillon Town" style="height:120px;"/>
</p>
## Links
* Homepage: https://vcmi.eu/
* Forums: https://forum.vcmi.eu/
* Bugtracker: https://github.com/vcmi/vcmi/issues
* Discord: https://discord.gg/chBT42V
* GPT Store: https://chat.openai.com/g/g-1kNhX0mlO-vcmi-assistant
* Homepage: <https://vcmi.eu/>
* Forums: <https://forum.vcmi.eu/>
* Bugtracker: <https://github.com/vcmi/vcmi/issues>
* Discord: <https://discord.gg/chBT42V>
* GPT Store: <https://chat.openai.com/g/g-1kNhX0mlO-vcmi-assistant>
## Latest release
@ -31,6 +30,7 @@ Loading saves made with different major version of VCMI is usually **not** suppo
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)
@ -70,6 +70,7 @@ See also installation guide for [Heroes Chronicles](players/Heroes_Chronicles.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)
@ -78,6 +79,7 @@ Development environment setup instructions:
- [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)
@ -95,6 +97,6 @@ Engine documentation: (NOTE: may be outdated)
## 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
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-2024 VCMI Team (check AUTHORS file for the contributors list)

View File

@ -6,16 +6,17 @@ There are two types of AI: adventure and battle.
**Battle AIs** are responsible for fighting, i.e. moving stacks on the battlefield
We have 3 battle AIs so far:
* BattleAI - strongest
* StupidAI - for neutrals, should be simple so that experienced players can abuse it
* Empty AI - should do nothing at all. If needed another battle AI can be introduced.
Each battle AI consist of a few classes, but the main class, kind of entry point usually has the same name as the package itself. In BattleAI it is the BattleAI class. It implements some battle specific interface, do not remember. Main method there is activeStack(battle::Unit* stack). It is invoked by the system when it's time to move your stack. The thing you use to interact with the game and receive the gamestate is usually referenced in the code as cb. CPlayerSpecificCallback it should be. It has a lot of methods and can do anything. For instance it has battleGetUnitsIf(), which returns all units on the battlefield matching some lambda condition.
Each side in a battle is represented by an CArmedInstance object. CHeroInstance and CGDwelling, CGMonster and more are subclasses of CArmedInstance. CArmedInstance contains a set of stacks. When the battle starts, these stacks are converted to battle stacks. Usually Battle AIs reference them using the interface battle::Unit *.
Each battle AI consist of a few classes, but the main class, kind of entry point usually has the same name as the package itself. In BattleAI it is the BattleAI class. It implements some battle specific interface, do not remember. Main method there is `activeStack(battle::Unit * stack)`. It is invoked by the system when it's time to move your stack. The thing you use to interact with the game and receive the gamestate is usually referenced in the code as `cb`. `CPlayerSpecificCallback` it should be. It has a lot of methods and can do anything. For instance it has battleGetUnitsIf(), which returns all units on the battlefield matching some lambda condition.
Each side in a battle is represented by an `CArmedInstance` object. `CHeroInstance` and `CGDwelling`, `CGMonster` and more are subclasses of `CArmedInstance`. `CArmedInstance` contains a set of stacks. When the battle starts, these stacks are converted to battle stacks. Usually Battle AIs reference them using the interface `battle::Unit *`.
Units have bonuses. Nearly everything aspect of a unit is configured in the form of bonuses. Attack, defense, health, retaliation, shooter or not, initial count of shots and so on.
When you call unit->getAttack() it summarizes all these bonuses and returns the resulting value.
When you call `unit->getAttack()` it summarizes all these bonuses and returns the resulting value.
One important class is HypotheticBattle. It is used to evaluate the effects of an action without changing the actual gamestate. It is a wrapper around CPlayerSpecificCallback or another HypotheticBattle so it can provide you data, Internally it has a set of modified unit states and intercepts some calls to underlying callback and returns these internal states instead. These states in turn are wrappers around original units and contain modified bonuses (CStackWithBonuses). So if you need to emulate an attack you can call hypotheticbattle.getforupdate() and it will return the CStackWithBonuses which you can safely change.
One important class is `HypotheticBattle`. It is used to evaluate the effects of an action without changing the actual gamestate. It is a wrapper around `CPlayerSpecificCallback` or another `HypotheticBattle` so it can provide you data, Internally it has a set of modified unit states and intercepts some calls to underlying callback and returns these internal states instead. These states in turn are wrappers around original units and contain modified bonuses (`CStackWithBonuses`). So if you need to emulate an attack you can call `hypotheticbattle.getforupdate()` and it will return the `CStackWithBonuses` which you can safely change.
## BattleAI
@ -38,17 +39,20 @@ BattleAI itself handles all the rest and issues actual commands
Adventure AI responsible for moving heroes on map, gathering things, developing town. Main idea is to gather all possible tasks on map, prioritize them and select the best one for each heroes. Initially was a fork of VCAI
### Parts
Gateway - a callback for server used to invoke AI actions when server thinks it is time to do something. Through this callback AI is informed about various events like hero level up, tile revialed, blocking dialogs and so on. In order to do this Gaateway implements specific interface. The interface is exactly the same for human and AI
Another important actor for server interaction is CCallback * cb. This one is used to retrieve gamestate information and ask server to do things like hero moving, spell casting and so on. Each AI has own instance of Gateway and it is a root object which holds all AI state. Gateway has an event method yourTurn which invokes makeTurn in another thread. The last passes control to Nullkiller engine.
Nullkiller engine - place where actual AI logic is organized. It contains a main loop for gathering and prioritizing things. Its algorithm:
* reset AI state, it avoids keeping some memory about the game in general to reduce amount of things serialized into savefile state. The only serialized things are in nullkiller->memory. This helps reducing save incompatibility. It should be mostly enough for AI to analyze data avaialble in CCallback
* main loop, loop iteration is called a pass
** update AI state, some state is lazy and updates once per day to avoid performance hit, some state is recalculated each loop iteration. At this stage analysers and pathfidner work
** gathering goals, prioritizing and decomposing them
** execute selected best goals
* update AI state, some state is lazy and updates once per day to avoid performance hit, some state is recalculated each loop iteration. At this stage analysers and pathfidner work
* gathering goals, prioritizing and decomposing them
* execute selected best goals
Analyzer - a module gathering data from CCallback *. Its goal to make some statistics and avoid making any significant decissions.
* HeroAnalyser - decides upong which hero suits better to be main (army carrier and fighter) and which is better to be a scout (gathering unguarded resources, exploring)
* BuildAnalyzer - prepares information on what we can build in our towns, and what resources we need to do this
* DangerHitMapAnalyser - checks if enemy hero can rich each tile, how fast and what is their army strangth
@ -61,9 +65,11 @@ Analyzer - a module gathering data from CCallback *. Its goal to make some stati
* PriorityEvaluator - gathers information on task rewards, evaluates their priority using Fuzzy Light library (fuzzy logic)
### Goals
Units of activity in AI. Can be AbstractGoal, Task, Marker and Behavior
Task - simple thing which can be done right away in order to gain some reward. Or a composition of simple things in case if more than one action is needed to gain the reward.
* AdventureSpellCast - town portal, water walk, air walk, summon boat
* BuildBoat - builds a boat in a specific shipyard
* BuildThis - builds a building in a specified town
@ -78,6 +84,7 @@ Task - simple thing which can be done right away in order to gain some reward. O
* StayAtTown - stay at town for the rest of the day (to regain mana)
Behavior - a core game activity
* CaptureObjectsBehavior - generally it is about visiting map objects which give reward. It can capture any object, even those which are behind monsters and so on. But due to performance considerations it is not allowed to handle monsters and quests now.
* ClusterBehavior - uses information of ObjectClusterizer to unblock objects hidden behind various blockers. It kills guards, completes quests, captures garrisons.
* BuildingBehavior - develops our towns
@ -89,6 +96,7 @@ Behavior - a core game activity
* DefenceBehavior - defend towns by eliminating treatening heroes or hiding in town garrison
AbstractGoal - some goals can not be completed because it is not clear how to do this. They express desire to do something, not exact plan. DeepDecomposer is used to refine such goals until they are turned into such plan or discarded. Some examples:
* CaptureObject - you need to visit some object (flag a shipyard for instance) but do not know how
* CompleteQuest - you need to bypass bordergate or borderguard or questguard but do not know how
AbstractGoal usually comes in form of composition with some elementar task blocked by abstract objective. For instance CaptureObject(Shipyard), ExecuteHeroChain(visit x, build boat, visit enemy town). When such composition is decomposed it can turn into either a pair of herochains or into another abstract composition if path to shipyard is also blocked with something.

View File

@ -26,6 +26,7 @@ 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).
@ -54,7 +55,7 @@ Updaters are objects attached to bonuses. They can modify a bonus (typically by
The following example shows an artifact providing a bonus based on the level of the hero that wears it:
```javascript
```json5
"core:greaterGnollsFlail":
{
"text" : { "description" : "This mighty flail increases the attack of all gnolls under the hero's command by twice the hero's level." },

View File

@ -1,26 +1,26 @@
# Building 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.
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/
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/
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 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
- Ccache: download from your package manager or from https://github.com/ccache/ccache/releases
- Ninja: download from your package manager or from <https://github.com/ninja-build/ninja/releases>
- Ccache: download from your package manager or from <https://github.com/ccache/ccache/releases>
## Obtaining source code
Clone https://github.com/vcmi/vcmi with submodules. Example for command line:
Clone <https://github.com/vcmi/vcmi> with submodules. Example for command line:
```
git clone --recurse-submodules https://github.com/vcmi/vcmi.git
@ -31,6 +31,7 @@ git clone --recurse-submodules https://github.com/vcmi/vcmi.git
We use Conan package manager to build/consume dependencies, find detailed usage instructions [here](./Conan.md). Note that the link points to the state of the current branch, for the latest release check the same document in the [master branch](https://github.com/vcmi/vcmi/blob/master/docs/developers/Сonan.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)
@ -38,7 +39,7 @@ On the step where you need to replace **PROFILE**, choose:
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. On the step where you need to replace **PROFILE**, choose _android-**X**-ndk_ where _**X**_ is either `32` or `64`.
- the easiest is to download NDK from Conan (option 1 in the docs), then all the magic happens automatically. On the step where you need to replace **PROFILE**, choose *android-**X**-ndk* where ***X*** is either `32` or `64`.
- to use an already installed NDK, you can simply pass it on the command line to `conan install`: (note that this will work only when consuming the pre-built binaries)
```

View File

@ -41,7 +41,7 @@ NOTE: `fuzzylite-devel` package is no longer available in recent version of Fedo
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/
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.
@ -109,9 +109,9 @@ This will generate `vcmiclient`, `vcmiserver`, `vcmilauncher` as well as .so lib
### 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
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:
1. 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
@ -120,30 +120,31 @@ sudo dnf install https://download1.rpmfusion.org/free/fedora/rpmfusion-free-rele
> [!NOTE]
> The stock ffmpeg from Fedora repo is no good as it lacks a 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. 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. Copy all files to ~/rpmbuild/SPECS with command: <pre>cp vcmi/* ~/rpmbuild/SPECS</pre>
3. Fetch all sources by using spectool:
4. 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:
5. 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:
6. 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
7. 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:

View File

@ -24,9 +24,11 @@ Warning! Replace `%VCMI_DIR%` with path you've chosen for VCMI installation in t
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)`
@ -38,13 +40,14 @@ You have two options: to use pre-built libraries or build your own. We strongly
#### Download and unpack archive
Vcpkg Archives are available at our GitHub: https://github.com/vcmi/vcmi-deps-windows/releases
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%`
@ -65,7 +68,9 @@ Be aware that building Vcpkg might take a lot of time depend on your CPU model a
From command line use:
```sh
git clone https://github.com/microsoft/vcpkg.git %VCMI_DIR%/vcpkg
```
#### Build vcpkg and dependencies
@ -85,6 +90,7 @@ Extract `ccache` to a folder of your choosing, add the folder to the `PATH` envi
## Build VCMI
#### From GIT GUI
- Open SourceTree
- File -> Clone
- select `https://github.com/vcmi/vcmi/` as source
@ -94,15 +100,18 @@ Extract `ccache` to a folder of your choosing, add the folder to the `PATH` envi
- 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 the combobox
- If you want to use ccache:
@ -113,7 +122,8 @@ Extract `ccache` to a folder of your choosing, add the folder to the `PATH` envi
- VCMI will be built in `%VCMI_DIR%/build/bin` folder!
### Compile VCMI with MinGW via MSYS2
- Install MSYS2 from https://www.msys2.org/
- Install MSYS2 from <https://www.msys2.org/>
- Start the `MSYS MinGW x64`-shell
- Install dependencies: `pacman -S mingw-w64-x86_64-SDL2 mingw-w64-x86_64-SDL2_image mingw-w64-x86_64-SDL2_mixer mingw-w64-x86_64-SDL2_ttf mingw-w64-x86_64-boost mingw-w64-x86_64-gcc mingw-w64-x86_64-ninja mingw-w64-x86_64-qt5-static mingw-w64-x86_64-qt5-tools mingw-w64-x86_64-tbb`
- Generate and build solution from VCMI-root dir: `cmake --preset windows-mingw-release && cmake --build --preset windows-mingw-release`
@ -134,8 +144,10 @@ Vcpkg might be very unstable due to limited popularity and fact of using bleedin
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
### 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\`

View File

@ -91,7 +91,7 @@ Open `VCMI.xcodeproj` from the build directory, select `vcmiclient` scheme and h
## 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.
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).

View File

@ -3,9 +3,7 @@
* `-D CMAKE_BUILD_TYPE=Debug`
* Enables debug info and disables optimizations
* `-D CMAKE_EXPORT_COMPILE_COMMANDS=ON`
* Creates `compile_commands.json` for [clangd](https://clangd.llvm.org/) language server.
For clangd to find the JSON, create a file named `.clangd` with this content
* Creates `compile_commands.json` for [clangd](https://clangd.llvm.org/) language server. For clangd to find the JSON, create a file named `.clangd` with this content
```
CompileFlags:
CompilationDatabase: build

View File

@ -29,6 +29,7 @@ Most of VCMI configuration files uses Json format and located in "config" direct
### 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
@ -94,7 +95,6 @@ Forward declarations of the lib in headers of other parts of the project need to
`<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>

View File

@ -4,7 +4,7 @@
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
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
@ -749,7 +749,7 @@ If you need a more detailed description for a method you can use such style:
/// @return Description of the return value
```
A good essay about writing comments: http://ardalis.com/when-to-comment-your-code
A good essay about writing comments: <http://ardalis.com/when-to-comment-your-code>
### Casing

View File

@ -27,7 +27,7 @@ The following platforms are supported and known to work, others might require ch
- **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 from https://github.com/vcmi/vcmi-dependencies/releases/latest
2. Download the binaries archive and unpack it to `~/.conan` directory from <https://github.com/vcmi/vcmi-dependencies/releases/latest>
- macOS: pick **dependencies-mac-intel.txz** if you have Intel Mac, otherwise - **dependencies-mac-arm.txz**
- iOS: pick ***dependencies-ios.txz***
@ -65,7 +65,7 @@ If you use `--build=never` and this command fails, then it means that you can't
VCMI "recipe" also has some options that you can specify. For example, if you don't care about game videos, you can disable FFmpeg dependency by passing `-o with_ffmpeg=False`. If you only want to make release build, you can use `GENERATE_ONLY_BUILT_CONFIG=1` environment variable to skip generating files for other configurations (our CI does this).
_Note_: you can find full reference of this command [in the official documentation](https://docs.conan.io/1/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/1/reference/commands/consumer/install.html) or by executing `conan help install`.
### Using our prebuilt binaries for macOS/iOS
@ -86,7 +86,7 @@ This subsection describes platform specifics to build libraries from source prop
#### 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.
- 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
@ -105,11 +105,11 @@ After applying patch(es):
2. Run `make`
3. Copy file `qtbase/jar/QtAndroid.jar` from the build directory to the **package directory**, e.g. `~/.conan/data/qt/5.15.14/_/_/package/SOME_HASH/jar`.
_Note_: if you plan to build Qt from source again, then you don't need to perform the above _After applying patch(es)_ steps after building.
*Note*: if you plan to build Qt from source again, then you don't need to perform the above *After applying patch(es)* steps after building.
##### Using recipes for system libraries
1. Clone/download https://github.com/kambala-decapitator/conan-system-libs
1. Clone/download <https://github.com/kambala-decapitator/conan-system-libs>
2. Execute `conan create PACKAGE vcmi/CHANNEL`, where `PACKAGE` is a directory path in that repository and `CHANNEL` is **apple** for macOS/iOS and **android** for Android. Do it for each library you need.
3. Now you can execute `conan install` to build all dependencies.
@ -172,7 +172,7 @@ cmake --preset ios-conan
`CMakeUserPresets.json` file:
```json
```json5
{
"version": 3,
"cmakeMinimumRequired": {

View File

@ -6,7 +6,7 @@ Qt Creator is the recommended IDE for VCMI development on Linux distributions, b
- 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
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

View File

@ -24,7 +24,7 @@ Some notes:
### Setup settings.json
``` javascript
```json5
{
"logging" : {
"console" : {
@ -68,7 +68,7 @@ The following code shows how the logging system can be configured:
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**
#### Console
Format: %m
Threshold: info
@ -76,17 +76,18 @@ coloredOutputEnabled: true
colorMapping: trace -\> gray, debug -\> white, info -\> green, warn -\> yellow, error -\> red
**File**
#### File
Format: %d %l %n \[%t\] - %m
**Loggers**
#### 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"));
```

View File

@ -2,7 +2,7 @@
## Configuration
``` javascript
```json5
{
//general purpose script, Lua or ERM, runs on server
"myScript":

View File

@ -5,12 +5,14 @@
For implementation details see files located at `lib/network` directory.
VCMI uses connection using TCP to communicate with server, even in single-player games. However, even though TCP is stream-based protocol, VCMI uses atomic messages for communication. Each message is a serialized stream of bytes, preceded by 4-byte message size:
```
int32_t messageSize;
byte messagePayload[messageSize];
```
Networking can be used by:
- game client (vcmiclient / VCMI_Client.exe). Actual application that player interacts with directly using UI.
- match server (vcmiserver / VCMI_Server.exe / part of game client). This app controls game logic and coordinates multiplayer games.
- lobby server (vcmilobby). This app provides access to global lobby through which players can play game over Internet.
@ -28,11 +30,13 @@ For gameplay, VCMI serializes data into a binary stream. See [Serialization](Ser
## Global lobby communication
For implementation details see:
- game client: `client/globalLobby/GlobalLobbyClient.h
- match server: `server/GlobalLobbyProcessor.h
- lobby server: `client/globalLobby/GlobalLobbyClient.h
In case of global lobby, message payload uses plaintext json format - utf-8 encoded string:
```
int32_t messageSize;
char jsonString[messageSize];
@ -43,6 +47,7 @@ Every message must be a struct (json object) that contains "type" field. Unlike
### Communication flow
Notes:
- invalid message, such as corrupted json format or failure to validate message will result in no reply from server
- in addition to specified messages, match server will send `operationFailed` message on failure to apply player request
@ -52,6 +57,7 @@ Notes:
- lobby -> client: `accountCreated`
#### Login
- client -> lobby: `clientLogin`
- lobby -> client: `loginSuccess`
- lobby -> client: `chatHistory`
@ -59,10 +65,12 @@ Notes:
- lobby -> client: `activeGameRooms`
#### Chat Message
- client -> lobby: `sendChatMessage`
- lobby -> every client: `chatMessage`
#### New Game Room
- client starts match server instance
- match -> lobby: `serverLogin`
- lobby -> match: `loginSuccess`
@ -73,19 +81,23 @@ Notes:
- lobby -> every client: `activeGameRooms`
#### Joining a game room
See [#Proxy mode](proxy-mode)
#### Leaving a game room
- client closes connection to match server
- match -> lobby: `leaveGameRoom`
#### Sending an invite:
#### Sending an invite
- client -> lobby: `sendInvite`
- lobby -> target client: `inviteReceived`
Note: there is no dedicated procedure to accept an invite. Instead, invited player will use same flow as when joining public game room
#### Logout
- client closes connection
- lobby -> every client: `activeAccounts`
@ -94,6 +106,7 @@ Note: there is no dedicated procedure to accept an invite. Instead, invited play
In order to connect players located behind NAT, VCMI lobby can operate in "proxy" mode. In this mode, connection will be act as proxy and will transmit gameplay data from client to a match server, without any data processing on lobby server.
Currently, process to establish connection using proxy mode is:
- Player attempt to join open game room using `joinGameRoom` message
- Lobby server validates requests and on success - notifies match server about new player in lobby using control connection
- Match server receives request, establishes new connection to game lobby, sends `serverProxyLogin` message to lobby server and immediately transfers this connection to VCMIServer class to use as connection for gameplay communication

View File

@ -94,13 +94,11 @@ Reserve accounts for other code hosting services:
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
## 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
### Droplet configuration
Currently we using two droplets:

View File

@ -1,12 +1,16 @@
# Release Process
## Versioning
For releases VCMI uses version numbering in form "1.X.Y", where:
- 'X' indicates major release. Different major versions are generally not compatible with each other. Save format is different, network protocol is different, mod format likely different.
- 'Y' indicates hotfix release. Despite its name this is usually not urgent, but planned release. Different hotfixes for same major version are fully compatible with each other.
## 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 `1.X.Y` when corresponding version is released. State of master branch represents state of latest public release.
- `beta` branch is for stabilization of ongoing release. Beta branch is created when new major release enters stabilization stage and is used for both major release itself as well as for subsequent hotfixes. Only changes that are safe, have minimal chance of regressions and improve player experience should be targeted into this branch. Breaking changes (e.g. save format changes) are forbidden in beta.
- `develop` branch is a main branch for ongoing development. Pull requests with new features should be targeted to this branch, `develop` version is one major release ahead of `beta`.
@ -14,12 +18,14 @@ Our branching strategy is very similar to GitFlow:
## Release process step-by-step
### Initial release setup (major releases only)
Should be done immediately after start of stabilization stage for previous release
- Create project named `Release 1.X`
- Add all features and bugs that should be fixed as part of this release into this project
### Start of stabilization stage (major releases only)
Should be done 2 weeks before planned release date. All major features should be finished at this point.
- Create `beta` branch from `develop`
@ -34,6 +40,7 @@ Should be done 2 weeks before planned release date. All major features should be
- Bump version and build ID for Android on `beta` branch
### Release preparation stage
Should be done 1 week before release. Release date should be decided at this point.
- Make sure to announce codebase freeze deadline (1 day before release) to all developers
@ -45,21 +52,23 @@ Should be done 1 week before release. Release date should be decided at this poi
- - Update downloads counter in `docs/readme.md`
### Release preparation stage
Should be done 1 day before release. At this point beta branch is in full freeze.
- Merge release preparation PR into `beta`
- Merge `beta` into `master`. This will trigger CI pipeline that will generate release packages
- Create draft release page, specify `1.x.y` as tag for `master` after publishing
- Check that artifacts for all platforms have been built by CI on `master` branch
- Download and rename all build artifacts to use form "VCMI-1.X.Y-Platform.xxx"
- Download and rename all build artifacts to use form `VCMI-1.X.Y-Platform.xxx`
- Attach build artifacts for all platforms to release page
- Manually extract Windows installer, remove `$PLUGINSDIR` directory which contains installer files and repackage data as .zip archive
- Attach produced zip archive to release page as an alternative Windows installer
- Upload built AAB to Google Play and send created release draft for review (usually takes several hours)
- Prepare pull request for [vcmi-updates](https://github.com/vcmi/vcmi-updates)
- (major releases only) Prepare pull request with release update for web site https://github.com/vcmi/VCMI.eu
- (major releases only) Prepare pull request with release update for web site <https://github.com/vcmi/VCMI.eu>
### Release publishing phase
Should be done on release date
- Trigger builds for new release on Ubuntu PPA

View File

@ -1,6 +1,7 @@
# Ubuntu PPA
## Main links
- [Team](https://launchpad.net/~vcmi)
- [Project](https://launchpad.net/vcmi)
- [Sources](https://code.launchpad.net/~vcmi/vcmi/+git/vcmi)
@ -14,22 +15,31 @@
## 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.
@ -37,8 +47,10 @@
- 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)
- [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>)

View File

@ -8,7 +8,7 @@ VCMI allows overriding HoMM3 .def files with .json replacement. Compared to .def
## Format description
``` javascript
```json5
{
// Base path of all images in animation. Optional.
// Can be used to avoid using long path to images
@ -58,12 +58,14 @@ VCMI allows overriding HoMM3 .def files with .json replacement. Compared to .def
### Replacing a button
This json file will allow replacing .def file for a button with png images. Buttons require following images:
1. Active state. Button is active and can be pressed by player
2. Pressed state. Player pressed button but have not released it yet
3. Blocked state. Button is blocked and can not be interacted with. Note that some buttons are never blocked and can be used without this image
4. Highlighted state. This state is used by only some buttons and only in some cases. For example, in main menu buttons will appear highlighted when mouse cursor is on top of the image. Another example is buttons that can be selected, such as settings that can be toggled on or off
```javascript
```json5
{
"basepath" : "interface/MyButton", // all images are located in this directory
"images" :
@ -80,7 +82,8 @@ This json file will allow replacing .def file for a button with png images. Butt
This json file allows defining one animation sequence, for example for adventure map objects or for town buildings.
```javascript
```json5
{
"basepath" : "myTown/myBuilding", // all images are located in this directory
"sequences" :

View File

@ -15,7 +15,7 @@ The limiters take no parameters:
Example:
``` javascript
```json5
"limiters" : [ "SHOOTER_ONLY" ]
```
@ -30,7 +30,7 @@ Parameters:
- (optional) bonus sourceType and sourceId in struct
- example: (from Adele's bless):
``` javascript
```json5
"limiters" : [
{
"type" : "HAS_ANOTHER_BONUS_LIMITER",
@ -64,6 +64,7 @@ Parameters:
If parameters is empty, level limiter works as CREATURES_ONLY limiter
Parameters:
- Minimal level
- Maximal level
@ -81,14 +82,14 @@ Parameters:
Example:
``` javascript
```json5
"limiters": [ {
"type":"CREATURE_TYPE_LIMITER",
"parameters": [ "angel", true ]
} ],
```
``` javascript
```json5
"limiters" : [ {
"type" : "CREATURE_TERRAIN_LIMITER",
"parameters" : ["sand"]
@ -112,7 +113,7 @@ and operate on the remaining limiters in that list:
Example:
``` javascript
```json5
"limiters" : [
"noneOf",
"IS_UNDEAD",

View File

@ -128,7 +128,7 @@ Allows to raise different creatures than Skeletons after battle.
- addInfo: Level of Necromancy secondary skill (1 - Basic, 3 - Expert)
- Example (from Cloak Of The Undead King):
```jsonc
```json5
{
"type" : "IMPROVED_NECROMANCY",
"subtype" : "creature.walkingDead",
@ -256,7 +256,7 @@ Gives creature under effect of this spell additional bonus, which is hardcoded a
Modifies 'val' parameter of spell effects that give bonuses by specified value. For example, Aenain makes Disrupting Ray decrease target's defense by additional 2 points:
```jsonc
```json5
"disruptingRay" : {
"addInfo" : -2,
"subtype" : "spell.disruptingRay",
@ -271,7 +271,7 @@ Modifies 'val' parameter of spell effects that give bonuses by specified value.
Changes 'val' parameter of spell effects that give bonuses to a specified value. For example, Fortune cast by Melody always modifies luck by +3:
```jsonc
```json5
"fortune" : {
"addInfo" : 3,
"subtype" : "spell.fortune",
@ -669,6 +669,7 @@ Affected unit can attack walls during siege battles (Cyclops)
### CATAPULT_EXTRA_SHOTS
Defines spell mastery level for spell used by CATAPULT bonus
- subtype: affected spell
- val: spell mastery level to use

View File

@ -12,25 +12,27 @@ Check the files in *config/heroes/* for additional usage examples.
- Type: Complex
- Parameters: valPer20, stepSize=1
- Effect: Updates val to
` ceil(valPer20 * floor(heroLevel / stepSize) / 20)`
- 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"`
` }`
```json5
"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"`
` }`
```json5
"updater" : {
"parameters" : [ 3 ],
"type" : "GROWS_WITH_LEVEL"
}
```
Remarks:
@ -42,13 +44,9 @@ Remarks:
## TIMES_HERO_LEVEL
- Type: Simple
- Effect: Updates val to
- Effect: Updates val to `val * heroLevel`
` val * heroLevel`
Usage:
` "updater" : "TIMES_HERO_LEVEL"`
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
@ -57,9 +55,7 @@ has been added for convenience.
## TIMES_STACK_LEVEL
- Type: Simple
- Effect: Updates val to
` val * stackLevel`
- Effect: Updates val to `val * stackLevel`
Usage:
@ -70,19 +66,17 @@ 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).
- 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"`
` }`
```json5
"updater" : {
"parameters" : [ 20, 3, 10, 700 ],
"type" : "ARMY_MOVEMENT"
}
```
## BONUS_OWNER_UPDATER

View File

@ -3,13 +3,18 @@
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))`
```
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)`
```
clamp(((BASE_NUMBER * (100 + PERCENT_TO_BASE) / 100) + ADDITIVE_VALUE) * (100 + PERCENT_TO_ALL) / 100), INDEPENDENT_MAX, INDEPENDENT_MIN)
```
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.

View File

@ -4,7 +4,7 @@
All parameters but type are optional.
``` javascript
```json5
{
// Type of the bonus. See Bonus Types for full list
"type": "BONUS_TYPE",
@ -81,7 +81,7 @@ See [Game Identifiers](Game_Identifiers.md) for full list of available identifie
### Example
``` javascript
```json5
"bonus" :
{
"type" : "HATE",

View File

@ -22,7 +22,7 @@ Includes:
Function of all of these objects can be enabled by this:
``` javascript
```json5
"function" : "castleGates"
```
@ -58,31 +58,31 @@ CBuilding class.
#### unlock guild level
``` javascript
```json5
"guildLevels" : 1
```
#### unlock hero recruitment
``` javascript
```json5
"allowsHeroPurchase" : true
```
#### unlock ship purchase
``` javascript
```json5
"allowsShipPurchase" : true
```
#### unlock building purchase
``` javascript
```json5
"allowsBuildingPurchase" : true
```
#### unlocks creatures
``` javascript
```json5
"dwelling" : { "level" : 1, "creature" : "archer" }
```
@ -92,31 +92,31 @@ Turn into town bonus? What about creature-specific bonuses from hordes?
#### gives resources
``` javascript
```json5
"provides" : { "gold" : 500 }
```
#### gives guild spells
``` javascript
```json5
"guildSpells" : [5, 0, 0, 0, 0]
```
#### gives thieves guild
``` javascript
```json5
"thievesGuildLevels" : 1
```
#### gives fortifications
``` javascript
```json5
"fortificationLevels" : 1
```
#### gives war machine
``` javascript
```json5
"warMachine" : "ballista"
```
@ -134,7 +134,7 @@ Includes:
- bonus to scouting range
- bonus to player
``` javascript
```json5
"bonuses" :
{
"moraleToDefenders" :
@ -162,12 +162,12 @@ 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
```json5
"onePerPlayer" : true
```
#### chance to be built on start
``` javascript
```json5
"prebuiltChance" : 75
```

View File

@ -3,12 +3,13 @@
## 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)
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 `header.json`. See also [Packing campaign](#packing-campaign)
Basic structure of this file is here, each section is described in details below
```js
```json5
{
"version" : 1,
@ -32,7 +33,8 @@ Basic structure of this file is here, each section is described in details below
## Header properties
In header are parameters describing campaign properties
```js
```json5
...
"regions": {...},
"name": "Campaign name",
@ -60,7 +62,8 @@ In header are parameters describing campaign properties
## Scenario description
Scenario description looks like follow:
```js
```json5
{
"map": "maps/SomeMap",
"preconditions": [],
@ -77,7 +80,7 @@ Scenario description looks like follow:
}
```
- `"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)
- `"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`
@ -96,7 +99,8 @@ Scenario description looks like follow:
### Prolog/Epilog
Prolog and epilog properties are optional
```js
```json5
{
"video": "NEUTRALA.smk", //video to show
"music": "musicFile.ogg", //music to play, should be located in music directory
@ -115,7 +119,7 @@ If `startOptions` is `none`, `bonuses` field will be ignored
If `startOptions` is `bonus`, bonus format may vary depending on its type.
```js
```json5
{
"what": "",
@ -158,19 +162,21 @@ If `startOptions` is `bonus`, bonus format may vary depending on its type.
If `startOptions` is `crossover`, heroes from specific scenario will be moved to this scenario. Bonus format is following
```js
```json5
{
"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
```json5
{
"playerColor": 0,
"hero": "random"
@ -184,7 +190,7 @@ If `startOptions` is `hero`, hero can be chosen as a starting bonus. Bonus forma
Predefined campaign regions are located in file `campaign_regions.json`
```js
```json5
{
"background": "ownRegionBackground.png",
"suffix": ["Enabled", "Selected", "Conquered"],
@ -213,6 +219,7 @@ This file is a zip archive.
The scenarios should be named as in `"map"` field from header. Subfolders are allowed.
## Compatibility table
| Version | Min VCMI | Max VCMI | Description |
|---------|----------|----------|-------------|
| 1 | 1.3 | | Initial release |

View File

@ -21,6 +21,7 @@ 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/
@ -31,7 +32,8 @@ extendedLobby/
```
File `mod.json` is generic and could look like this:
```json
```json5
{
"name" : "Configurable UI tutorial mod",
"description" : "See tutorial here https://github.com/vcmi/vcmi/wiki/Configurable-UI-widgets",
@ -44,7 +46,7 @@ File `mod.json` is generic and could look like this:
}
```
After that you can copy `extendedLobby/ folder to `mods/` folder and your mod will immediately appear in launcher but it does nothing for now.
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
@ -64,7 +66,8 @@ So we need to modify turn duration label and add combo box with timer types
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
```json5
{
"items"
[
@ -85,7 +88,8 @@ Let's find first element, which is label
```
And modify it a bit
```json
```json5
{
"name": "labelTimer", //add name, only for convenience
"type": "label",
@ -98,7 +102,8 @@ And modify it a bit
```
But we also need proper background image for this label. Add image widget BEFORE labelTimer widget:
```json
```json5
{
"type": "picture",
"image": "RmgTTBk",
@ -109,6 +114,7 @@ But we also need proper background image for this label. Add image widget BEFORE
...
},
```
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.
@ -121,7 +127,7 @@ Copy image `DrDoCoBk.bmp` to `content/sprites/`. Button objects use animated ima
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
```json5
{
"sequences" :
[
@ -140,7 +146,7 @@ Thus we created file with animation, containing single frame which can be used f
Let's add one more element after `//timer` comment:
```json
```json5
...
//timer
{
@ -157,7 +163,7 @@ Let's add one more element after `//timer` comment:
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
```json5
...
//timer
{
@ -189,7 +195,7 @@ First of all, add images to `content/sprites/` folder: `List2Bk.bmp` for drop-do
Now specify items inside `dropDown` field
```json
```json5
"dropDown":
{
"items":
@ -272,7 +278,8 @@ 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
```json5
"variables":
{
"timers":
@ -303,7 +310,7 @@ Now we show and hide elements, but visually you still can some "artifacts":
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
```json5
...
// timer
{
@ -328,9 +335,10 @@ It works and can switch elements, the only missing part is chess timer configura
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
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
```json5
{
"name": "chessFieldBase",
"type": "textInput",
@ -345,6 +353,7 @@ We can add editors for them into items list, their format will be following:
```
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`
@ -363,7 +372,7 @@ 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
Read JSON documentation for primitive types description: <https://www.json.org/json-en.html>
#### Text
@ -430,7 +439,8 @@ One of predefined values:
### Configurable objects
Configurable object has following structure:
```json
```json5
{
"items": [],
"variables": {}, //optional
@ -748,10 +758,12 @@ Used only as special object for [combo box](#combo-box)
`"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
@ -769,7 +781,8 @@ Used only as special object for [combo box](#combo-box)
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++
```cpp
#include "gui/InterfaceObjectConfigurable.h" //assuming we are in client folder
class MyYesNoDialog: public InterfaceObjectConfigurable
@ -781,7 +794,7 @@ class MyYesNoDialog: public InterfaceObjectConfigurable
To make new object work, it's sufficient to define constructor, which receives const reference to `JsonNode`.
```C++
```cpp
MyYesNoDialog::MyYesNoDialog(const JsonNode & config):
InterfaceObjectConfigurable(), //you can pass arguments same as for CIntObject
{
@ -808,13 +821,13 @@ MyYesNoDialog::MyYesNoDialog(const JsonNode & config):
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++
```cpp
REGISTER_BUILDER("myItem", &MyYesNoDialog::buildMyItem);
```
You have to define function, which takes JsonNode as an argument and return pointer to built widget
```C++
```cpp
std::shared_ptr<MyYesNoDialog::Item> MyYesNoDialog::buildMyItem(const JsonNode & config)
{
auto position = readPosition(config["position"]);
@ -824,7 +837,7 @@ std::shared_ptr<MyYesNoDialog::Item> MyYesNoDialog::buildMyItem(const JsonNode &
After that, if your JSON file has items with type "MyItem", the new Item element will be constructed.
```json
```json5
{
"items":
[
@ -840,7 +853,7 @@ After that, if your JSON file has items with type "MyItem", the new Item element
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++
```cpp
build(config);
if(variables["colorfulText"].Bool())

View File

@ -7,7 +7,7 @@ Difficulty configuration is located in [config/difficulty.json](../config/diffic
## Format summary
``` javascript
```json5
{
"human": //parameters impacting human players only
{
@ -50,7 +50,7 @@ For both types of bonuses, `source` should be specified as `OTHER`.
## Example
```js
```json5
{ //will give 150% extra health to all players' creatures if specified in "battleBonuses" array
"type" : "STACK_HEALTH",
"val" : 150,

View File

@ -12,7 +12,7 @@ In order to make functional artifact you also need:
## Format
``` jsonc
```json5
{
// Type of this artifact - creature, hero or commander
"type": ["HERO", "CREATURE", "COMMANDER"]

View File

@ -1,6 +1,6 @@
# Battle Obstacle Format
```jsonc
```json5
// List of terrains on which this obstacle can be used
"allowedTerrains" : []

View File

@ -1,6 +1,6 @@
# Battlefield Format
```jsonc
```json5
// Human-readable name of the battlefield
"name" : "",

View File

@ -8,7 +8,7 @@ The purpose is to create visually attractive and consistent maps, which will als
If not enough biomes are defined for [terrain type](Terrain_Format.md), map generator will fall back to using all available templates that match this terrain, which was original behavior before 1.5.0.
``` json
```json5
"obstacleSetId" : {
"biome" : {
"terrain" : "grass", // Id or vector of Ids this obstacle set can spawn at
@ -38,5 +38,3 @@ Currently algorithm picks randomly:
- One or two sets of **rocks** (small objects)
- One of each remaining types of object (**structure**, **animal**, **other**), until enough number of sets is picked.
- Obstacles marked as **other** are picked last, and are generally rare.

View File

@ -23,7 +23,7 @@ In order to make functional creature you also need:
## Format
``` javascript
```json5
// camelCase unique creature identifier
"creatureName" :
{

View File

@ -5,6 +5,7 @@ This page helps you to create a creature (i.e. a unit that fights in a battle) f
## Utilities
You need to download the two utilities [`DefPreview`](https://sourceforge.net/projects/grayface-misc/files/DefPreview-1.2.1/) and [`H3DefTool`](https://sourceforge.net/projects/grayface-misc/files/H3DefTool-3.4.2/) from the internet:
- `DefPreview` converts a `.def` file to `.bmp` images
- `H3DefTool` converts `.bmp` images to a `.def` file
@ -21,7 +22,9 @@ The sun is always at zenith, so the shadow is always behind. The reason is that
We don't know the right elevation angle for the view.
### 3D render
You can render your creature using a 3D software like _Blender_. You can start with those free-licenced rigged 3D models:
You can render your creature using a 3D software like *Blender*. You can start with those free-licenced rigged 3D models:
- [Fantasy-bandit](https://www.cgtrader.com/free-3d-models/character/man/fantasy-bandit)
- [Monster-4](https://www.cgtrader.com/free-3d-models/character/fantasy-character/monster-4-f5757b92-dc9c-4f5e-ad0d-593203d14fe2)
- [Crypt-fiend-modular-character](https://www.cgtrader.com/free-3d-models/character/fantasy-character/crypt-fiend-modular-character-demo-scene)
@ -33,57 +36,60 @@ You can render your creature using a 3D software like _Blender_. You can start w
- [Shani](https://www.cgtrader.com/free-3d-models/character/woman/shani-3d-character)
You can also create your 3D model from a single image:
- _Stable Fast 3D_: https://huggingface.co/spaces/stabilityai/stable-fast-3d
- _Unique3D_: https://huggingface.co/spaces/abreza/Unique3D
To use it in _Blender_, create a `.blend` project and import the file. To render the texture:
1. Add a _Principled BSDF_ material to the object
1. Create a _Color Attribute_ in the _Shader Editor_ view
1. Link the Color output of the _Color Attribute_ to the _Base color_ input of the _Principled BSDF_
- *Stable Fast 3D*: <https://huggingface.co/spaces/stabilityai/stable-fast-3d>
- *Unique3D*: <https://huggingface.co/spaces/abreza/Unique3D>
You can improve details by cropping the source image on a detail and generate a model for this detail. Once both imported in _Blender_, melt them together.
To use it in *Blender*, create a `.blend` project and import the file. To render the texture:
Render the images without background by selecting png RVBA and disabling background (_Film_ -> _Filter_ -> _Transparent_). It avoids the creatures to have an ugly dark border. Then, to correctly separate the creature from the cyan area, in _GIMP_, apply the threeshold on the transparency by clicking on _Layer_ -> _Transparency_ -> _Alpha threeshold_.
1. Add a *Principled BSDF* material to the object
1. Create a *Color Attribute* in the *Shader Editor* view
1. Link the Color output of the *Color Attribute* to the *Base color* input of the *Principled BSDF*
You can improve details by cropping the source image on a detail and generate a model for this detail. Once both imported in *Blender*, melt them together.
Render the images without background by selecting png RVBA and disabling background (*Film* -> *Filter* -> *Transparent*). It avoids the creatures to have an ugly dark border. Then, to correctly separate the creature from the cyan area, in *GIMP*, apply the threeshold on the transparency by clicking on *Layer* -> *Transparency* -> *Alpha threeshold*.
The global FPS of the game is 10 f/s but you can render at a higher level and configure it in the `.json` files. We are not in the 1990's.
### IA render
You can also use an AI like _Flux_ to generate the main creature representation: https://huggingface.co/spaces/multimodalart/FLUX.1-merged
You can also use an AI like *Flux* to generate the main creature representation: <https://huggingface.co/spaces/multimodalart/FLUX.1-merged>
Then you can add random animations for idle states with _SVD_: https://huggingface.co/spaces/xi0v/Stable-Video-Diffusion-Img2Vid
Then you can add random animations for idle states with *SVD*: <https://huggingface.co/spaces/xi0v/Stable-Video-Diffusion-Img2Vid>
Most of the time, the creatures do not move more than one pixel in an idle animation. The reason may be to avoid too much animation on screen and make the transition with the other animations always seamless. Use poses with _ControlNet_ or _OpenPose_. For specific animations, I recommend to use _Cinemo_ because it adds a description prompt but the resolution is smaller: https://huggingface.co/spaces/maxin-cn/Cinemo
Most of the time, the creatures do not move more than one pixel in an idle animation. The reason may be to avoid too much animation on screen and make the transition with the other animations always seamless. Use poses with *ControlNet* or *OpenPose*. For specific animations, I recommend to use *Cinemo* because it adds a description prompt but the resolution is smaller: <https://huggingface.co/spaces/maxin-cn/Cinemo>
Make animations seamless from one to another. To do this, you can draw the first and the last images with a prompt with _ToonCrafter_: https://huggingface.co/spaces/ChristianHappy/tooncrafter
Make animations seamless from one to another. To do this, you can draw the first and the last images with a prompt with *ToonCrafter*: <https://huggingface.co/spaces/ChristianHappy/tooncrafter>
Most of the time, you need to increase the resolution or the quality of your template image, so use _SUPIR_: https://huggingface.co/spaces/Fabrice-TIERCELIN/SUPIR
Most of the time, you need to increase the resolution or the quality of your template image, so use *SUPIR*: <https://huggingface.co/spaces/Fabrice-TIERCELIN/SUPIR>
## Battle sound effect
To create the audio effects, I recommend to use _Tango 2_: https://huggingface.co/spaces/declare-lab/tango2
To create the audio effects, I recommend to use *Tango 2*: <https://huggingface.co/spaces/declare-lab/tango2>
The quality is better than _Stable Audio_.
The quality is better than *Stable Audio*.
## Map render
We don't know the right elevation angle for the view but 45° elevation seems to be a good choice. For the sunlight direction, I would say 45° elevation and 45° azimut.
The map creatures are not rendered on the map with vanishing points but in isometric. You can [get an orthogonal render in Blender](https://blender.stackexchange.com/a/135384/2768). If you are creating a creature and its updated version, most of the time, the both creatures are not oriented to the same side on the map. I think that the animation on the map is usually the _Mouse Over_ animation on battle.
The map creatures are not rendered on the map with vanishing points but in isometric. You can [get an orthogonal render in Blender](https://blender.stackexchange.com/a/135384/2768). If you are creating a creature and its updated version, most of the time, the both creatures are not oriented to the same side on the map. I think that the animation on the map is usually the *Mouse Over* animation on battle.
You can see that the view angle is higher than on a battle. To change the angle from a battle sprite, you can use _Zero 1-to-3_: https://huggingface.co/spaces/cvlab/zero123-live
You can see that the view angle is higher than on a battle. To change the angle from a battle sprite, you can use *Zero 1-to-3*: <https://huggingface.co/spaces/cvlab/zero123-live>
You can get higher resolution using this Video AI that can control the motion of the camera: https://huggingface.co/spaces/TencentARC/MotionCtrl_SVD
You can get higher resolution using this Video AI that can control the motion of the camera: <https://huggingface.co/spaces/TencentARC/MotionCtrl_SVD>
If you have a 3D software, you can get better quality by converting your image into 3D model and then render it from another angle using _Stable Fast 3D_: https://huggingface.co/spaces/stabilityai/stable-fast-3d
If you have a 3D software, you can get better quality by converting your image into 3D model and then render it from another angle using *Stable Fast 3D*: <https://huggingface.co/spaces/stabilityai/stable-fast-3d>
Follow this comment to retrieve the color: https://huggingface.co/stabilityai/TripoSR/discussions/1#65e8a8e5e214f37d85dad366
Follow this comment to retrieve the color: <https://huggingface.co/stabilityai/TripoSR/discussions/1#65e8a8e5e214f37d85dad366>
### Shadow render
There are no strong rules in the original game about the angle of the shadows on the map. Different buildings have inconsistent shadows. To draw the shadow, I recommend the following technique:
Let's consider that the object is a vertical cone:
| | | | | | | | | | |
|---|---|---|---|---|---|---|---|---|---|
| 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 |
@ -98,6 +104,7 @@ Let's consider that the object is a vertical cone:
| 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 |
Locate the top and its projection to the ground:
| | | | | | | | | | |
|---|---|---|---|---|---|---|---|---|---|
| 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 |
@ -112,6 +119,7 @@ Locate the top and its projection to the ground:
| 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 |
Then draw a rectangle triangle on the left:
| | | | | | | | | | |
|---|---|---|---|---|---|---|---|---|---|
| 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 |
@ -126,6 +134,7 @@ Then draw a rectangle triangle on the left:
| 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 |
The square top is the projection of the shadow of the top of the cone:
| | | | | | | | | | |
|---|---|---|---|---|---|---|---|---|---|
| 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 |
@ -140,6 +149,7 @@ The square top is the projection of the shadow of the top of the cone:
| 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 |
Then you can draw the rest of the shadow:
| | | | | | | | | | |
|---|---|---|---|---|---|---|---|---|---|
| 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 | 🟦 |

View File

@ -47,7 +47,7 @@ Each town requires a set of buildings (Around 30-45 buildings)
## Faction node (root entry for town configuration)
```jsonc
```json5
// Unique faction identifier.
"myFaction" :
{
@ -108,7 +108,7 @@ Each town requires a set of buildings (Around 30-45 buildings)
## Town node
```jsonc
```json5
{
// Field that describes behavior of map object part of town. Town-specific part of object format
"mapObject" :
@ -256,7 +256,7 @@ Each town requires a set of buildings (Around 30-45 buildings)
## Siege node
```jsonc
```json5
// 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"
@ -340,7 +340,9 @@ Each town requires a set of buildings (Around 30-45 buildings)
```
## Building node
See [Town Building Format](Town_Building_Format.md)
## Structure node
See [Town Building Format](Town_Building_Format.md)

View File

@ -3,90 +3,109 @@
This page helps you to create from scratch a VCMI mod that adds a new faction. The faction mod structure is described [here](Faction_Format.md).
## Questioning the faction creation
Before creating a faction, be aware that creating a faction mod is lots of work. You can start [creating creatures](Creature_Help.md) in a creature mod that can be converted into a faction mod after. This way, you are sure to release something. The smallest contribution is a hero portrait that you can suggest on an existing mod. You can also restore the former version of the [Ruins faction](https://github.com/vcmi-mods/ruins-town/tree/1bea30a1d915770e2fd0f95d158030815ff462cd). You would only have to remake the similar parts to the new version.
## Make a playable faction mod
Before creating your content, retrieve the content of an existing faction mod like [Highlands town](https://github.com/vcmi-mods/highlands-town). To download the project, click on the _Code_ button and click on _Download ZIP_. The first thing to do is to change all the faction identifiers in the files following the [faction format](Faction_Format.md) and manage to play with the faction and the original without any conflict. To play to a faction, you have to add all the files in your _Mods_ folder. When it works, you will be able to modify the content step by step.
Before creating your content, retrieve the content of an existing faction mod like [Highlands town](https://github.com/vcmi-mods/highlands-town). To download the project, click on the *Code* button and click on *Download ZIP*. The first thing to do is to change all the faction identifiers in the files following the [faction format](Faction_Format.md) and manage to play with the faction and the original without any conflict. To play to a faction, you have to add all the files in your *Mods* folder. When it works, you will be able to modify the content step by step.
Keep in mind that the most important part of a faction mod, above the animations, the graphisms and the musics, is the concept because if you have to change it, you have to change everything else. All the remaining content can be improved by the community.
## Town screen
### Background
Beware to direct all the shadows to the same direction. The easiest way to create the background is to use a text-to-image AI. The free most powerful AI at the moment is _Flux_ available here: https://huggingface.co/spaces/multimodalart/FLUX.1-merged
In the _Advanced Options_, set the width to 800px and set the height to 374px.
### Background
Beware to direct all the shadows to the same direction. The easiest way to create the background is to use a text-to-image AI. The free most powerful AI at the moment is *Flux* available here: <https://huggingface.co/spaces/multimodalart/FLUX.1-merged>
In the *Advanced Options*, set the width to 800px and set the height to 374px.
### Buildings
To render a building upon the background, I recommend to use an inpainting AI like _BRIA Inpaint_: https://huggingface.co/spaces/briaai/BRIA-2.3-Inpainting
To render a building upon the background, I recommend to use an inpainting AI like *BRIA Inpaint*: <https://huggingface.co/spaces/briaai/BRIA-2.3-Inpainting>
The idea is to select the area where you want to add the building. As a prompt, describe the new building. The advantage is a perfect match between the background and the building. Keep in mind that to correctly integrate a building image, it must contain the image of the background on its edges. It simulates the semi-transparency.
You can also animate the building or the background using _Stable Video Diffusion_: https://huggingface.co/spaces/multimodalart/stable-video-diffusion
You can also animate the building or the background using *Stable Video Diffusion*: <https://huggingface.co/spaces/multimodalart/stable-video-diffusion>
## Map dwellings
You may want to get the same render as in the town, so you have to change the angle and the shadows. If you handle a 3D model software, you can start with _Stable Fast 3D_: https://huggingface.co/spaces/stabilityai/stable-fast-3d
You may want to get the same render as in the town, so you have to change the angle and the shadows. If you handle a 3D model software, you can start with *Stable Fast 3D*: <https://huggingface.co/spaces/stabilityai/stable-fast-3d>
The map dwellings are not rendered on the map with vanishing points but in isometric. You can [get an orthogonal render in Blender](https://blender.stackexchange.com/a/135384/2768).
Without 3D, you can use _Zero 1-to-3_: https://huggingface.co/spaces/cvlab/zero123-live
Without 3D, you can use *Zero 1-to-3*: <https://huggingface.co/spaces/cvlab/zero123-live>
You can get higher resolution using this Video AI that can control the motion of the camera: https://huggingface.co/spaces/TencentARC/MotionCtrl_SVD
You can get higher resolution using this Video AI that can control the motion of the camera: <https://huggingface.co/spaces/TencentARC/MotionCtrl_SVD>
The buildings on the map are more satured than on town screen. If you have to reduce the size of an image, do not use interpolation (LANCZOS, Bilinear...) to get more details, not a blurred image. If you need to increase the resolution or the quality of your template image, use _SUPIR_: https://huggingface.co/spaces/Fabrice-TIERCELIN/SUPIR
The buildings on the map are more satured than on town screen. If you have to reduce the size of an image, do not use interpolation (LANCZOS, Bilinear...) to get more details, not a blurred image. If you need to increase the resolution or the quality of your template image, use *SUPIR*: <https://huggingface.co/spaces/Fabrice-TIERCELIN/SUPIR>
## Map buildings
The AIs badly understand the sun direction and the perspective angles. To generate the buildings on the adventure map:
1. Open the HOMM3 map editor
1. Put items all around a big empty area
1. Make a screenshot
1. Go on an AI like _BRIA Inpaint_: https://huggingface.co/spaces/briaai/BRIA-2.3-Inpainting
1. Go on an AI like *BRIA Inpaint*: <https://huggingface.co/spaces/briaai/BRIA-2.3-Inpainting>
1. Inpaint the (big) empty middle with the brush
1. Use a prompt like: `A dark house, at the center of the image, map, isometric, parallel perspective, sunlight from the bottom right`
## Music
Here are unused available themes:
* [Synthetic Horizon](https://github.com/Fabrice-TIERCELIN/forge/raw/theme/content/music/factions/theme.ogg)
1. Prompt: `Dystopy, Cinematic classical, Science fiction, 160 bpm, Best quality, Futuristic`
1. Initially created for: _Forge town_
1. Initially created for: *Forge town*
* [Quantum Overture](https://github.com/Fabrice-TIERCELIN/asylum-town/raw/theme/asylum-town/content/Music/factions/AsylumTown.ogg)
1. Prompt: `Clef shifting, Fantasy, Mystical, Overworldly, Cinematic classical`
1. Initially created for: _Asylum town_
1. Initially created for: *Asylum town*
* [Warrior s March](https://github.com/vcmi-mods/ruins-town/assets/20668759/964f27de-6feb-4ef6-9d25-455f52938cef)
1. Prompt: `Powerful percussions, Drums, Battle Anthem, Rythm, Warrior, 160 bpm, Celtic, New age, Instrumental, Accoustic, Medieval`
1. Initially created for: _Ruins town_
1. Initially created for: *Ruins town*
* [Clan of Echoes](https://github.com/Fabrice-TIERCELIN/ruins-town/raw/theme/ruins-town/content/music/ruins.ogg)
1. Prompt: `new age, medieval, celtic, warrior, battle, soundtrack, accoustic, drums, rythm`
1. Initially created for: _Ruins town_
1. Initially created for: *Ruins town*
* [Enchanted Reverie](https://github.com/Fabrice-TIERCELIN/grove/raw/theme/Grove/content/Music/factions/GroveTown.ogg)
1. Prompt: `Classical music, Soundtrack, Score, Instrumental, 160 bpm, ((((fantasy)))), mystic`
1. Initially created for: _Grove town_
1. Initially created for: *Grove town*
* [World Discovery](https://github.com/vcmi-mods/asylum-town/assets/20668759/34438523-8a44-44ca-b493-127501b474a6)
1. Prompt: `Clef shifting, fantasy, mystical, overworldly, Cinematic classical`
1. Initially created for: _Asylum town_
1. Initially created for: *Asylum town*
* [Enchanted Ballad](https://github.com/vcmi-mods/fairy-town/assets/20668759/619e6e33-d940-4899-8c76-9c1e8d3d20aa)
1. Prompt: `Females vocalize, Cinematic classical, Harp, Fairy tale, Princess, 160 bpm`
1. Initially created for: _Fairy town_
1. Initially created for: *Fairy town*
* [Baroque Resurgence](https://github.com/Fabrice-TIERCELIN/courtyard_proposal/raw/theme/Courtyard/Content/music/factions/courtyard/CourtTown.ogg)
1. Prompt: `Baroque, Instrumental, 160 bpm, Cinematic classical, Best quality`
1. Initially created for: _Courtyard town_
1. Initially created for: *Courtyard town*
* [Harvest Parade](https://github.com/Fabrice-TIERCELIN/greenhouse-town/raw/theme/Greenhouse/content/Music/town.ogg)
1. Prompt: `Marching band, Best quality, Happy, Vegetables`
1. Initially created for: _Green town_
Those themes have been generated using _[Udio](https://udio.com)_.
1. Prompt: `Marching band, Best quality, Happy, Vegetables`
1. Initially created for: *Green town*
Those themes have been generated using *[Udio](https://udio.com)*.
## Screenshots
Most of the time, the first screenshot is the townscreen because it's the most specific content.
## Recycle
Some mods contain neutral heroes or creatures. You can integrate them in your faction mod. Don't forget to remove the content from the original mod.

View File

@ -9,7 +9,7 @@ In order to make functional hero class you also need:
## Format
``` javascript
```json5
// Unique identifier of hero class, camelCase
"myClassName" :
{

View File

@ -9,7 +9,7 @@ In order to make functional hero you also need:
## Format
``` javascript
```json5
"myHeroName" :
{
// Identifier of class this hero belongs to. Such as knight or battleMage

View File

@ -2,7 +2,7 @@
## Format
```jsonc
```json5
"newRiver" :
{
// Two-letters unique identifier for this river. Used in map format

View File

@ -2,7 +2,7 @@
## Format
```jsonc
```json5
"newRoad" :
{
// Two-letters unique identifier for this road. Used in map format

View File

@ -2,7 +2,7 @@
## Main format
```jsonc
```json5
{
// Skill be only be available on maps with water
"onlyOnWaterMap" : false,
@ -11,7 +11,7 @@
}
```
```jsonc
```json5
{
"skillName":
{
@ -55,7 +55,7 @@ level fields become optional if they equal "base" configuration.
## Skill level format
```jsonc
```json5
{
// Localizable description
// Use {xxx} for formatting
@ -87,7 +87,7 @@ level fields become optional if they equal "base" configuration.
The following modifies the tactics skill to grant an additional speed
boost at advanced and expert levels.
```jsonc
```json5
"core:tactics" : {
"base" : {
"effects" : {

View File

@ -2,7 +2,7 @@
## Main format
``` javascript
```json5
{
"spellName":
{
@ -156,7 +156,7 @@
TODO
``` javascript
```json5
{
"projectile": [
{"minimumAngle": 0 ,"defName":"C20SPX4"},
@ -179,7 +179,7 @@ Json object with data common for all levels can be put here. These configuration
This will make spell affect single target on all levels except expert, where it is massive spell.
``` javascript
```json5
"base":{
"range": 0
},
@ -192,7 +192,7 @@ This will make spell affect single target on all levels except expert, where it
TODO
``` javascript
```json5
{
//Mandatory, localizable description. Use {xxx} for formatting
@ -262,7 +262,7 @@ Configurable spells ignore *offensive* flag, *effects* and *cumulativeEffects*.
TODO
``` javascript
```json5
"mod:effectId":{
@ -283,7 +283,7 @@ TODO
TODO
``` javascript
```json5
"mod:effectId":{
@ -304,7 +304,7 @@ TODO
Configurable version of Clone spell.
``` javascript
```json5
"mod:effectId":{
@ -320,7 +320,7 @@ TODO
If effect is automatic, spell behave like offensive spell (uses power, levelPower etc)
``` javascript
```json5
"mod:effectId":{
@ -368,7 +368,7 @@ TODO
If effect is automatic, spell behave like \[de\]buff spell (effect and
cumulativeEffects ignored)
``` javascript
```json5
"mod:effectId":{

View File

@ -2,7 +2,7 @@
## Format
```jsonc
```json5
"newTerrain" :
{
// Two-letters unique identifier for this terrain. Used in map format

View File

@ -10,11 +10,14 @@ Each building requires following assets:
- Town hall icon (1 image)
## Examples
These are just a couple of examples of what can be done in VCMI. See vcmi configuration files to check how buildings from Heroes III are implemented or other mods for more examples
####
##### Order of Fire from Inferno:
```jsonc
##### Order of Fire from Inferno
```json5
"special4": {
"requires" : [ "mageGuild1" ],
"name" : "Order of Fire",
@ -37,7 +40,8 @@ These are just a couple of examples of what can be done in VCMI. See vcmi config
```
##### Mana Vortex from Dungeon
```jsonc
```json5
"special2": {
"requires" : [ "mageGuild1" ],
"name" : "Mana Vortex",
@ -65,7 +69,8 @@ These are just a couple of examples of what can be done in VCMI. See vcmi config
```
#### Resource Silo with custom production
```jsonc
```json5
"resourceSilo": {
"name" : "Wood Resource Silo",
"description" : "Produces 2 wood every day",
@ -80,7 +85,8 @@ These are just a couple of examples of what can be done in VCMI. See vcmi config
```
#### Brotherhood of Sword - bonuses in siege
```jsonc
```json5
"special3": {
// replaces +1 Morale bonus from Tavern
"upgradeReplacesBonuses" : true,
@ -96,7 +102,8 @@ These are just a couple of examples of what can be done in VCMI. See vcmi config
```
#### Lighthouse - bonus to all heroes under player control
```jsonc
```json5
"special1": {
"bonuses": [
{
@ -112,7 +119,7 @@ These are just a couple of examples of what can be done in VCMI. See vcmi config
## Town Building node
```jsonc
```json5
{
// Numeric identifier of this building
"id" : 0,
@ -211,7 +218,7 @@ These are just a couple of examples of what can be done in VCMI. See vcmi config
Building requirements can be described using logical expressions:
```jsonc
```json5
"requires" :
[
"allOf", // Normal H3 "build all" mode
@ -228,10 +235,13 @@ Building requirements can be described using logical expressions:
]
]
```
### List of unique town buildings
#### Buildings from Heroes III
Following Heroes III buildings can be used as unique buildings for a town. Their functionality should be identical to a corresponding H3 building. H3 buildings that are not present in this list contain no hardcoded functionality. See vcmi json configuration to see how such buildings can be implemented in a mod.
- `mysticPond`
- `artifactMerchant`
- `freelancersGuild`
@ -244,16 +254,18 @@ Following Heroes III buildings can be used as unique buildings for a town. Their
- `treasury`
#### Buildings from other Heroes III mods
Following HotA buildings can be used as unique building for a town. Functionality should match corresponding HotA building:
- `bank`
#### Custom buildings
In addition to above, it is possible to use same format as [Rewardable](../Map_Objects/Rewardable.md) map objects for town buildings. In order to do that, configuration of a rewardable object must be placed into `configuration` json node in building config.
In addition to above, it is possible to use same format as [Rewardable](../Map_Objects/Rewardable.md) map objects for town buildings. In order to do that, configuration of a rewardable object must be placed into `configuration` json node in building config.
### Town Structure node
```jsonc
```json5
{
// Main animation file for this building
"animation" : "",
@ -281,16 +293,18 @@ In addition to above, it is possible to use same format as [Rewardable](../Map_O
}
```
#### Markets in towns
Market buildings require list of available [modes](../Map_Objects/Market.md)
##### Marketplace
```jsonc
```json5
"marketplace": { "marketModes" : ["resource-resource", "resource-player"] },
```
##### Artifact merchant
```jsonc
```json5
"special1": { "type" : "artifactMerchant", "requires" : [ "marketplace" ], "marketModes" : ["resource-artifact", "artifact-resource"] },
```

View File

@ -7,6 +7,7 @@ In most cases, VCMI supports formats that were supported by Heroes III, with add
### Images
For images VCMI supports:
- png. Recommended for usage in mods
- bmp. While this format is supported, bmp images have no compressions leading to large file sizes
- pcx (h3 version). Note that this is format that is specific to Heroes III and has nothing in common with widely known .pcx format. Files in this format generally can only be found inside of .lod archive of Heroes III and are usually extracted as .bmp files
@ -26,6 +27,7 @@ For animations VCMI supports .def format from Heroes III as well as alternative
### Sounds
For sounds VCMI currently supports:
- .ogg/vorbis format - preferred for mods. Unlike wav, vorbis uses compression which may cause some data loss, however even 128kbit is generally undistinguishable from lossless formats
- .wav format. This is format used by H3. It is supported by vcmi, but it may result in large file sizes (and as result - large mods)
@ -36,6 +38,7 @@ Support for additional formats, such as ogg/opus or flac may be added in future
### Music
For music VCMI currently supports:
- .ogg/vorbis format - preferred for mods. Generally offers better quality and lower sizes compared to mp3
- .mp3 format. This is format used by H3
@ -51,6 +54,7 @@ Starting from VCMI 1.6, following video container formats are supported by VCMI:
- .webm - modern, free format that is recommended for modding.
Supported video codecs:
- bink and smacker - formats used by Heroes III, should be used only to avoid re-encoding
- theora - used by Heroes III: HD Edition
- vp8 - modern format with way better compression compared to formats used by Heroes III
@ -59,6 +63,7 @@ Supported video codecs:
Support for av1 video codec is likely to be added in future.
Supported audio codecs:
- binkaudio and smackaud - formats used by Heroes III
- vorbis - modern format with good compression level
- opus - recommended, improvement over vorbis. Any bitrate is supported, with 128 kbit probably being the best option

View File

@ -13,6 +13,7 @@ If user for example selects 3x resolution and only 2x exists in mod then the 2x
## Mod
For upscaled images you have to use following folders (next to `sprites` and `data` folders):
- `sprites2x`, `sprites3x`, `sprites4x` for sprites
- `data2x`, `data3x`, `data4x` for images
@ -24,11 +25,13 @@ It's also possible (but not necessary) to add high-definition shadows: Just plac
In future, such shadows will likely become required to correctly exclude shadow from effects such as Clone spell.
Shadow images are used only for animations of following objects:
- All adventure map objects
- All creature animations in combat
Same for overlays with `-overlay`. But overlays are **necessary** for some animation graphics. They will be colorized by VCMI.
Currently needed for:
- Flaggable adventure map objects. Overlay must contain a transparent image with white flags on it and will be used to colorize flags to owning player
- Creature battle animations, idle and mouse hover group. Overlay must contain a transparent image with white outline of creature for highlighting on mouse hover)

View File

@ -60,7 +60,7 @@ There are 3 buttons switching views <img width="131" alt="Снимок экра
<img width="190" src="https://user-images.githubusercontent.com/9308612/188778010-a1d45d59-7333-4432-b83f-57190fbe09f4.png">
# Setup terrain
## Setup terrain
1. Select brush you want
<img width="124" src="https://user-images.githubusercontent.com/9308612/188776299-fd688696-a98d-4f89-8bef-e81c90d3724b.png">
@ -85,9 +85,10 @@ To erase roads or rivers, you need to select tiles to be cleaned and press empty
<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_
*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)
@ -171,7 +172,7 @@ You can modify general properties of the map
## Player settings
Open **Map** menu on the top and select **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">
@ -208,6 +209,7 @@ vcmieditor loads set of mods using exactly same mechanism as game uses and mod m
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

View File

@ -16,7 +16,7 @@ Full object consists from 3 parts:
## Object group format
``` javascript
```json5
{
"myCoolObjectGroup":
@ -42,6 +42,7 @@ Full object consists from 3 parts:
## Object types
### Moddable types
These are object types that are available for modding and have configurable properties
- `configurable` - see [Rewardable](Map_Objects/Rewardable.md). Visitable object which grants all kinds of rewards (gold, experience, Bonuses etc...)
@ -55,6 +56,7 @@ These are object types that are available for modding and have configurable prop
- `terrain` - Defines terrain overlays such as magic grounds. TODO: documentation. See config files in vcmi installation for reference
### Common types
These are types that don't have configurable properties, however it is possible to add additional map templates for this objects, for use in editor or in random maps generator
- `static` - Defines unpassable static map obstacles that can be used by RMG
@ -79,6 +81,7 @@ These are types that don't have configurable properties, however it is possible
- `monolith`
### Internal types
These are internal types that are generally not available for modding and are handled by vcmi internally.
- `hero`
@ -96,7 +99,7 @@ These are internal types that are generally not available for modding and are ha
## Object type format
``` javascript
```json5
{
"myCoolObject":
{
@ -150,7 +153,7 @@ These are internal types that are generally not available for modding and are ha
## Object template format
``` javascript
```json5
{
"myCoolObjectTemplate" :
{

View File

@ -1,6 +1,6 @@
# Boat
``` javascript
```json5
{
// Layer on which this boat moves. Possible values:
// "land" - same rules as movement of hero on land

View File

@ -6,9 +6,11 @@ Format of rewards is same as in [Rewardable Objects](Rewardable.md)
Deprecated in 1.6. Please use [Rewardable Objects](Rewardable.md) instead. See Conversion from 1.5 format section below for help with migration
### Example
This example defines a rewardable object with functionality similar of H3 creature bank.
See [Rewardable Objects](Rewardable.md) for detailed documentation of these properties.
```jsonc
```json5
{
"name" : "Cyclops Stockpile",
@ -93,6 +95,7 @@ See [Rewardable Objects](Rewardable.md) for detailed documentation of these prop
```
### Conversion from 1.5 format
This is a list of changes that needs to be done to bank config to migrate it to 1.6 system. See [Rewardable Objects](Rewardable.md) documentation for description of new fields
- If your object type has defined `handler`, change its value from `bank` to `configurable`
@ -112,7 +115,7 @@ This is a list of changes that needs to be done to bank config to migrate it to
### Old format (1.5 or earlier)
``` jsonc
```json5
{
/// If true, battle setup will be like normal - Attacking player on the left, enemy on the right
"regularUnitPlacement" : true,

View File

@ -1,6 +1,6 @@
# Dwelling
``` javascript
```json5
{
/// 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)

View File

@ -3,12 +3,13 @@
Flaggable object are those that can be captured by a visiting hero. H3 examples are mines, dwellings, or lighthouse.
Currently, it is possible to make flaggable objects that provide player with:
- Any [Bonus](Bonus_Format.md) supported by bonus system
- Daily resources income (wood, ore, gold, etc)
## Format description
```jsonc
```json5
{
"baseObjectName" : {
"name" : "Object name",

View File

@ -7,7 +7,7 @@ Markets can be added as any other object with special handler called "market".
Here is schema describing such object
```js
```json5
"seafaringAcademy" : //object name
{
"handler" : "market", //market handler
@ -34,6 +34,7 @@ Here is schema describing such object
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
@ -49,19 +50,20 @@ Following options are supported:
### Trading post
Trading post allows to exchange resources and send resources to another player, so it shall be configured this way:
```json
```json5
"modes" : ["resource-resource", "resource-player"]
```
### Black market
```json
```json5
"modes" : ["resource-artifact"]
```
### Freelance guild
```json
```json5
"modes" : ["creature-resource"]
```
@ -71,7 +73,7 @@ Altar of sacrifice allows exchange creatures for experience for evil factions an
So both modes shall be available in the market.
Game logic prohibits using modes unavailable for faction
```json
```json5
"modes" : ["creature-experience", "artifact-experience"]
```
@ -83,14 +85,14 @@ See [Secondary skills](Rewardable.md#secondary-skills) description for more deta
### Example for University of magic (e.g conflux building)
```js
```json5
"modes" : ["resource-skill"],
"offer" : ["airMagic", "waterMagic", "earthMagic", "fireMagic"]
```
### Example for regular University
```js
```json5
"modes" : ["resource-skill"],
"offer" : [ //4 random skills except necromancy
{ "noneOf" : ["necromancy"] },

View File

@ -1,8 +1,10 @@
# Rewardable
## 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.
```jsonc
```json5
{
"baseObjectName" : {
"name" : "Object name",
@ -34,7 +36,8 @@ Rewardable object is defined similarly to other objects, with key difference bei
```
## Configurable object definition
```jsonc
```json5
// List of potential rewards
"rewards" : [
{
@ -173,7 +176,8 @@ This property allows defining "variables" that are shared between all rewards an
Variables are randomized only once, so you can use them multiple times for example, to give skill only if hero does not have this skill (e.g. Witch Hut).
Example of creation of a variable named "gainedSkill" of type "secondarySkill":
```json
```json5
"variables" : {
"secondarySkill" : {
"gainedSkill" : {
@ -187,6 +191,7 @@ Example of creation of a variable named "gainedSkill" of type "secondarySkill":
```
Possible variable types:
- number: can be used in any place that expects a number
- artifact
- spell
@ -194,19 +199,22 @@ Possible variable types:
- secondarySkill
To reference variable in limiter prepend variable name with '@' symbol:
```json
```json5
"secondary" : {
"@gainedSkill" : 1
},
```
## Reset Parameters definition
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"
```jsonc
```json5
"resetParameters" : {
"period" : 7,
"visitors" : true,
@ -215,15 +223,17 @@ This property describes how object state should be reset. Objects without this f
```
## 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.
Note that object that uses appearChance MUST have continuous range for every value in 0-99 range. For example, object with 3 different rewards may want to define them as
- `"min" : 0, "max" : 33`
- `"min" : 33, "max" : 66`
- `"min" : 66, "max" : 100`
In other words, min chance of second reward must be equal to max chance of previous reward
```jsonc
```json5
"appearChance":
{
// (Advanced) rewards with different dice number will get different dice number
@ -240,8 +250,10 @@ In other words, min chance of second reward must be equal to max chance of previ
```
## Configurable Properties
Unless stated othervice, all numbers in this section can be replaced with random values, e.g.
```jsonc
```json5
"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
```
@ -250,32 +262,35 @@ In this case, actual value for minLevel will be picked randomly.
Keep in mind, that all randomization is performed on map load and on object reset (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
```jsonc
```json5
"dayOfWeek" : 0
```
- Can only be used as limiter. To pass, number of days since game started must be at equal or greater than this value
```jsonc
```json5
"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
```jsonc
```json5
"resources": {
"crystal" : 6,
"gold" : -1000,
},
```
- Alternative format that allows random selection of a resource type
```jsonc
```json5
"resources": [
{
"anyOf" : [ "wood", "ore" ],
@ -289,68 +304,75 @@ Keep in mind, that all randomization is performed on map load and on object rese
```
### Experience
- Can be used as limiter
- Can be used as reward to grant experience to hero
```jsonc
```json5
"heroExperience" : 1000,
```
### Hero Level
- Can be used as limiter. Hero requires to have at least specified level
- 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)
```jsonc
```json5
"heroLevel" : 1,
```
### Mana Points
- 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
```jsonc
```json5
"manaPoints": -10,
```
- 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.
```jsonc
```json5
"manaOverflowFactor" : 50,
```
### Mana Percentage
- 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)
```jsonc
```json5
"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.
```jsonc
```json5
"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
```jsonc
```json5
"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
- Each primary skill can be explicitly specified or randomly selected
- Possible values: `"attack", "defence", "spellpower", "knowledge"`
```jsonc
```json5
"primary": [
{
// Specific primary skill
@ -376,13 +398,15 @@ Keep in mind, that all randomization is performed on map load and on object rese
```
### 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)
- Each secondary skill can be explicitly specified or randomly selected
```jsonc
```json5
"secondary": [
{
// Specific skill
@ -411,17 +435,18 @@ Keep in mind, that all randomization is performed on map load and on object rese
- Can be used as limiter. Hero must have free skill slot to pass limiter
```json
```json5
"canLearnSkills" : true
```
### Bonus System
- Can be used as reward, to grant bonus to player
- if present, MORALE and LUCK bonus will add corresponding image component to UI.
- Note that unlike most values, parameter of bonuses can NOT be randomized
- Description can be string or number of corresponding string from `arraytxt.txt`
```json
```json5
"bonuses" : [
{
"type" : "MORALE",
@ -433,11 +458,12 @@ Keep in mind, that all randomization is performed on map load and on object rese
```
### 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
- Artifacts added as reward will be used for text substitution. First `%s` in text string will be replaced with name of an artifact
```jsonc
```json5
"artifacts": [
"ribCage"
],
@ -447,7 +473,7 @@ Keep in mind, that all randomization is performed on map load and on object rese
- For artifact class possible values are "TREASURE", "MINOR", "MAJOR", "RELIC"
- Artifact value range can be specified with min value and max value
```jsonc
```json5
"artifacts": [
{
"class" : "TREASURE",
@ -458,11 +484,12 @@ Keep in mind, that all randomization is performed on map load and on object rese
```
### Spells
- Can be used as limiter
- Can be used as reward, to give new spell to a hero
- Spells added as reward will be used for text substitution. First `%s` in text string will be replaced with spell name
```jsonc
```json5
"spells": [
"magicArrow"
],
@ -471,7 +498,7 @@ Keep in mind, that all randomization is performed on map load and on object rese
- Alternative format, random spell selection
- Spell can be selected from specifically selected school
```jsonc
```json5
"spells": [
{
"level" : 1,
@ -488,18 +515,20 @@ Keep in mind, that all randomization is performed on map load and on object rese
- - he does not have a spellbook
- - he does not have sufficient Wisdom level for this spell
```json
```json5
"canLearnSpells" : [
"magicArrow"
],
```
### 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 probability to receive upgraded creature
```jsonc
```json5
"creatures" : [
{
"type" : "archer",
@ -510,13 +539,15 @@ Keep in mind, that all randomization is performed on map load and on object rese
```
### Guards
- When used in a reward, these creatures will be added to guards of the objects
- Hero must defeat all guards before being able to receive rewards
- Guards are only reset when object rewards are reset
- Requires `guardsLayout` property to be set in main part of object configuration
- It is possible to add up to 7 slots of creatures
- Guards of the same creature type will never merge or rearrange their stacks
```jsonc
```json5
"guards" : [
{ "type" : "archer", "amount" : 20 },
{ "type" : "archer", "amount" : 20, "upgradeChance" : 30 },
@ -525,22 +556,24 @@ Keep in mind, that all randomization is performed on map load and on object rese
```
### Creatures Change
- Can NOT be used as limiter
- 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
- This parameter will not change creatures given by `creatures` parameter on the same visit
```jsonc
```json5
"changeCreatures" : {
"cavalier" : "champion"
}
```
### Spell cast
- Can NOT be used as limiter
- 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)
```json
```json5
"spellCast" : {
"spell" : "townPortal",
"schoolLevel": 3
@ -555,7 +588,7 @@ Keep in mind, that all randomization is performed on map load and on object rese
- It is possible to specify which terrain classes should be affected. Tile will be affected if sum of values its classes is positive. For example, `"water" : 1` will affect all water tiles, while `"surface" : 1, "subterra" : -1` will include terrains that have "surface" flag but do not have "subterra" flag
- If 'hide' is set to true, then instead of revealing terrain, game will hide affected tiles for all other players
```json
```json5
"revealTiles" : {
"radius" : 20,
"surface" : 1,
@ -567,28 +600,31 @@ Keep in mind, that all randomization is performed on map load and on object rese
```
### Player color
- Can be used as limiter
- Can NOT be used as reward
- Only players with specific color can pass the limiter
```jsonc
```json5
"colors" : [ "red", "blue", "tan", "green", "orange", "purple", "teal", "pink" ]
```
### Hero types
- Can be used as limiter
- Can NOT be used as reward
- Only specific heroes can pass the limiter
```jsonc
```json5
"heroes" : [ "orrin" ]
```
### Hero classes
- Can be used as limiter
- Can NOT be used as reward
- Only heroes belonging to specific classes can pass the limiter
```jsonc
```json5
"heroClasses" : [ "battlemage" ]
```

View File

@ -2,7 +2,7 @@
## Fields with description of mod
``` javascript
```json5
{
// 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
@ -91,7 +91,7 @@
These are fields that are present only in local mod.json file
``` javascript
```json5
{
// Following section describes configuration files with content added by mod
@ -210,7 +210,7 @@ See [Translations](Translations.md) for more information
These are fields that are present only in remote repository and are generally not used in mod.json
```jsonc
```json5
{
// URL to mod.json that describes this mod
"mod" : "https://raw.githubusercontent.com/vcmi-mods/vcmi-extras/vcmi-1.4/mod.json",

View File

@ -2,7 +2,7 @@
## Template format
``` javascript
```json5
/// Unique template name
"Triangle" :
{
@ -56,7 +56,7 @@
## Zone format
``` javascript
```json5
{
// Type of this zone. Possible values are:
// "playerStart", "cpuStart", "treasure", "junction"

View File

@ -21,8 +21,8 @@ Example of how directory structure of your mod may look like:
sprites/ - animation, image sets (H3 .def files or VCMI .json files)
video/ - video files, .bik, .smk, .ogv .webm
```
See [File Formats](File_Formats.md) page for more information on which formats are supported or recommended for vcmi
See [File Formats](File_Formats.md) page for more information on which formats are supported or recommended for vcmi
## Creating mod file
@ -30,7 +30,7 @@ All VCMI configuration files use [JSON format](http://en.wikipedia.org/wiki/Json
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
```json5
{
"name" : "My test mod",
"description" : "My test mod that add a lot of useless stuff into the game",
@ -45,6 +45,7 @@ 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
@ -52,9 +53,11 @@ In order to create new object use following steps:
### 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 Requirement](Entities_Format/Creature_Format.md)
- [Creature Help](Entities_Format/Creature_Help.md)
@ -66,6 +69,7 @@ Game Entities:
- [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)
@ -74,6 +78,7 @@ Map objects:
- - [Boat](Map_Objects/Boat.md)
Other:
- [Terrain](Entities_Format/Terrain_Format.md)
- [River](Entities_Format/River_Format.md)
- [Road](Entities_Format/Road_Format.md)
@ -96,7 +101,8 @@ VCMI uses strings to reference objects. Examples:
### Modifying existing objects
Alternatively to creating new objects, you can edit existing objects. Normally, when creating new objects you specify object name as:
``` javascript
```json5
"newCreature" : {
// creature parameters
}
@ -104,7 +110,7 @@ Alternatively to creating new objects, you can edit existing objects. Normally,
In order to access and modify existing object you need to specify mod that you wish to edit:
``` javascript
```json5
/// "core" specifier refers to objects that exist in H3
"core:archer" : {
/// This will set health of Archer to 10
@ -123,6 +129,7 @@ In order to access and modify existing object you need to specify mod that you w
"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.
@ -132,6 +139,7 @@ This allows using objects editing not just for rebalancing mods but also to prov
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
@ -145,12 +153,13 @@ This includes archives added by expansions (e.g. **H3ab_bmp.lod** uses same rule
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
```json5
{
// List of replaced images
"images" :
@ -191,7 +200,7 @@ Same way we can also create special stable branch for every mod under "vcmi-mods
### 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
Link to our mod will looks like that: <https://github.com/vcmi-mods/adventure-ai-trace>
## Rules of repository
@ -199,8 +208,10 @@ Link to our mod will looks like that: https://github.com/vcmi-mods/adventure-ai-
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.

View File

@ -70,9 +70,11 @@ Alternative usage: `vcmiexp <amount>` - gives selected hero specified amount of
`nwcbluepill` or `vcmimelkor` or `vcmilose` - player loses
### Misc
`nwctheone` or `vcmigod` - reveals the whole map, gives 5 archangels in each empty slot, unlimited movement points and permanent flight
## Using cheat codes on other players
By default, all cheat codes apply to current player. Alternatively, it is possible to specify player that you want to target:
- Specific players: `red`/`blue`/`green`...
@ -89,12 +91,14 @@ By default, all cheat codes apply to current player. Alternatively, it is possib
## Multiplayer chat commands
Following commands can be used in multiplayer only by host player to control the session:
- `!exit` - finish the game
- `!save <filename>` - save the game into the specified file
- `!kick red/blue/tan/green/orange/purple/teal/pink` - kick player of specified color from the 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`)
- `!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`)
Following commands can be used by any player in multiplayer:
- `!help` - displays in-game list of available commands
- `!cheaters` - lists players that have entered cheat at any point of the game
- `!vote` - initiates voting to change one of the possible options:
@ -114,12 +118,14 @@ Windows builds of VCMI run separate console window by default, on other platform
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
`translate` - save game texts into json files
`translate missing` - save untranslated game texts into json files
`translate maps` - save map and campaign texts into json files
@ -131,15 +137,17 @@ Below a list of supported commands, with their arguments wrapped in `<>`
`generate assets` - generate all assets at once
#### 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_
-`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
@ -147,6 +155,7 @@ Below a list of supported commands, with their arguments wrapped in `<>`
-`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)

View File

@ -174,6 +174,7 @@ TODO
Simultaneous turns allow multiple players to act at the same time, speeding up early game phase in multiplayer games. During this phase if different players (allies or not) attempt to interact with each other, such as capture objects owned by other players (mines, dwellings, towns) or attack their heroes, game will block such actions. Interaction with same map objects at the same time, such as attacking same wandering monster is also blocked.
Following options can be used to configure simultaneous turns:
- Minimal duration (at least for): this is duration during which simultaneous turns will run unconditionally. Until specified number of days have passed, simultaneous turns will never break and game will not attempt to detect contacts.
- Maximal duration (at most for): this is duration after which simultaneous turns will end unconditionally, even if players still have not contacted each other. However if contact detection discovers contact between two players, simultaneous turns between them might end before specified duration.
- Simultaneous turns for AI: If this option is on, AI can act at the same time as human players. Note that AI shares settings for simultaneous turns with human players - if no simultaneous turns have been set up this option has no effect.
@ -185,6 +186,7 @@ Players are considered to be "in contact" if movement range of their heroes at t
Once detected, contact can never be "lost". If game detected contact between two players, this contact will remain active till the end of the game, even if their heroes move far enough from each other.
Game performs contact detection once per turn, at the very start of each in-game day. Once contact detection has been performed, players that are not in contact with each other can start making turn. For example, in game with 4 players: red, blue, brown and green. If game detected contact between red and blue following will happen:
- red, brown and green will all instantly start turn
- once red ends his turn, blue will be able to start his own turn (even if brown or green are still making turn)
@ -197,4 +199,4 @@ Differences compared to HD Mod version:
## 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.
- <https://heroes.thelazy.net/index.php/Main_Page> Wiki that aims to be a complete reference to Heroes of Might and Magic III.

View File

@ -9,6 +9,7 @@ VCMI requires data from original Heroes 3: Shadow of Death or Complete editions.
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
@ -20,25 +21,30 @@ To install VCMI from PPA use:
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
```
### Ubuntu - 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
@ -52,6 +58,7 @@ Stable VCMI version is available in RPM Fusion repository. Learn how to enable i
sudo dnf update
sudo dnf install vcmi
```
### Flatpak (distribution-agnostic)
Latest public release build can be installed via Flatpak.
@ -87,11 +94,13 @@ To install Heroes 3 data using automated script you need any of:
- 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:
@ -107,9 +116,11 @@ Download both files for the "offline backup game installers" and extract them us
You can select both downloaded files in launcher to extract automatically.
Alternatively you can use the classic way:
```
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 place existing files. Select the ~/Downloads/HoMM3 directory. Once placing is complete, you can delete both offline installer files as well as ~/Downloads/HoMM3.

View File

@ -19,15 +19,14 @@ iii) To install the .ipa file on your device do one of the following:
- In AltStore go to >My Apps > press + in the top left corner. Select VCMI-iOS.ipa to install,
- or drag and drop the .ipa file into your iOS device in iTunes
## Step 2: Installing Heroes III data files
If you bought HoMM3 on [GOG](https://www.gog.com/de/game/heroes_of_might_and_magic_3_complete_edition), you can download the files directly from the browser in the device.
Launch VCMI app on the device and the launcher will prompt two files to complete the installation. Select the **.bin** file first, then the **.exe** file. This may take a few seconds. Please be patient.
## Step 3: Configuration settings
Once you have installed VCMI and have the launcher opened, select Settings on the left bar. The following Video settings are recommended:
- Lower reserved screen area to zero.
@ -54,7 +53,9 @@ The easiest way to install the ipa on your device is to do one of the following:
Alternatively, to install the signed ipa on your device, you can use Xcode or Apple Configurator (available on the Mac App Store for free). The latter also allows installing ipa from the command line, here's an example that assumes you have only 1 device connected to your Mac and the signed ipa is on your desktop:
```
/Applications/Apple\ Configurator.app/Contents/MacOS/cfgutil install-app ~/Desktop/vcmi.ipa
```
## Alternative Step 2: Installing Heroes III data files

View File

@ -23,6 +23,7 @@ This is list of all languages that are currently supported by VCMI. If your lang
- Vietnamese
## Progress of the translations
You can see the current progress of the different translations here:
[Translation progress](https://github.com/vcmi/vcmi-translation-status)
@ -32,17 +33,18 @@ The page will be automatically updated once a week.
VCMI allows translating game data into languages other than English. In order to translate Heroes III in your language easiest approach is to:
- Copy existing translation, such as English translation from here: https://github.com/vcmi-mods/h3-for-vcmi-englisation (delete sound and video folders)
- Copy text-free images from here: https://github.com/vcmi-mods/empty-translation
- Copy existing translation, such as English translation from here: <https://github.com/vcmi-mods/h3-for-vcmi-englisation> (delete sound and video folders)
- Copy text-free images from here: <https://github.com/vcmi-mods/empty-translation>
- Rename mod to indicate your language, preferred form is "(language)-translation"
- Update mod.json to match your mod
- Translate all texts strings from `game.json`, `campaigns.json` and `maps.json`
- Replace images in data and sprites with translated ones (or delete it if you don't want to translate them)
- If unicode characters needed for language: Create a submod with a free font like here: https://github.com/vcmi-mods/vietnamese-translation/tree/vcmi-1.4/vietnamese-translation/mods/VietnameseTrueTypeFonts
- If unicode characters needed for language: Create a submod with a free font like here: <https://github.com/vcmi-mods/vietnamese-translation/tree/vcmi-1.4/vietnamese-translation/mods/VietnameseTrueTypeFonts>
If you can't produce some content on your own (like the images or the sounds):
- Create a `README.md` file at the root of the mod
- Write into the file the translations and the <ins>detailled</ins> location
- Write into the file the translations and the **detailled** location
This way, a contributor that is not a native speaker can do it for you in the future.
@ -57,8 +59,10 @@ This will export all strings from game into `Documents/My Games/VCMI/extracted/t
To export maps and campaigns, use '/translate maps' command instead.
### Video subtitles
It's possible to add video subtitles. Create a JSON file in `video` folder of translation mod with the name of the video (e.g. `H3Intro.json`):
```
```json5
[
{
"timeStart" : 5.640, // start time, seconds
@ -84,6 +88,7 @@ Before you start, make sure that you have copy of VCMI source code. If you are n
### Translation of in-game data
In order to translate in-game data you need:
- Add section with your language to `<VCMI>/Mods/VCMI/mod.json`, similar to other languages
- Copy English translation file in `<VCMI>/Mods/VCMI/config/vcmi/english.json` and rename it to name of your language. Note that while you can copy any language other than English, other files might not be up to date and may have missing strings.
- Translate copied file to your language.
@ -94,7 +99,7 @@ After this, you can set language in Launcher to your language and start game. Al
VCMI Launcher and Map Editor use translation system provided by Qt framework so it requires slightly different approach than in-game translations:
- Install Qt Linguist. You can find find standalone version here: https://download.qt.io/linguist_releases/
- Install Qt Linguist. You can find find standalone version here: <https://download.qt.io/linguist_releases/>
- Open `<VCMI Sources>/launcher/translation/` directory, copy `english.ts` file and rename it to your language
- Open `<VCMI Sources>/launcher/CMakeLists.txt` file with a text editor. In there you need to find list of existing translation files and add new file to the list.
- Launch Qt Linguist, select Open and navigate to your copied file
@ -112,23 +117,27 @@ TODO: how to test translation locally
The [AppStream](https://freedesktop.org/software/appstream/docs/chap-Metadata.html) [metainfo file](https://github.com/vcmi/vcmi/blob/develop/launcher/eu.vcmi.VCMI.metainfo.xml) is used for Linux software centers.
It can be translated using a text editor or using [jdAppStreamEdit](https://flathub.org/apps/page.codeberg.JakobDev.jdAppStreamEdit):
- Install jdAppStreamEdit
- Open `<VCMI>/launcher/eu.vcmi.VCMI.metainfo.xml`
- Translate and save the file
##### Desktop file
- Edit `<VCMI>/launcher/vcmilauncher.desktop` and `<VCMI>/launcher/vcmieditor.desktop`
- Add `GenericName[xyz]` and `Comment[xyz]` with your language code and translation
##### Translation of Android Launcher
- Copy `<VCMI>/android/vcmi-app/src/main/res/values/strings.xml` to `<VCMI>/android/vcmi-app/src/main/res/values-xyz/strings.xml` (`xyz` is your language code)
- Translate this file
See also here: https://developer.android.com/guide/topics/resources/localization
See also here: <https://developer.android.com/guide/topics/resources/localization>
### Submitting changes
Once you have finished with translation you need to submit these changes to vcmi team using git or Github Desktop
- Commit all your changed files
- Push changes to your forked repository
- Create pull request in VCMI repository with your changes
@ -152,8 +161,10 @@ If your mod also contains maps or campaigns that you want to translate, then use
If you want to update existing translation, you can use '/translate missing' command that will export only strings that were not translated
### Translating mod information
In order to display information in Launcher in language selected by user add following block into your `mod.json`:
```
```json5
"<language>" : {
"name" : "<translated name>",
"description" : "<translated description>",
@ -163,6 +174,7 @@ In order to display information in Launcher in language selected by user add fol
]
},
```
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.
### Translating in-game strings
@ -174,7 +186,9 @@ Use any text editor (Notepad++ is recommended for Windows) and translate all str
## Developers documentation
### 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 `lib/Languages.h` entry. This will trigger static_assert's in places that needs an update in code
- Add new language into json schemas validation list - settings schema and mod schema
@ -187,7 +201,8 @@ Also, make full search for a name of an existing language to ensure that there a
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
```
```sh
lupdate -no-obsolete * -ts translation/*.ts
```
@ -197,5 +212,6 @@ There *may* be a way to do the same via QtCreator UI or via CMake, if you find o
### 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`