diff --git a/Mods/vcmi/config/vcmi/chinese.json b/Mods/vcmi/config/vcmi/chinese.json
index 3135bd2c8..3d48a4f41 100644
--- a/Mods/vcmi/config/vcmi/chinese.json
+++ b/Mods/vcmi/config/vcmi/chinese.json
@@ -118,17 +118,17 @@
// few strings from WoG used by vcmi
"vcmi.stackExperience.description" : "» 经 验 获 得 明 细 «\n\n生物类型 ................... : %s\n经验等级 ................. : %s (%i)\n经验点数 ............... : %i\n下一个等级所需经验 .. : %i\n每次战斗最大获得经验 ... : %i%% (%i)\n获得经验的生物数量 .... : %i\n最大招募数量\n不会丢失经验升级 .... : %i\n经验倍数 ........... : %.2f\n升级倍数 .............. : %.2f\n10级后经验值 ........ : %i\n最大招募数量下\n 升级到10级所需经验数量: %i",
- "vcmi.stackExperience.rank.1" : "新兵 1级",
- "vcmi.stackExperience.rank.2" : "列兵 2级",
- "vcmi.stackExperience.rank.3" : "下士 3级",
- "vcmi.stackExperience.rank.4" : "中士 4级",
- "vcmi.stackExperience.rank.5" : "上士 5级",
- "vcmi.stackExperience.rank.6" : "少尉 6级",
- "vcmi.stackExperience.rank.7" : "中尉 7级",
- "vcmi.stackExperience.rank.8" : "上尉 8级",
- "vcmi.stackExperience.rank.9" : "少校 9级",
- "vcmi.stackExperience.rank.10" : "中校 10级",
- "vcmi.stackExperience.rank.11" : "上校 11级",
+ "vcmi.stackExperience.rank.0" : "新兵 1级",
+ "vcmi.stackExperience.rank.1" : "列兵 2级",
+ "vcmi.stackExperience.rank.2" : "下士 3级",
+ "vcmi.stackExperience.rank.3" : "中士 4级",
+ "vcmi.stackExperience.rank.4" : "上士 5级",
+ "vcmi.stackExperience.rank.5" : "少尉 6级",
+ "vcmi.stackExperience.rank.6" : "中尉 7级",
+ "vcmi.stackExperience.rank.7" : "上尉 8级",
+ "vcmi.stackExperience.rank.8" : "少校 9级",
+ "vcmi.stackExperience.rank.9" : "中校 10级",
+ "vcmi.stackExperience.rank.10" : "上校 11级",
"core.bonus.ADDITIONAL_ATTACK.name": "双击",
"core.bonus.ADDITIONAL_ATTACK.description": "可以攻击两次",
@@ -244,10 +244,6 @@
"core.bonus.REBIRTH.description": "{val}% 数量死亡后会复活",
"core.bonus.RETURN_AFTER_STRIKE.name": "攻击并返回",
"core.bonus.RETURN_AFTER_STRIKE.description": "攻击后回到初始位置",
- "core.bonus.SELF_LUCK.name": "永久幸运",
- "core.bonus.SELF_LUCK.description": "永久拥有幸运值",
- "core.bonus.SELF_MORALE.name": "士气高涨",
- "core.bonus.SELF_MORALE.description": "永久拥有高昂的士气",
"core.bonus.SHOOTER.name": "射手",
"core.bonus.SHOOTER.description": "生物可以设计",
"core.bonus.SHOOTS_ALL_ADJACENT.name": "范围远程攻击",
diff --git a/Mods/vcmi/config/vcmi/english.json b/Mods/vcmi/config/vcmi/english.json
index 68b0c81ee..f60407b3d 100644
--- a/Mods/vcmi/config/vcmi/english.json
+++ b/Mods/vcmi/config/vcmi/english.json
@@ -1,5 +1,5 @@
{
- "vcmi.adventureMap.monsterThreat.title" : "\n\n Threat: ",
+ "vcmi.adventureMap.monsterThreat.title" : "\n\nThreat: ",
"vcmi.adventureMap.monsterThreat.levels.0" : "Effortless",
"vcmi.adventureMap.monsterThreat.levels.1" : "Very Weak",
"vcmi.adventureMap.monsterThreat.levels.2" : "Weak",
@@ -13,24 +13,24 @@
"vcmi.adventureMap.monsterThreat.levels.10" : "Deadly",
"vcmi.adventureMap.monsterThreat.levels.11" : "Impossible",
- "vcmi.adventureMap.confirmRestartGame" : "Are you sure you want to restart game?",
- "vcmi.adventureMap.noTownWithMarket" : "No available marketplace!",
- "vcmi.adventureMap.noTownWithTavern" : "No available town with tavern!",
- "vcmi.adventureMap.spellUnknownProblem" : "Unknown problem with this spell, no more information available.",
+ "vcmi.adventureMap.confirmRestartGame" : "Are you sure you want to restart the game?",
+ "vcmi.adventureMap.noTownWithMarket" : "There are no available marketplaces!",
+ "vcmi.adventureMap.noTownWithTavern" : "There are no available towns with taverns!",
+ "vcmi.adventureMap.spellUnknownProblem" : "There is an unknown problem with this spell! No more information is available.",
"vcmi.adventureMap.playerAttacked" : "Player has been attacked: %s",
"vcmi.adventureMap.moveCostDetails" : "Movement points - Cost: %TURNS turns + %POINTS points, Remaining points: %REMAINING",
"vcmi.adventureMap.moveCostDetailsNoTurns" : "Movement points - Cost: %POINTS points, Remaining points: %REMAINING",
- "vcmi.server.errors.existingProcess" : "Another vcmiserver process is running, please terminate it first",
- "vcmi.server.errors.modsIncompatibility" : "Required mods to load game:",
- "vcmi.server.confirmReconnect" : "Connect to the last session?",
+ "vcmi.server.errors.existingProcess" : "Another VCMI server process is running. Please terminate it before starting a new game.",
+ "vcmi.server.errors.modsIncompatibility" : "The following mods are required to load the game:",
+ "vcmi.server.confirmReconnect" : "Do you want to reconnect to the last session?",
"vcmi.settingsMainWindow.generalTab.hover" : "General",
"vcmi.settingsMainWindow.generalTab.help" : "Switches to General Options tab, which contains settings related to general game client behavior",
"vcmi.settingsMainWindow.battleTab.hover" : "Battle",
"vcmi.settingsMainWindow.battleTab.help" : "Switches to Battle Options tab, which allows configuring game behavior during battles",
"vcmi.settingsMainWindow.adventureTab.hover" : "Adventure Map",
- "vcmi.settingsMainWindow.adventureTab.help" : "Switches to Adventure Map Options tab - adventure map is part of the game where you can move your heroes",
+ "vcmi.settingsMainWindow.adventureTab.help" : "Switches to Adventure Map Options tab (adventure map is the section of the game where players can control the movements of their heroes)",
"vcmi.systemOptions.videoGroup" : "Video Settings",
"vcmi.systemOptions.audioGroup" : "Audio Settings",
@@ -38,51 +38,50 @@
"vcmi.systemOptions.townsGroup" : "Town Screen",
"vcmi.systemOptions.fullscreenButton.hover" : "Fullscreen",
- "vcmi.systemOptions.fullscreenButton.help" : "{Fullscreen}\n\n If selected, VCMI will run in fullscreen mode, otherwise VCMI will run in window",
+ "vcmi.systemOptions.fullscreenButton.help" : "{Fullscreen}\n\nIf selected, VCMI will run in fullscreen mode, otherwise it will run in windowed mode",
"vcmi.systemOptions.resolutionButton.hover" : "Resolution: %wx%h",
- "vcmi.systemOptions.resolutionButton.help" : "{Select Resolution}\n\n Change in-game screen resolution. Game restart required to apply new resolution.",
+ "vcmi.systemOptions.resolutionButton.help" : "{Select Resolution}\n\nChange in-game screen resolution. A game restart is required to apply the new resolution.",
"vcmi.systemOptions.resolutionMenu.hover" : "Select Resolution",
"vcmi.systemOptions.resolutionMenu.help" : "Change in-game screen resolution.",
- "vcmi.systemOptions.fullscreenFailed" : "{Fullscreen}\n\n Failed to switch to fullscreen mode! Current resolution is not supported by display!",
+ "vcmi.systemOptions.fullscreenFailed" : "{Fullscreen}\n\nFailed to switch to fullscreen mode! The current resolution is not supported by the display!",
"vcmi.systemOptions.framerateButton.hover" : "Show FPS",
- "vcmi.systemOptions.framerateButton.help" : "{Show FPS}\n\n Toggles visibility of Frames Per Second counter in corner of game window.",
+ "vcmi.systemOptions.framerateButton.help" : "{Show FPS}\n\nToggle the visibility of the Frames Per Second counter in the corner of the game window",
"vcmi.adventureOptions.infoBarPick.hover" : "Show Messages in Info Panel",
- "vcmi.adventureOptions.infoBarPick.help" : "{Show Messages in Info Panel}\n\nWhenever possible, game messages from visiting map objects will be shown in info bar instead of showing up as popup windows",
+ "vcmi.adventureOptions.infoBarPick.help" : "{Show Messages in Info Panel}\n\nWhenever possible, game messages from visiting map objects will be shown in the info pannel, instead of popping up in a separate window.",
"vcmi.adventureOptions.numericQuantities.hover" : "Numeric Creature Quantities",
- "vcmi.adventureOptions.numericQuantities.help" : "{Numeric Creature Quantities}\n\n Shows approximate enemy creatures quantities in numeric A-B format.",
+ "vcmi.adventureOptions.numericQuantities.help" : "{Numeric Creature Quantities}\n\nShow the approximate quantities of enemy creatures in the numeric A-B format.",
"vcmi.adventureOptions.forceMovementInfo.hover" : "Always Show Movement Cost",
- "vcmi.adventureOptions.forceMovementInfo.help" : "{Always Show Movement Cost}\n\n Replaces default status bar info with movement points data without need to hold ALT button.",
+ "vcmi.adventureOptions.forceMovementInfo.help" : "{Always Show Movement Cost}\n\nAlways show movement points data in status bar information. (Instead of viewing it only while you hold down ALT key)",
"vcmi.adventureOptions.showGrid.hover" : "Show Grid",
- "vcmi.adventureOptions.showGrid.help" : "{Show Grid}\n\n Shows grid overlay, showing borders between adventure map tiles.",
- "vcmi.adventureOptions.mapSwipe.hover" : "Map Swipe",
- "vcmi.adventureOptions.mapSwipe.help" : "{Map Swipe}\n\n Allows map movement via finger swipe gesture on systems with touchscreen. As of right now, can also be accessed via left mouse button.",
+ "vcmi.adventureOptions.showGrid.help" : "{Show Grid}\n\nShow the grid overlay, highlighting the borders between adventure map tiles.",
+ "vcmi.adventureOptions.mapSwipe.hover" : "Map Swipe/Panning",
+ "vcmi.adventureOptions.mapSwipe.help" : "{Map Swipe/Panning}\n\nOn touchscreen devices, you can move the map by swiping with your finger. To pan the map using the mouse, hold down the left or middle mouse button and move the mouse.",
"vcmi.adventureOptions.mapScrollSpeed1.hover": "",
"vcmi.adventureOptions.mapScrollSpeed5.hover": "",
"vcmi.adventureOptions.mapScrollSpeed6.hover": "",
- "vcmi.adventureOptions.mapScrollSpeed1.help": "Set map scrolling speed to very slow",
- "vcmi.adventureOptions.mapScrollSpeed5.help": "Set map scrolling speed to very fast",
- "vcmi.adventureOptions.mapScrollSpeed6.help": "Set map scrolling speed to instantaneous.",
+ "vcmi.adventureOptions.mapScrollSpeed1.help": "Set the map scrolling speed to very slow",
+ "vcmi.adventureOptions.mapScrollSpeed5.help": "Set the map scrolling speed to very fast",
+ "vcmi.adventureOptions.mapScrollSpeed6.help": "Set the map scrolling speed to instantaneous.",
- "vcmi.battleOptions.queueSizeLabel.hover": "Show Creature Turn Order",
+ "vcmi.battleOptions.queueSizeLabel.hover": "Show Turn Order Queue",
"vcmi.battleOptions.queueSizeNoneButton.hover": "OFF",
"vcmi.battleOptions.queueSizeAutoButton.hover": "AUTO",
"vcmi.battleOptions.queueSizeSmallButton.hover": "SMALL",
"vcmi.battleOptions.queueSizeBigButton.hover": "BIG",
- "vcmi.battleOptions.queueSizeNoneButton.help": "Completely disables visibility of creature turn order in battle",
- "vcmi.battleOptions.queueSizeAutoButton.help": "Sets turn order size depending on game resolution (small when playing with screen resolution below 700 pixels high, big otherwise)",
- "vcmi.battleOptions.queueSizeSmallButton.help": "Sets turn order size to small",
- "vcmi.battleOptions.queueSizeBigButton.help": "Sets turn order size to big (not supported if game resolution is less than 700 pixels high)",
+ "vcmi.battleOptions.queueSizeNoneButton.help": "Do not display Turn Order Queue",
+ "vcmi.battleOptions.queueSizeAutoButton.help": "Automatically adjust the size of the turn order queue based on the game's resolution(SMALL size is used when playing the game on a resolution with a height lower than 700 pixels, BIG size is used otherwise)",
+ "vcmi.battleOptions.queueSizeSmallButton.help": "Sets turn order queue size to SMALL",
+ "vcmi.battleOptions.queueSizeBigButton.help": "Sets turn order queue size to BIG (not supported if game resolution height is less than 700 pixels)",
"vcmi.battleOptions.animationsSpeed1.hover": "",
"vcmi.battleOptions.animationsSpeed5.hover": "",
"vcmi.battleOptions.animationsSpeed6.hover": "",
- "vcmi.battleOptions.animationsSpeed1.help": "Sets animation speed to very slow",
- "vcmi.battleOptions.animationsSpeed5.help": "Sets animation speed to very fast",
- "vcmi.battleOptions.animationsSpeed6.help": "Sets animation speed to instantaneous",
+ "vcmi.battleOptions.animationsSpeed1.help": "Set animation speed to very slow",
+ "vcmi.battleOptions.animationsSpeed5.help": "Set animation speed to very fast",
+ "vcmi.battleOptions.animationsSpeed6.help": "Set animation speed to instantaneous",
"vcmi.battleOptions.skipBattleIntroMusic.hover": "Skip Intro Music",
- "vcmi.battleOptions.skipBattleIntroMusic.help": "{Skip Intro Music}\n\n Skip short music that plays at beginning of each battle before action starts. Can also be skipped by pressing ESC key.",
-
- "vcmi.battleWindow.pressKeyToSkipIntro" : "Press any key to skip battle intro",
+ "vcmi.battleOptions.skipBattleIntroMusic.help": "{Skip Intro Music}\n\nAllow actions during the intro music that plays at the beginning of each battle",
+ "vcmi.battleWindow.pressKeyToSkipIntro" : "Press any key to start battle immediately",
"vcmi.battleWindow.damageEstimation.melee" : "Attack %CREATURE (%DAMAGE).",
"vcmi.battleWindow.damageEstimation.meleeKills" : "Attack %CREATURE (%DAMAGE, %KILLS).",
@@ -96,11 +95,11 @@
"vcmi.battleWindow.damageEstimation.kills.1" : "%d will perish",
"vcmi.otherOptions.availableCreaturesAsDwellingLabel.hover" : "Show Available Creatures",
- "vcmi.otherOptions.availableCreaturesAsDwellingLabel.help" : "{Show Available Creatures}\n\n Shows creatures available to purchase instead of their growth in town summary (bottom-left corner).",
+ "vcmi.otherOptions.availableCreaturesAsDwellingLabel.help" : "{Show Available Creatures}\n\nShow the number of creatures available to purchase instead of their growth in town summary (bottom-left corner of town screen).",
"vcmi.otherOptions.creatureGrowthAsDwellingLabel.hover" : "Show Weekly Growth of Creatures",
- "vcmi.otherOptions.creatureGrowthAsDwellingLabel.help" : "{Show Weekly Growth of Creatures}\n\n Shows creatures' weekly growth instead of available amount in town summary (bottom-left corner).",
+ "vcmi.otherOptions.creatureGrowthAsDwellingLabel.help" : "{Show Weekly Growth of Creatures}\n\nShow creatures' weekly growth instead of available amount in town summary (bottom-left corner of town screen).",
"vcmi.otherOptions.compactTownCreatureInfo.hover": "Compact Creature Info",
- "vcmi.otherOptions.compactTownCreatureInfo.help": "{Compact Creature Info}\n\n Smaller town creatures information in town summary.",
+ "vcmi.otherOptions.compactTownCreatureInfo.help": "{Compact Creature Info}\n\nShow smaller information for town creatures in town summary (bottom-left corner of town screen).",
"vcmi.townHall.missingBase" : "Base building %s must be built first",
"vcmi.townHall.noCreaturesToRecruit" : "There are no creatures to recruit!",
@@ -120,20 +119,20 @@
"vcmi.logicalExpressions.allOf" : "All of the following:",
"vcmi.logicalExpressions.noneOf" : "None of the following:",
- "vcmi.heroWindow.openCommander.hover" : "Open commander window",
- "vcmi.heroWindow.openCommander.help" : "Displays information about commander of this hero",
+ "vcmi.heroWindow.openCommander.hover" : "Open commander info window",
+ "vcmi.heroWindow.openCommander.help" : "Shows details about the commander of this hero",
- "vcmi.commanderWindow.artifactMessage" : "Do you want to give this artifact back to hero?",
+ "vcmi.commanderWindow.artifactMessage" : "Do you want to return this artifact to the hero?",
"vcmi.creatureWindow.showBonuses.hover" : "Switch to bonuses view",
- "vcmi.creatureWindow.showBonuses.help" : "Displays all active bonuses of the commander",
+ "vcmi.creatureWindow.showBonuses.help" : "Display all active bonuses of the commander",
"vcmi.creatureWindow.showSkills.hover" : "Switch to skills view",
- "vcmi.creatureWindow.showSkills.help" : "Displays all learned skills of the commander",
- "vcmi.creatureWindow.returnArtifact.hover" : "Give back artifact",
- "vcmi.creatureWindow.returnArtifact.help" : "Use this button to return stack artifact back into hero backpack",
+ "vcmi.creatureWindow.showSkills.help" : "Display all learned skills of the commander",
+ "vcmi.creatureWindow.returnArtifact.hover" : "Return artifact",
+ "vcmi.creatureWindow.returnArtifact.help" : "Click this button to return the artifact to the hero's backpack",
"vcmi.questLog.hideComplete.hover" : "Hide complete quests",
- "vcmi.questLog.hideComplete.help" : "Hide all quests that already completed",
+ "vcmi.questLog.hideComplete.help" : "Hide all completed quests",
"vcmi.randomMapTab.widgets.defaultTemplate" : "(default)",
"vcmi.randomMapTab.widgets.templateLabel" : "Template",
@@ -143,108 +142,108 @@
// few strings from WoG used by vcmi
"vcmi.stackExperience.description" : "» S t a c k E x p e r i e n c e D e t a i l s «\n\nCreature Type ................... : %s\nExperience Rank ................. : %s (%i)\nExperience Points ............... : %i\nExperience Points to Next Rank .. : %i\nMaximum Experience per Battle ... : %i%% (%i)\nNumber of Creatures in stack .... : %i\nMaximum New Recruits\n without losing current Rank .... : %i\nExperience Multiplier ........... : %.2f\nUpgrade Multiplier .............. : %.2f\nExperience after Rank 10 ........ : %i\nMaximum New Recruits to remain at\n Rank 10 if at Maximum Experience : %i",
- "vcmi.stackExperience.rank.1" : "Basic",
- "vcmi.stackExperience.rank.2" : "Novice",
- "vcmi.stackExperience.rank.3" : "Trained",
- "vcmi.stackExperience.rank.4" : "Skilled",
- "vcmi.stackExperience.rank.5" : "Proven",
- "vcmi.stackExperience.rank.6" : "Veteran",
- "vcmi.stackExperience.rank.7" : "Adept",
- "vcmi.stackExperience.rank.8" : "Expert",
- "vcmi.stackExperience.rank.9" : "Elite",
- "vcmi.stackExperience.rank.10" : "Master",
- "vcmi.stackExperience.rank.11" : "Ace",
+ "vcmi.stackExperience.rank.0" : "Basic",
+ "vcmi.stackExperience.rank.1" : "Novice",
+ "vcmi.stackExperience.rank.2" : "Trained",
+ "vcmi.stackExperience.rank.3" : "Skilled",
+ "vcmi.stackExperience.rank.4" : "Proven",
+ "vcmi.stackExperience.rank.5" : "Veteran",
+ "vcmi.stackExperience.rank.6" : "Adept",
+ "vcmi.stackExperience.rank.7" : "Expert",
+ "vcmi.stackExperience.rank.8" : "Elite",
+ "vcmi.stackExperience.rank.9" : "Master",
+ "vcmi.stackExperience.rank.10" : "Ace",
"core.bonus.ADDITIONAL_ATTACK.name": "Double Strike",
"core.bonus.ADDITIONAL_ATTACK.description": "Attacks twice",
"core.bonus.ADDITIONAL_RETALIATION.name": "Additional retaliations",
- "core.bonus.ADDITIONAL_RETALIATION.description": "May Retaliate ${val} extra times",
+ "core.bonus.ADDITIONAL_RETALIATION.description": "May retaliate ${val} extra times",
"core.bonus.AIR_IMMUNITY.name": "Air immunity",
- "core.bonus.AIR_IMMUNITY.description": "Immune to all Air school spells",
+ "core.bonus.AIR_IMMUNITY.description": "Immune to all spells from the school of Air magic",
"core.bonus.ATTACKS_ALL_ADJACENT.name": "Attack all around",
"core.bonus.ATTACKS_ALL_ADJACENT.description": "Attacks all adjacent enemies",
"core.bonus.BLOCKS_RETALIATION.name": "No retaliation",
"core.bonus.BLOCKS_RETALIATION.description": "Enemy cannot retaliate",
"core.bonus.BLOCKS_RANGED_RETALIATION.name": "No ranged retaliation",
- "core.bonus.BLOCKS_RANGED_RETALIATION.description": "Enemy cannot Retaliate by shooting",
+ "core.bonus.BLOCKS_RANGED_RETALIATION.description": "Enemy cannot retaliate by using a ranged attack",
"core.bonus.CATAPULT.name": "Catapult",
"core.bonus.CATAPULT.description": "Attacks siege walls",
"core.bonus.CATAPULT_EXTRA_SHOTS.name": "Additional siege attacks",
"core.bonus.CATAPULT_EXTRA_SHOTS.description": "Can hit siege walls ${val} extra times per attack",
"core.bonus.CHANGES_SPELL_COST_FOR_ALLY.name": "Reduce Casting Cost (${val})",
- "core.bonus.CHANGES_SPELL_COST_FOR_ALLY.description": "Reduces spell cost for hero",
+ "core.bonus.CHANGES_SPELL_COST_FOR_ALLY.description": "Reduces the spellcasting cost for the hero by ${val}",
"core.bonus.CHANGES_SPELL_COST_FOR_ENEMY.name": "Magic Damper (${val})",
- "core.bonus.CHANGES_SPELL_COST_FOR_ENEMY.description": "Increases Cost of enemy spells",
+ "core.bonus.CHANGES_SPELL_COST_FOR_ENEMY.description": "Increases spellcasting cost of enemy spells by ${val}",
"core.bonus.CHARGE_IMMUNITY.name": "Immune to Charge",
- "core.bonus.CHARGE_IMMUNITY.description": "Immune to Champion charge",
+ "core.bonus.CHARGE_IMMUNITY.description": "Immune to Cavalier's and Champion's Charge",
"core.bonus.DARKNESS.name": "Darkness cover",
- "core.bonus.DARKNESS.description": "Adds ${val} darkness radius",
+ "core.bonus.DARKNESS.description": "Creates a shroud of darkness with a ${val} radius",
"core.bonus.DEATH_STARE.name": "Death Stare (${val}%)",
- "core.bonus.DEATH_STARE.description": "${val}% chance to kill single creature",
+ "core.bonus.DEATH_STARE.description": "Has a ${val}% chance to kill a single creature",
"core.bonus.DEFENSIVE_STANCE.name": "Defense Bonus",
"core.bonus.DEFENSIVE_STANCE.description": "+${val} Defense when defending",
"core.bonus.DESTRUCTION.name": "Destruction",
"core.bonus.DESTRUCTION.description": "Has ${val}% chance to kill extra units after attack",
"core.bonus.DOUBLE_DAMAGE_CHANCE.name": "Death Blow",
- "core.bonus.DOUBLE_DAMAGE_CHANCE.description": "${val}% chance for double damage",
+ "core.bonus.DOUBLE_DAMAGE_CHANCE.description": "Has a ${val}% chance of dealing double base damage when attacking",
"core.bonus.DRAGON_NATURE.name": "Dragon",
"core.bonus.DRAGON_NATURE.description": "Creature has a Dragon Nature",
"core.bonus.DIRECT_DAMAGE_IMMUNITY.name": "Direct Damage Immunity",
"core.bonus.DIRECT_DAMAGE_IMMUNITY.description": "Immune to direct damage spells",
"core.bonus.EARTH_IMMUNITY.name": "Earth immunity",
- "core.bonus.EARTH_IMMUNITY.description": "Immune to all Earth school spells",
+ "core.bonus.EARTH_IMMUNITY.description": "Immune to all spells from the school of Earth magic",
"core.bonus.ENCHANTER.name": "Enchanter",
"core.bonus.ENCHANTER.description": "Can cast mass ${subtype.spell} every turn",
"core.bonus.ENCHANTED.name": "Enchanted",
"core.bonus.ENCHANTED.description": "Affected by permanent ${subtype.spell}",
"core.bonus.ENEMY_DEFENCE_REDUCTION.name": "Ignore Defense (${val}%)",
- "core.bonus.ENEMY_DEFENCE_REDUCTION.description": "Ignores part of Defence for the attack",
+ "core.bonus.ENEMY_DEFENCE_REDUCTION.description": "When attacking, ${val}% of the defender's defense is ignored",
"core.bonus.FIRE_IMMUNITY.name": "Fire immunity",
- "core.bonus.FIRE_IMMUNITY.description": "Immune to all Fire school spells",
+ "core.bonus.FIRE_IMMUNITY.description": "Immune to all spells from the school of Fire magic",
"core.bonus.FIRE_SHIELD.name": "Fire Shield (${val}%)",
"core.bonus.FIRE_SHIELD.description": "Reflects part of melee damage",
"core.bonus.FIRST_STRIKE.name": "First Strike",
- "core.bonus.FIRST_STRIKE.description": "This creature attacks first instead of retaliating",
+ "core.bonus.FIRST_STRIKE.description": "This creature retaliates before being attacked",
"core.bonus.FEAR.name": "Fear",
"core.bonus.FEAR.description": "Causes Fear on an enemy stack",
"core.bonus.FEARLESS.name": "Fearless",
"core.bonus.FEARLESS.description": "Immune to Fear ability",
"core.bonus.FLYING.name": "Fly",
- "core.bonus.FLYING.description": "Can Fly (ignores obstacles)",
+ "core.bonus.FLYING.description": "Flies when moving (ignores obstacles)",
"core.bonus.FREE_SHOOTING.name": "Shoot Close",
- "core.bonus.FREE_SHOOTING.description": "Can shoot in Close Combat",
+ "core.bonus.FREE_SHOOTING.description": "Can use ranged attacks at melee range",
"core.bonus.GARGOYLE.name": "Gargoyle",
- "core.bonus.GARGOYLE.description": "Cannot be rised or healed",
+ "core.bonus.GARGOYLE.description": "Cannot be raised or healed",
"core.bonus.GENERAL_DAMAGE_REDUCTION.name": "Reduce Damage (${val}%)",
- "core.bonus.GENERAL_DAMAGE_REDUCTION.description": "Reduces physical damage from ranged or melee",
+ "core.bonus.GENERAL_DAMAGE_REDUCTION.description": "Reduces physical damage from ranged or melee attacks",
"core.bonus.HATE.name": "Hates ${subtype.creature}",
- "core.bonus.HATE.description": "Does ${val}% more damage",
+ "core.bonus.HATE.description": "Does ${val}% more damage to ${subtype.creature}",
"core.bonus.HEALER.name": "Healer",
"core.bonus.HEALER.description": "Heals allied units",
"core.bonus.HP_REGENERATION.name": "Regeneration",
"core.bonus.HP_REGENERATION.description": "Heals ${SHval} hit points every round",
- "core.bonus.JOUSTING.name": "Champion Charge",
- "core.bonus.JOUSTING.description": "+${val}% damage per hex travelled",
+ "core.bonus.JOUSTING.name": "Champion charge",
+ "core.bonus.JOUSTING.description": "+${val}% damage for each hex travelled",
"core.bonus.KING.name": "King",
"core.bonus.KING.description": "Vulnerable to SLAYER level ${val} or higher",
"core.bonus.LEVEL_SPELL_IMMUNITY.name": "Spell immunity 1-${val}",
"core.bonus.LEVEL_SPELL_IMMUNITY.description": "Immune to spells of levels 1-${val}",
"core.bonus.LIMITED_SHOOTING_RANGE.name" : "Limited shooting range",
- "core.bonus.LIMITED_SHOOTING_RANGE.description" : "Cannot shoot targets beyond ${val} hexes away",
+ "core.bonus.LIMITED_SHOOTING_RANGE.description" : "Unable to target units farther than ${val} hexes",
"core.bonus.LIFE_DRAIN.name": "Drain life (${val}%)",
"core.bonus.LIFE_DRAIN.description": "Drains ${val}% of damage dealt",
"core.bonus.MANA_CHANNELING.name": "Magic Channel ${val}%",
- "core.bonus.MANA_CHANNELING.description": "Gives your hero mana spent by enemy",
+ "core.bonus.MANA_CHANNELING.description": "Gives your hero ${val}% of the mana spent by the enemy",
"core.bonus.MANA_DRAIN.name": "Mana Drain",
"core.bonus.MANA_DRAIN.description": "Drains ${val} mana every turn",
"core.bonus.MAGIC_MIRROR.name": "Magic Mirror (${val}%)",
- "core.bonus.MAGIC_MIRROR.description": "${val}% chance to redirects an offensive spell to enemy",
- "core.bonus.MAGIC_RESISTANCE.name": "Magic Resistance(${val}%)",
- "core.bonus.MAGIC_RESISTANCE.description": "${val}% chance to resist enemy spell",
+ "core.bonus.MAGIC_MIRROR.description": "Has a ${val}% chance to redirect an offensive spell to an enemy unit",
+ "core.bonus.MAGIC_RESISTANCE.name": "Magic Resistance (${val}%)",
+ "core.bonus.MAGIC_RESISTANCE.description": "Has a ${val}% chance to resist an enemy spell",
"core.bonus.MIND_IMMUNITY.name": "Mind Spell Immunity",
"core.bonus.MIND_IMMUNITY.description": "Immune to Mind-type spells",
"core.bonus.NO_DISTANCE_PENALTY.name": "No distance penalty",
- "core.bonus.NO_DISTANCE_PENALTY.description": "Full damage from any distance",
+ "core.bonus.NO_DISTANCE_PENALTY.description": "Does full damage at any distance",
"core.bonus.NO_MELEE_PENALTY.name": "No melee penalty",
"core.bonus.NO_MELEE_PENALTY.description": "Creature has no Melee Penalty",
"core.bonus.NO_MORALE.name": "Neutral Morale",
@@ -263,10 +262,6 @@
"core.bonus.REBIRTH.description": "${val}% of stack will rise after death",
"core.bonus.RETURN_AFTER_STRIKE.name": "Attack and Return",
"core.bonus.RETURN_AFTER_STRIKE.description": "Returns after melee attack",
- "core.bonus.SELF_LUCK.name": "Positive luck",
- "core.bonus.SELF_LUCK.description": "Always has Positive Luck",
- "core.bonus.SELF_MORALE.name": "Positive morale",
- "core.bonus.SELF_MORALE.description": "Always has Positive Morale",
"core.bonus.SHOOTER.name": "Ranged",
"core.bonus.SHOOTER.description": "Creature can shoot",
"core.bonus.SHOOTS_ALL_ADJACENT.name": "Shoot all around",
@@ -276,11 +271,11 @@
"core.bonus.SPELLCASTER.name": "Spellcaster",
"core.bonus.SPELLCASTER.description": "Can cast ${subtype.spell}",
"core.bonus.SPELL_AFTER_ATTACK.name": "Cast After Attack",
- "core.bonus.SPELL_AFTER_ATTACK.description": "${val}% to cast ${subtype.spell} after attack",
+ "core.bonus.SPELL_AFTER_ATTACK.description": "Has a ${val}% chance to cast ${subtype.spell} after it attacks",
"core.bonus.SPELL_BEFORE_ATTACK.name": "Cast Before Attack",
- "core.bonus.SPELL_BEFORE_ATTACK.description": "${val}% to cast ${subtype.spell} before attack",
+ "core.bonus.SPELL_BEFORE_ATTACK.description": "Has a ${val}% chance to cast ${subtype.spell} before it attacks",
"core.bonus.SPELL_DAMAGE_REDUCTION.name": "Spell Resistance",
- "core.bonus.SPELL_DAMAGE_REDUCTION.description": "Damage from spells reduced ${val}%.",
+ "core.bonus.SPELL_DAMAGE_REDUCTION.description": "Damage from spells reduced by ${val}%.",
"core.bonus.SPELL_IMMUNITY.name": "Spell immunity",
"core.bonus.SPELL_IMMUNITY.description": "Immune to ${subtype.spell}",
"core.bonus.SPELL_LIKE_ATTACK.name": "Spell-like attack",
@@ -288,7 +283,7 @@
"core.bonus.SPELL_RESISTANCE_AURA.name": "Aura of Resistance",
"core.bonus.SPELL_RESISTANCE_AURA.description": "Nearby stacks get ${val}% magic resistance",
"core.bonus.SUMMON_GUARDIANS.name": "Summon guardians",
- "core.bonus.SUMMON_GUARDIANS.description": "At battle start summons ${subtype.creature} (${val}%)",
+ "core.bonus.SUMMON_GUARDIANS.description": "At the start of battle summons ${subtype.creature} (${val}%)",
"core.bonus.SYNERGY_TARGET.name": "Synergizable",
"core.bonus.SYNERGY_TARGET.description": "This creature is vulnerable to synergy effect",
"core.bonus.TWO_HEX_ATTACK_BREATH.name": "Breath",
@@ -296,13 +291,13 @@
"core.bonus.THREE_HEADED_ATTACK.name": "Three-headed attack",
"core.bonus.THREE_HEADED_ATTACK.description": "Attacks three adjacent units",
"core.bonus.TRANSMUTATION.name": "Transmutation",
- "core.bonus.TRANSMUTATION.description": "${val}% chance to transform attacked unit to other type",
+ "core.bonus.TRANSMUTATION.description": "${val}% chance to transform attacked unit to a different type",
"core.bonus.UNDEAD.name": "Undead",
"core.bonus.UNDEAD.description": "Creature is Undead",
"core.bonus.UNLIMITED_RETALIATIONS.name": "Unlimited retaliations",
- "core.bonus.UNLIMITED_RETALIATIONS.description": "Retaliates any number of attacks",
+ "core.bonus.UNLIMITED_RETALIATIONS.description": "Can retaliate against an unlimited number of attacks",
"core.bonus.WATER_IMMUNITY.name": "Water immunity",
- "core.bonus.WATER_IMMUNITY.description": "Immune to all Water school spells",
+ "core.bonus.WATER_IMMUNITY.description": "Immune to all spells from the school of Water magic",
"core.bonus.WIDE_BREATH.name": "Wide breath",
"core.bonus.WIDE_BREATH.description": "Wide breath attack (multiple hexes)"
}
diff --git a/Mods/vcmi/config/vcmi/german.json b/Mods/vcmi/config/vcmi/german.json
index 9c53ac960..c11bd019b 100644
--- a/Mods/vcmi/config/vcmi/german.json
+++ b/Mods/vcmi/config/vcmi/german.json
@@ -47,6 +47,8 @@
"vcmi.systemOptions.framerateButton.hover" : "FPS anzeigen",
"vcmi.systemOptions.framerateButton.help" : "{FPS anzeigen}\n\n Schaltet die Sichtbarkeit des Zählers für die Bilder pro Sekunde in der Ecke des Spielfensters um.",
+ "vcmi.adventureOptions.infoBarPick.hover" : "Meldungen im Infobereich anzeigen",
+ "vcmi.adventureOptions.infoBarPick.help" : "{Meldungen im Infobereich anzeigen}\n\nWann immer möglich, werden Spielnachrichten von besuchten Kartenobjekten in der Infoleiste angezeigt, anstatt als Popup-Fenster zu erscheinen",
"vcmi.adventureOptions.numericQuantities.hover" : "Numerische Kreaturenmengen",
"vcmi.adventureOptions.numericQuantities.help" : "{Numerische Kreaturenmengen}\n\n Zeigt die ungefähre Menge der feindlichen Kreaturen im numerischen Format A-B an.",
"vcmi.adventureOptions.forceMovementInfo.hover" : "Bewegungskosten immer anzeigen",
@@ -79,6 +81,19 @@
"vcmi.battleOptions.animationsSpeed6.help": "Setzt die Animationsgeschwindigkeit auf sofort",
"vcmi.battleOptions.skipBattleIntroMusic.hover": "Intro-Musik überspringen",
"vcmi.battleOptions.skipBattleIntroMusic.help": "{Intro-Musik überspringen}\n\n Überspringe die kurze Musik, die zu Beginn eines jeden Kampfes gespielt wird, bevor die Action beginnt. Kann auch durch Drücken der ESC-Taste übersprungen werden.",
+
+ "vcmi.battleWindow.pressKeyToSkipIntro" : "Beliebige Taste drücken, um das Kampf-Intro zu überspringen",
+
+ "vcmi.battleWindow.damageEstimation.melee" : "Angriff auf %CREATURE (%DAMAGE).",
+ "vcmi.battleWindow.damageEstimation.meleeKills" : "Angriff auf %CREATURE (%DAMAGE, %KILLS).",
+ "vcmi.battleWindow.damageEstimation.ranged" : "Schuss auf %CREATURE (%SHOTS, %DAMAGE).",
+ "vcmi.battleWindow.damageEstimation.rangedKills" : "Schuss auf %CREATURE (%SHOTS, %DAMAGE, %KILLS).",
+ "vcmi.battleWindow.damageEstimation.shots" : "%d Schüsse verbleibend",
+ "vcmi.battleWindow.damageEstimation.shots.1" : "%d Schüsse verbleibend",
+ "vcmi.battleWindow.damageEstimation.damage" : "%d Schaden",
+ "vcmi.battleWindow.damageEstimation.damage.1" : "%d Schaden",
+ "vcmi.battleWindow.damageEstimation.kills" : "%d werden verenden",
+ "vcmi.battleWindow.damageEstimation.kills.1" : "%d werden verenden",
"vcmi.otherOptions.availableCreaturesAsDwellingLabel.hover" : "Verfügbare Kreaturen anzeigen",
"vcmi.otherOptions.availableCreaturesAsDwellingLabel.help" : "{Verfügbare Kreaturen anzeigen}\n\n Zeigt in der Stadtübersicht (linke untere Ecke) die zum Kauf verfügbaren Kreaturen anstelle ihres Wachstums an.",
@@ -128,17 +143,17 @@
// few strings from WoG used by vcmi
"vcmi.stackExperience.description" : "» D e t a i l s z u r S t a p e l e r f a h r u n g «\n\nKreatur-Typ ................... : %s\nErfahrungsrang ................. : %s (%i)\nErfahrungspunkte ............... : %i\nErfahrungspunkte für den nächsten Rang .. : %i\nMaximale Erfahrung pro Kampf ... : %i%% (%i)\nAnzahl der Kreaturen im Stapel .... : %i\nMaximale Anzahl neuer Rekruten\n ohne Verlust von aktuellem Rang .... : %i\nErfahrungs-Multiplikator ........... : %.2f\nUpgrade-Multiplikator .............. : %.2f\nErfahrung nach Rang 10 ........ : %i\nMaximale Anzahl der neuen Rekruten, die bei\n Rang 10 bei maximaler Erfahrung übrig sind : %i",
- "vcmi.stackExperience.rank.1" : "Grundlagen",
- "vcmi.stackExperience.rank.2" : "Neuling",
- "vcmi.stackExperience.rank.3" : "Ausgebildet",
- "vcmi.stackExperience.rank.4" : "Kompetent",
- "vcmi.stackExperience.rank.5" : "Bewährt",
- "vcmi.stackExperience.rank.6" : "Veteran",
- "vcmi.stackExperience.rank.7" : "Gekonnt",
- "vcmi.stackExperience.rank.8" : "Experte",
- "vcmi.stackExperience.rank.9" : "Elite",
- "vcmi.stackExperience.rank.10" : "Meister",
- "vcmi.stackExperience.rank.11" : "Ass",
+ "vcmi.stackExperience.rank.0" : "Grundlagen",
+ "vcmi.stackExperience.rank.1" : "Neuling",
+ "vcmi.stackExperience.rank.2" : "Ausgebildet",
+ "vcmi.stackExperience.rank.3" : "Kompetent",
+ "vcmi.stackExperience.rank.4" : "Bewährt",
+ "vcmi.stackExperience.rank.5" : "Veteran",
+ "vcmi.stackExperience.rank.6" : "Gekonnt",
+ "vcmi.stackExperience.rank.7" : "Experte",
+ "vcmi.stackExperience.rank.8" : "Elite",
+ "vcmi.stackExperience.rank.9" : "Meister",
+ "vcmi.stackExperience.rank.10" : "Ass",
"core.bonus.ADDITIONAL_ATTACK.name": "Doppelschlag",
"core.bonus.ADDITIONAL_ATTACK.description": "Greift zweimal an",
@@ -210,12 +225,8 @@
"core.bonus.HP_REGENERATION.description": "Heilt ${SHval} Trefferpunkte jede Runde",
"core.bonus.JOUSTING.name": "Champion Charge",
"core.bonus.JOUSTING.description": "+${val}% Schaden pro zurückgelegtem Feld",
- "core.bonus.KING1.name": "König 1",
- "core.bonus.KING1.description": "Anfällig für grundlegende SLAYER",
- "core.bonus.KING2.name": "König 2",
- "core.bonus.KING2.description": "Anfällig für erweiterte SLAYER",
- "core.bonus.KING3.name": "König3",
- "core.bonus.KING3.description":"Anfällig für Experten-SLAYER",
+ "core.bonus.KING.name": "König",
+ "core.bonus.KING.description": "Anfällig für SLAYER Level ${val} oder höher",
"core.bonus.LEVEL_SPELL_IMMUNITY.name": "Zauberimmunität 1-${val}",
"core.bonus.LEVEL_SPELL_IMMUNITY.description": "Immun gegen Zaubersprüche der Stufen 1-${val}",
"core.bonus.LIMITED_SHOOTING_RANGE.name" : "Begrenzte Schussweite",
@@ -252,10 +263,6 @@
"core.bonus.REBIRTH.description": "${val}% des Stacks wird nach dem Tod auferstehen",
"core.bonus.RETURN_AFTER_STRIKE.name": "Angriff und Rückkehr",
"core.bonus.RETURN_AFTER_STRIKE.description": "Kehrt nach Nahkampfangriff zurück",
- "core.bonus.SELF_LUCK.name": "Positives Glück",
- "core.bonus.SELF_LUCK.description": "Hat immer positives Glück",
- "core.bonus.SELF_MORALE.name": "Positive Moral",
- "core.bonus.SELF_MORALE.description": "Hat immer positive Moral",
"core.bonus.SHOOTER.name": "Fernkämpfer",
"core.bonus.SHOOTER.description": "Kreatur kann schießen",
"core.bonus.SHOOTS_ALL_ADJACENT.name": "Schießt rundherum",
diff --git a/Mods/vcmi/config/vcmi/polish.json b/Mods/vcmi/config/vcmi/polish.json
index 68affb700..eb21ecf03 100644
--- a/Mods/vcmi/config/vcmi/polish.json
+++ b/Mods/vcmi/config/vcmi/polish.json
@@ -249,10 +249,6 @@
"core.bonus.REBIRTH.description": "${val}% stworzeń powstanie po śmierci",
"core.bonus.RETURN_AFTER_STRIKE.name": "Atak i Powrót",
"core.bonus.RETURN_AFTER_STRIKE.description": "Wraca po ataku wręcz",
- "core.bonus.SELF_LUCK.name": "Pozytywne szczęście",
- "core.bonus.SELF_LUCK.description": "Zawsze posiada pozytywne szczęście",
- "core.bonus.SELF_MORALE.name": "Pozytywne Morale",
- "core.bonus.SELF_MORALE.description": "Zawsze posiada pozytywne morale",
"core.bonus.SHOOTER.name": "Dystansowy",
"core.bonus.SHOOTER.description": "Stworzenie może strzelać",
"core.bonus.SHOOTS_ALL_ADJACENT.name": "Ostrzeliwuje wszystko dookoła",
diff --git a/Mods/vcmi/config/vcmi/russian.json b/Mods/vcmi/config/vcmi/russian.json
index c6bd0cae7..f98c7880d 100644
--- a/Mods/vcmi/config/vcmi/russian.json
+++ b/Mods/vcmi/config/vcmi/russian.json
@@ -145,17 +145,17 @@
// few strings from WoG used by vcmi
"vcmi.stackExperience.description" : "» О п ы т с у щ е с т в «\n\nТип существа ................... : %s\nРанг опыта ................. : %s (%i)\nОчки опыта ............... : %i\nДо следующего .. : %i\nМаксимум за битву ... : %i%% (%i)\nЧисло в отряде .... : %i\nМаксимум новичков\n без потери ранга .... : %i\nМножитель опыта ........... : %.2f\nМножитель улучшения .......... : %.2f\nОпыт после 10 ранга ........ : %i\nМаксимум новичков для сохранения\n ранга 10 при максимальном опыте : %i",
- "vcmi.stackExperience.rank.1" : "Рекрут",
- "vcmi.stackExperience.rank.2" : "Новичок",
- "vcmi.stackExperience.rank.3" : "Тренирован",
- "vcmi.stackExperience.rank.4" : "Знающий",
- "vcmi.stackExperience.rank.5" : "Подтвержденный",
- "vcmi.stackExperience.rank.6" : "Ветеран",
- "vcmi.stackExperience.rank.7" : "Адепт",
- "vcmi.stackExperience.rank.8" : "Эксперт",
- "vcmi.stackExperience.rank.9" : "Элита",
- "vcmi.stackExperience.rank.10" : "Мастер",
- "vcmi.stackExperience.rank.11" : "Ас",
+ "vcmi.stackExperience.rank.0" : "Рекрут",
+ "vcmi.stackExperience.rank.1" : "Новичок",
+ "vcmi.stackExperience.rank.2" : "Тренирован",
+ "vcmi.stackExperience.rank.3" : "Знающий",
+ "vcmi.stackExperience.rank.4" : "Подтвержденный",
+ "vcmi.stackExperience.rank.5" : "Ветеран",
+ "vcmi.stackExperience.rank.6" : "Адепт",
+ "vcmi.stackExperience.rank.7" : "Эксперт",
+ "vcmi.stackExperience.rank.8" : "Элита",
+ "vcmi.stackExperience.rank.9" : "Мастер",
+ "vcmi.stackExperience.rank.10" : "Ас",
"core.bonus.ADDITIONAL_ATTACK.name": "Двойной удар",
"core.bonus.ADDITIONAL_ATTACK.description": "Бьет дважды",
@@ -265,10 +265,6 @@
"core.bonus.REBIRTH.description": "${val}% отряда оживет после его гибели",
"core.bonus.RETURN_AFTER_STRIKE.name": "Атака с возвратом",
"core.bonus.RETURN_AFTER_STRIKE.description": "После атаки возвращается на начальный гекс",
- "core.bonus.SELF_LUCK.name": "Удачливый",
- "core.bonus.SELF_LUCK.description": "Удача всегда позитивна",
- "core.bonus.SELF_MORALE.name": "Воодушевленный",
- "core.bonus.SELF_MORALE.description": "Боевой дух всегда позитивен",
"core.bonus.SHOOTER.name": "Стрелок",
"core.bonus.SHOOTER.description": "Совершает атаки в дальнем бою",
"core.bonus.SHOOTS_ALL_ADJACENT.name": "Стреляет по области",
diff --git a/Mods/vcmi/config/vcmi/spanish.json b/Mods/vcmi/config/vcmi/spanish.json
index 312a90254..7da50f97e 100644
--- a/Mods/vcmi/config/vcmi/spanish.json
+++ b/Mods/vcmi/config/vcmi/spanish.json
@@ -131,17 +131,17 @@
// few strings from WoG used by vcmi
"vcmi.stackExperience.description" : "» D e t a l l e s d e E x p e r i e n c i a d e l G r u p o «\n\nTipo de Criatura ................ : %s\nRango de Experiencia ............ : %s (%i)\nPuntos de Experiencia ............ : %i\nPuntos de Experiencia para el\nSiguiente Rango ............... : %i\nExperiencia Máxima por Batalla .. : %i%% (%i)\nNúmero de Criaturas en el grupo .. : %i\nMáximo de Nuevos Reclutas sin\nPerder el Rango Actual ......... : %i\nMultiplicador de Experiencia .... : %.2f\nMultiplicador de Actualización .. : %.2f\nExperiencia después del Rango 10 : %i\nMáximo de Nuevos Reclutas para\nMantener el Rango 10 si\nEstá en la Experiencia Máxima : %i",
- "vcmi.stackExperience.rank.1" : "Básico",
- "vcmi.stackExperience.rank.2" : "Novato",
- "vcmi.stackExperience.rank.3" : "Entrenado",
- "vcmi.stackExperience.rank.4" : "Hábil",
- "vcmi.stackExperience.rank.5" : "Probado",
- "vcmi.stackExperience.rank.6" : "Veterano",
- "vcmi.stackExperience.rank.7" : "Experto",
- "vcmi.stackExperience.rank.8" : "Experto Superior",
- "vcmi.stackExperience.rank.9" : "Élite",
- "vcmi.stackExperience.rank.10" : "Maestro",
- "vcmi.stackExperience.rank.11" : "As",
+ "vcmi.stackExperience.rank.0" : "Básico",
+ "vcmi.stackExperience.rank.1" : "Novato",
+ "vcmi.stackExperience.rank.2" : "Entrenado",
+ "vcmi.stackExperience.rank.3" : "Hábil",
+ "vcmi.stackExperience.rank.4" : "Probado",
+ "vcmi.stackExperience.rank.5" : "Veterano",
+ "vcmi.stackExperience.rank.6" : "Experto",
+ "vcmi.stackExperience.rank.7" : "Experto Superior",
+ "vcmi.stackExperience.rank.8" : "Élite",
+ "vcmi.stackExperience.rank.9" : "Maestro",
+ "vcmi.stackExperience.rank.10" : "As",
"core.bonus.ADDITIONAL_ATTACK.name": "Doble Ataque",
"core.bonus.ADDITIONAL_ATTACK.description": "Ataca dos veces",
@@ -257,10 +257,6 @@
"core.bonus.REBIRTH.description": "El ${val}% del grupo resucitará después de la muerte",
"core.bonus.RETURN_AFTER_STRIKE.name": "Atacar y volver",
"core.bonus.RETURN_AFTER_STRIKE.description": "Regresa después de un ataque cuerpo a cuerpo",
- "core.bonus.SELF_LUCK.name": "Suerte positiva",
- "core.bonus.SELF_LUCK.description": "Siempre tiene suerte positiva",
- "core.bonus.SELF_MORALE.name": "Moral positiva",
- "core.bonus.SELF_MORALE.description": "Siempre tiene moral positiva",
"core.bonus.SHOOTER.name": "A distancia",
"core.bonus.SHOOTER.description": "La criatura puede disparar",
"core.bonus.SHOOTS_ALL_ADJACENT.name": "Dispara en todas direcciones",
diff --git a/Mods/vcmi/config/vcmi/ukrainian.json b/Mods/vcmi/config/vcmi/ukrainian.json
index 758bb53b8..e805423b7 100644
--- a/Mods/vcmi/config/vcmi/ukrainian.json
+++ b/Mods/vcmi/config/vcmi/ukrainian.json
@@ -249,10 +249,6 @@
"core.bonus.REBIRTH.description" : "${val}% загону відродиться після смерті",
"core.bonus.RETURN_AFTER_STRIKE.name" : "Атакує і повертається",
"core.bonus.RETURN_AFTER_STRIKE.description" : "Повертається після атаки ближнього бою",
- "core.bonus.SELF_LUCK.name" : "Позитивна удача",
- "core.bonus.SELF_LUCK.description" : "Завжди має позитивну удачу",
- "core.bonus.SELF_MORALE.name" : "Позитивний бойовий дух",
- "core.bonus.SELF_MORALE.description" : "Завжди має позитивний бойовий дух",
"core.bonus.SHOOTER.name" : "Стрілок",
"core.bonus.SHOOTER.description" : "Істота може стріляти",
"core.bonus.SHOOTS_ALL_ADJACENT.name" : "Стріляйте по площі",
@@ -295,15 +291,15 @@
"core.bonus.LIMITED_SHOOTING_RANGE.description" : "Не може стріляти по цілях на відстані більше ${val} гексів",
"vcmi.stackExperience.description" : "» S t a c k E x p e r i e n c e D e t a i l s «\n\nCreature Type ................... : %s\nExperience Rank ................. : %s (%i)\nExperience Points ............... : %i\nExperience Points to Next Rank .. : %i\nMaximum Experience per Battle ... : %i%% (%i)\nNumber of Creatures in stack .... : %i\nMaximum New Recruits\n without losing current Rank .... : %i\nExperience Multiplier ........... : %.2f\nUpgrade Multiplier .............. : %.2f\nExperience after Rank 10 ........ : %i\nMaximum New Recruits to remain at\n Rank 10 if at Maximum Experience : %i",
- "vcmi.stackExperience.rank.1" : "Початковий",
- "vcmi.stackExperience.rank.2" : "Новачок",
- "vcmi.stackExperience.rank.3" : "Підготовлений",
- "vcmi.stackExperience.rank.4" : "Досвідчений",
- "vcmi.stackExperience.rank.5" : "Випробуваний",
- "vcmi.stackExperience.rank.6" : "Ветеран",
- "vcmi.stackExperience.rank.7" : "Адепт",
- "vcmi.stackExperience.rank.8" : "Експерт",
- "vcmi.stackExperience.rank.9" : "Еліта",
- "vcmi.stackExperience.rank.10" : "Майстер",
- "vcmi.stackExperience.rank.11" : "Профі",
+ "vcmi.stackExperience.rank.0" : "Початковий",
+ "vcmi.stackExperience.rank.1" : "Новачок",
+ "vcmi.stackExperience.rank.2" : "Підготовлений",
+ "vcmi.stackExperience.rank.3" : "Досвідчений",
+ "vcmi.stackExperience.rank.4" : "Випробуваний",
+ "vcmi.stackExperience.rank.5" : "Ветеран",
+ "vcmi.stackExperience.rank.6" : "Адепт",
+ "vcmi.stackExperience.rank.7" : "Експерт",
+ "vcmi.stackExperience.rank.8" : "Еліта",
+ "vcmi.stackExperience.rank.9" : "Майстер",
+ "vcmi.stackExperience.rank.10" : "Профі",
}
diff --git a/Mods/vcmi/mod.json b/Mods/vcmi/mod.json
index be2734f86..e24f67a5c 100644
--- a/Mods/vcmi/mod.json
+++ b/Mods/vcmi/mod.json
@@ -16,7 +16,6 @@
"name" : "VCMI - grundlegende Dateien",
"description" : "Grundlegende Dateien, die für die korrekte Ausführung von VCMI erforderlich sind",
"author" : "VCMI-Team",
- "modType" : "Grafik",
"skipValidation" : true,
"translations" : [
@@ -28,7 +27,6 @@
"name" : "Podstawowe pliki VCMI",
"description" : "Dodatkowe pliki wymagane do prawidłowego działania VCMI",
"author" : "Zespół VCMI",
- "modType" : "Graficzny",
"skipValidation" : true,
"translations" : [
@@ -40,7 +38,6 @@
"name" : "Ключевые файлы VCMI",
"description" : "Файлы, необходимые для полноценной работы VCMI",
"author" : "Команда VCMI",
- "modType" : "Графический",
"skipValidation" : true,
"translations" : [
@@ -52,7 +49,6 @@
"name" : "VCMI - ключові файли",
"description" : "Ключові файли необхідні для повноцінної роботи VCMI",
"author" : "Команда VCMI",
- "modType" : "Графіка",
"translations" : [
"config/vcmi/ukrainian.json"
@@ -63,7 +59,6 @@
"name" : "VCMI - ficheros necesarios",
"description" : "Ficheros necesarios para ejecutar VCMI correctamente",
"author" : "Abel Rivas",
- "modType" : "Gráfico",
"skipValidation" : true,
"translations" : [
diff --git a/client/CMusicHandler.cpp b/client/CMusicHandler.cpp
index 4acc87d98..f15ad9c3f 100644
--- a/client/CMusicHandler.cpp
+++ b/client/CMusicHandler.cpp
@@ -142,11 +142,13 @@ Mix_Chunk *CSoundHandler::GetSoundChunk(std::string &sound, bool cache)
int CSoundHandler::ambientDistToVolume(int distance) const
{
- if(distance >= ambientConfig["distances"].Vector().size())
+ const auto & distancesVector = ambientConfig["distances"].Vector();
+
+ if(distance >= distancesVector.size())
return 0;
- int volume = static_cast(ambientConfig["distances"].Vector()[distance].Integer());
- return volume * (int)ambientConfig["volume"].Integer() * getVolume() / 10000;
+ int volume = static_cast(distancesVector[distance].Integer());
+ return volume * (int)ambientConfig["volume"].Integer() / 100;
}
void CSoundHandler::ambientStopSound(std::string soundId)
@@ -211,7 +213,20 @@ void CSoundHandler::setVolume(ui32 percent)
CAudioBase::setVolume(percent);
if (initialized)
+ {
setChannelVolume(-1, volume);
+
+ for (auto const & channel : channelVolumes)
+ updateChannelVolume(channel.first);
+ }
+}
+
+void CSoundHandler::updateChannelVolume(int channel)
+{
+ if (channelVolumes.count(channel))
+ setChannelVolume(channel, getVolume() * channelVolumes[channel] / 100);
+ else
+ setChannelVolume(channel, getVolume());
}
// Sets the sound volume, from 0 (mute) to 100
@@ -258,29 +273,40 @@ void CSoundHandler::ambientUpdateChannels(std::map soundsArg)
std::vector stoppedSounds;
for(auto & pair : ambientChannels)
{
- if(!vstd::contains(soundsArg, pair.first))
+ const std::string & soundId = pair.first;
+ const int channel = pair.second;
+
+ if(!vstd::contains(soundsArg, soundId))
{
- ambientStopSound(pair.first);
- stoppedSounds.push_back(pair.first);
+ ambientStopSound(soundId);
+ stoppedSounds.push_back(soundId);
}
else
{
- int volume = ambientDistToVolume(soundsArg[pair.first]);
- CCS->soundh->setChannelVolume(pair.second, volume);
+ int volume = ambientDistToVolume(soundsArg[soundId]);
+ channelVolumes[channel] = volume;
+ updateChannelVolume(channel);
}
}
for(auto soundId : stoppedSounds)
+ {
+ channelVolumes.erase(ambientChannels[soundId]);
ambientChannels.erase(soundId);
+ }
for(auto & pair : soundsArg)
{
- if(!vstd::contains(ambientChannels, pair.first))
- {
- int channel = CCS->soundh->playSound(pair.first, -1);
- int volume = ambientDistToVolume(pair.second);
+ const std::string & soundId = pair.first;
+ const int distance = pair.second;
- CCS->soundh->setChannelVolume(channel, volume);
- CCS->soundh->ambientChannels.insert(std::make_pair(pair.first, channel));
+ if(!vstd::contains(ambientChannels, soundId))
+ {
+ int channel = playSound(soundId, -1);
+ int volume = ambientDistToVolume(distance);
+ channelVolumes[channel] = volume;
+
+ updateChannelVolume(channel);
+ ambientChannels[soundId] = channel;
}
}
}
@@ -293,6 +319,7 @@ void CSoundHandler::ambientStopAllChannels()
{
ambientStopSound(ch.first);
}
+ channelVolumes.clear();
ambientChannels.clear();
}
diff --git a/client/CMusicHandler.h b/client/CMusicHandler.h
index 5d3319052..9c909c347 100644
--- a/client/CMusicHandler.h
+++ b/client/CMusicHandler.h
@@ -51,9 +51,12 @@ private:
int ambientDistToVolume(int distance) const;
void ambientStopSound(std::string soundId);
+ void updateChannelVolume(int channel);
const JsonNode ambientConfig;
+
std::map ambientChannels;
+ std::map channelVolumes;
public:
CSoundHandler();
diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp
index 6927611f0..91e6516fe 100644
--- a/client/CPlayerInterface.cpp
+++ b/client/CPlayerInterface.cpp
@@ -2033,7 +2033,7 @@ bool CPlayerInterface::capturedAllEvents()
return true;
}
- bool needToLockAdventureMap = adventureInt->active && CGI->mh->hasOngoingAnimations();
+ bool needToLockAdventureMap = adventureInt && adventureInt->active && CGI->mh->hasOngoingAnimations();
if (ignoreEvents || needToLockAdventureMap)
{
diff --git a/client/battle/BattleActionsController.cpp b/client/battle/BattleActionsController.cpp
index 6d86edb31..2f48f2492 100644
--- a/client/battle/BattleActionsController.cpp
+++ b/client/battle/BattleActionsController.cpp
@@ -119,7 +119,10 @@ BattleActionsController::BattleActionsController(BattleInterface & owner):
void BattleActionsController::endCastingSpell()
{
if(heroSpellToCast)
+ {
heroSpellToCast.reset();
+ owner.windowObject->blockUI(false);
+ }
if(owner.stacksController->getActiveStack())
possibleActions = getPossibleActionsForStack(owner.stacksController->getActiveStack()); //restore actions after they were cleared
@@ -287,6 +290,8 @@ void BattleActionsController::castThisSpell(SpellID spellID)
possibleActions.push_back (spellSelMode); //only this one action can be performed at the moment
GH.fakeMouseMove();//update cursor
}
+
+ owner.windowObject->blockUI(true);
}
const CSpell * BattleActionsController::getHeroSpellToCast( ) const
@@ -520,6 +525,8 @@ bool BattleActionsController::actionIsLegal(PossiblePlayerBattleAction action, B
switch (action.get())
{
case PossiblePlayerBattleAction::CHOOSE_TACTICS_STACK:
+ return (targetStack && targetStackOwned && targetStack->Speed() > 0);
+
case PossiblePlayerBattleAction::CREATURE_INFO:
return (targetStack && targetStackOwned);
@@ -689,14 +696,14 @@ void BattleActionsController::actionRealize(PossiblePlayerBattleAction action, B
if (action.spell() == SpellID::SACRIFICE)
{
heroSpellToCast->aimToHex(targetHex);
- possibleActions.push_back(PossiblePlayerBattleAction::SACRIFICE);
+ possibleActions.push_back({PossiblePlayerBattleAction::SACRIFICE, action.spell()});
owner.stacksController->setSelectedStack(targetStack);
return;
}
if (action.spell() == SpellID::TELEPORT)
{
heroSpellToCast->aimToUnit(targetStack);
- possibleActions.push_back(PossiblePlayerBattleAction::TELEPORT);
+ possibleActions.push_back({PossiblePlayerBattleAction::TELEPORT, action.spell()});
owner.stacksController->setSelectedStack(targetStack);
return;
}
diff --git a/client/battle/BattleAnimationClasses.cpp b/client/battle/BattleAnimationClasses.cpp
index 30f1eb2b7..96ffffbd4 100644
--- a/client/battle/BattleAnimationClasses.cpp
+++ b/client/battle/BattleAnimationClasses.cpp
@@ -756,7 +756,15 @@ void ShootingAnimation::createProjectile(const Point & from, const Point & dest)
uint32_t ShootingAnimation::getAttackClimaxFrame() const
{
const CCreature *shooterInfo = getCreature();
- return shooterInfo->animation.attackClimaxFrame;
+
+ uint32_t maxFrames = stackAnimation(attackingStack)->framesInGroup(getGroup());
+ uint32_t climaxFrame = shooterInfo->animation.attackClimaxFrame;
+ uint32_t selectedFrame = vstd::clamp(shooterInfo->animation.attackClimaxFrame, 1, maxFrames);
+
+ if (climaxFrame != selectedFrame)
+ logGlobal->warn("Shooter %s has ranged attack climax frame set to %d, but only %d available!", shooterInfo->getNamePluralTranslated(), climaxFrame, maxFrames);
+
+ return selectedFrame - 1; // H3 counts frames from 1
}
ECreatureAnimType ShootingAnimation::getUpwardsGroup() const
diff --git a/client/battle/BattleFieldController.cpp b/client/battle/BattleFieldController.cpp
index 369fc78ac..c11d82a93 100644
--- a/client/battle/BattleFieldController.cpp
+++ b/client/battle/BattleFieldController.cpp
@@ -35,8 +35,6 @@
#include "../../lib/CStack.h"
#include "../../lib/spells/ISpellMechanics.h"
-#include
-
BattleFieldController::BattleFieldController(BattleInterface & owner):
owner(owner)
{
@@ -67,10 +65,7 @@ BattleFieldController::BattleFieldController(BattleInterface & owner):
backgroundWithHexes = std::make_unique
";
QString incompatibleString = redPrefix + tr("Mod is incompatible") + "";
QString supportedVersions = redPrefix + "%2 %3 %4";
@@ -242,9 +262,7 @@ QString CModListView::genModInfoText(CModEntry & mod)
result += urlTemplate.arg(tr("Contact")).arg(mod.getValue("contact").toString()).arg(mod.getValue("contact").toString());
//compatibility info
- if(mod.isCompatible())
- result += compatibleString.arg(tr("Compatibility"));
- else
+ if(!mod.isCompatible())
{
auto compatibilityInfo = mod.getValue("compatibility").toMap();
auto minStr = compatibilityInfo.value("min").toString();
@@ -267,9 +285,34 @@ QString CModListView::genModInfoText(CModEntry & mod)
}
}
- result += replaceIfNotEmpty(mod.getValue("depends"), lineTemplate.arg(tr("Required mods")));
- result += replaceIfNotEmpty(mod.getValue("conflicts"), lineTemplate.arg(tr("Conflicting mods")));
- result += replaceIfNotEmpty(mod.getValue("description"), textTemplate.arg(tr("Description")));
+ QStringList supportedLanguages;
+ QVariant baseLanguageVariant = mod.getBaseValue("language");
+ QString baseLanguageID = baseLanguageVariant.isValid() ? baseLanguageVariant.toString() : "english";
+
+ bool needToShowSupportedLanguages = false;
+
+ for(const auto & language : Languages::getLanguageList())
+ {
+ if (!language.hasTranslation)
+ continue;
+
+ QString languageID = QString::fromStdString(language.identifier);
+
+ if (languageID != baseLanguageID && !mod.getValue(languageID).isValid())
+ continue;
+
+ if (languageID != baseLanguageID)
+ needToShowSupportedLanguages = true;
+
+ supportedLanguages += QApplication::translate("Language", language.nameEnglish.c_str());
+ }
+
+ if(needToShowSupportedLanguages)
+ result += replaceIfNotEmpty(supportedLanguages, lineTemplate.arg(tr("Languages")));
+
+ result += replaceIfNotEmpty(getModNames(mod.getValue("depends").toStringList()), lineTemplate.arg(tr("Required mods")));
+ result += replaceIfNotEmpty(getModNames(mod.getValue("conflicts").toStringList()), lineTemplate.arg(tr("Conflicting mods")));
+ result += replaceIfNotEmpty(getModNames(mod.getValue("description").toStringList()), textTemplate.arg(tr("Description")));
result += ""; // to get some empty space
@@ -281,12 +324,12 @@ QString CModListView::genModInfoText(CModEntry & mod)
QString notes;
- notes += replaceIfNotEmpty(findInvalidDependencies(mod.getName()), listTemplate.arg(unknownDeps));
- notes += replaceIfNotEmpty(findBlockingMods(mod.getName()), listTemplate.arg(blockingMods));
+ notes += replaceIfNotEmpty(getModNames(findInvalidDependencies(mod.getName())), listTemplate.arg(unknownDeps));
+ notes += replaceIfNotEmpty(getModNames(findBlockingMods(mod.getName())), listTemplate.arg(blockingMods));
if(mod.isEnabled())
- notes += replaceIfNotEmpty(findDependentMods(mod.getName(), true), listTemplate.arg(hasActiveDependentMods));
+ notes += replaceIfNotEmpty(getModNames(findDependentMods(mod.getName(), true)), listTemplate.arg(hasActiveDependentMods));
if(mod.isInstalled())
- notes += replaceIfNotEmpty(findDependentMods(mod.getName(), false), listTemplate.arg(hasDependentMods));
+ notes += replaceIfNotEmpty(getModNames(findDependentMods(mod.getName(), false)), listTemplate.arg(hasDependentMods));
if(mod.getName().contains('.'))
notes += noteTemplate.arg(thisIsSubmod);
@@ -829,10 +872,10 @@ void CModListView::doInstallMod(const QString & modName)
}
}
-bool CModListView::isModInstalled(const QString & modName)
+bool CModListView::isModAvailable(const QString & modName)
{
auto mod = modModel->getMod(modName);
- return mod.isInstalled();
+ return mod.isAvailable();
}
bool CModListView::isModEnabled(const QString & modName)
diff --git a/launcher/modManager/cmodlistview_moc.h b/launcher/modManager/cmodlistview_moc.h
index 7b7566339..7b3b0f3dc 100644
--- a/launcher/modManager/cmodlistview_moc.h
+++ b/launcher/modManager/cmodlistview_moc.h
@@ -47,6 +47,9 @@ class CModListView : public QWidget
void checkManagerErrors();
+ /// replace mod ID's with proper human-readable mod names
+ QStringList getModNames(QStringList input);
+
// find mods unknown to mod list (not present in repo and not installed)
QStringList findInvalidDependencies(QString mod);
// find mods that block enabling of this mod: conflicting with this mod or one of required mods
@@ -86,8 +89,8 @@ public:
/// install mod by name
void doInstallMod(const QString & modName);
- /// returns true if mod is currently installed
- bool isModInstalled(const QString & modName);
+ /// returns true if mod is available in repository and can be installed
+ bool isModAvailable(const QString & modName);
/// finds translation mod for specified languages. Returns empty string on error
QString getTranslationModName(const QString & language);
diff --git a/launcher/settingsView/csettingsview_moc.cpp b/launcher/settingsView/csettingsview_moc.cpp
index 3f464f688..b304f3ea8 100644
--- a/launcher/settingsView/csettingsview_moc.cpp
+++ b/launcher/settingsView/csettingsview_moc.cpp
@@ -375,7 +375,7 @@ void CSettingsView::loadTranslation()
if (!translationExists)
return;
- bool translationInstalled = mainWindow->getModView()->isModInstalled(modName);
+ bool translationAvailable = mainWindow->getModView()->isModAvailable(modName);
bool translationEnabled = mainWindow->getModView()->isModEnabled(modName);
ui->pushButtonTranslation->setVisible(!translationEnabled);
@@ -385,13 +385,13 @@ void CSettingsView::loadTranslation()
ui->labelTranslationStatus->setText(tr("Active"));
}
- if (translationInstalled && !translationEnabled)
+ if (!translationEnabled && !translationAvailable)
{
ui->labelTranslationStatus->setText(tr("Disabled"));
ui->pushButtonTranslation->setText(tr("Enable"));
}
- if (!translationInstalled)
+ if (translationAvailable)
{
ui->labelTranslationStatus->setText(tr("Not Installed"));
ui->pushButtonTranslation->setText(tr("Install"));
@@ -413,15 +413,15 @@ void CSettingsView::on_pushButtonTranslation_clicked()
if (modName.isEmpty())
return;
- if (mainWindow->getModView()->isModInstalled(modName))
- {
- mainWindow->getModView()->enableModByName(modName);
- }
- else
+ if (mainWindow->getModView()->isModAvailable(modName))
{
mainWindow->switchToModsTab();
mainWindow->getModView()->doInstallMod(modName);
}
+ else
+ {
+ mainWindow->getModView()->enableModByName(modName);
+ }
}
void CSettingsView::on_comboBoxLanguageBase_currentIndexChanged(int index)
diff --git a/launcher/translation/english.ts b/launcher/translation/english.ts
index d3bd72292..9de39fd25 100644
--- a/launcher/translation/english.ts
+++ b/launcher/translation/english.ts
@@ -4,17 +4,111 @@
CModListModel
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
@@ -63,7 +157,7 @@
-
+
@@ -113,114 +207,113 @@
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+
-
-
+
+
-
+
-
+
-
+
+
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
-
-
-
-
+
@@ -449,32 +542,32 @@
-
+
-
+
-
+
-
+
-
+
-
+
@@ -484,84 +577,135 @@
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/launcher/translation/german.ts b/launcher/translation/german.ts
index ad4592135..32f2109a2 100644
--- a/launcher/translation/german.ts
+++ b/launcher/translation/german.ts
@@ -4,17 +4,111 @@
CModListModel
-
+
+
+ Übersetzung
+
+
+
+
+ Stadt
+
+
+
+
+ Test
+
+
+
+
+ Templates
+
+
+
+
+ Zaubersprüche
+
+
+
+
+ Musik
+
+
+
+
+ Sounds
+
+
+
+
+ Fertigkeiten
+
+
+
+
+
+ Andere
+
+
+
+
+ Objekte
+
+
+
+
+
+ Mechaniken
+
+
+
+
+
+ Schnittstelle
+
+
+
+
+ Helden
+
+
+
+
+
+ Grafisches
+
+
+
+
+ Erweiterung
+
+
+
+
+ Kreaturen
+
+
+
+
+ Artefakte
+
+
+
+
+ KI
+
+
+ Name
-
+ Typ
-
+ Version
@@ -63,7 +157,7 @@
-
+ Beschreibung
@@ -113,114 +207,113 @@
Abbrechen
-
+ Mod-Name
-
+ Installierte Version
-
+ Letzte Version
-
+ Downloadgröße
-
+ Autoren
-
+ Lizenz
-
+
-
+ Kontakt
-
-
+ Kompatibilität
-
-
+
+ Benötigte VCMI Version
-
+ Unterstützte VCMI Version
-
+ Unterstützte VCMI Versionen
-
+
+
+ Sprachen
+
+
+ Benötigte Mods
-
+ Mods mit Konflikt
-
+ Diese Mod kann nicht installiert oder aktiviert werden, da die folgenden Abhängigkeiten nicht vorhanden sind
-
+ Diese Mod kann nicht aktiviert werden, da folgende Mods nicht mit dieser Mod kompatibel sind
-
+ Diese Mod kann nicht deaktiviert werden, da sie zum Ausführen der folgenden Mods erforderlich ist
-
+ Diese Mod kann nicht deinstalliert oder aktualisiert werden, da sie für die folgenden Mods erforderlich ist
-
+ Dies ist eine Submod und kann nicht separat von der Hauptmod installiert oder deinstalliert werden
-
+ Anmerkungen
-
+ Screenshot %1
-
-
- Mod ist kompatibel
-
-
-
+ Mod ist inkompatibel
@@ -242,7 +335,7 @@
-
+ Abenteuerkarte KI
@@ -261,18 +354,18 @@
-
+ Künstliche Intelligenz
-
+ Mod-Repositorien
-
+ Jetzt aktualisieren
@@ -285,37 +378,37 @@
-
+ Zeiger
-
+ Sprache der Heroes III Daten
-
+ Standard
-
+ Hardware
-
+ Software
-
+ Heroes III Übersetzung
-
+ Beim Start prüfen
@@ -408,27 +501,27 @@
- Aktiv
+ Aktiv
-
+ Deaktiviert
- Aktivieren
+ Aktivieren
-
+ Nicht installiert
- Installieren
+ Installieren
@@ -436,134 +529,191 @@
-
+ Sprache
-
+ Heroes III Daten
-
+ Mods Voreinstellung
-
+
-
+ Ihre Heroes III-Datendateien wurden erfolgreich gefunden.
-
+
-
+ Optional können Sie jetzt oder zu einem beliebigen späteren Zeitpunkt zusätzliche Mods installieren:
-
+
-
+ Installieren Sie Unterstützung für das Spielen von Heroes III in anderen Auflösungen als 800x600.
-
+
-
+ Installieren Sie die kompatible Version des Addons Horn of the Abyss: eine von Fans entwickelte Heroes III-Erweiterung, portiert vom VCMI-Team
-
+
-
+ Installieren Sie die kompatible Version des Addons "In The Wake of Gods": von Fans entwickelte Heroes III-Erweiterung
-
+
-
+ Fertigstellen
-
+ Schritt %v von %m
-
+
-
+ Wählen Sie Ihre Sprache
-
-
+
+
+ VCMI auf Github
+
+
+
+
+ VCMI auf Slack
+
+
+
+
+ VCMI auf Discord
+
+
+
+
+ Haben Sie eine Frage? Einen Fehler gefunden? Möchten Sie helfen? Machen Sie mit:
+
+
+
+
+ Vielen Dank für die Installation von VCMI.
+
+Es sind noch ein paar Schritte notwendig, bevor Sie mit dem Spielen beginnen können.
+
+Denken Sie daran, dass Sie die Originaldateien, Heroes III: Complete Edition oder Shadow of Death besitzen müssen, um VCMI verwenden zu können.
+
+Heroes III: HD Edition wird derzeit nicht unterstützt
+
+
+
+
-
+ Weiter
-
+
-
+ Heroes III Daten suchen
-
+
-
-
-
-
-
-
-
-
-
-
-
+ Hilfe im Browser öffnen
+
+ Erneut suchen
+
+
+
+
+ Wenn Sie keine Kopie von Heroes III installiert haben, können Sie unser automatisches Installationstool 'vcmibuilder' verwenden, um Daten aus dem GoG.com-Installationsprogramm zu extrahieren. Besuchen Sie unser Wiki für detaillierte Anweisungen.
+
+
+
-
+ VCMI benötigt Heroes III Daten in einem der oben aufgeführten Verzeichnisse. Bitte kopieren Sie die Heroes III-Daten in eines dieser Verzeichnisse.
-
+
-
+ Heroes III Dateien
-
+
-
+ Alternativ können Sie ein Verzeichnis mit installierten Heroes III-Daten auswählen, und VCMI wird die vorhandenen Daten automatisch kopieren.
-
+
-
+ Vorhandene Daten kopieren
-
+
-
+ Ihre Heroes III-Sprache wurde erfolgreich erkannt.
-
+
-
+ Automatische Erkennung der Sprache fehlgeschlagen. Bitte wählen Sie die Sprache Ihrer Heroes III Kopie
-
+
-
+ Heroes III Sprache
-
-
+
+
-
+ Zurück
-
+
-
+ VCMI Mod Voreinstellung installieren
-
+
+
+ Horn of the Abyss
+
+
+
+
+ Heroes III Übersetzung
+
+
+
+
+ Unterstützung für hohe Auflösungen
+
+
+
+
+ In The Wake of Gods
+
+
+
-
+ Übersetzung von Heroes III für Ihre Sprache installieren
@@ -579,67 +729,67 @@
-
+ Chinesisch
- English (Englisch)
+ Englisch
-
+ Französisch
-
+ Deutsch
-
+ Koreanisch
-
+ Polnisch
-
+ Russisch
-
+ Spanisch
-
+ Ukrainisch
-
+ Sonstige (osteuropäisch)
-
+ Sonstige (kyrillische Schrift)
-
+ Sonstige (westeuropäisch)
-
+ Auto (%1)
@@ -663,12 +813,12 @@
-
+ Personen in der Lobby
-
+ Lobby-Chat
@@ -683,17 +833,17 @@
-
+ Auflösen
-
+ Neues Spiel
-
+ Spiel laden
@@ -733,12 +883,12 @@
-
+ Verbindung trennen
-
+ Keine Probleme festgestellt
@@ -789,7 +939,7 @@
-
+ Karteneditor
diff --git a/launcher/translation/polish.ts b/launcher/translation/polish.ts
index e6bcc32fa..1424c8d87 100644
--- a/launcher/translation/polish.ts
+++ b/launcher/translation/polish.ts
@@ -4,17 +4,111 @@
CModListModel
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Nazwa
-
+ Typ
-
+ Wersja
@@ -63,7 +157,7 @@
-
+ Opis
@@ -113,114 +207,113 @@
Przerwij
-
+ Nazwa moda
-
+ Zainstalowana wersja
-
+ Najnowsza wersja
-
+ Rozmiar pobierania
-
+ Autorzy
-
+ Licencja
-
+ Kontakt
-
-
+ Kompatybilność
-
-
+
+ Wymagana wersja VCMI
-
+ Wspierana wersja VCMI
-
+ Wspierane wersje VCMI
-
+
+
+
+
+
+ Wymagane mody
-
+ Konfliktujące mody
-
+ Ten mod nie może zostać zainstalowany lub włączony ponieważ następujące zależności nie zostały spełnione
-
+ Ten mod nie może zostać włączony ponieważ następujące mody są z nim niekompatybilne
-
+ Ten mod nie może zostać wyłączony ponieważ jest wymagany by do uruchomienia następujących modów
-
+ Ten mod nie może zostać odinstalowany lub zaktualizowany ponieważ jest wymagany do uruchomienia następujących modów
-
+ To jest moduł składowy innego moda i nie może być zainstalowany lub odinstalowany oddzielnie od moda nadrzędnego
-
+ Uwagi
-
+ Zrzut ekranu %1
-
-
- Mod jest kompatybilny
-
-
-
+ Mod jest niekompatybilny
@@ -449,32 +542,32 @@
Zestaw modów
-
+ Twoje pliki Heroes III zostały pomyślnie znalezione.
-
+ Opcjonalnie możesz zainstalować dodatkowe modyfikacje teraz lub później:
-
+ Zapinstaluj wsparcie dla grania w Heroes III w rozdzielczości innej niż 800x600.
-
+ Zainstaluj kompatybilną wersję fanowskiego dodatku Horn of the Abyss przeportowaną przez zespół VCMI
-
+ Zainstaluj kompatybilną wersję fanowskiego dodatku "In The Wake Of Gods"
-
+ Zakończ
@@ -484,84 +577,135 @@
Krok %v z %m
-
+ Wybierz język
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Dalej
-
+ Znajdź pliki Heroes III
-
+ Otwórz pomoc w przeglądarce
-
+ Szukaj ponownie
-
+ Jeśli nie masz zainstalowanej kopii Heroes III istnieje możliwość użycia naszego automatycznego narzędzia instalacyjnego 'vcmibuilder' by wyodrębnić dane z instalatora GoG.com. Odwiedź nasze wiki po szczegółowe instrukcje.
-
+ VCMI wymaga plików Heroes III w jednej z wymienionych wyżej lokalizacji. Proszę, skopiuj pliki Heroes III do jednego z tych katalogów.
-
+ Pliki Heroes III
-
+ Możesz też wybrać folder z zainstalowanym Heroes III i VCMI automatycznie skopiuje istniejące dane.
-
+ Skopiuj istniejące dane
-
+ Twój język Heroes III został pomyślnie wykryty.
-
+ Automatyczna detekcja języka nie powiodła się. Proszę wybrać język twojego Heroes III
-
+ Język Heroes III
-
-
+
+ Wstecz
-
+ Zainstaluj zestaw modyfikacji
-
+
+
+
+
+
+
+
+ Tłumaczenie Heroes III
+
+
+
+
+
+
+
+
+
+
+
+
+ Zainstaluj tłumaczenie Heroes III dla twojego języka
diff --git a/launcher/translation/russian.ts b/launcher/translation/russian.ts
index bf4f89f7b..e0f81f50d 100644
--- a/launcher/translation/russian.ts
+++ b/launcher/translation/russian.ts
@@ -4,17 +4,111 @@
CModListModel
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Название
-
+ Тип
-
+ Версия
@@ -63,7 +157,7 @@
-
+ Описание
@@ -113,114 +207,113 @@
Отмена
-
+ Название мода
-
+ Установленная версия
-
+ Последняя версия
-
+ Размер загрузки
-
+ Авторы
-
+ Лицензия
-
+
-
-
+ Совместимость
-
-
+
+ Требуемая версия VCMI
-
+ Поддерживаемая версия VCMI
-
+ Поддерживаемые версии VCMI
-
+
+
+
+
+
+ Зависимости
-
+ Конфликтующие моды
-
+ Этот мод не может быть установлен или активирован, так как отсутствуют следующие зависимости
-
+ Этот мод не может быть установлен или активирован, так как следующие моды несовместимы с этим
-
+ Этот мод не может быть выключен, так как он является зависимостью для следующих
-
+ Этот мод не может быть удален или обновлен, так как является зависимостью для следующих модов
-
+ Это вложенный мод, он не может быть установлен или удален отдельно от родительского
-
+ Замечания
-
+ Скриншот %1
-
-
- Мод совместим
-
-
-
+ Мод несовместим
@@ -449,32 +542,32 @@
-
+
-
+
-
+
-
+
-
+
-
+
@@ -484,84 +577,135 @@
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
-
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/launcher/translation/spanish.ts b/launcher/translation/spanish.ts
index 859e98a34..d1dc21041 100644
--- a/launcher/translation/spanish.ts
+++ b/launcher/translation/spanish.ts
@@ -4,101 +4,180 @@
CModListModel
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Nombre
-
+ Tipo
-
+ Versión
-
-
-
- Tamaño
-
-
-
-
- Autor
-
- CModListView
+ CModListView
-
+ Filtrar
-
+ Todos los mods
-
+ Descargables
-
+ Instalado
-
+ Actualizables
-
+ Activo
-
+ Inactivo
-
+ Descargar y actualizar repositorios
-
-
+
+ Descripción
-
+ Registro de cambios
-
+ Capturas de pantalla
-
-
- Mostrar detalles
-
-
-
+ Desinstalar
-
+ Activar
@@ -108,134 +187,133 @@
Desactivar
-
+ Actualizar
-
+ Instalar
-
+ %p% (%v KB de %m KB)
-
+ Cancelar
-
+ Nombre del mod
-
+ Versión instalada
-
+ Última versión
-
+ Tamaño de descarga
-
+ Autores
-
+ Licencia
-
-
- Página principal
+
+
+
-
-
+ Compatibilidad
-
-
+
+ Versión de VCMI requerida
-
+ Versión de VCMI compatible
-
+ Versiones de VCMI compatibles
-
+
+
+
+
+
+ Mods requeridos
-
+ Mods conflictivos
-
+ Este mod no se puede instalar o habilitar porque no están presentes las siguientes dependencias
-
+ Este mod no se puede habilitar porque los siguientes mods son incompatibles con él
-
+ No se puede desactivar este mod porque es necesario para ejecutar los siguientes mods
-
+ No se puede desinstalar o actualizar este mod porque es necesario para ejecutar los siguientes mods
-
+ Este es un submod y no se puede instalar o desinstalar por separado del mod principal
-
+ Notas
-
+ Captura de pantalla %1
-
-
- El mod es compatible
-
-
-
+ El mod es incompatible
@@ -243,217 +321,393 @@
CSettingsView
-
+ Cambiar
-
-
-
+
+
+ Abrir
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Directorio de datos de usuario
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Apagado
-
-
-
-
+
+
+
+ Encendido
-
+ Pantalla completa
-
-
- Repositorios
-
-
-
-
- Buscar actualizaciones
-
-
-
+ IA Neutral
-
+ Realista
-
+
+ General
-
-
- IA de jugador
-
-
-
+ Idioma de VCMI
-
-
- Europa central (Windows 1250)
-
-
-
-
- Cyrillic script (Windows 1251)
-
-
-
-
- Europa oriental (Windows 1252)
-
-
-
-
- Chino simplificado (GBK)
-
-
-
-
- Chino simplificado (GB2312)
-
-
-
-
- Koreano (Windows 949)
-
-
-
-
- English (Inglés)
-
-
-
-
- Deutsch (Alemán)
-
-
-
-
- Polska (Polaco)
-
-
-
-
- Русский (Ruso)
-
-
-
-
- Українська (Ucraniano)
-
-
-
+ IA amistosa
-
+ Resolución
-
-
- IA en el mapa
-
-
-
+ Autoguardado
-
+
+
+
+
+
+ Mostrar índice
-
-
- Comprobar repositorios al iniciar
-
-
-
+ Puerto de red
-
+
+ Directorios de datos
-
+
+ Vídeo
-
-
- Juego de caracteres de Heroes III
-
-
-
+ Directorio de datos extra
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Directorio de archivos de registro
-
+ Mostrar introducción
-
-
- Configuración del lanzador
-
-
-
+ Versión
-
+
+
+
+
+
+
+
+
+
+
+ IA enemiga
-
-
- IA en el campo de batalla
+
+
+ Activo
+
+
+
+
+
+
+
+
+
+ Activar
+
+
+
+
+
+
+
+
+
+ Instalar
+
+
+
+ FirstLaunchView
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -464,68 +718,172 @@
Visor de imágenes
+
+ Language
+
+
+
+
+
+
+
+
+ English (Inglés)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Lobby
-
+
+ Conectar
-
+ Nombre de usuario
-
+ Servidor
-
+
+
+
+
+
+
+
+
+
+
+ Sesión
-
+ Jugadores
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Nueva sala
-
+ Unirse a la sala
-
+ Listo
-
+ No coinciden los mods
-
+ Salir
-
+ Expulsar jugador
-
+ Jugadores en la sala
+
+
+
+
+
+
+
+
+
+ LobbyRoomRequest
@@ -553,52 +911,52 @@
MainWindow
-
-
- Lanzador de VCMI
+
+
+ Lanzador de VCMI
-
-
- Configuración
+
+
+ Configuración
-
-
- Editor de Mapas
+
+
+ Editor de Mapas
-
-
- Iniciar juego
+
+
+ Iniciar juego
-
-
- Sala de Espera
+
+
+ Sala de Espera
-
-
- Mods
+
+
+ ModsUpdateDialog
-
-
- Tienes la última versión
+
+
+ Tienes la última versión
-
-
- Cerrar
+
+
+ Cerrar
-
-
- Comprobar actualizaciones al iniciar
+
+
+ Comprobar actualizaciones al iniciar
diff --git a/launcher/translation/ukrainian.ts b/launcher/translation/ukrainian.ts
index 1b059748f..e69f5b18b 100644
--- a/launcher/translation/ukrainian.ts
+++ b/launcher/translation/ukrainian.ts
@@ -4,17 +4,111 @@
CModListModel
-
+
+
+ Переклад
+
+
+
+
+ Місто
+
+
+
+
+ Тестування
+
+
+
+
+ Шаблони
+
+
+
+
+ Закляття
+
+
+
+
+ Музика
+
+
+
+
+ Звуки
+
+
+
+
+ Вміння
+
+
+
+
+
+ Інше
+
+
+
+
+ Об'єкти
+
+
+
+
+
+ Механіки
+
+
+
+
+
+ Інтерфейс
+
+
+
+
+ Герої
+
+
+
+
+
+ Графічний
+
+
+
+
+ Розширення
+
+
+
+
+ Істоти
+
+
+
+
+ Артефакти
+
+
+
+
+ ШІ
+
+
+ Назва
-
+ Тип
-
+ Версія
@@ -63,7 +157,7 @@
-
+ Опис
@@ -113,114 +207,113 @@
Відмінити
-
+ Назва модифікації
-
+ Встановлена версія
-
+ Найновіша версія
-
+ Розмір для завантаження
-
+ Автори
-
+ Ліцензія
-
+ Контакти
-
-
+ Сумісність
-
-
+
+ Необхідна версія VCMI
-
+ Підтримувана версія VCMI
-
+ Підтримувані версії VCMI
-
+
+
+ Мови
+
+
+ Необхідні модифікації
-
+ Конфліктуючі модифікації
-
+ Цю модифікацію не можна встановити чи активувати, оскільки відсутні наступні залежності
-
+ Цю модифікацію не можна ввімкнути, оскільки наступні модифікації несумісні з цією модифікацією
-
+ Цю модифікацію не можна відключити, оскільки вона необхідна для запуску наступних модифікацій
-
+ Цю модифікацію не можна видалити або оновити, оскільки вона необхідна для запуску наступних модифікацій
-
+ Це вкладена модифікація, і її не можна встановити або видалити окремо від батьківської модифікації
-
+ Примітки
-
+ Знімок екрану %1
-
-
- Модифікація сумісна
-
-
-
+ Модифікація несумісна
@@ -449,32 +542,32 @@
Початкові модифікації
-
+ Файли даних вашої гри Heroes III успішно знайдено.
-
+ За бажанням ви можете встановити додаткові модифікації зараз або пізніше:
-
+
-
+ Встановити підтримку для гри в Heroes III у роздільних здатностях, більших за 800x600.
-
+
-
+ Встановити сумісну версію доповнення Horn of the Abyss: фанатське доповнення Heroes III, портоване командою VCMI
-
+
-
+ Встановити сумісну версію доповнення " In The Wake of Gods": фанатське доповнення до Heroes III
-
+ Завершити
@@ -484,84 +577,141 @@
Крок %v з %m
-
+ Оберіть свою мову
-
-
+
+
+ VCMI на Github
+
+
+
+
+ VCMI на Slack
+
+
+
+
+ VCMI на Discord
+
+
+
+
+ Маєте питання? Виявили помилку? Хочете допомогти? Приєднуйтесь до нас:
+
+
+
+
+ Дякуємо, що встановили VCMI.
+
+Залишилося зробити ще кілька кроків, перш ніж ви зможете почати грати.
+
+Майте на увазі, що для використання VCMI вам потрібно мати оригінальні файли гри Heroes III: Complete Edition або Shadow of Death.
+
+Heroes III: HD Edition наразі не підтримується
+
+
+
+ Далі
-
+ Пошук файлів даних Heroes III
-
+ Відкрити довідку у браузері
-
+ Повторити пошук
-
+
-
+ Якщо у вас не встановлена копія Heroes III, ви можете скористатися нашим засобом встановлення "vcmibuilder", щоб видобути дані з інсталятора GoG.com. Докладні інструкції можна знайти у нашій вікі.
-
+
-
+ VCMI потребує файлів даних Heroes III в одному з перелічених вище розташувань. Будь ласка, скопіюйте дані Heroes III в одну з цих директорій.
-
+ Файли даних Heroes III
-
+
-
+ Або ж ви можете вибрати директорію зі встановленими даними Heroes III, і VCMI автоматично скопіює ці дані.
-
+ Копіювати наявні дані
-
+ Мову вашої гри Heroes III успішно визначено.
-
+ Не вдалося визначити мову гри. Будь ласка, виберіть мову вашої копії Heroes III
-
+ Мова Heroes III
-
-
+
+ Назад
-
+ Встановлення початкових модифікацій VCMI
-
+
+
+ Horn of the Abyss
+
+
+
+
+ Переклад Heroes III
+
+
+
+
+ Підтримка високих роздільних здатностей
+
+
+
+
+ In The Wake of Gods
+
+
+ Встановити переклад Heroes III на вашу мову
diff --git a/lib/CGeneralTextHandler.cpp b/lib/CGeneralTextHandler.cpp
index 3eae09b95..8e492240b 100644
--- a/lib/CGeneralTextHandler.cpp
+++ b/lib/CGeneralTextHandler.cpp
@@ -48,6 +48,20 @@ void CGeneralTextHandler::detectInstallParameters()
"ukrainian"
} };
+ if(!CResourceHandler::get("core")->existsResource(ResourceID("DATA/GENRLTXT.TXT", EResType::TEXT)))
+ {
+ Settings language = settings.write["session"]["language"];
+ language->String() = "english";
+
+ Settings confidence = settings.write["session"]["languageDeviation"];
+ confidence->Float() = 1.0;
+
+ Settings encoding = settings.write["session"]["encoding"];
+ encoding->String() = Languages::getLanguageOptions("english").encoding;
+
+ return;
+ }
+
// load file that will be used for footprint generation
// this is one of the most text-heavy files in game and consists solely from translated texts
auto resource = CResourceHandler::get("core")->load(ResourceID("DATA/GENRLTXT.TXT", EResType::TEXT));
@@ -254,7 +268,7 @@ const std::string & CGeneralTextHandler::deserialize(const TextIdentifier & iden
return identifier.get();
}
- auto const & entry = stringsLocalizations.at(identifier.get());
+ const auto & entry = stringsLocalizations.at(identifier.get());
if (!entry.overrideValue.empty())
return entry.overrideValue;
@@ -312,7 +326,7 @@ bool CGeneralTextHandler::validateTranslation(const std::string & language, cons
{
bool allPresent = true;
- for (auto const & string : stringsLocalizations)
+ for(const auto & string : stringsLocalizations)
{
if (string.second.modContext != modContext)
continue; // Not our mod
@@ -341,7 +355,7 @@ bool CGeneralTextHandler::validateTranslation(const std::string & language, cons
bool allFound = true;
- for (auto const & string : config.Struct())
+ for(const auto & string : config.Struct())
{
if (stringsLocalizations.count(string.first) > 0)
continue;
diff --git a/lib/JsonDetail.cpp b/lib/JsonDetail.cpp
index 083ec7dcb..8d64812cc 100644
--- a/lib/JsonDetail.cpp
+++ b/lib/JsonDetail.cpp
@@ -1059,8 +1059,7 @@ namespace
std::string defFile(const JsonNode & node)
{
- TEST_FILE(node.meta, "Sprites/", node.String(), EResType::ANIMATION);
- return "Def file \"" + node.String() + "\" was not found";
+ return testAnimation(node.String(), node.meta);
}
std::string animationFile(const JsonNode & node)
diff --git a/lib/NetPacksBase.h b/lib/NetPacksBase.h
index e59308baa..e7b3da5f1 100644
--- a/lib/NetPacksBase.h
+++ b/lib/NetPacksBase.h
@@ -308,8 +308,6 @@ public:
RESET_STATE,
UPDATE,
REMOVE,
- ACTIVATE_AND_UPDATE,
- ACTIVATE_AND_REMOVE
};
JsonNode data;
diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp
index fe93dc7a2..15a02192f 100644
--- a/lib/NetPacksLib.cpp
+++ b/lib/NetPacksLib.cpp
@@ -2166,6 +2166,7 @@ void BattleTriggerEffect::applyGs(CGameState * gs) const
break;
}
case Bonus::ENCHANTER:
+ case Bonus::MORALE:
break;
case Bonus::FEAR:
st->fear = true;
@@ -2398,7 +2399,6 @@ void BattleObstaclesChanged::applyBattle(IBattleState * battleState)
case BattleChanges::EOperation::ADD:
battleState->addObstacle(change);
break;
- case BattleChanges::EOperation::ACTIVATE_AND_UPDATE:
case BattleChanges::EOperation::UPDATE:
battleState->updateObstacle(change);
break;
diff --git a/lib/VCMIDirs.cpp b/lib/VCMIDirs.cpp
index 1e8dc49ac..5c56dc54f 100644
--- a/lib/VCMIDirs.cpp
+++ b/lib/VCMIDirs.cpp
@@ -346,7 +346,7 @@ std::vector VCMIDirsWIN32::dataPaths() const
}
bfs::path VCMIDirsWIN32::clientPath() const { return binaryPath() / "VCMI_client.exe"; }
-bfs::path VCMIDirsWIN32::mapEditorPath() const { return binaryPath() / "VCMI_editor.exe"; }
+bfs::path VCMIDirsWIN32::mapEditorPath() const { return binaryPath() / "VCMI_mapeditor.exe"; }
bfs::path VCMIDirsWIN32::serverPath() const { return binaryPath() / "VCMI_server.exe"; }
bfs::path VCMIDirsWIN32::libraryPath() const { return "."; }
diff --git a/lib/battle/CBattleInfoCallback.cpp b/lib/battle/CBattleInfoCallback.cpp
index c0198c530..3d0e6c8c3 100644
--- a/lib/battle/CBattleInfoCallback.cpp
+++ b/lib/battle/CBattleInfoCallback.cpp
@@ -798,19 +798,21 @@ std::vector> CBattleInfoCallback::battl
return obstacles;
}
-std::vector> CBattleInfoCallback::getAllAffectedObstaclesByStack(const battle::Unit * unit) const
+std::vector> CBattleInfoCallback::getAllAffectedObstaclesByStack(const battle::Unit * unit, const std::set & passed) const
{
- std::vector> affectedObstacles = std::vector>();
+ auto affectedObstacles = std::vector>();
RETURN_IF_NOT_BATTLE(affectedObstacles);
if(unit->alive())
{
- affectedObstacles = battleGetAllObstaclesOnPos(unit->getPosition(), false);
+ if(!passed.count(unit->getPosition()))
+ affectedObstacles = battleGetAllObstaclesOnPos(unit->getPosition(), false);
if(unit->doubleWide())
{
- BattleHex otherHex = unit->occupiedHex(unit->getPosition());
- if(otherHex.isValid())
+ BattleHex otherHex = unit->occupiedHex();
+ if(otherHex.isValid() && !passed.count(otherHex))
for(auto & i : battleGetAllObstaclesOnPos(otherHex, false))
- affectedObstacles.push_back(i);
+ if(!vstd::contains(affectedObstacles, i))
+ affectedObstacles.push_back(i);
}
for(auto hex : unit->getHexes())
if(hex == ESiegeHex::GATE_BRIDGE)
@@ -932,6 +934,8 @@ ReachabilityInfo CBattleInfoCallback::makeBFS(const AccessibilityInfo &accessibi
return ret;
const std::set obstacles = getStoppers(params.perspective);
+ auto checkParams = params;
+ checkParams.ignoreKnownAccessible = true; //Ignore starting hexes obstacles
std::queue hexq; //bfs queue
@@ -949,7 +953,7 @@ ReachabilityInfo CBattleInfoCallback::makeBFS(const AccessibilityInfo &accessibi
hexq.pop();
//walking stack can't step past the obstacles
- if(curHex != params.startPosition && isInObstacle(curHex, obstacles, params))
+ if(isInObstacle(curHex, obstacles, checkParams))
continue;
const int costToNeighbour = ret.distances[curHex.hex] + 1;
@@ -982,6 +986,9 @@ bool CBattleInfoCallback::isInObstacle(
for(auto occupiedHex : occupiedHexes)
{
+ if(params.ignoreKnownAccessible && vstd::contains(params.knownAccessible, occupiedHex))
+ continue;
+
if(vstd::contains(obstacles, occupiedHex))
{
if(occupiedHex == ESiegeHex::GATE_BRIDGE)
diff --git a/lib/battle/CBattleInfoCallback.h b/lib/battle/CBattleInfoCallback.h
index dccdac50c..1adcbf8c8 100644
--- a/lib/battle/CBattleInfoCallback.h
+++ b/lib/battle/CBattleInfoCallback.h
@@ -60,7 +60,7 @@ public:
boost::optional battleIsFinished() const override; //return none if battle is ongoing; otherwise the victorious side (0/1) or 2 if it is a draw
std::vector> battleGetAllObstaclesOnPos(BattleHex tile, bool onlyBlocking = true) const override;
- std::vector> getAllAffectedObstaclesByStack(const battle::Unit * unit) const override;
+ std::vector> getAllAffectedObstaclesByStack(const battle::Unit * unit, const std::set & passed) const override;
const CStack * battleGetStackByPos(BattleHex pos, bool onlyAlive = true) const;
diff --git a/lib/battle/CBattleInfoEssentials.cpp b/lib/battle/CBattleInfoEssentials.cpp
index 081030394..ac3929ea3 100644
--- a/lib/battle/CBattleInfoEssentials.cpp
+++ b/lib/battle/CBattleInfoEssentials.cpp
@@ -47,10 +47,7 @@ std::vector> CBattleInfoEssentials::bat
else
{
if(!!player && *perspective != battleGetMySide())
- {
- logGlobal->error("Unauthorized obstacles access attempt!");
- return ret;
- }
+ logGlobal->warn("Unauthorized obstacles access attempt, assuming massive spell");
}
for(const auto & obstacle : getBattle()->getAllObstacles())
diff --git a/lib/battle/IBattleInfoCallback.h b/lib/battle/IBattleInfoCallback.h
index 8f8ab8c80..223986eef 100644
--- a/lib/battle/IBattleInfoCallback.h
+++ b/lib/battle/IBattleInfoCallback.h
@@ -72,7 +72,7 @@ public:
//blocking obstacles makes tile inaccessible, others cause special effects (like Land Mines, Moat, Quicksands)
virtual std::vector> battleGetAllObstaclesOnPos(BattleHex tile, bool onlyBlocking = true) const = 0;
- virtual std::vector> getAllAffectedObstaclesByStack(const battle::Unit * unit) const = 0;
+ virtual std::vector> getAllAffectedObstaclesByStack(const battle::Unit * unit, const std::set & passed) const = 0;
};
diff --git a/lib/battle/ReachabilityInfo.h b/lib/battle/ReachabilityInfo.h
index 134390605..6931e1662 100644
--- a/lib/battle/ReachabilityInfo.h
+++ b/lib/battle/ReachabilityInfo.h
@@ -28,6 +28,7 @@ struct DLL_LINKAGE ReachabilityInfo
ui8 side = 0;
bool doubleWide = false;
bool flying = false;
+ bool ignoreKnownAccessible = false; //Ignore obstacles if it is in accessible hexes
std::vector knownAccessible; //hexes that will be treated as accessible, even if they're occupied by stack (by default - tiles occupied by stack we do reachability for, so it doesn't block itself)
BattleHex startPosition; //assumed position of stack
diff --git a/lib/mapObjects/CRewardableConstructor.cpp b/lib/mapObjects/CRewardableConstructor.cpp
index 7e860c074..cb3d0f741 100644
--- a/lib/mapObjects/CRewardableConstructor.cpp
+++ b/lib/mapObjects/CRewardableConstructor.cpp
@@ -16,6 +16,7 @@
#include "../CModHandler.h"
#include "JsonRandom.h"
#include "../IGameCallback.h"
+#include "../CGeneralTextHandler.h"
VCMI_LIB_NAMESPACE_BEGIN
@@ -307,9 +308,22 @@ bool CRandomRewardObjectInfo::givesBonuses() const
return testForKey(parameters, "bonuses");
}
+const JsonNode & CRandomRewardObjectInfo::getParameters() const
+{
+ return parameters;
+}
+
void CRewardableConstructor::initTypeData(const JsonNode & config)
{
objectInfo.init(config);
+
+ if (!config["name"].isNull())
+ VLC->generaltexth->registerString( config.meta, getNameTextID(), config["name"].String());
+}
+
+bool CRewardableConstructor::hasNameTextID() const
+{
+ return !objectInfo.getParameters()["name"].isNull();
}
CGObjectInstance * CRewardableConstructor::create(std::shared_ptr tmpl) const
diff --git a/lib/mapObjects/CRewardableConstructor.h b/lib/mapObjects/CRewardableConstructor.h
index 6e41c7ce6..f47571410 100644
--- a/lib/mapObjects/CRewardableConstructor.h
+++ b/lib/mapObjects/CRewardableConstructor.h
@@ -28,6 +28,8 @@ class DLL_LINKAGE CRandomRewardObjectInfo : public IObjectInfo
void configureReward(CRewardableObject * object, CRandomGenerator & rng, CRewardInfo & info, const JsonNode & source) const;
void configureResetInfo(CRewardableObject * object, CRandomGenerator & rng, CRewardResetInfo & info, const JsonNode & source) const;
public:
+ const JsonNode & getParameters() const;
+
bool givesResources() const override;
bool givesExperience() const override;
@@ -60,6 +62,8 @@ class DLL_LINKAGE CRewardableConstructor : public AObjectTypeHandler
void initTypeData(const JsonNode & config) override;
public:
+ bool hasNameTextID() const override;
+
CGObjectInstance * create(std::shared_ptr tmpl = nullptr) const override;
void configureObject(CGObjectInstance * object, CRandomGenerator & rng) const override;
diff --git a/lib/serializer/Connection.cpp b/lib/serializer/Connection.cpp
index ca7845ae0..ec00d5c63 100644
--- a/lib/serializer/Connection.cpp
+++ b/lib/serializer/Connection.cpp
@@ -83,7 +83,7 @@ CConnection::CConnection(const std::string & host, ui16 port, std::string Name,
if(error)
{
logNetwork->error("Problem with resolving: \n%s", error.message());
- goto connerror1;
+ throw std::runtime_error("Can't establish connection: Problem with resolving");
}
pom = endpoint_iterator;
if(pom != end)
@@ -91,7 +91,7 @@ CConnection::CConnection(const std::string & host, ui16 port, std::string Name,
else
{
logNetwork->error("Critical problem: No endpoints found!");
- goto connerror1;
+ throw std::runtime_error("Can't establish connection: No endpoints found!");
}
while(pom != end)
{
@@ -110,20 +110,12 @@ CConnection::CConnection(const std::string & host, ui16 port, std::string Name,
}
else
{
- logNetwork->error("Problem with connecting: %s", error.message());
+ throw std::runtime_error("Can't establish connection: Failed to connect!");
}
endpoint_iterator++;
}
-
- //we shouldn't be here - error handling
-connerror1:
- logNetwork->error("Something went wrong... checking for error info");
- if(error)
- logNetwork->error(error.message());
- else
- logNetwork->error("No error info. ");
- throw std::runtime_error("Can't establish connection :(");
}
+
CConnection::CConnection(std::shared_ptr Socket, std::string Name, std::string UUID):
iser(this),
oser(this),
diff --git a/lib/spells/effects/Obstacle.cpp b/lib/spells/effects/Obstacle.cpp
index 443b168bb..36b60d908 100644
--- a/lib/spells/effects/Obstacle.cpp
+++ b/lib/spells/effects/Obstacle.cpp
@@ -121,6 +121,9 @@ void Obstacle::adjustAffectedHexes(std::set & hexes, const Mechanics
bool Obstacle::applicable(Problem & problem, const Mechanics * m) const
{
+ if(hidden && m->battle()->battleHasNativeStack(m->battle()->otherSide(m->casterSide)))
+ return m->adaptProblem(ESpellCastProblem::NO_APPROPRIATE_TARGET, problem);
+
return LocationEffect::applicable(problem, m);
}
@@ -270,12 +273,7 @@ void Obstacle::placeObstacles(ServerCallback * server, const Mechanics * m, cons
BattleObstaclesChanged pack;
- boost::optional perspective;
-
- if(!m->battle()->getPlayerID())
- perspective = boost::make_optional(BattlePerspective::ALL_KNOWING);
-
- auto all = m->battle()->battleGetAllObstacles(perspective);
+ auto all = m->battle()->battleGetAllObstacles(BattlePerspective::ALL_KNOWING);
int obstacleIdToGive = 1;
for(auto & one : all)
diff --git a/lib/spells/effects/RemoveObstacle.cpp b/lib/spells/effects/RemoveObstacle.cpp
index 71535484f..c268fd8c8 100644
--- a/lib/spells/effects/RemoveObstacle.cpp
+++ b/lib/spells/effects/RemoveObstacle.cpp
@@ -72,7 +72,7 @@ bool RemoveObstacle::canRemove(const CObstacleInstance * obstacle) const
return true;
const auto *spellObstacle = dynamic_cast(obstacle);
- if(removeAllSpells && spellObstacle)
+ if(removeAllSpells && obstacle->obstacleType == CObstacleInstance::SPELL_CREATED)
return true;
if(spellObstacle && !removeSpells.empty())
@@ -89,7 +89,7 @@ std::set RemoveObstacle::getTargets(const Mechanics *
std::set possibleTargets;
if(m->isMassive() || alwaysMassive)
{
- for(const auto & obstacle : m->battle()->battleGetAllObstacles())
+ for(const auto & obstacle : m->battle()->battleGetAllObstacles(BattlePerspective::ALL_KNOWING))
if(canRemove(obstacle.get()))
possibleTargets.insert(obstacle.get());
}
diff --git a/lib/spells/effects/UnitEffect.cpp b/lib/spells/effects/UnitEffect.cpp
index e2ef48402..124e35829 100644
--- a/lib/spells/effects/UnitEffect.cpp
+++ b/lib/spells/effects/UnitEffect.cpp
@@ -40,7 +40,7 @@ bool UnitEffect::applicable(Problem & problem, const Mechanics * m) const
{
//stack effect is applicable in general if there is at least one smart target
- auto mainFilter = std::bind(&UnitEffect::getStackFilter, this, m, true, _1);
+ auto mainFilter = std::bind(&UnitEffect::getStackFilter, this, m, false, _1);
auto predicate = std::bind(&UnitEffect::eraseByImmunityFilter, this, m, _1);
auto targets = m->battle()->battleGetUnitsIf(mainFilter);
@@ -59,12 +59,12 @@ bool UnitEffect::applicable(Problem & problem, const Mechanics * m) const
bool UnitEffect::applicable(Problem & problem, const Mechanics * m, const EffectTarget & target) const
{
- //stack effect is applicable if it affects at least one smart target
- //assume target correctly transformed, just reapply smart filter
+ //stack effect is applicable if it affects at least one target (smartness should not be checked)
+ //assume target correctly transformed, just reapply filter
for(const auto & item : target)
if(item.unitValue)
- if(getStackFilter(m, true, item.unitValue))
+ if(getStackFilter(m, false, item.unitValue))
return true;
return false;
diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp
index 18ba84335..9643b3bef 100644
--- a/server/CGameHandler.cpp
+++ b/server/CGameHandler.cpp
@@ -51,6 +51,8 @@
#include "../lib/serializer/Cast.h"
#include "../lib/serializer/JsonSerializer.h"
#include "../lib/ScriptHandler.h"
+#include "vstd/CLoggerBase.h"
+#include
#include
#include
#include
@@ -1398,6 +1400,11 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
//initing necessary tables
auto accessibility = getAccesibility(curStack);
+ std::set passed;
+ //Ignore obstacles on starting position
+ passed.insert(curStack->getPosition());
+ if(curStack->doubleWide())
+ passed.insert(curStack->occupiedHex());
//shifting destination (if we have double wide stack and we can occupy dest but not be exactly there)
if(!stackAtEnd && curStack->doubleWide() && !accessibility.accessible(dest, curStack))
@@ -1427,7 +1434,10 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
ret = path.second;
- int creSpeed = gs->curB->tacticDistance ? GameConstants::BFIELD_SIZE : curStack->Speed(0, true);
+ int creSpeed = curStack->Speed(0, true);
+
+ if (gs->curB->tacticDistance > 0 && creSpeed > 0)
+ creSpeed = GameConstants::BFIELD_SIZE;
auto isGateDrawbridgeHex = [&](BattleHex hex) -> bool
{
@@ -1590,10 +1600,12 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
if(otherHex.isValid() && !obstacle2.empty())
obstacleHit = true;
}
+ if(!obstacleHit)
+ passed.insert(hex);
}
}
- if (tiles.size() > 0)
+ if (!tiles.empty())
{
//commit movement
BattleStackMoved sm;
@@ -1609,7 +1621,12 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
if (curStack->getPosition() != dest)
{
if(stackIsMoving && start != curStack->getPosition())
- stackIsMoving = handleDamageFromObstacle(curStack, stackIsMoving);
+ {
+ stackIsMoving = handleDamageFromObstacle(curStack, stackIsMoving, passed);
+ passed.insert(curStack->getPosition());
+ if(curStack->doubleWide())
+ passed.insert(curStack->occupiedHex());
+ }
if (gateStateChanging)
{
if (curStack->getPosition() == openGateAtHex)
@@ -1637,7 +1654,7 @@ int CGameHandler::moveStack(int stack, BattleHex dest)
}
//handling obstacle on the final field (separate, because it affects both flying and walking stacks)
- handleDamageFromObstacle(curStack);
+ handleDamageFromObstacle(curStack, false, passed);
return ret;
}
@@ -1659,6 +1676,12 @@ CGameHandler::CGameHandler(CVCMIServer * lobby)
CGameHandler::~CGameHandler()
{
+ if (battleThread)
+ {
+ //Setting battleMadeAction is needed because battleThread waits for the action to continue the main loop
+ battleMadeAction.setn(true);
+ battleThread->join();
+ }
delete spellEnv;
delete gs;
}
@@ -2700,7 +2723,7 @@ void CGameHandler::startBattlePrimary(const CArmedInstance *army1, const CArmedI
auto battleQuery = std::make_shared(this, gs->curB);
queries.addQuery(battleQuery);
- boost::thread(&CGameHandler::runBattle, this);
+ this->battleThread = std::make_unique(boost::thread(&CGameHandler::runBattle, this));
}
void CGameHandler::startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, bool creatureBank)
@@ -5288,13 +5311,13 @@ void CGameHandler::stackTurnTrigger(const CStack *st)
}
}
-bool CGameHandler::handleDamageFromObstacle(const CStack * curStack, bool stackIsMoving)
+bool CGameHandler::handleDamageFromObstacle(const CStack * curStack, bool stackIsMoving, const std::set & passed)
{
if(!curStack->alive())
return false;
bool containDamageFromMoat = false;
- bool movementStoped = false;
- for(auto & obstacle : getAllAffectedObstaclesByStack(curStack))
+ bool movementStopped = false;
+ for(auto & obstacle : getAllAffectedObstaclesByStack(curStack, passed))
{
if(obstacle->obstacleType == CObstacleInstance::SPELL_CREATED)
{
@@ -5305,7 +5328,7 @@ bool CGameHandler::handleDamageFromObstacle(const CStack * curStack, bool stackI
if(!spellObstacle)
COMPLAIN_RET("Invalid obstacle instance");
- if(spellObstacle->trigger)
+ if(spellObstacle->triggersEffects())
{
const bool oneTimeObstacle = spellObstacle->removeOnTrigger;
@@ -5323,9 +5346,9 @@ bool CGameHandler::handleDamageFromObstacle(const CStack * curStack, bool stackI
ObstacleChanges changeInfo;
changeInfo.id = spellObstacle->uniqueID;
if (oneTimeObstacle)
- changeInfo.operation = ObstacleChanges::EOperation::ACTIVATE_AND_REMOVE;
+ changeInfo.operation = ObstacleChanges::EOperation::REMOVE;
else
- changeInfo.operation = ObstacleChanges::EOperation::ACTIVATE_AND_UPDATE;
+ changeInfo.operation = ObstacleChanges::EOperation::UPDATE;
SpellCreatedObstacle changedObstacle;
changedObstacle.uniqueID = spellObstacle->uniqueID;
@@ -5369,13 +5392,13 @@ bool CGameHandler::handleDamageFromObstacle(const CStack * curStack, bool stackI
return false;
if((obstacle->stopsMovement() && stackIsMoving))
- movementStoped = true;
+ movementStopped = true;
}
if(stackIsMoving)
- return curStack->alive() && !movementStoped;
- else
- return curStack->alive();
+ return curStack->alive() && !movementStopped;
+
+ return curStack->alive();
}
void CGameHandler::handleTimeEvents()
@@ -6412,7 +6435,7 @@ void CGameHandler::runBattle()
//tactic round
{
- while (gs->curB->tacticDistance && !battleResult.get())
+ while ((lobby->state != EServerState::SHUTDOWN) && gs->curB->tacticDistance && !battleResult.get())
boost::this_thread::sleep(boost::posix_time::milliseconds(50));
}
@@ -6490,7 +6513,7 @@ void CGameHandler::runBattle()
bool firstRound = true;//FIXME: why first round is -1?
//main loop
- while (!battleResult.get()) //till the end of the battle ;]
+ while ((lobby->state != EServerState::SHUTDOWN) && !battleResult.get()) //till the end of the battle ;]
{
BattleNextRound bnr;
bnr.round = gs->curB->round + 1;
@@ -6555,7 +6578,7 @@ void CGameHandler::runBattle()
};
const CStack * next = nullptr;
- while((next = getNextStack()))
+ while((lobby->state != EServerState::SHUTDOWN) && (next = getNextStack()))
{
BattleUnitsChanged removeGhosts;
for(auto stack : curB.stacks)
@@ -6734,7 +6757,7 @@ void CGameHandler::runBattle()
boost::unique_lock lock(battleMadeAction.mx);
battleMadeAction.data = false;
- while (!actionWasMade())
+ while ((lobby->state != EServerState::SHUTDOWN) && !actionWasMade())
{
battleMadeAction.cond.wait(lock);
if (battleGetStackByID(nextId, false) != next)
@@ -6790,7 +6813,8 @@ void CGameHandler::runBattle()
firstRound = false;
}
- endBattle(gs->curB->tile, gs->curB->battleGetFightingHero(0), gs->curB->battleGetFightingHero(1));
+ if (lobby->state != EServerState::SHUTDOWN)
+ endBattle(gs->curB->tile, gs->curB->battleGetFightingHero(0), gs->curB->battleGetFightingHero(1));
}
bool CGameHandler::makeAutomaticAction(const CStack *stack, BattleAction &ba)
diff --git a/server/CGameHandler.h b/server/CGameHandler.h
index 89bde24e9..0ed407424 100644
--- a/server/CGameHandler.h
+++ b/server/CGameHandler.h
@@ -96,6 +96,7 @@ class CGameHandler : public IGameCallback, public CBattleInfoCallback, public En
{
CVCMIServer * lobby;
std::shared_ptr> applier;
+ std::unique_ptr battleThread;
public:
using FireShieldInfo = std::vector>;
//use enums as parameters, because doMove(sth, true, false, true) is not readable
@@ -232,7 +233,7 @@ public:
bool makeCustomAction(BattleAction &ba);
void stackEnchantedTrigger(const CStack * stack);
void stackTurnTrigger(const CStack *stack);
- bool handleDamageFromObstacle(const CStack * curStack, bool stackIsMoving = false); //checks if obstacle is land mine and handles possible consequences
+ bool handleDamageFromObstacle(const CStack * curStack, bool stackIsMoving = false, const std::set & passed = {}); //checks if obstacle is land mine and handles possible consequences
void removeObstacle(const CObstacleInstance &obstacle);
bool queryReply( QueryID qid, const JsonNode & answer, PlayerColor player );
diff --git a/server/CQuery.cpp b/server/CQuery.cpp
index a9849ba4c..cdfd90527 100644
--- a/server/CQuery.cpp
+++ b/server/CQuery.cpp
@@ -380,6 +380,9 @@ bool CGarrisonDialogQuery::blocksPack(const CPack * pack) const
if(auto upgrade = dynamic_ptr_cast(pack))
return !vstd::contains(ourIds, upgrade->id);
+ if(auto formation = dynamic_ptr_cast(pack))
+ return !vstd::contains(ourIds, formation->hid);
+
return CDialogQuery::blocksPack(pack);
}
diff --git a/server/CVCMIServer.cpp b/server/CVCMIServer.cpp
index ce24bba5e..1c95a2c3e 100644
--- a/server/CVCMIServer.cpp
+++ b/server/CVCMIServer.cpp
@@ -59,10 +59,6 @@
#include "../lib/CGameState.h"
-#if defined(__GNUC__) && !defined(__UCLIBC__) && !defined(__MINGW32__) && !defined(VCMI_MOBILE)
-#include
-#endif
-
template class CApplyOnServer;
class CBaseForServerApply
@@ -999,33 +995,6 @@ ui8 CVCMIServer::getIdOfFirstUnallocatedPlayer() const
return 0;
}
-#if defined(__GNUC__) && !defined(__UCLIBC__) && !defined(__MINGW32__) && !defined(VCMI_MOBILE)
-void handleLinuxSignal(int sig)
-{
- const int STACKTRACE_SIZE = 100;
- void * buffer[STACKTRACE_SIZE];
- int ptrCount = backtrace(buffer, STACKTRACE_SIZE);
- char * * strings;
-
- logGlobal->error("Error: signal %d :", sig);
- strings = backtrace_symbols(buffer, ptrCount);
- if(strings == nullptr)
- {
- logGlobal->error("There are no symbols.");
- }
- else
- {
- for(int i = 0; i < ptrCount; ++i)
- {
- logGlobal->error(strings[i]);
- }
- free(strings);
- }
-
- _exit(EXIT_FAILURE);
-}
-#endif
-
static void handleCommandOptions(int argc, const char * argv[], boost::program_options::variables_map & options)
{
namespace po = boost::program_options;
@@ -1101,11 +1070,6 @@ int main(int argc, const char * argv[])
// Correct working dir executable folder (not bundle folder) so we can use executable relative paths
boost::filesystem::current_path(boost::filesystem::system_complete(argv[0]).parent_path());
#endif
- // Installs a sig sev segmentation violation handler
- // to log stacktrace
-#if defined(__GNUC__) && !defined(__UCLIBC__) && !defined(__MINGW32__) && !defined(VCMI_MOBILE)
- signal(SIGSEGV, handleLinuxSignal);
-#endif
#ifndef VCMI_IOS
console = new CConsoleHandler();