mirror of
https://github.com/vcmi/vcmi.git
synced 2024-11-21 17:17:06 +02:00
Merge branch 'vcmi/master' into 'vcmi/develop'
This commit is contained in:
commit
2ddb41e654
19
ChangeLog.md
19
ChangeLog.md
@ -2,8 +2,11 @@
|
||||
|
||||
### General
|
||||
* Added Portuguese (Brazilian) translation
|
||||
* Added basic support for game controllers
|
||||
* Added option to disable cheats in game
|
||||
* Game will no longer run vcmiserver as a separate process on desktop systems
|
||||
* Game will no longer show server error messages in game chat in release builds
|
||||
* Implemented switchable artifact sets from HD Mod
|
||||
|
||||
### Stability
|
||||
* Fixed possible crash in Altar of Sacrifice
|
||||
@ -19,12 +22,19 @@
|
||||
* Fixed crash on moving through whirlpool when hero has no troops other than commander
|
||||
* Fixed possible freeze when moving hero over events that give enough experience to cause a level-up
|
||||
* Fixed possible crash on movement of double-wide creatures next to gates during siege
|
||||
* Fixed possible hanging app on attempt to close game during loading
|
||||
|
||||
### Multiplayer
|
||||
* Game map will no longer be locked during turn of other human players, allowing to change hero paths or inspect towns or heroes
|
||||
* Game will now correctly block most of player actions outside of their turn
|
||||
* Implemented new lobby, available in game with persistent accounts and chat
|
||||
* Removed old lobby previously available in launcher
|
||||
* Fixed potential crash that could occur if two players act at the very same time
|
||||
* Game will no longer pause due to network lag after every tile when instant movement speed is selected in multiplayer
|
||||
* Game will now show "X player's turn" dialog on new turn in online multiplayer
|
||||
* Fixed loading of turn timers state from saved games
|
||||
* Simultaneous turns will now break when players are 1 turn away from each other instead of 2 turns
|
||||
* Implemented rolling and banning of towns before game start
|
||||
|
||||
### Interface
|
||||
* Implemented configurable keyboard shortcuts, editable in file config/shortcutsConfig.json
|
||||
@ -35,6 +45,7 @@
|
||||
* It is no longer possible to start single scenario by pressing "Enter", in line with H3 and to prevent interference with game chat
|
||||
* Empty treasure banks will no longer ask for confirmation when entering
|
||||
* Game will now save last used difficulty settings
|
||||
* Opening random map tab or scenario selection tab in pregame will no longer reset starting towns or heroes unless different map was selected
|
||||
* Town Portal dialog will now show town icons
|
||||
* Town Portal dialog will now show town info on right click
|
||||
* Town Portal dialog will center on town on clicking it
|
||||
@ -55,10 +66,12 @@
|
||||
* Fixed translation of some bonuses using incorrect language
|
||||
* Added option to use 'nearest' rounding mode for UI scaling
|
||||
* Fixed various minor bugs in trade window interface
|
||||
* Removed animation of spawning of every single new monster on new month
|
||||
* Game will now correctly reset artifact drag-and-drop cursor if player opens another dialog on top of hero window
|
||||
* If player has no valid saves, game will pick "NEWGAME" as proposed save name instead of empty field
|
||||
* Fixed incorrect visitation sounds of Crypt, Shipwreck and Abandoned Ship
|
||||
* Fixed double sound playback on capturing mines
|
||||
* Recruitment costs that consist from 3 different resources should now fit recruitment window UI better
|
||||
|
||||
### Campaigns
|
||||
* Game will now correctly track who defeated the hero or wandering monsters for related quests and victory conditions
|
||||
@ -88,6 +101,7 @@
|
||||
### Mechanics
|
||||
* It is no longer possible to learn spells from Pandora or events if hero can not learn them
|
||||
* Fixed behavior of 'Dimension Door' spell to be in line with H3:SoD
|
||||
* Fixed behavior of 'Fly' spell to be in line with H3:SoD
|
||||
* If it is not possible to cast 'Dimension Door', game will show message immediately on picking spell in spellbook
|
||||
* Added options to configure 'Dimension Door' spell to be in line with HotA
|
||||
* Casting 'Town Portal' while in boat will now show correct message box instead of server error
|
||||
@ -117,6 +131,8 @@
|
||||
* Decreased minimal density of obstacles on undergound level of the map
|
||||
* Density of objects should now closely resemble H3 RMG
|
||||
* Generator will now avoid routing road under guarded objects whenever possible
|
||||
* Generator will now avoid placing guards near roads
|
||||
* Generator will not place a guard near the road if it's stronger than 1/3 of max guard strength for this zone
|
||||
* Interactive objects will now appear on top of static objects
|
||||
* Windmill will now appear on top of all other objects
|
||||
|
||||
@ -140,6 +156,8 @@
|
||||
|
||||
### AI
|
||||
* Fixed possible crash on updating NKAI pathfinding data
|
||||
* Fixed possible crash if hero has only commander left without army
|
||||
* Fixed possible crash on attempt to build tavern in a town
|
||||
* Fixed counting mana usage cost of Fly spell
|
||||
* Added estimation of value of Pyramid and Cyclops Stockpile
|
||||
* Reduced memory usage and improved performance of AI pathfinding
|
||||
@ -153,6 +171,7 @@
|
||||
|
||||
### Modding
|
||||
* Added new game setting that allows inviting heroes to taverns
|
||||
* It is now possible to add creature or faction description accessible via right-click of the icon
|
||||
* Fixed reversed Overlord and Warlock classes mapping
|
||||
* Added 'selectAll' mode for configurable objects which grants all potential rewards
|
||||
* It is now possible to use most of json5 format in vcmi json files
|
||||
|
9
Global.h
9
Global.h
@ -523,6 +523,15 @@ namespace vstd
|
||||
}
|
||||
}
|
||||
|
||||
// Removes all duplicate elements from the vector
|
||||
template<typename T>
|
||||
void unique(std::vector<T> &vec)
|
||||
{
|
||||
std::sort(vec.begin(), vec.end());
|
||||
auto newEnd = std::unique(vec.begin(), vec.end());
|
||||
vec.erase(newEnd, vec.end());
|
||||
}
|
||||
|
||||
template<typename InputRange, typename OutputIterator, typename Predicate>
|
||||
OutputIterator copy_if(const InputRange &input, OutputIterator result, Predicate pred)
|
||||
{
|
||||
|
@ -50,7 +50,7 @@ import eu.vcmi.vcmi.util.ServerResponse;
|
||||
public class ActivityMods extends ActivityWithToolbar
|
||||
{
|
||||
private static final boolean ENABLE_REPO_DOWNLOADING = true;
|
||||
private static final String REPO_URL = "https://raw.githubusercontent.com/vcmi/vcmi-mods-repository/develop/vcmi-1.4.json";
|
||||
private static final String REPO_URL = "https://raw.githubusercontent.com/vcmi/vcmi-mods-repository/develop/vcmi-1.5.json";
|
||||
private VCMIModsRepo mRepo;
|
||||
private RecyclerView mRecycler;
|
||||
|
||||
|
@ -199,7 +199,7 @@ public:
|
||||
void startBattlePrimary(const CArmedInstance * army1, const CArmedInstance * army2, int3 tile, const CGHeroInstance * hero1, const CGHeroInstance * hero2, bool creatureBank = false, const CGTownInstance * town = nullptr) override {}; //use hero=nullptr for no hero
|
||||
void startBattleI(const CArmedInstance * army1, const CArmedInstance * army2, int3 tile, bool creatureBank = false) override {}; //if any of armies is hero, hero will be used
|
||||
void startBattleI(const CArmedInstance * army1, const CArmedInstance * army2, bool creatureBank = false) override {}; //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle
|
||||
bool moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, bool transit = false, PlayerColor asker = PlayerColor::NEUTRAL) override {return false;};
|
||||
bool moveHero(ObjectInstanceID hid, int3 dst, EMovementMode movementMode, bool transit = false, PlayerColor asker = PlayerColor::NEUTRAL) override {return false;};
|
||||
void giveHeroBonus(GiveBonus * bonus) override {};
|
||||
void setMovePoints(SetMovePoints * smp) override {};
|
||||
void setMovePoints(ObjectInstanceID hid, int val, bool absolute) override {};
|
||||
|
@ -32,9 +32,24 @@ InputSourceKeyboard::InputSourceKeyboard()
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string InputSourceKeyboard::getKeyNameWithModifiers(const std::string & keyName) const
|
||||
{
|
||||
std::string result;
|
||||
|
||||
if (isKeyboardCtrlDown())
|
||||
result += "Ctrl+";
|
||||
if (isKeyboardAltDown())
|
||||
result += "Alt+";
|
||||
if (isKeyboardShiftDown())
|
||||
result += "Shift+";
|
||||
result += keyName;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void InputSourceKeyboard::handleEventKeyDown(const SDL_KeyboardEvent & key)
|
||||
{
|
||||
std::string keyName = SDL_GetKeyName(key.keysym.sym);
|
||||
std::string keyName = getKeyNameWithModifiers(SDL_GetKeyName(key.keysym.sym));
|
||||
logGlobal->trace("keyboard: key '%s' pressed", keyName);
|
||||
assert(key.state == SDL_PRESSED);
|
||||
|
||||
|
@ -15,6 +15,7 @@ struct SDL_KeyboardEvent;
|
||||
/// Class that handles keyboard input from SDL events
|
||||
class InputSourceKeyboard
|
||||
{
|
||||
std::string getKeyNameWithModifiers(const std::string & keyName) const;
|
||||
public:
|
||||
InputSourceKeyboard();
|
||||
|
||||
|
@ -466,6 +466,9 @@ void CInteractableTownTooltip::init(const CGTownInstance * town)
|
||||
if(town->id == townId && town->builtBuildings.count(BuildingID::TAVERN))
|
||||
LOCPLINT->showTavernWindow(town, nullptr, QueryID::NONE);
|
||||
}
|
||||
}, [&]{
|
||||
if(!town->town->faction->getDescriptionTranslated().empty())
|
||||
CRClickPopup::createAndPush(town->town->faction->getDescriptionTranslated());
|
||||
});
|
||||
fastMarket = std::make_shared<LRClickableArea>(Rect(143, 31, 30, 34), []()
|
||||
{
|
||||
|
@ -1351,6 +1351,9 @@ void CCastleInterface::recreateIcons()
|
||||
{
|
||||
if(town->builtBuildings.count(BuildingID::TAVERN))
|
||||
LOCPLINT->showTavernWindow(town, nullptr, QueryID::NONE);
|
||||
}, [&]{
|
||||
if(!town->town->faction->getDescriptionTranslated().empty())
|
||||
CRClickPopup::createAndPush(town->town->faction->getDescriptionTranslated());
|
||||
});
|
||||
|
||||
creainfo.clear();
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "../widgets/Images.h"
|
||||
#include "../widgets/TextControls.h"
|
||||
#include "../widgets/ObjectLists.h"
|
||||
#include "../windows/InfoWindows.h"
|
||||
#include "../gui/CGuiHandler.h"
|
||||
#include "../gui/Shortcut.h"
|
||||
|
||||
@ -517,6 +518,10 @@ CStackWindow::MainSection::MainSection(CStackWindow * owner, int yOffset, bool s
|
||||
};
|
||||
|
||||
animation = std::make_shared<CCreaturePic>(5, 41, parent->info->creature);
|
||||
animationArea = std::make_shared<LRClickableArea>(Rect(5, 41, 100, 130), nullptr, [&]{
|
||||
if(!parent->info->creature->getDescriptionTranslated().empty())
|
||||
CRClickPopup::createAndPush(parent->info->creature->getDescriptionTranslated());
|
||||
});
|
||||
|
||||
if(parent->info->stackNode != nullptr && parent->info->commander == nullptr)
|
||||
{
|
||||
|
@ -29,6 +29,7 @@ class CButton;
|
||||
class CMultiLineLabel;
|
||||
class CListBox;
|
||||
class CCommanderArtPlace;
|
||||
class LRClickableArea;
|
||||
|
||||
class CCommanderSkillIcon : public LRClickableAreaWText //TODO: maybe bring commander skill button initialization logic inside?
|
||||
{
|
||||
@ -132,6 +133,7 @@ class CStackWindow : public CWindowObject
|
||||
};
|
||||
|
||||
std::shared_ptr<CCreaturePic> animation;
|
||||
std::shared_ptr<LRClickableArea> animationArea;
|
||||
std::shared_ptr<CLabel> name;
|
||||
std::shared_ptr<CPicture> icons;
|
||||
std::shared_ptr<MoraleLuckBox> morale;
|
||||
|
@ -811,6 +811,9 @@ CTownItem::CTownItem(const CGTownInstance * Town)
|
||||
{
|
||||
if(town->builtBuildings.count(BuildingID::TAVERN))
|
||||
LOCPLINT->showTavernWindow(town, nullptr, QueryID::NONE);
|
||||
}, [&]{
|
||||
if(!town->town->faction->getDescriptionTranslated().empty())
|
||||
CRClickPopup::createAndPush(town->town->faction->getDescriptionTranslated());
|
||||
});
|
||||
fastMarket = std::make_shared<LRClickableArea>(Rect(153, 6, 65, 64), []()
|
||||
{
|
||||
|
@ -41,6 +41,10 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"description" : {
|
||||
"type" : "string",
|
||||
"description" : "Description of creature"
|
||||
},
|
||||
"faction" : {
|
||||
"type" : "string",
|
||||
"description" : "Faction this creature belongs to. Examples: castle, rampart"
|
||||
|
@ -40,6 +40,10 @@
|
||||
"type" : "string",
|
||||
"description" : "Localizable faction name, e.g. Rampart"
|
||||
},
|
||||
"description" : {
|
||||
"type" : "string",
|
||||
"description" : "Description about the faction"
|
||||
},
|
||||
"alignment" : {
|
||||
"type" : "string",
|
||||
"enum" : [ "good", "neutral", "evil" ],
|
||||
|
@ -4,6 +4,7 @@
|
||||
// For players (Linux): create file ~/.config/vcmi/shortcutsConfig.json (or ~/.var/app/eu.vcmi.VCMI/config for Flatpak) to modify this set
|
||||
//
|
||||
// When creating your own config, you can remove all hotkeys that you have not changed and game will read them from this file
|
||||
// It is possible to add modifiers to keys: Ctrl, Shift, or Alt. For example, "Ctrl+Tab" hotkey will only activate if Ctrl is pressed
|
||||
{
|
||||
"keyboard" : {
|
||||
"globalAccept": [ "Return", "Keypad Enter"],
|
||||
@ -112,6 +113,10 @@
|
||||
"battleTacticsEnd": [ "Return", "Keypad Enter"],
|
||||
"battleToggleHeroesStats": [],
|
||||
"battleSelectAction": "S",
|
||||
"lobbyActivateInterface": "Ctrl+Tab",
|
||||
"spectateTrackHero": "F5",
|
||||
"spectateSkipBattle": "F7",
|
||||
"spectateSkipBattleResult": "F8",
|
||||
"townOpenTavern": "T",
|
||||
"townSwapArmies": "Space",
|
||||
"recruitmentMax": "End",
|
||||
|
2
debian/changelog
vendored
2
debian/changelog
vendored
@ -8,7 +8,7 @@ vcmi (1.5.0) jammy; urgency=medium
|
||||
|
||||
* New upstream release
|
||||
|
||||
-- Ivan Savenko <saven.ivan@gmail.com> Fri, 1 Mar 2024 12:00:00 +0200
|
||||
-- Ivan Savenko <saven.ivan@gmail.com> Fri, 10 May 2024 12:00:00 +0200
|
||||
|
||||
vcmi (1.4.5) jammy; urgency=medium
|
||||
|
||||
|
@ -1,8 +1,5 @@
|
||||
[![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.4.0/total)](https://github.com/vcmi/vcmi/releases/tag/1.4.0)
|
||||
[![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/1.4.1/total)](https://github.com/vcmi/vcmi/releases/tag/1.4.1)
|
||||
[![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/1.4.2/total)](https://github.com/vcmi/vcmi/releases/tag/1.4.2)
|
||||
[![Github Downloads](https://img.shields.io/github/downloads/vcmi/vcmi/1.4.5/total)](https://github.com/vcmi/vcmi/releases/tag/1.4.5)
|
||||
[![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/total)](https://github.com/vcmi/vcmi/releases)
|
||||
|
||||
# VCMI Project
|
||||
|
@ -18,7 +18,7 @@ Should be done immediately after start of stabilization stage for previous relea
|
||||
- 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-4 weeks before planned release date. All major features should be finished at this point.
|
||||
Should be done 2 weeks before planned release date. All major features should be finished at this point.
|
||||
|
||||
- Create `beta` branch from `develop`
|
||||
- Bump vcmi version in CMake on `develop` branch
|
||||
@ -37,9 +37,10 @@ Should be done 1 week before release. Release date should be decided at this poi
|
||||
- Make sure to announce codebase freeze deadline (1 day before release) to all developers
|
||||
- Create pull request for release preparation tasks targeting `beta`:
|
||||
- - Update [changelog](https://github.com/vcmi/vcmi/blob/develop/ChangeLog.md)
|
||||
- - Update release date for Linux packaging. See [example](https://github.com/vcmi/vcmi/pull/1258)
|
||||
- - Update build ID for Android packaging. See [example](https://github.com/vcmi/vcmi/pull/2090)
|
||||
- - Update downloads counter in readme.md. See [example](https://github.com/vcmi/vcmi/pull/2091)
|
||||
- - Update release date in `debian/changelog`
|
||||
- - Update release date in `launcher/eu.vcmi.VCMI.metainfo.xml`
|
||||
- - Update build ID `android/vcmi-app/build.gradle`
|
||||
- - 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.
|
||||
|
@ -10,6 +10,7 @@ If not enough biomes are defined for [terrain type](Terrain_Format.md), map gene
|
||||
"obstacleSetId" : {
|
||||
"biome" : {
|
||||
"terrain" : "grass", // Id or vector of Ids this obstacle set can spawn at
|
||||
"level" : "underground", // or "surface", by default both
|
||||
"faction" : ["castle", "rampart"], //Id or vector of faction Ids. Set will only be used if zone belongs to this faction
|
||||
"alignment" : ["good", "evil", "neutral"], //Alignment of the zone. Set will only be used if zone has this alignment
|
||||
"objectType": "mountain"
|
||||
|
@ -29,6 +29,10 @@ In order to make functional creature you also need:
|
||||
"singular" : "Creature",
|
||||
"plural" : "Creatures"
|
||||
},
|
||||
|
||||
// Description of creature
|
||||
"description" : "",
|
||||
|
||||
"level" : 0,
|
||||
|
||||
// Marks this object as special and not available by default
|
||||
|
@ -57,6 +57,9 @@ Each town requires a set of buildings (Around 30-45 buildings)
|
||||
// Localizable faction name, e.g. "Rampart"
|
||||
"name" : "",
|
||||
|
||||
// Description of town (e.g. history or story about town)
|
||||
"description" : "",
|
||||
|
||||
// Faction alignment. Can be good, neutral (default) or evil.
|
||||
"alignment" : "",
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
<summary>Open-source game engine for Heroes of Might and Magic III</summary>
|
||||
<summary xml:lang="cs">Herní engine s otevřeným kódem pro Heroes of Might and Magic III</summary>
|
||||
<summary xml:lang="de">Open-Source-Spielengine für Heroes of Might and Magic III</summary>
|
||||
<summary xml:lang="uk">Ігровий рушій з відкритим початковим кодом для Heroes of Might and Magic III</summary>
|
||||
<developer id="eu.vcmi">
|
||||
<name>VCMI Team</name>
|
||||
<name xml:lang="cs">Tým VCMI</name>
|
||||
@ -15,35 +16,45 @@
|
||||
<p>VCMI is an open-source engine for Heroes of Might and Magic III with new possibilities. Years of intensive work resulted in an impressive amount of features. Among the current features are:</p>
|
||||
<p xml:lang="cs">VCMI je engine s otevřeným kódem a novými možnostmi pro Heroes of Might and Magic III. Roky usilovné práce vyústily v úchvatném počtu nových funkcí. Mezi současnými funkcemi jsou:</p>
|
||||
<p xml:lang="de">VCMI ist eine Open-Source-Engine für Heroes of Might and Magic III mit neuen Möglichkeiten. Jahrelange intensive Arbeit führte zu einer beeindruckenden Anzahl von Features. Zu den aktuellen Features gehören:</p>
|
||||
<p xml:lang="uk">VCMI - це рушій з відкритим початковим кодом для Heroes of Might and Magic III з новими можливостями. Роки інтенсивної роботи вилилися у вражаючу кількість функцій. Серед поточних можливостей можна виділити наступні:</p>
|
||||
<ul>
|
||||
<li>Complete gameplay mechanics</li>
|
||||
<li xml:lang="cs">Kompletní herní mechaniky</li>
|
||||
<li xml:lang="de">Vollständige Spielmechanik</li>
|
||||
<li xml:lang="uk">Уся ігрова механіка</li>
|
||||
<li>Almost all objects, abilities, spells and other content</li>
|
||||
<li xml:lang="cs">Skoro všechny předměty, schopnosti, kouzla a ostatní obsah</li>
|
||||
<li xml:lang="de">Fast alle Objekte, Fähigkeiten, Zaubersprüche und andere Inhalte</li>
|
||||
<li xml:lang="uk">Практично всі об'єкти, вміння, закляття та інший вміст</li>
|
||||
<li>Basic battle AI and adventure AI</li>
|
||||
<li xml:lang="cs">Základní AI boje a mapy světa</li>
|
||||
<li xml:lang="de">Grundlegende Kampf- und Abenteuer-KI</li>
|
||||
<li xml:lang="uk">Базовий ШІ для бою та для мапи пригод</li>
|
||||
<li>Many GUI improvements: high resolutions, stack queue, creature window</li>
|
||||
<li xml:lang="cs">Mnoho vylepšení rozhraní: vyšší rozlišení, fronta oddílů a okno bojovníků</li>
|
||||
<li xml:lang="de">Viele GUI-Verbesserungen: Hohe Auflösungen, Truppenwarteschlange, Kreaturenfenster</li>
|
||||
<li xml:lang="uk">Численні покращення графічного інтерфейсу: висока роздільна здатність, черга ходу істот, нове вікно істот</li>
|
||||
<li>Advanced and easy mod support - add new towns, creatures, heroes, artifacts and spells without limits or conflicts</li>
|
||||
<li xml:lang="cs">Pokročilá a jednoduchá podpora modifikací - přidání nových měst, bojovníků, hrdinů, artefaktů a kouzel bez limitů a konfliktů</li>
|
||||
<li xml:lang="de">Erweiterte und einfache Mod-Unterstützung - füge neue Städte, Kreaturen, Helden, Artefakte und Zaubersprüche ohne Einschränkungen oder Konflikte hinzu</li>
|
||||
<li xml:lang="uk">Просунута і проста підтримка модів - додавайте нові міста, істот, героїв, артефакти і закляття без обмежень і конфліктів</li>
|
||||
<li>Launcher for easy configuration - download mods from our server and install them immediately!</li>
|
||||
<li xml:lang="cs">Spouštěč pro jednoduché nastavení - stahujte modifikace z našeho serveru a hned je instalujte!</li>
|
||||
<li xml:lang="de">Launcher für einfache Konfiguration - Mods von unserem Server herunterladen und sofort installieren!</li>
|
||||
<li xml:lang="uk">Лаунчер для легкого налаштування гри - завантажуйте моди з нашого сервера та встановлюйте їх одразу!</li>
|
||||
<li>Random map generator that supports objects added by mods</li>
|
||||
<li xml:lang="cs">Náhodný generátor map, který podporuje předměty přidané modifikacemi</li>
|
||||
<li xml:lang="de">Zufallsgenerator für Karten, der von Mods hinzugefügte Objekte unterstützt</li>
|
||||
<li xml:lang="uk">Генератор випадкових карт, який підтримує об'єкти, додані модами</li>
|
||||
</ul>
|
||||
<p>Note: In order to play the game using VCMI you need to own data files for Heroes of Might and Magic III: The Shadow of Death.</p>
|
||||
<p xml:lang="cs">Poznámka: pokud chcete hrát hru přes VCMI, musíte vlastnit datové soubory Heroes of Might and Magic III: The Shadow of Death.</p>
|
||||
<p xml:lang="de">Hinweis: Um das Spiel mit VCMI spielen zu können, sind die Originaldateien für Heroes of Might and Magic III: The Shadow of Death erforderlich.</p>
|
||||
<p xml:lang="uk">Примітка: Для того, щоб грати в гру за допомогою VCMI, вам потрібно мати файли даних для гри Heroes of Might and Magic III: The Shadow of Death.</p>
|
||||
<p>If you want help, please check our forum, bug tracker or GitHub page.</p>
|
||||
<p xml:lang="cs">Pokud chcete pomoct, prosíme, podívejte se na naše fórum nebo GitHub.</p>
|
||||
<p xml:lang="de">Wird Hilfe benötigt, besucht bitte unser Forum, den Bugtracker oder die GitHub-Seite.</p>
|
||||
<p xml:lang="uk">Якщо вам потрібна допомога, зверніться до нашого форуму, баг-трекера або на сторінку GitHub.</p>
|
||||
</description>
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
@ -80,7 +91,7 @@
|
||||
<launchable type="desktop-id">vcmilauncher.desktop</launchable>
|
||||
<releases>
|
||||
<release version="1.6.0" date="2024-08-30" type="development"/>
|
||||
<release version="1.5.0" date="2024-03-01" type="development"/>
|
||||
<release version="1.5.0" date="2024-05-10" type="stable"/>
|
||||
<release version="1.4.5" date="2024-01-23" type="stable"/>
|
||||
<release version="1.4.4" date="2024-01-20" type="stable"/>
|
||||
<release version="1.4.3" date="2024-01-19" type="stable"/>
|
||||
|
@ -254,7 +254,7 @@
|
||||
<message>
|
||||
<location filename="../modManager/cmodlistview_moc.ui" line="373"/>
|
||||
<source>Install from file</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Zainstaluj z pliku</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodlistview_moc.ui" line="424"/>
|
||||
@ -350,18 +350,18 @@
|
||||
<message>
|
||||
<location filename="../modManager/cmodlistview_moc.cpp" line="310"/>
|
||||
<source>please upgrade mod</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>proszę zaktualizować moda</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodlistview_moc.cpp" line="182"/>
|
||||
<location filename="../modManager/cmodlistview_moc.cpp" line="796"/>
|
||||
<source>mods repository index</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>indeks repozytorium modów</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodlistview_moc.cpp" line="312"/>
|
||||
<source>or newer</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>lub nowsze</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodlistview_moc.cpp" line="315"/>
|
||||
@ -416,42 +416,42 @@
|
||||
<message>
|
||||
<location filename="../modManager/cmodlistview_moc.cpp" line="627"/>
|
||||
<source>All supported files</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Wszystkie wspierane pliki</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodlistview_moc.cpp" line="627"/>
|
||||
<source>Maps</source>
|
||||
<translation type="unfinished">Mapy</translation>
|
||||
<translation>Mapy</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodlistview_moc.cpp" line="627"/>
|
||||
<source>Campaigns</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Kampanie</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodlistview_moc.cpp" line="627"/>
|
||||
<source>Configs</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Konfiguracje</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodlistview_moc.cpp" line="627"/>
|
||||
<source>Mods</source>
|
||||
<translation type="unfinished">Mody</translation>
|
||||
<translation>Mody</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodlistview_moc.cpp" line="628"/>
|
||||
<source>Select files (configs, mods, maps, campaigns) to install...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Wybierz pliki (konfiguracyjne, mody, mapy, kampanie) do zainstalowania...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodlistview_moc.cpp" line="654"/>
|
||||
<source>Replace config file?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Zastąpić plik konfiguracji?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodlistview_moc.cpp" line="654"/>
|
||||
<source>Do you want to replace %1?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Czy chcesz zastąpić %1?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodlistview_moc.cpp" line="693"/>
|
||||
@ -505,7 +505,7 @@ Zainstalować pomyślnie pobrane?</translation>
|
||||
<message>
|
||||
<location filename="../modManager/cmodlistview_moc.cpp" line="960"/>
|
||||
<source>screenshots</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>zrzuty ekranu</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodlistview_moc.cpp" line="966"/>
|
||||
@ -523,95 +523,96 @@ Zainstalować pomyślnie pobrane?</translation>
|
||||
<message>
|
||||
<location filename="../modManager/cmodmanager.cpp" line="160"/>
|
||||
<source>Can not install submod</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Nie można zainstalować submoda</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodmanager.cpp" line="163"/>
|
||||
<source>Mod is already installed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Mod jest już zainstalowany</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodmanager.cpp" line="172"/>
|
||||
<source>Can not uninstall submod</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Nie można odinstalować submoda</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodmanager.cpp" line="175"/>
|
||||
<source>Mod is not installed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Mod nie jest zainstalowany</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodmanager.cpp" line="185"/>
|
||||
<source>Mod is already enabled</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Mod jest już włączony</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodmanager.cpp" line="188"/>
|
||||
<location filename="../modManager/cmodmanager.cpp" line="231"/>
|
||||
<source>Mod must be installed first</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Mod musi zostać najpierw zainstalowany</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodmanager.cpp" line="192"/>
|
||||
<source>Mod is not compatible, please update VCMI and checkout latest mod revisions</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Mod nie jest kompatybilny, proszę zaktualizować VCMI i odświeżyć listę modów</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodmanager.cpp" line="197"/>
|
||||
<source>Required mod %1 is missing</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Brakuje wymaganego moda %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodmanager.cpp" line="202"/>
|
||||
<source>Required mod %1 is not enabled</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Wymagany mod %1 jest wyłączony</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodmanager.cpp" line="211"/>
|
||||
<location filename="../modManager/cmodmanager.cpp" line="218"/>
|
||||
<source>This mod conflicts with %1</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Ten mod konfliktuje z %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodmanager.cpp" line="228"/>
|
||||
<source>Mod is already disabled</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Mod jest już wyłączony</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodmanager.cpp" line="238"/>
|
||||
<source>This mod is needed to run %1</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Ten mod jest potrzebny do uruchomienia %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodmanager.cpp" line="280"/>
|
||||
<source>Mod archive is missing</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Brakuje archiwum modyfikacji</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodmanager.cpp" line="283"/>
|
||||
<source>Mod with such name is already installed</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Mod z taką nazwą jest już zainstalowany</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodmanager.cpp" line="288"/>
|
||||
<source>Mod archive is invalid or corrupted</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Archiwum moda jest niepoprawne lub uszkodzone</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodmanager.cpp" line="314"/>
|
||||
<source>Failed to extract mod data</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Nieudane wyodrębnienie danych moda</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodmanager.cpp" line="342"/>
|
||||
<source>Data with this mod was not found</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Dane z tym modem nie zostały znalezione</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodmanager.cpp" line="346"/>
|
||||
<source>Mod is located in protected directory, please remove it manually:
|
||||
</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Mod jest umiejscowiony w chronionym folderze, proszę go usunąć ręcznie:
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@ -716,7 +717,7 @@ Zainstalować pomyślnie pobrane?</translation>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="624"/>
|
||||
<source>Renderer</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Renderer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../settingsView/csettingsview_moc.ui" line="246"/>
|
||||
@ -858,27 +859,27 @@ Pełny ekran klasyczny - gra przysłoni cały ekran uruchamiając się w wybrane
|
||||
<message>
|
||||
<location filename="../modManager/cmodlist.cpp" line="21"/>
|
||||
<source>%1 B</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>%1 B</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodlist.cpp" line="22"/>
|
||||
<source>%1 KiB</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>%1 KiB</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodlist.cpp" line="23"/>
|
||||
<source>%1 MiB</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>%1 MiB</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodlist.cpp" line="24"/>
|
||||
<source>%1 GiB</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>%1 GiB</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodlist.cpp" line="25"/>
|
||||
<source>%1 TiB</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>%1 TiB</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@ -934,7 +935,7 @@ Heroes III: HD Edition nie jest obecnie wspierane!</translation>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.ui" line="288"/>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="350"/>
|
||||
<source>Install gog.com files</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Użyj instalatora z gog.com</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.ui" line="362"/>
|
||||
@ -1020,7 +1021,7 @@ Heroes III: HD Edition nie jest obecnie wspierane!</translation>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.ui" line="346"/>
|
||||
<source>If you don't have a copy of Heroes III installed, VCMI can import your Heroes III data using the offline installer from gog.com.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Jeśli nie masz zainstalowanego Heroes III, VCMI może użyć danych z instalatora offline gog.com.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.ui" line="384"/>
|
||||
@ -1071,64 +1072,64 @@ Heroes III: HD Edition nie jest obecnie wspierane!</translation>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="148"/>
|
||||
<source>Heroes III installation found!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Znaleziono zainstalowane Heroes III!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="148"/>
|
||||
<source>Copy data to VCMI folder?</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Skopiować dane do folderu VCMI?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="289"/>
|
||||
<source>Select %1 file...</source>
|
||||
<comment>param is file extension</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Wybierz plik %1...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="290"/>
|
||||
<source>You have to select %1 file!</source>
|
||||
<comment>param is file extension</comment>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Musisz wybrać plik %1!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="292"/>
|
||||
<source>GOG file (*.*)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Instalator GOG (*.*)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="293"/>
|
||||
<source>File selection</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Wybór pliku</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="300"/>
|
||||
<source>Invalid file selected</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Wybrano nieprawidłowy plik</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="307"/>
|
||||
<source>GOG installer</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Instalator GOG</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="310"/>
|
||||
<source>GOG data</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Dane GOG</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="314"/>
|
||||
<source>Installing... Please wait!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Instalowanie... Proszę czekać!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="349"/>
|
||||
<source>No Heroes III data!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Brak danych Heroes III!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="349"/>
|
||||
<source>Selected files do not contain Heroes III data!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Wybrane pliki nie zawierają danych Heroes III!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="387"/>
|
||||
@ -1136,26 +1137,29 @@ Heroes III: HD Edition nie jest obecnie wspierane!</translation>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="408"/>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="413"/>
|
||||
<source>Heroes III data not found!</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Dane Heroes III nie znalezione!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="387"/>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="401"/>
|
||||
<source>Failed to detect valid Heroes III data in chosen directory.
|
||||
Please select directory with installed Heroes III data.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Nieudane znalezienie poprawnych plików Heroes III w podanej lokalizacji.
|
||||
Proszę wybrać folder z zainstalowanymi danymi Heroes III.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="408"/>
|
||||
<source>Heroes III: HD Edition files are not supported by VCMI.
|
||||
Please select directory with Heroes III: Complete Edition or Heroes III: Shadow of Death.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Pliki Heroes III HD Edition nie są wspierane przez VCMI.
|
||||
Proszę wybrać folder z Heroes III: Complete Edition lub Heroes III: Shadow of Death.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../firstLaunch/firstlaunch_moc.cpp" line="413"/>
|
||||
<source>Unknown or unsupported Heroes III version found.
|
||||
Please select directory with Heroes III: Complete Edition or Heroes III: Shadow of Death.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Znaleziono nieznaną lub niewspieraną wersję Heroes III.
|
||||
Proszę wybrać folder z Heroes III: Complete Edition lub Heroes III: Shadow of Death.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@ -1312,17 +1316,17 @@ Please select directory with Heroes III: Complete Edition or Heroes III: Shadow
|
||||
<message>
|
||||
<location filename="../modManager/cmodlistmodel_moc.cpp" line="172"/>
|
||||
<source>Name</source>
|
||||
<translation type="unfinished">Nazwa</translation>
|
||||
<translation>Nazwa</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodlistmodel_moc.cpp" line="175"/>
|
||||
<source>Type</source>
|
||||
<translation type="unfinished">Typ</translation>
|
||||
<translation>Typ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../modManager/cmodlistmodel_moc.cpp" line="176"/>
|
||||
<source>Version</source>
|
||||
<translation type="unfinished">Wersja</translation>
|
||||
<translation>Wersja</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@ -1345,12 +1349,12 @@ Please select directory with Heroes III: Complete Edition or Heroes III: Shadow
|
||||
<message>
|
||||
<location filename="../updatedialog_moc.cpp" line="64"/>
|
||||
<source>Network error</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Błąd sieciowy</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../updatedialog_moc.cpp" line="101"/>
|
||||
<source>Cannot read JSON from url or incorrect JSON data</source>
|
||||
<translation type="unfinished"></translation>
|
||||
<translation>Nie można odczytać JSON z url lub JSON ma błędną zawartość</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
@ -199,6 +199,11 @@ std::string CCreature::getNameTextID() const
|
||||
return getNameSingularTextID();
|
||||
}
|
||||
|
||||
std::string CCreature::getDescriptionTranslated() const
|
||||
{
|
||||
return VLC->generaltexth->translate(getDescriptionTextID());
|
||||
}
|
||||
|
||||
std::string CCreature::getNamePluralTextID() const
|
||||
{
|
||||
return TextIdentifier("creatures", modScope, identifier, "name", "plural" ).get();
|
||||
@ -209,6 +214,11 @@ std::string CCreature::getNameSingularTextID() const
|
||||
return TextIdentifier("creatures", modScope, identifier, "name", "singular" ).get();
|
||||
}
|
||||
|
||||
std::string CCreature::getDescriptionTextID() const
|
||||
{
|
||||
return TextIdentifier("creatures", modScope, identifier, "description").get();
|
||||
}
|
||||
|
||||
CCreature::CreatureQuantityId CCreature::getQuantityID(const int & quantity)
|
||||
{
|
||||
if (quantity<5)
|
||||
@ -600,6 +610,7 @@ CCreature * CCreatureHandler::loadFromJson(const std::string & scope, const Json
|
||||
|
||||
VLC->generaltexth->registerString(scope, cre->getNameSingularTextID(), node["name"]["singular"].String());
|
||||
VLC->generaltexth->registerString(scope, cre->getNamePluralTextID(), node["name"]["plural"].String());
|
||||
VLC->generaltexth->registerString(scope, cre->getDescriptionTextID(), node["description"].String());
|
||||
|
||||
cre->addBonus(node["hitPoints"].Integer(), BonusType::STACK_HEALTH);
|
||||
cre->addBonus(node["speed"].Integer(), BonusType::STACKS_SPEED);
|
||||
|
@ -51,6 +51,9 @@ class DLL_LINKAGE CCreature : public Creature, public CBonusSystemNode
|
||||
TResources cost; //cost[res_id] - amount of that resource required to buy creature from dwelling
|
||||
|
||||
public:
|
||||
std::string getDescriptionTranslated() const;
|
||||
std::string getDescriptionTextID() const;
|
||||
|
||||
ui32 ammMin; // initial size of stack of these creatures on adventure map (if not set in editor)
|
||||
ui32 ammMax;
|
||||
|
||||
|
@ -188,6 +188,16 @@ std::string CFaction::getNameTextID() const
|
||||
return TextIdentifier("faction", modScope, identifier, "name").get();
|
||||
}
|
||||
|
||||
std::string CFaction::getDescriptionTranslated() const
|
||||
{
|
||||
return VLC->generaltexth->translate(getDescriptionTextID());
|
||||
}
|
||||
|
||||
std::string CFaction::getDescriptionTextID() const
|
||||
{
|
||||
return TextIdentifier("faction", modScope, identifier, "description").get();
|
||||
}
|
||||
|
||||
FactionID CFaction::getId() const
|
||||
{
|
||||
return FactionID(index);
|
||||
@ -1037,6 +1047,7 @@ CFaction * CTownHandler::loadFromJson(const std::string & scope, const JsonNode
|
||||
faction->identifier = identifier;
|
||||
|
||||
VLC->generaltexth->registerString(scope, faction->getNameTextID(), source["name"].String());
|
||||
VLC->generaltexth->registerString(scope, faction->getDescriptionTranslated(), source["description"].String());
|
||||
|
||||
faction->creatureBg120 = ImagePath::fromJson(source["creatureBackground"]["120px"]);
|
||||
faction->creatureBg130 = ImagePath::fromJson(source["creatureBackground"]["130px"]);
|
||||
|
@ -192,6 +192,8 @@ public:
|
||||
|
||||
std::string getNameTranslated() const override;
|
||||
std::string getNameTextID() const override;
|
||||
std::string getDescriptionTranslated() const;
|
||||
std::string getDescriptionTextID() const;
|
||||
|
||||
bool hasTown() const override;
|
||||
TerrainId getNativeTerrain() const override;
|
||||
|
@ -117,7 +117,7 @@ public:
|
||||
virtual void startBattlePrimary(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, const CGTownInstance *town = nullptr)=0; //use hero=nullptr for no hero
|
||||
virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, bool creatureBank = false)=0; //if any of armies is hero, hero will be used
|
||||
virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, bool creatureBank = false)=0; //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle
|
||||
virtual bool moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, bool transit = false, PlayerColor asker = PlayerColor::NEUTRAL)=0;
|
||||
virtual bool moveHero(ObjectInstanceID hid, int3 dst, EMovementMode moveMove, bool transit = false, PlayerColor asker = PlayerColor::NEUTRAL)=0;
|
||||
virtual bool swapGarrisonOnSiege(ObjectInstanceID tid)=0;
|
||||
virtual void giveHeroBonus(GiveBonus * bonus)=0;
|
||||
virtual void setMovePoints(SetMovePoints * smp)=0;
|
||||
|
@ -253,4 +253,13 @@ enum class EArmyFormation : int8_t
|
||||
TIGHT
|
||||
};
|
||||
|
||||
enum class EMovementMode : int8_t
|
||||
{
|
||||
STANDARD,
|
||||
DIMENSION_DOOR,
|
||||
MONOLITH,
|
||||
CASTLE_GATE,
|
||||
TOWN_PORTAL,
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@ -524,7 +524,7 @@ void CGMonolith::teleportDialogAnswered(const CGHeroInstance *hero, ui32 answer,
|
||||
else
|
||||
dPos = hero->convertFromVisitablePos(cb->getObj(randomExit)->visitablePos());
|
||||
|
||||
cb->moveHero(hero->id, dPos, true);
|
||||
cb->moveHero(hero->id, dPos, EMovementMode::MONOLITH);
|
||||
}
|
||||
|
||||
void CGMonolith::initObj(CRandomGenerator & rand)
|
||||
@ -703,7 +703,7 @@ void CGWhirlpool::teleportDialogAnswered(const CGHeroInstance *hero, ui32 answer
|
||||
dPos = hero->convertFromVisitablePos(*RandomGeneratorUtil::nextItem(tiles, CRandomGenerator::getDefault()));
|
||||
}
|
||||
|
||||
cb->moveHero(hero->id, dPos, true);
|
||||
cb->moveHero(hero->id, dPos, EMovementMode::MONOLITH);
|
||||
}
|
||||
|
||||
bool CGWhirlpool::isProtected(const CGHeroInstance * h)
|
||||
|
@ -19,13 +19,15 @@ VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
ObstacleSet::ObstacleSet():
|
||||
type(INVALID),
|
||||
allowedTerrains({TerrainId::NONE})
|
||||
allowedTerrains({TerrainId::NONE}),
|
||||
level(EMapLevel::ANY)
|
||||
{
|
||||
}
|
||||
|
||||
ObstacleSet::ObstacleSet(EObstacleType type, TerrainId terrain):
|
||||
type(type),
|
||||
allowedTerrains({terrain})
|
||||
allowedTerrains({terrain}),
|
||||
level(EMapLevel::ANY)
|
||||
{
|
||||
}
|
||||
|
||||
@ -47,16 +49,26 @@ void ObstacleSet::removeEmptyTemplates()
|
||||
});
|
||||
}
|
||||
|
||||
ObstacleSetFilter::ObstacleSetFilter(std::vector<ObstacleSet::EObstacleType> allowedTypes, TerrainId terrain = TerrainId::ANY_TERRAIN, FactionID faction = FactionID::ANY, EAlignment alignment = EAlignment::ANY):
|
||||
ObstacleSetFilter::ObstacleSetFilter(std::vector<ObstacleSet::EObstacleType> allowedTypes,
|
||||
TerrainId terrain = TerrainId::ANY_TERRAIN,
|
||||
ObstacleSet::EMapLevel level = ObstacleSet::EMapLevel::ANY,
|
||||
FactionID faction = FactionID::ANY,
|
||||
EAlignment alignment = EAlignment::ANY):
|
||||
allowedTypes(allowedTypes),
|
||||
level(level),
|
||||
faction(faction),
|
||||
alignment(alignment),
|
||||
terrain(terrain)
|
||||
{
|
||||
}
|
||||
|
||||
ObstacleSetFilter::ObstacleSetFilter(ObstacleSet::EObstacleType allowedType, TerrainId terrain = TerrainId::ANY_TERRAIN, FactionID faction = FactionID::ANY, EAlignment alignment = EAlignment::ANY):
|
||||
ObstacleSetFilter::ObstacleSetFilter(ObstacleSet::EObstacleType allowedType,
|
||||
TerrainId terrain = TerrainId::ANY_TERRAIN,
|
||||
ObstacleSet::EMapLevel level = ObstacleSet::EMapLevel::ANY,
|
||||
FactionID faction = FactionID::ANY,
|
||||
EAlignment alignment = EAlignment::ANY):
|
||||
allowedTypes({allowedType}),
|
||||
level(level),
|
||||
faction(faction),
|
||||
alignment(alignment),
|
||||
terrain(terrain)
|
||||
@ -70,6 +82,14 @@ bool ObstacleSetFilter::filter(const ObstacleSet &set) const
|
||||
return false;
|
||||
}
|
||||
|
||||
if (level != ObstacleSet::EMapLevel::ANY && set.getLevel() != ObstacleSet::EMapLevel::ANY)
|
||||
{
|
||||
if (level != set.getLevel())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (faction != FactionID::ANY)
|
||||
{
|
||||
auto factions = set.getFactions();
|
||||
@ -117,6 +137,16 @@ void ObstacleSet::addTerrain(TerrainId terrain)
|
||||
this->allowedTerrains.insert(terrain);
|
||||
}
|
||||
|
||||
ObstacleSet::EMapLevel ObstacleSet::getLevel() const
|
||||
{
|
||||
return level;
|
||||
}
|
||||
|
||||
void ObstacleSet::setLevel(ObstacleSet::EMapLevel newLevel)
|
||||
{
|
||||
level = newLevel;
|
||||
}
|
||||
|
||||
std::set<FactionID> ObstacleSet::getFactions() const
|
||||
{
|
||||
return allowedFactions;
|
||||
@ -248,6 +278,22 @@ std::string ObstacleSet::toString() const
|
||||
return OBSTACLE_TYPE_STRINGS.at(type);
|
||||
}
|
||||
|
||||
ObstacleSet::EMapLevel ObstacleSet::levelFromString(const std::string &str)
|
||||
{
|
||||
static const std::map<std::string, EMapLevel> LEVEL_NAMES =
|
||||
{
|
||||
{"surface", SURFACE},
|
||||
{"underground", UNDERGROUND}
|
||||
};
|
||||
|
||||
if (LEVEL_NAMES.find(str) != LEVEL_NAMES.end())
|
||||
{
|
||||
return LEVEL_NAMES.at(str);
|
||||
}
|
||||
|
||||
throw std::runtime_error("Invalid map level: " + str);
|
||||
}
|
||||
|
||||
std::vector<ObstacleSet::EObstacleType> ObstacleSetFilter::getAllowedTypes() const
|
||||
{
|
||||
return allowedTypes;
|
||||
@ -325,6 +371,12 @@ std::shared_ptr<ObstacleSet> ObstacleSetHandler::loadFromJson(const std::string
|
||||
logMod->error("No terrain specified for obstacle set %s", name);
|
||||
}
|
||||
|
||||
if (biome["level"].isString())
|
||||
{
|
||||
auto level = biome["level"].String();
|
||||
os->setLevel(ObstacleSet::levelFromString(level));
|
||||
}
|
||||
|
||||
auto handleFaction = [os, scope](const std::string & str)
|
||||
{
|
||||
VLC->identifiers()->requestIdentifier(scope, "faction", str, [os](si32 id)
|
||||
|
@ -37,6 +37,14 @@ public:
|
||||
ANIMALS, // Living, or bones
|
||||
OTHER // Crystals, shipwrecks, barrels, etc.
|
||||
};
|
||||
|
||||
enum EMapLevel // TODO: Move somewhere to map definitions
|
||||
{
|
||||
ANY = -1,
|
||||
SURFACE = 0,
|
||||
UNDERGROUND = 1
|
||||
};
|
||||
|
||||
ObstacleSet();
|
||||
explicit ObstacleSet(EObstacleType type, TerrainId terrain);
|
||||
|
||||
@ -51,6 +59,8 @@ public:
|
||||
void setTerrain(TerrainId terrain);
|
||||
void setTerrains(const std::set<TerrainId> & terrains);
|
||||
void addTerrain(TerrainId terrain);
|
||||
EMapLevel getLevel() const;
|
||||
void setLevel(EMapLevel level);
|
||||
std::set<EAlignment> getAlignments() const;
|
||||
void addAlignment(EAlignment alignment);
|
||||
std::set<FactionID> getFactions() const;
|
||||
@ -58,12 +68,14 @@ public:
|
||||
|
||||
static EObstacleType typeFromString(const std::string &str);
|
||||
std::string toString() const;
|
||||
static EMapLevel levelFromString(const std::string &str);
|
||||
|
||||
si32 id;
|
||||
|
||||
private:
|
||||
|
||||
EObstacleType type;
|
||||
EMapLevel level;
|
||||
std::set<TerrainId> allowedTerrains; // Empty means all terrains
|
||||
std::set<FactionID> allowedFactions; // Empty means all factions
|
||||
std::set<EAlignment> allowedAlignments; // Empty means all alignments
|
||||
@ -75,8 +87,8 @@ using TObstacleTypes = std::vector<std::shared_ptr<ObstacleSet>>;
|
||||
class DLL_LINKAGE ObstacleSetFilter
|
||||
{
|
||||
public:
|
||||
ObstacleSetFilter(ObstacleSet::EObstacleType allowedType, TerrainId terrain, FactionID faction, EAlignment alignment);
|
||||
ObstacleSetFilter(std::vector<ObstacleSet::EObstacleType> allowedTypes, TerrainId terrain, FactionID faction, EAlignment alignment);
|
||||
ObstacleSetFilter(ObstacleSet::EObstacleType allowedType, TerrainId terrain, ObstacleSet::EMapLevel level, FactionID faction, EAlignment alignment);
|
||||
ObstacleSetFilter(std::vector<ObstacleSet::EObstacleType> allowedTypes, TerrainId terrain, ObstacleSet::EMapLevel level, FactionID faction, EAlignment alignment);
|
||||
|
||||
bool filter(const ObstacleSet &set) const;
|
||||
|
||||
@ -93,6 +105,7 @@ private:
|
||||
EAlignment alignment;
|
||||
// TODO: Filter by faction, surface/underground, etc.
|
||||
const TerrainId terrain;
|
||||
ObstacleSet::EMapLevel level;
|
||||
};
|
||||
|
||||
// TODO: Instantiate ObstacleSetHandler
|
||||
|
@ -12,12 +12,12 @@
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
NetworkConnection::NetworkConnection(INetworkConnectionListener & listener, const std::shared_ptr<NetworkSocket> & socket, const std::shared_ptr<NetworkContext> & context)
|
||||
NetworkConnection::NetworkConnection(INetworkConnectionListener & listener, const std::shared_ptr<NetworkSocket> & socket)
|
||||
: socket(socket)
|
||||
, context(context)
|
||||
, listener(listener)
|
||||
{
|
||||
socket->set_option(boost::asio::ip::tcp::no_delay(true));
|
||||
socket->set_option(boost::asio::socket_base::keep_alive(true));
|
||||
|
||||
// iOS throws exception on attempt to set buffer size
|
||||
constexpr auto bufferSize = 4 * 1024 * 1024;
|
||||
@ -43,32 +43,12 @@ NetworkConnection::NetworkConnection(INetworkConnectionListener & listener, cons
|
||||
|
||||
void NetworkConnection::start()
|
||||
{
|
||||
heartbeat();
|
||||
|
||||
boost::asio::async_read(*socket,
|
||||
readBuffer,
|
||||
boost::asio::transfer_exactly(messageHeaderSize),
|
||||
[self = shared_from_this()](const auto & ec, const auto & endpoint) { self->onHeaderReceived(ec); });
|
||||
}
|
||||
|
||||
void NetworkConnection::heartbeat()
|
||||
{
|
||||
constexpr auto heartbeatInterval = std::chrono::seconds(10);
|
||||
|
||||
auto timer = std::make_shared<NetworkTimer>(*context, heartbeatInterval);
|
||||
timer->async_wait( [self = shared_from_this(), timer](const auto & ec)
|
||||
{
|
||||
if (ec)
|
||||
return;
|
||||
|
||||
if (!self->socket->is_open())
|
||||
return;
|
||||
|
||||
self->sendPacket({});
|
||||
self->heartbeat();
|
||||
});
|
||||
}
|
||||
|
||||
void NetworkConnection::onHeaderReceived(const boost::system::error_code & ecHeader)
|
||||
{
|
||||
if (ecHeader)
|
||||
@ -91,7 +71,7 @@ void NetworkConnection::onHeaderReceived(const boost::system::error_code & ecHea
|
||||
|
||||
if (messageSize == 0)
|
||||
{
|
||||
//heartbeat package with no payload - wait for next packet
|
||||
// Zero-sized packet. Strange, but safe to ignore. Start reading next packet
|
||||
start();
|
||||
return;
|
||||
}
|
||||
@ -124,13 +104,16 @@ void NetworkConnection::onPacketReceived(const boost::system::error_code & ec, u
|
||||
|
||||
void NetworkConnection::sendPacket(const std::vector<std::byte> & message)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(writeMutex);
|
||||
|
||||
boost::system::error_code ec;
|
||||
|
||||
// create array with single element - boost::asio::buffer can be constructed from containers, but not from plain integer
|
||||
std::array<uint32_t, 1> messageSize{static_cast<uint32_t>(message.size())};
|
||||
|
||||
boost::asio::write(*socket, boost::asio::buffer(messageSize), ec );
|
||||
boost::asio::write(*socket, boost::asio::buffer(message), ec );
|
||||
if (message.size() > 0)
|
||||
boost::asio::write(*socket, boost::asio::buffer(message), ec );
|
||||
|
||||
//Note: ignoring error code, intended
|
||||
}
|
||||
|
@ -19,17 +19,16 @@ class NetworkConnection : public INetworkConnection, public std::enable_shared_f
|
||||
static const int messageMaxSize = 64 * 1024 * 1024; // arbitrary size to prevent potential massive allocation if we receive garbage input
|
||||
|
||||
std::shared_ptr<NetworkSocket> socket;
|
||||
std::shared_ptr<NetworkContext> context;
|
||||
std::mutex writeMutex;
|
||||
|
||||
NetworkBuffer readBuffer;
|
||||
INetworkConnectionListener & listener;
|
||||
|
||||
void heartbeat();
|
||||
void onHeaderReceived(const boost::system::error_code & ec);
|
||||
void onPacketReceived(const boost::system::error_code & ec, uint32_t expectedPacketSize);
|
||||
|
||||
public:
|
||||
NetworkConnection(INetworkConnectionListener & listener, const std::shared_ptr<NetworkSocket> & socket, const std::shared_ptr<NetworkContext> & context);
|
||||
NetworkConnection(INetworkConnectionListener & listener, const std::shared_ptr<NetworkSocket> & socket);
|
||||
|
||||
void start();
|
||||
void close() override;
|
||||
|
@ -34,14 +34,14 @@ void NetworkHandler::connectToRemote(INetworkClientListener & listener, const st
|
||||
auto socket = std::make_shared<NetworkSocket>(*io);
|
||||
boost::asio::ip::tcp::resolver resolver(*io);
|
||||
auto endpoints = resolver.resolve(host, std::to_string(port));
|
||||
boost::asio::async_connect(*socket, endpoints, [this, socket, &listener](const boost::system::error_code& error, const boost::asio::ip::tcp::endpoint& endpoint)
|
||||
boost::asio::async_connect(*socket, endpoints, [socket, &listener](const boost::system::error_code& error, const boost::asio::ip::tcp::endpoint& endpoint)
|
||||
{
|
||||
if (error)
|
||||
{
|
||||
listener.onConnectionFailed(error.message());
|
||||
return;
|
||||
}
|
||||
auto connection = std::make_shared<NetworkConnection>(listener, socket, io);
|
||||
auto connection = std::make_shared<NetworkConnection>(listener, socket);
|
||||
connection->start();
|
||||
|
||||
listener.onConnectionEstablished(connection);
|
||||
|
@ -39,7 +39,7 @@ void NetworkServer::connectionAccepted(std::shared_ptr<NetworkSocket> upcomingCo
|
||||
}
|
||||
|
||||
logNetwork->info("We got a new connection! :)");
|
||||
auto connection = std::make_shared<NetworkConnection>(*this, upcomingConnection, io);
|
||||
auto connection = std::make_shared<NetworkConnection>(*this, upcomingConnection);
|
||||
connections.insert(connection);
|
||||
connection->start();
|
||||
listener.onNewConnection(connection);
|
||||
|
@ -30,7 +30,7 @@ struct DLL_LINKAGE CPack
|
||||
template <typename Handler> void serialize(Handler &h)
|
||||
{
|
||||
logNetwork->error("CPack serialized... this should not happen!");
|
||||
assert(false && "CPack serialized");
|
||||
throw std::runtime_error("CPack serialized... this should not happen!");
|
||||
}
|
||||
|
||||
void applyGs(CGameState * gs)
|
||||
|
@ -130,6 +130,7 @@ std::unique_ptr<CMap> CMapGenerator::generate()
|
||||
catch (rmgException &e)
|
||||
{
|
||||
logGlobal->error("Random map generation received exception: %s", e.what());
|
||||
throw;
|
||||
}
|
||||
Load::Progress::finish();
|
||||
return std::move(map->mapInstance);
|
||||
|
@ -21,21 +21,32 @@ Point2D Point2D::operator * (float scale) const
|
||||
return Point2D(x() * scale, y() * scale);
|
||||
}
|
||||
|
||||
Point2D Point2D::operator / (float scale) const
|
||||
{
|
||||
return Point2D(x() / scale, y() / scale);
|
||||
}
|
||||
|
||||
Point2D Point2D::operator + (const Point2D& other) const
|
||||
{
|
||||
return Point2D(x() + other.x(), y() + other.y());
|
||||
}
|
||||
|
||||
Point2D Point2D::operator - (const Point2D& other) const
|
||||
{
|
||||
return Point2D(x() - other.x(), y() - other.y());
|
||||
}
|
||||
|
||||
bool Point2D::operator < (const Point2D& other) const
|
||||
{
|
||||
if (x() < other.x())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return y() < other.y();
|
||||
}
|
||||
if (x() != other.x())
|
||||
return x() < other.x();
|
||||
|
||||
return y() < other.y();
|
||||
}
|
||||
|
||||
bool Point2D::operator == (const Point2D& other) const
|
||||
{
|
||||
return vstd::isAlmostEqual(x(), other.x()) && vstd::isAlmostEqual(y(), other.y());
|
||||
}
|
||||
|
||||
std::string Point2D::toString() const
|
||||
@ -163,6 +174,16 @@ std::set<Point2D> PenroseTiling::generatePenroseTiling(size_t numZones, CRandomG
|
||||
|
||||
split(t, points, indices, DEPTH);
|
||||
}
|
||||
// Remove duplicates
|
||||
vstd::unique(points);
|
||||
|
||||
// Shift center to (0.5, 0.5)
|
||||
for (auto & point : points)
|
||||
{
|
||||
point = point + Point2D(0.5f, 0.5f);
|
||||
};
|
||||
|
||||
// For 8XM8 map, only 650 out of 15971 points are in the range
|
||||
|
||||
vstd::copy_if(points, vstd::set_inserter(finalPoints), [](const Point2D point)
|
||||
{
|
||||
|
@ -28,10 +28,13 @@ public:
|
||||
using point_xy::point_xy;
|
||||
|
||||
Point2D operator * (float scale) const;
|
||||
Point2D operator / (float scale) const;
|
||||
Point2D operator + (const Point2D& other) const;
|
||||
Point2D operator - (const Point2D& other) const;
|
||||
Point2D rotated(float radians) const;
|
||||
|
||||
bool operator < (const Point2D& other) const;
|
||||
bool operator == (const Point2D& other) const;
|
||||
|
||||
std::string toString() const;
|
||||
};
|
||||
|
@ -38,7 +38,11 @@ void ObstaclePlacer::process()
|
||||
|
||||
auto faction = zone.getTownType().toFaction();
|
||||
|
||||
ObstacleSetFilter filter(ObstacleSet::EObstacleType::INVALID, zone.getTerrainType(), faction->getId(), faction->alignment);
|
||||
ObstacleSetFilter filter(ObstacleSet::EObstacleType::INVALID,
|
||||
zone.getTerrainType(),
|
||||
static_cast<ObstacleSet::EMapLevel>(zone.isUnderground()),
|
||||
faction->getId(),
|
||||
faction->alignment);
|
||||
|
||||
if (!prepareBiome(filter, zone.getRand()))
|
||||
{
|
||||
|
@ -439,7 +439,7 @@ void DimensionDoorMechanics::endCast(SpellCastEnvironment * env, const Adventure
|
||||
const TerrainTile * curr = env->getCb()->getTile(casterPosition);
|
||||
|
||||
if(dest->isClear(curr))
|
||||
env->moveHero(ObjectInstanceID(parameters.caster->getCasterUnitId()), parameters.caster->getHeroCaster()->convertFromVisitablePos(parameters.pos), true);
|
||||
env->moveHero(ObjectInstanceID(parameters.caster->getCasterUnitId()), parameters.caster->getHeroCaster()->convertFromVisitablePos(parameters.pos), EMovementMode::DIMENSION_DOOR);
|
||||
}
|
||||
|
||||
///TownPortalMechanics
|
||||
@ -567,7 +567,7 @@ void TownPortalMechanics::endCast(SpellCastEnvironment * env, const AdventureSpe
|
||||
destination = dynamic_cast<const CGTownInstance*>(topObj);
|
||||
}
|
||||
|
||||
if(env->moveHero(ObjectInstanceID(parameters.caster->getCasterUnitId()), parameters.caster->getHeroCaster()->convertFromVisitablePos(destination->visitablePos()), true))
|
||||
if(env->moveHero(ObjectInstanceID(parameters.caster->getCasterUnitId()), parameters.caster->getHeroCaster()->convertFromVisitablePos(destination->visitablePos()), EMovementMode::TOWN_PORTAL))
|
||||
{
|
||||
SetMovePoints smp;
|
||||
smp.hid = ObjectInstanceID(parameters.caster->getCasterUnitId());
|
||||
|
@ -59,7 +59,7 @@ public:
|
||||
virtual const CMap * getMap() const = 0;
|
||||
virtual const CGameInfoCallback * getCb() const = 0;
|
||||
|
||||
virtual bool moveHero(ObjectInstanceID hid, int3 dst, bool teleporting) = 0; //TODO: remove
|
||||
virtual bool moveHero(ObjectInstanceID hid, int3 dst, EMovementMode mode) = 0; //TODO: remove
|
||||
|
||||
virtual void genericQuery(Query * request, PlayerColor color, std::function<void(std::optional<int32_t>)> callback) = 0;//TODO: type safety on query, use generic query packet when implemented
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -543,7 +543,7 @@ void CGameHandler::init(StartInfo *si, Load::ProgressAccumulator & progressTrack
|
||||
{
|
||||
if (si->seedToBeUsed == 0)
|
||||
{
|
||||
si->seedToBeUsed = static_cast<ui32>(std::time(nullptr));
|
||||
si->seedToBeUsed = CRandomGenerator::getDefault().nextInt();
|
||||
}
|
||||
CMapService mapService;
|
||||
gs = new CGameState();
|
||||
@ -1073,11 +1073,11 @@ bool CGameHandler::removeObject(const CGObjectInstance * obj, const PlayerColor
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, bool transit, PlayerColor asker)
|
||||
bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, EMovementMode movementMode, bool transit, PlayerColor asker)
|
||||
{
|
||||
const CGHeroInstance *h = getHero(hid);
|
||||
// not turn of that hero or player can't simply teleport hero (at least not with this function)
|
||||
if(!h || (asker != PlayerColor::NEUTRAL && teleporting))
|
||||
if(!h || (asker != PlayerColor::NEUTRAL && movementMode != EMovementMode::STANDARD))
|
||||
{
|
||||
if(h && getStartInfo()->turnTimerInfo.isEnabled() && gs->players[h->getOwner()].turnTimer.turnTimer == 0)
|
||||
return true; //timer expired, no error
|
||||
@ -1164,13 +1164,13 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, boo
|
||||
if(h->boat && h->boat->layer == EPathfindingLayer::SAIL && t.terType->isLand() && t.blocked)
|
||||
return complainRet("Cannot disembark hero, tile is blocked!");
|
||||
|
||||
if(distance(h->pos, dst) >= 1.5 && !teleporting)
|
||||
if(distance(h->pos, dst) >= 1.5 && movementMode == EMovementMode::STANDARD)
|
||||
return complainRet("Tiles are not neighboring!");
|
||||
|
||||
if(h->inTownGarrison)
|
||||
return complainRet("Can not move garrisoned hero!");
|
||||
|
||||
if(h->movementPointsRemaining() < cost && dst != h->pos && !teleporting)
|
||||
if(h->movementPointsRemaining() < cost && dst != h->pos && movementMode == EMovementMode::STANDARD)
|
||||
return complainRet("Hero doesn't have any movement points left!");
|
||||
|
||||
if (transit && !canFly && !(canWalkOnSea && t.terType->isWater()) && !CGTeleport::isTeleport(objectToVisit))
|
||||
@ -1259,12 +1259,12 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, boo
|
||||
return doMove(TryMoveHero::DISEMBARK, CHECK_FOR_GUARDS, VISIT_DEST, LEAVING_TILE);
|
||||
}
|
||||
|
||||
if (teleporting)
|
||||
if (movementMode != EMovementMode::STANDARD)
|
||||
{
|
||||
if (blockingVisit()) // e.g. hero on the other side of teleporter
|
||||
return true;
|
||||
|
||||
EGuardLook guardsCheck = VLC->settings()->getBoolean(EGameSettings::DIMENSION_DOOR_TRIGGERS_GUARDS)
|
||||
EGuardLook guardsCheck = (VLC->settings()->getBoolean(EGameSettings::DIMENSION_DOOR_TRIGGERS_GUARDS) && movementMode == EMovementMode::DIMENSION_DOOR)
|
||||
? CHECK_FOR_GUARDS
|
||||
: IGNORE_GUARDS;
|
||||
|
||||
@ -1337,7 +1337,7 @@ bool CGameHandler::teleportHero(ObjectInstanceID hid, ObjectInstanceID dstid, ui
|
||||
return false;
|
||||
|
||||
int3 pos = h->convertFromVisitablePos(t->visitablePos());
|
||||
moveHero(hid,pos,1);
|
||||
moveHero(hid,pos,EMovementMode::CASTLE_GATE);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -140,7 +140,7 @@ public:
|
||||
void startBattlePrimary(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, const CGTownInstance *town = nullptr) override; //use hero=nullptr for no hero
|
||||
void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, bool creatureBank = false) override; //if any of armies is hero, hero will be used
|
||||
void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, bool creatureBank = false) override; //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle
|
||||
bool moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, bool transit = false, PlayerColor asker = PlayerColor::NEUTRAL) override;
|
||||
bool moveHero(ObjectInstanceID hid, int3 dst, EMovementMode movementMode, bool transit = false, PlayerColor asker = PlayerColor::NEUTRAL) override;
|
||||
void giveHeroBonus(GiveBonus * bonus) override;
|
||||
void setMovePoints(SetMovePoints * smp) override;
|
||||
void setMovePoints(ObjectInstanceID hid, int val, bool absolute) override;
|
||||
|
@ -65,7 +65,7 @@ void ApplyGhNetPackVisitor::visitMoveHero(MoveHero & pack)
|
||||
|
||||
for (auto const & dest : pack.path)
|
||||
{
|
||||
if (!gh.moveHero(pack.hid, dest, 0, pack.transit, pack.player))
|
||||
if (!gh.moveHero(pack.hid, dest, EMovementMode::STANDARD, pack.transit, pack.player))
|
||||
{
|
||||
result = false;
|
||||
return;
|
||||
|
@ -89,9 +89,9 @@ const CMap * ServerSpellCastEnvironment::getMap() const
|
||||
return gh->gameState()->map;
|
||||
}
|
||||
|
||||
bool ServerSpellCastEnvironment::moveHero(ObjectInstanceID hid, int3 dst, bool teleporting)
|
||||
bool ServerSpellCastEnvironment::moveHero(ObjectInstanceID hid, int3 dst, EMovementMode mode)
|
||||
{
|
||||
return gh->moveHero(hid, dst, teleporting, false);
|
||||
return gh->moveHero(hid, dst, mode, false);
|
||||
}
|
||||
|
||||
void ServerSpellCastEnvironment::genericQuery(Query * request, PlayerColor color, std::function<void(std::optional<int32_t>)> callback)
|
||||
|
@ -36,7 +36,7 @@ public:
|
||||
|
||||
const CMap * getMap() const override;
|
||||
const CGameInfoCallback * getCb() const override;
|
||||
bool moveHero(ObjectInstanceID hid, int3 dst, bool teleporting) override;
|
||||
bool moveHero(ObjectInstanceID hid, int3 dst, EMovementMode mode) override;
|
||||
void genericQuery(Query * request, PlayerColor color, std::function<void(std::optional<int32_t>)> callback) override;
|
||||
private:
|
||||
CGameHandler * gh;
|
||||
|
@ -121,7 +121,7 @@ public:
|
||||
return gameState.get();
|
||||
}
|
||||
|
||||
bool moveHero(ObjectInstanceID hid, int3 dst, bool teleporting) override
|
||||
bool moveHero(ObjectInstanceID hid, int3 dst, EMovementMode movementMode) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ public:
|
||||
void startBattlePrimary(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, const CGTownInstance *town = nullptr) override {} //use hero=nullptr for no hero
|
||||
void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, bool creatureBank = false) override {} //if any of armies is hero, hero will be used
|
||||
void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, bool creatureBank = false) override {} //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle
|
||||
bool moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, bool transit = false, PlayerColor asker = PlayerColor::NEUTRAL) override {return false;}
|
||||
bool moveHero(ObjectInstanceID hid, int3 dst, EMovementMode movementMode, bool transit = false, PlayerColor asker = PlayerColor::NEUTRAL) override {return false;}
|
||||
bool swapGarrisonOnSiege(ObjectInstanceID tid) override {return false;}
|
||||
void giveHeroBonus(GiveBonus * bonus) override {}
|
||||
void setMovePoints(SetMovePoints * smp) override {}
|
||||
|
Loading…
Reference in New Issue
Block a user