Browse Source

Merge branch 'develop' into feature/nullkiller2

Mircea TheHonestCTO 2 weeks ago
parent
commit
0ee10c9213
100 changed files with 5948 additions and 2235 deletions
  1. 3 1
      AI/Nullkiller/Engine/PriorityEvaluator.cpp
  2. BIN
      Mods/vcmi/Content/Sprites/lobby/battle-normal.png
  3. BIN
      Mods/vcmi/Content/Sprites/lobby/battle-pressed.png
  4. 8 0
      Mods/vcmi/Content/Sprites/lobby/battleButton.json
  5. 9 0
      Mods/vcmi/Content/config/english.json
  6. 7 0
      Mods/vcmi/Content/config/german.json
  7. 1104 2
      Mods/vcmi/Content/config/romanian.json
  8. 2 0
      client/CMakeLists.txt
  9. 3 2
      client/CPlayerInterface.cpp
  10. 7 0
      client/CServerHandler.cpp
  11. 2 0
      client/CServerHandler.h
  12. 1 0
      client/LobbyClientNetPackVisitors.h
  13. 9 2
      client/NetPacksClient.cpp
  14. 13 0
      client/NetPacksLobbyClient.cpp
  15. 12 3
      client/battle/BattleActionsController.cpp
  16. 1 1
      client/battle/BattleFieldController.cpp
  17. 1 1
      client/battle/BattleProjectileController.cpp
  18. 12 1
      client/battle/BattleResultWindow.cpp
  19. 3 0
      client/battle/BattleWindow.cpp
  20. 1 1
      client/gui/CursorHandler.h
  21. 517 0
      client/lobby/BattleOnlyMode.cpp
  22. 92 0
      client/lobby/BattleOnlyMode.h
  23. 16 4
      client/lobby/RandomMapTab.cpp
  24. 11 0
      client/lobby/SelectionTab.cpp
  25. 2 0
      client/lobby/SelectionTab.h
  26. 3 1
      client/netlag/PackRollbackGeneratorVisitor.cpp
  27. 89 11
      client/render/AssetGenerator.cpp
  28. 2 0
      client/render/AssetGenerator.h
  29. 2 0
      client/render/CanvasImage.cpp
  30. 59 32
      client/widgets/CTextInput.cpp
  31. 2 2
      client/widgets/CTextInput.h
  32. 15 4
      client/widgets/Images.cpp
  33. 3 0
      client/widgets/Images.h
  34. 5 3
      client/widgets/MiscWidgets.cpp
  35. 25 1
      client/windows/CCastleInterface.cpp
  36. 12 0
      client/windows/CCastleInterface.h
  37. 3 3
      client/windows/CCreatureWindow.cpp
  38. 4 3
      client/windows/CHeroOverview.cpp
  39. 2 2
      client/windows/CHeroOverview.h
  40. 4 0
      client/windows/CSpellWindow.cpp
  41. 3 1
      client/windows/CWindowObject.cpp
  42. 23 18
      client/windows/GUIClasses.cpp
  43. 3 3
      client/windows/GUIClasses.h
  44. 10 2
      config/bonuses.json
  45. 1 1
      config/factions/conflux.json
  46. 1 1
      config/factions/inferno.json
  47. 1 1
      config/schemas/townBuilding.json
  48. 19 7
      config/terrainViewPatterns.json
  49. 13 6
      docs/developers/Building_Windows.md
  50. 18 1
      docs/modders/Bonus/Bonus_Types.md
  51. 2 4
      docs/modders/Entities_Format/Town_Building_Format.md
  52. 2 2
      docs/players/Installation_macOS.md
  53. 1 1
      launcher/lib/innoextract
  54. 8 4
      launcher/modManager/cmodlistview_moc.cpp
  55. 26 1
      launcher/modManager/modstateitemmodel_moc.cpp
  56. 3 1
      launcher/modManager/modstateitemmodel_moc.h
  57. 355 176
      launcher/translation/belarusian.ts
  58. 355 176
      launcher/translation/bulgarian.ts
  59. 36 26
      launcher/translation/chinese.ts
  60. 31 21
      launcher/translation/czech.ts
  61. 12 12
      launcher/translation/english.ts
  62. 355 176
      launcher/translation/finnish.ts
  63. 69 41
      launcher/translation/french.ts
  64. 31 21
      launcher/translation/german.ts
  65. 355 176
      launcher/translation/greek.ts
  66. 69 41
      launcher/translation/hungarian.ts
  67. 69 41
      launcher/translation/italian.ts
  68. 185 174
      launcher/translation/japanese.ts
  69. 355 176
      launcher/translation/korean.ts
  70. 355 176
      launcher/translation/norwegian.ts
  71. 42 41
      launcher/translation/polish.ts
  72. 31 21
      launcher/translation/portuguese.ts
  73. 178 164
      launcher/translation/romanian.ts
  74. 89 48
      launcher/translation/russian.ts
  75. 69 41
      launcher/translation/spanish.ts
  76. 14 13
      launcher/translation/swedish.ts
  77. 355 176
      launcher/translation/turkish.ts
  78. 71 42
      launcher/translation/ukrainian.ts
  79. 69 41
      launcher/translation/vietnamese.ts
  80. 4 0
      lib/CMakeLists.txt
  81. 9 0
      lib/StartInfo.cpp
  82. 23 0
      lib/StartInfo.h
  83. 8 6
      lib/battle/CBattleInfoCallback.cpp
  84. 16 2
      lib/battle/DamageCalculator.cpp
  85. 2 1
      lib/battle/DamageCalculator.h
  86. 10 0
      lib/battle/Unit.cpp
  87. 1 0
      lib/battle/Unit.h
  88. 17 0
      lib/bonuses/BonusCustomTypes.cpp
  89. 23 2
      lib/bonuses/BonusCustomTypes.h
  90. 1 0
      lib/bonuses/BonusEnum.h
  91. 3 1
      lib/constants/Enumerations.h
  92. 3 1
      lib/constants/StringConstants.h
  93. 16 12
      lib/gameState/CGameState.cpp
  94. 0 2
      lib/gameState/CGameStateCampaign.h
  95. 8 0
      lib/json/JsonBonus.cpp
  96. 0 22
      lib/mapObjects/CGHeroInstance.cpp
  97. 0 2
      lib/mapObjects/CGHeroInstance.h
  98. 0 7
      lib/mapObjects/CGTownInstance.cpp
  99. 0 1
      lib/mapObjects/CGTownInstance.h
  100. 54 22
      lib/mapping/CDrawRoadsOperation.cpp

+ 3 - 1
AI/Nullkiller/Engine/PriorityEvaluator.cpp

@@ -281,7 +281,9 @@ uint64_t RewardEvaluator::getArmyReward(
 			for(const auto & stackInfo : info.reward.creatures)
 				rewardValue += stackInfo.getType()->getAIValue() * stackInfo.getCount();
 
-			totalValue += rewardValue > 0 ? rewardValue / (info.reward.grantedArtifacts.size() + info.reward.creatures.size()) : 0;
+			auto combined_size = std::min(static_cast<size_t>(1), info.reward.grantedArtifacts.size() + info.reward.creatures.size() + info.reward.grantedScrolls.size());
+
+			totalValue += rewardValue > 0 ? rewardValue / combined_size : 0;
 		}
 
 		return totalValue;

BIN
Mods/vcmi/Content/Sprites/lobby/battle-normal.png


BIN
Mods/vcmi/Content/Sprites/lobby/battle-pressed.png


+ 8 - 0
Mods/vcmi/Content/Sprites/lobby/battleButton.json

@@ -0,0 +1,8 @@
+{
+	"basepath" : "lobby/",
+	"images" :
+	[
+		{ "frame" : 0, "file" : "battle-normal.png"},
+		{ "frame" : 1, "file" : "battle-pressed.png"}
+	]
+}

+ 9 - 0
Mods/vcmi/Content/config/english.json

@@ -138,6 +138,13 @@
 	"vcmi.lobby.deleteFile" : "Do you want to delete following file?",
 	"vcmi.lobby.deleteFolder" : "Do you want to delete following folder?",
 	"vcmi.lobby.deleteMode" : "Switch to delete mode and back",
+	"vcmi.lobby.battleOnlyMode" : "Battle only mode",
+	"vcmi.lobby.battleOnlyModeBattlefield" : "Battlefield",
+	"vcmi.lobby.battleOnlyModeBattlefieldSelect" : "Select Battlefield",
+	"vcmi.lobby.battleOnlyModeHeroSelect" : "Select Hero",
+	"vcmi.lobby.battleOnlyModeCreatureSelect" : "Select Creature",
+	"vcmi.lobby.battleOnlyModeSelect" : "Select",
+	"vcmi.lobby.battleOnlyModeReset" : "Reset",
 	"vcmi.lobby.templatesSelect.hover" : "Templates",
 	"vcmi.lobby.templatesSelect.help" : "Search and select template",
 
@@ -970,6 +977,7 @@
 
 	"core.bonus.ADDITIONAL_ATTACK.description" : "{Additional attacks}\nUnit can attack an additional ${val} times", // TODO: alternative descriptions for melee/ranged effect range
 	"core.bonus.ADDITIONAL_RETALIATION.description" : "{Additional retaliations}\nUnit can retaliate ${val} extra times",
+	"core.bonus.ALWAYS_MAXIMUM_DAMAGE.description" : "{Maximum Damage}\nThis unit always deals the maximum possible damage",
 	"core.bonus.ATTACKS_ALL_ADJACENT.description" : "{Attack all around}\nAttacks all adjacent enemies in addition to the primary target",
 	"core.bonus.BLOCKS_RANGED_RETALIATION.description" : "{No ranged retaliation}\nThe enemy cannot retaliate when shot by this unit",
 	"core.bonus.BLOCKS_RETALIATION.description" : "{No retaliation}\nThe enemy cannot retaliate when attacked in melee by this unit",
@@ -1016,6 +1024,7 @@
 	"core.bonus.MANA_DRAIN.description" : "{Drains enemy mana}\nDrains ${val} mana every turn from enemy hero",
 	"core.bonus.MECHANICAL.description" : "{Mechanical}\nThis unit is immune to effects that only affect living and can be repaired",
 	"core.bonus.MIND_IMMUNITY.description" : "{Mind Spell Immunity}\nThis unit cannot be targeted by spells that affect its mind",
+	"core.bonus.MORE_DAMAGE_FROM_SPELL.description" : "{Vulnerable to ${subtype.spell}}\nThe damage taken by this unit when hit by a ${subtype.spell} is increased by ${val}%",
 	"core.bonus.NO_DISTANCE_PENALTY.description" : "{No distance penalty}\nRanged attacks deal full damage at any distance",
 	"core.bonus.NO_MELEE_PENALTY.description" : "{No melee penalty}\nThis ranged unit deals full damage with melee attacks",
 	"core.bonus.NO_MORALE.description" : "{Neutral Morale}\nCreature is immune to morale effects",

+ 7 - 0
Mods/vcmi/Content/config/german.json

@@ -138,6 +138,13 @@
 	"vcmi.lobby.deleteFile" : "Möchtet Ihr folgende Datei löschen?",
 	"vcmi.lobby.deleteFolder" : "Möchtet Ihr folgenden Ordner löschen?",
 	"vcmi.lobby.deleteMode" : "In den Löschmodus wechseln und zurück",
+	"vcmi.lobby.battleOnlyMode" : "Nur Kämpfen Modus",
+	"vcmi.lobby.battleOnlyModeBattlefield" : "Schlachtfeld",
+	"vcmi.lobby.battleOnlyModeBattlefieldSelect" : "Schlachtfeld auswählen",
+	"vcmi.lobby.battleOnlyModeHeroSelect" : "Helden auswählen",
+	"vcmi.lobby.battleOnlyModeCreatureSelect" : "Kreatur auswählen",
+	"vcmi.lobby.battleOnlyModeSelect" : "Wählen",
+	"vcmi.lobby.battleOnlyModeReset" : "Zurücksetzen",
 	"vcmi.lobby.templatesSelect.hover" : "Templates",
 	"vcmi.lobby.templatesSelect.help" : "Suche und wähle Template aus",
 

+ 1104 - 2
Mods/vcmi/Content/config/romanian.json

@@ -1,3 +1,1105 @@
 {
-
-}
+	"vcmi.adventureMap.monsterThreat.title"     : "\n\nAmenințare: ",
+	"vcmi.adventureMap.monsterThreat.levels.0"  : "Fără efort",
+	"vcmi.adventureMap.monsterThreat.levels.1"  : "Foarte slab",
+	"vcmi.adventureMap.monsterThreat.levels.2"  : "Slab",
+	"vcmi.adventureMap.monsterThreat.levels.3"  : "Puțin mai slab",
+	"vcmi.adventureMap.monsterThreat.levels.4"  : "Egalitate",
+	"vcmi.adventureMap.monsterThreat.levels.5"  : "Puțin mai puternic",
+	"vcmi.adventureMap.monsterThreat.levels.6"  : "Puternic",
+	"vcmi.adventureMap.monsterThreat.levels.7"  : "Foarte puternic",
+	"vcmi.adventureMap.monsterThreat.levels.8"  : "Provocator",
+	"vcmi.adventureMap.monsterThreat.levels.9"  : "Extrema",
+	"vcmi.adventureMap.monsterThreat.levels.10" : "Letala",
+	"vcmi.adventureMap.monsterThreat.levels.11" : "Imposibil",
+	"vcmi.adventureMap.monsterLevel"            : "\n\nNivel: %LEVEL \nOras: %TOWN \nAtac: %ATTACK_TYPE",
+	"vcmi.adventureMap.monsterMeleeType"        : "Apropiere",
+	"vcmi.adventureMap.monsterRangedType"       : "Distanță",
+	"vcmi.adventureMap.search.hover"            : "Caută obiect pe hartă",
+	"vcmi.adventureMap.search.help"             : "Selectează obiectul de căutat pe hartă.",
+	
+	"vcmi.adventureMap.confirmRestartGame"               : "Ești sigur că vrei să repornești jocul?",
+	"vcmi.adventureMap.noTownWithMarket"                 : "Nu există piețe disponibile!",
+	"vcmi.adventureMap.noTownWithTavern"                 : "Nu există cetăți disponibile cu taverne!",
+	"vcmi.adventureMap.spellUnknownProblem"              : "Există o problemă necunoscută cu această vrajă! Nu sunt disponibile informații suplimentare.",
+	"vcmi.adventureMap.playerAttacked"                   : "Jucătorul a fost atacat: %s",
+	"vcmi.adventureMap.moveCostDetails"                  : "Mutarea aici va costa {%TOTAL} puncte în total ({%TURNS} ture și {%POINTS} puncte). Vor rămâne {%REMAINING} puncte după mutare.",
+	"vcmi.adventureMap.moveCostDetailsNoTurns"           : "Mutarea aici va costa {%POINTS} puncte. Vor rămâne {%REMAINING} puncte după mutare.",
+	"vcmi.adventureMap.movementPointsHeroInfo"           : "(Puncte de mișcare: %REMAINING / %POINTS)",
+	"vcmi.adventureMap.replayOpponentTurnNotImplemented" : "Ne pare rău, redarea turei inamicului nu este încă implementată!",
+	
+	"vcmi.adventureMap.dwelling2" : "{%s}\n\nDorești să recrutezi %s sau %s?",
+	"vcmi.adventureMap.dwelling3" : "{%s}\n\nDorești să recrutezi %s, %s sau %s?",
+	
+	"vcmi.artifact.charges" : "Încărcări",
+	
+	"vcmi.battle.action.move"   : "Mută unitatea în locația specificată",
+	"vcmi.battle.action.info"   : "Afișează informațiile unității",
+	"vcmi.battle.action.shoot"  : "Folosește atacul la distanță",
+	"vcmi.battle.action.attack" : "Folosește atacul corp-la-corp",
+	"vcmi.battle.action.return" : "Atac corp-la-corp și retragere",
+	"vcmi.battle.action.genie"  : "Aruncă o vrajă benefică aleatorie",
+	
+	"vcmi.bonusSource.artifact"  : "Artefact",
+	"vcmi.bonusSource.creature"  : "Abilitate",
+	"vcmi.bonusSource.spell"     : "Vrajă",
+	"vcmi.bonusSource.hero"      : "Erou",
+	"vcmi.bonusSource.commander" : "Comandant",
+	"vcmi.bonusSource.other"     : "Altul",
+	
+	"vcmi.capitalColors.0" : "Roșu",
+	"vcmi.capitalColors.1" : "Albastru",
+	"vcmi.capitalColors.2" : "Bej",
+	"vcmi.capitalColors.3" : "Verde",
+	"vcmi.capitalColors.4" : "Portocaliu",
+	"vcmi.capitalColors.5" : "Mov",
+	"vcmi.capitalColors.6" : "Turcoaz",
+	"vcmi.capitalColors.7" : "Roz",
+	
+	"vcmi.heroOverview.startingArmy"     : "Unități de început",
+	"vcmi.heroOverview.warMachine"       : "Mașini de război",
+	"vcmi.heroOverview.secondarySkills"  : "Abilități secundare",
+	"vcmi.heroOverview.spells"           : "Vrăji",
+	
+	"vcmi.quickExchange.moveUnit"         : "Mută unitatea",
+	"vcmi.quickExchange.moveAllUnits"     : "Mută toate unitățile",
+	"vcmi.quickExchange.swapAllUnits"     : "Schimbă armatele",
+	"vcmi.quickExchange.moveAllArtifacts" : "Mută toate artefactele",
+	"vcmi.quickExchange.swapAllArtifacts" : "Schimbă artefactele",
+	
+	"vcmi.radialWheel.mergeSameUnit"     : "Combină creaturile identice",
+	"vcmi.radialWheel.fillSingleUnit"    : "Completează cu creaturi individuale",
+	"vcmi.radialWheel.splitSingleUnit"   : "Desparte o creatură individuală",
+	"vcmi.radialWheel.splitUnitEqually"  : "Împarte creaturile în mod egal",
+	"vcmi.radialWheel.moveUnit"          : "Mută creaturile într-o altă armată",
+	"vcmi.radialWheel.splitUnit"         : "Desparte creatura într-un alt slot",
+	
+	"vcmi.radialWheel.heroGetArmy"       : "Preia armata de la alt erou",
+	"vcmi.radialWheel.heroSwapArmy"      : "Schimbă armata cu alt erou",
+	"vcmi.radialWheel.heroExchange"      : "Deschide schimbul de eroi",
+	"vcmi.radialWheel.heroGetArtifacts"  : "Preia artefacte de la alt erou",
+	"vcmi.radialWheel.heroSwapArtifacts" : "Schimbă artefactele cu alt erou",
+	"vcmi.radialWheel.heroDismiss"       : "Concediază eroul",
+	"vcmi.radialWheel.upgradeCreatures"  : "Îmbunătățește toate creaturile",
+	
+	"vcmi.radialWheel.moveTop"    : "Mută sus",
+	"vcmi.radialWheel.moveUp"     : "Mută în sus",
+	"vcmi.radialWheel.moveDown"   : "Mută în jos",
+	"vcmi.radialWheel.moveBottom" : "Mută jos",
+	
+	"vcmi.randomMap.description"            : "Hartă creată de Generatorul de hărți aleatorii.\nȘablonul a fost %s, dimensiunea %dx%d, niveluri %d, jucători %d, calculatoare %d, apă %s, monștri %s, hartă VCMI",
+	"vcmi.randomMap.description.isHuman"    : ", %s este uman",
+	"vcmi.randomMap.description.townChoice" : ", alegerea cetății lui %s este %s",
+	"vcmi.randomMap.description.water.none"   : "fără",
+	"vcmi.randomMap.description.water.normal" : "normală",
+	"vcmi.randomMap.description.water.islands": "insule",
+	"vcmi.randomMap.description.monster.weak"   : "slabi",
+	"vcmi.randomMap.description.monster.normal" : "normali",
+	"vcmi.randomMap.description.monster.strong" : "puternici",
+	
+	"vcmi.overlay.battery"  : "Baterie",
+	"vcmi.overlay.charging"  : "Se încarcă",
+	
+	"vcmi.spellBook.search" : "căutare...",
+	"vcmi.spellBook.tab.hover" : "Vrăji %s",
+	"vcmi.spellBook.tab.help" : "Schimbă pentru a vedea vrăjile %s",
+	
+	"vcmi.spellResearch.canNotAfford" : "Nu îți permiți să înlocuiești {%SPELL1} cu {%SPELL2}. Dar poți totuși să renunți la această vrajă și să continui cercetarea.",
+	"vcmi.spellResearch.comeAgain" : "Cercetarea a fost deja făcută astăzi. Revino mâine.",
+	"vcmi.spellResearch.pay" : "Dorești să înlocuiești {%SPELL1} cu {%SPELL2}? Sau să renunți la această vrajă și să continui cercetarea?",
+	"vcmi.spellResearch.research" : "Cercetează această vrajă",
+	"vcmi.spellResearch.skip" : "Sari peste această vrajă",
+	"vcmi.spellResearch.abort" : "Anulează",
+	"vcmi.spellResearch.noMoreSpells" : "Nu mai sunt vrăji disponibile pentru cercetare.",
+	
+	"vcmi.mainMenu.serverConnecting" : "Se conectează...",
+	"vcmi.mainMenu.serverAddressEnter" : "Introdu adresa:",
+	"vcmi.mainMenu.serverConnectionFailed" : "Conectarea a eșuat",
+	"vcmi.mainMenu.serverClosing" : "Se închide...",
+	"vcmi.mainMenu.hostTCP" : "Găzduiește joc TCP/IP",
+	"vcmi.mainMenu.joinTCP" : "Alătură-te jocului TCP/IP",
+	
+	"vcmi.lobby.filepath" : "Calea fișierului",
+	"vcmi.lobby.creationDate" : "Data creării",
+	"vcmi.lobby.scenarioName" : "Numele scenariului",
+	"vcmi.lobby.mapPreview" : "Previzualizare hartă",
+	"vcmi.lobby.noPreview" : "fără previzualizare",
+	"vcmi.lobby.noUnderground" : "fără subteran",
+	"vcmi.lobby.sortDate" : "Sortează hărțile după data modificării",
+	"vcmi.lobby.backToLobby" : "Înapoi la lobby",
+	"vcmi.lobby.author" : "Autor",
+	"vcmi.lobby.handicap" : "Handicap",
+	"vcmi.lobby.handicap.resource" : "Oferă jucătorilor resurse suplimentare la început, pe lângă cele normale. Valorile negative sunt permise, dar totalul nu poate fi sub 0 (jucătorul nu începe niciodată cu resurse negative).",
+	"vcmi.lobby.handicap.income" : "Schimbă veniturile jucătorului cu procentul specificat. Se rotunjește în sus.",
+	"vcmi.lobby.handicap.growth" : "Schimbă rata de creștere a creaturilor din cetățile deținute de jucător. Se rotunjește în sus.",
+	"vcmi.lobby.deleteUnsupportedSave" : "{Salvări neacceptate găsite}\n\nVCMI a găsit %d fișiere de salvare care nu mai sunt compatibile, probabil din cauza diferențelor de versiune.\n\nVrei să le ștergi?",
+	"vcmi.lobby.deleteSaveGameTitle" : "Selectează un joc salvat pentru ștergere",
+	"vcmi.lobby.deleteMapTitle" : "Selectează un scenariu pentru ștergere",
+	"vcmi.lobby.deleteFile" : "Dorești să ștergi următorul fișier?",
+	"vcmi.lobby.deleteFolder" : "Dorești să ștergi următorul folder?",
+	"vcmi.lobby.deleteMode" : "Comută între modul de ștergere și cel normal",
+	"vcmi.lobby.battleOnlyMode" : "Mod doar luptă",
+	"vcmi.lobby.battleOnlyModeBattlefield" : "Câmp de luptă",
+	"vcmi.lobby.battleOnlyModeBattlefieldSelect" : "Selectează câmpul de luptă",
+	"vcmi.lobby.battleOnlyModeHeroSelect" : "Selectează erou",
+	"vcmi.lobby.battleOnlyModeCreatureSelect" : "Selectează creatură",
+	"vcmi.lobby.battleOnlyModeSelect" : "Selectează",
+	"vcmi.lobby.battleOnlyModeReset" : "Resetează",
+	"vcmi.lobby.templatesSelect.hover" : "Șabloane",
+	"vcmi.lobby.templatesSelect.help" : "Caută și selectează șablon",
+	
+	"vcmi.broadcast.failedLoadGame" : "Eroare la încărcarea jocului",
+	"vcmi.broadcast.command" : "Folosește '!help' pentru a lista comenzile disponibile",
+	"vcmi.broadcast.simturn.end" : "Turele simultane s-au încheiat",
+	"vcmi.broadcast.simturn.endBetween" : "Turele simultane dintre jucătorii %s și %s s-au încheiat",
+	"vcmi.broadcast.serverProblem" : "Serverul a întâmpinat o problemă",
+	"vcmi.broadcast.gameTerminated" : "jocul a fost încheiat",
+	"vcmi.broadcast.gameSavedAs" : "joc salvat ca",
+	"vcmi.broadcast.noCheater" : "Niciun trișor înregistrat!",
+	"vcmi.broadcast.playerCheater" : "Jucătorul %s este trișor!",
+	"vcmi.broadcast.statisticFile" : "Fișierele statistice pot fi găsite în directorul %s",
+	"vcmi.broadcast.help.commands" : "Comenzi disponibile pentru gazdă:",
+	"vcmi.broadcast.help.exit" : "'!exit' - termină imediat jocul curent",
+	"vcmi.broadcast.help.kick" : "'!kick <player>' - elimină jucătorul specificat din joc",
+	"vcmi.broadcast.help.save" : "'!save <filename>' - salvează jocul sub numele specificat",
+	"vcmi.broadcast.help.statistic" : "'!statistic' - salvează statisticile jocului ca fișier csv",
+	"vcmi.broadcast.help.commandsAll" : "Comenzi disponibile pentru toți jucătorii:",
+	"vcmi.broadcast.help.help" : "'!help' - afișează această listă de ajutor",
+	"vcmi.broadcast.help.cheaters" : "'!cheaters' - listează jucătorii care au folosit comenzi de cheat în timpul jocului",
+	"vcmi.broadcast.help.vote" : "'!vote' - permite schimbarea unor setări dacă toți jucătorii votează pentru",
+	"vcmi.broadcast.vote.allow" : "'!vote simturns allow X' - permite ture simultane pentru un număr specificat de zile sau până la contact",
+	"vcmi.broadcast.vote.force" : "'!vote simturns force X' - forțează ture simultane pentru un număr specificat de zile, blocând contactele între jucători",
+	"vcmi.broadcast.vote.abort" : "'!vote simturns abort' - oprește turele simultane după finalul acestei ture",
+	"vcmi.broadcast.vote.timer" : "'!vote timer prolong X' - prelungește cronometrul de bază pentru toți jucătorii cu numărul specificat de secunde",
+	"vcmi.broadcast.vote.noActive" : "Niciun vot activ!",
+	"vcmi.broadcast.vote.yes" : "da",
+	"vcmi.broadcast.vote.no" : "nu",
+	"vcmi.broadcast.vote.notRecognized" : "Comanda de vot nu a fost recunoscută!",
+	"vcmi.broadcast.vote.success.untilContacts" : "Vot reușit. Turele simultane vor continua %s zile, sau până la contact",
+	"vcmi.broadcast.vote.success.contactsBlocked" : "Vot reușit. Turele simultane vor continua %s zile. Contactele sunt blocate",
+	"vcmi.broadcast.vote.success.nextDay" : "Vot reușit. Turele simultane se vor încheia mâine",
+	"vcmi.broadcast.vote.success.timer" : "Vot reușit. Cronometrul pentru toți jucătorii a fost prelungit cu %s secunde",
+	"vcmi.broadcast.vote.aborted" : "Un jucător a votat împotrivă. Votul a fost anulat",
+	"vcmi.broadcast.vote.start.untilContacts" : "A început votul pentru a permite ture simultane pentru %s zile",
+	"vcmi.broadcast.vote.start.contactsBlocked" : "A început votul pentru a forța ture simultane pentru %s zile",
+	"vcmi.broadcast.vote.start.nextDay" : "A început votul pentru a încheia turele simultane începând de mâine",
+	"vcmi.broadcast.vote.start.timer" : "A început votul pentru a prelungi cronometrul pentru toți jucătorii cu %s secunde",
+	"vcmi.broadcast.vote.hint" : "Tastează '!vote yes' pentru a fi de acord sau '!vote no' pentru a vota împotrivă",
+	
+	"vcmi.lobby.login.title" : "VCMI Lobby Online",
+	"vcmi.lobby.login.username" : "Nume utilizator:",
+	"vcmi.lobby.login.connecting" : "Se conectează...",
+	"vcmi.lobby.login.error" : "Eroare de conexiune: %s",
+	"vcmi.lobby.login.create" : "Cont nou",
+	"vcmi.lobby.login.login" : "Autentificare",
+	"vcmi.lobby.login.as" : "Autentificat ca %s",
+	"vcmi.lobby.login.spectator" : "Spectator",
+	"vcmi.lobby.header.rooms" : "Camere de joc - %d",
+	"vcmi.lobby.header.channels" : "Canale de chat",
+	"vcmi.lobby.header.chat.global" : "Chat global al jocului - %s", // %s -> language name
+	"vcmi.lobby.header.chat.match" : "Chat din jocul anterior pe %s", // %s -> game start date & time
+	"vcmi.lobby.header.chat.player" : "Chat privat cu %s", // %s -> nickname of another player
+	"vcmi.lobby.header.history" : "Jocurile tale anterioare",
+	"vcmi.lobby.header.players" : "Jucători online - %d",
+	"vcmi.lobby.match.solo" : "Joc singleplayer",
+	"vcmi.lobby.match.duel" : "Joc cu %s", // %s -> nickname of another player
+	"vcmi.lobby.match.multi" : "%d jucători",
+	"vcmi.lobby.room.create.hover" : "Creează cameră nouă",
+	"vcmi.lobby.room.create.help" : "Creează o cameră nouă în lobby-ul online la care alți jucători se pot alătura.",
+	"vcmi.lobby.room.players.limit" : "Limită jucători",
+	"vcmi.lobby.room.description.public" : "Orice jucător se poate alătura camerei publice.",
+	"vcmi.lobby.room.description.private" : "Numai jucătorii invitați se pot alătura camerei private.",
+	"vcmi.lobby.room.description.new" : "Pentru a începe jocul, selectează un scenariu sau setează o hartă aleatorie.",
+	"vcmi.lobby.room.description.load" : "Pentru a începe jocul, folosește unul dintre jocurile tale salvate.",
+	"vcmi.lobby.room.description.limit" : "Până la %d jucători pot intra în camera ta, inclusiv tu.",
+	"vcmi.lobby.invite.header" : "Invită jucători",
+	"vcmi.lobby.invite.notification" : "Un jucător te-a invitat în camera sa de joc. Te poți alătura acum camerei private.",
+	"vcmi.lobby.preview.title" : "Alătură-te camerei de joc",
+	"vcmi.lobby.preview.subtitle" : "Joc pe %s, găzduit de %s", //TL Note: 1) name of map or RMG template 2) nickname of game host
+	"vcmi.lobby.preview.version" : "Versiunea jocului:",
+	"vcmi.lobby.preview.players" : "Jucători:",
+	"vcmi.lobby.preview.mods" : "Moduri folosite:",
+	"vcmi.lobby.preview.allowed" : "Te poți alătura camerei de joc?",
+	"vcmi.lobby.preview.error.header" : "Nu se poate intra în această cameră.",
+	"vcmi.lobby.preview.error.playing" : "Trebuie să părăsești mai întâi jocul curent.",
+	"vcmi.lobby.preview.error.full" : "Camera este deja plină.",
+	"vcmi.lobby.preview.error.busy" : "Camera nu mai acceptă jucători noi.",
+	"vcmi.lobby.preview.error.invite" : "Nu ai fost invitat în această cameră.",
+	"vcmi.lobby.preview.error.mods" : "Folosești un set diferit de moduri.",
+	"vcmi.lobby.preview.error.version" : "Folosești o versiune diferită de VCMI.",
+	"vcmi.lobby.channel.add" : "Adaugă canal",
+	"vcmi.lobby.channel.sendMessage.hover" : "Trimite mesaj",
+	"vcmi.lobby.channel.sendMessage.help" : "Trimite mesaj",
+	"vcmi.lobby.room.new" : "Joc nou",
+	"vcmi.lobby.room.load" : "Încarcă joc",
+	"vcmi.lobby.room.type" : "Tip cameră",
+	"vcmi.lobby.room.mode" : "Mod de joc",
+	"vcmi.lobby.room.state.public" : "Public",
+	"vcmi.lobby.room.state.private" : "Privat",
+	"vcmi.lobby.room.state.busy" : "În joc",
+	"vcmi.lobby.room.state.invited" : "Invitat",
+	"vcmi.lobby.mod.state.compatible" : "Compatibil",
+	"vcmi.lobby.mod.state.disabled" : "Trebuie activat",
+	"vcmi.lobby.mod.state.version" : "Versiune incompatibilă",
+	"vcmi.lobby.mod.state.excessive" : "Trebuie dezactivat",
+	"vcmi.lobby.mod.state.missing" : "Neinstalat",
+	"vcmi.lobby.pvp.coin.hover" : "Monedă",
+	"vcmi.lobby.pvp.coin.help" : "Aruncă o monedă",
+	"vcmi.lobby.pvp.randomTown.hover" : "Cetate aleatorie",
+	"vcmi.lobby.pvp.randomTown.help" : "Scrie o cetate aleatorie în chat",
+	"vcmi.lobby.pvp.randomTownVs.hover" : "Cetate aleatorie vs.",
+	"vcmi.lobby.pvp.randomTownVs.help" : "Scrie două cetăți aleatorii în chat",
+	"vcmi.lobby.pvp.versus" : "vs.",
+	
+	"vcmi.client.errors.invalidMap" : "{Hartă sau campanie invalidă}\n\nEșec la pornirea jocului! Harta sau campania selectată poate fi invalidă sau coruptă. Motiv:\n%s",
+	"vcmi.client.errors.modLoadingFailure" : "{Eroare la încărcarea modurilor}\n\nAu fost găsite probleme critice la încărcarea modurilor! Jocul poate funcționa incorect sau se poate bloca! Actualizează sau dezactivează următoarele moduri:\n\n",
+	"vcmi.server.errors.disconnected" : "{Eroare de rețea}\n\nConexiunea la serverul de joc a fost pierdută!",
+	"vcmi.server.errors.playerLeft" : "{Jucător deconectat}\n\nJucătorul %s s-a deconectat din joc!", //%s -> player color
+	"vcmi.server.errors.existingProcess" : "Un alt proces VCMI server rulează deja. Închide-l înainte de a începe un joc nou.",
+	"vcmi.server.errors.modsToEnable" : "{Următoarele moduri sunt necesare}",
+	"vcmi.server.errors.modsToDisable" : "{Următoarele moduri trebuie dezactivate}",
+	"vcmi.server.errors.saveFile.unknownEntity" : "Eroare la încărcarea salvării! Entitate necunoscută '%s' găsită în fișierul salvat! Salvarea poate fi incompatibilă cu versiunea curentă a modurilor!",
+	"vcmi.server.errors.campOrMapFile.unknownEntity" : "Eroare la încărcarea fișierului! Entitate necunoscută '%s' găsită! Fișierul poate fi incompatibil cu versiunea curentă a modurilor!",
+	"vcmi.server.errors.wrongIdentified" : "Ai fost identificat ca jucător %s, dar se aștepta %s",
+	"vcmi.server.errors.notAllowed" : "Nu ai permisiunea să efectuezi această acțiune!",
+	
+	"vcmi.dimensionDoor.seaToLandError" : "Nu este posibilă teleportarea de pe mare pe uscat sau invers folosind Poarta Dimensiunilor.",
+	
+	"vcmi.settingsMainWindow.generalTab.hover" : "General",
+	"vcmi.settingsMainWindow.generalTab.help" : "Comută la fila Opțiuni Generale, care conține setările legate de comportamentul general al clientului de joc.",
+	"vcmi.settingsMainWindow.battleTab.hover" : "Luptă",
+	"vcmi.settingsMainWindow.battleTab.help" : "Comută la fila Opțiuni Luptă, care permite configurarea comportamentului jocului în timpul bătăliilor.",
+	"vcmi.settingsMainWindow.adventureTab.hover" : "Hartă",
+	"vcmi.settingsMainWindow.adventureTab.help" : "Comută la fila Opțiuni Hartă (harta este secțiunea jocului unde jucătorii pot controla mișcările eroilor).",
+	
+	"vcmi.keyBindings.button.hover" : "Comenzi rapide",
+	"vcmi.keyBindings.button.help" : "{Comenzi rapide}\n\nAfișează meniul pentru vizualizarea și ajustarea tastelor rapide",
+	"vcmi.keyBindings.editButton.help" : "Editează combinația de taste",
+	"vcmi.keyBindings.input" : "Schimbă combinația de taste pentru {%s}.\n\nIntrodu o tastă sau o combinație. Fă clic în afară pentru a anula.",
+	"vcmi.keyBindings.inputSet" : "Combinația de taste pentru {%s} va fi schimbată în {%s}.\n\nAdaugi la combinațiile existente? Altfel va fi înlocuită.",
+	"vcmi.keyBindings.popup" : "Pentru {%s} sunt configurate următoarele taste:\n\n",
+	"vcmi.keyBindings.reset" : "Resetează",
+	"vcmi.keyBindings.reset.help" : "{Resetează}\n\nResetează combinațiile de taste la valorile implicite",
+	"vcmi.keyBindings.resetConfirm" : "Vrei să resetezi toate combinațiile de taste la valorile implicite?",
+	"vcmi.keyBindings.group.keyboard" : "Tastatură",
+	"vcmi.keyBindings.group.joystickAxes" : "Axe joystick",
+	"vcmi.keyBindings.group.joystickButtons" : "Butoane joystick",
+	"vcmi.keyBindings.keyBinding.adventureCastSpell" : "Hartă: aruncă vrajă",
+	"vcmi.keyBindings.keyBinding.adventureDigGrail" : "Hartă: sapă pentru Graal",
+	"vcmi.keyBindings.keyBinding.adventureEndTurn" : "Hartă: termină tura",
+	"vcmi.keyBindings.keyBinding.adventureExitWorldView" : "Hartă: ieșire din vizualizarea globală",
+	"vcmi.keyBindings.keyBinding.adventureFirstHero" : "Hartă: primul erou",
+	"vcmi.keyBindings.keyBinding.adventureFirstTown" : "Hartă: prima cetate",
+	"vcmi.keyBindings.keyBinding.adventureGameOptions" : "Hartă: opțiuni joc",
+	"vcmi.keyBindings.keyBinding.adventureKingdomOverview" : "Hartă: prezentare regat",
+	"vcmi.keyBindings.keyBinding.adventureLoadGame" : "Hartă: încarcă joc",
+	"vcmi.keyBindings.keyBinding.adventureMainMenu" : "Hartă: meniu principal",
+	"vcmi.keyBindings.keyBinding.adventureMarketplace" : "Hartă: piață",
+	"vcmi.keyBindings.keyBinding.adventureMoveHero" : "Hartă: mută eroul",
+	"vcmi.keyBindings.keyBinding.adventureMoveHeroEE" : "Hartă: mută eroul EE",
+	"vcmi.keyBindings.keyBinding.adventureMoveHeroNE" : "Hartă: mută eroul NE",
+	"vcmi.keyBindings.keyBinding.adventureMoveHeroNN": "Hartă: mută eroul NN",
+	"vcmi.keyBindings.keyBinding.adventureMoveHeroNW": "Hartă: mută eroul NV",
+	"vcmi.keyBindings.keyBinding.adventureMoveHeroSE": "Hartă: mută eroul SE",
+	"vcmi.keyBindings.keyBinding.adventureMoveHeroSS": "Hartă: mută eroul SS",
+	"vcmi.keyBindings.keyBinding.adventureMoveHeroSW": "Hartă: mută eroul SV",
+	"vcmi.keyBindings.keyBinding.adventureMoveHeroWW": "Hartă: mută eroul VV",
+	"vcmi.keyBindings.keyBinding.adventureNewGame": "Hartă: joc nou",
+	"vcmi.keyBindings.keyBinding.adventureNextHero": "Hartă: erou următor",
+	"vcmi.keyBindings.keyBinding.adventureNextObject": "Hartă: obiect următor",
+	"vcmi.keyBindings.keyBinding.adventureNextTown": "Hartă: cetate următoare",
+	"vcmi.keyBindings.keyBinding.adventureQuestLog": "Hartă: jurnal misiuni",
+	"vcmi.keyBindings.keyBinding.adventureQuitGame": "Hartă: ieșire din joc",
+	"vcmi.keyBindings.keyBinding.adventureReplayTurn": "Hartă: redă tura",
+	"vcmi.keyBindings.keyBinding.adventureRestartGame": "Hartă: repornește jocul",
+	"vcmi.keyBindings.keyBinding.adventureSaveGame": "Hartă: salvează jocul",
+	"vcmi.keyBindings.keyBinding.adventureSetHeroAsleep": "Hartă: pune eroul la somn",
+	"vcmi.keyBindings.keyBinding.adventureSetHeroAwake": "Hartă: trezește eroul",
+	"vcmi.keyBindings.keyBinding.adventureThievesGuild": "Hartă: bresla hoților",
+	"vcmi.keyBindings.keyBinding.adventureToggleGrid": "Hartă: comută grila",
+	"vcmi.keyBindings.keyBinding.adventureToggleVisitable": "Hartă: comută obiectele vizitabile",
+	"vcmi.keyBindings.keyBinding.adventureToggleBlocked": "Hartă: comută blocajele",
+	"vcmi.keyBindings.keyBinding.adventureToggleMapLevel": "Hartă: comută nivelul hărții",
+	"vcmi.keyBindings.keyBinding.adventureToggleSleep": "Hartă: comută somnul eroilor",
+	"vcmi.keyBindings.keyBinding.adventureTrackHero": "Hartă: urmărește eroul",
+	"vcmi.keyBindings.keyBinding.adventureViewPuzzle": "Hartă: vizualizează puzzle-ul",
+	"vcmi.keyBindings.keyBinding.adventureViewScenario": "Hartă: vizualizează scenariul",
+	"vcmi.keyBindings.keyBinding.adventureViewSelected": "Hartă: vizualizează selecția",
+	"vcmi.keyBindings.keyBinding.adventureViewWorld": "Hartă: vizualizează lumea",
+	"vcmi.keyBindings.keyBinding.adventureViewWorld1": "Hartă: vizualizează lumea 1",
+	"vcmi.keyBindings.keyBinding.adventureViewWorld2": "Hartă: vizualizează lumea 2",
+	"vcmi.keyBindings.keyBinding.adventureViewWorld4": "Hartă: vizualizează lumea 4",
+	"vcmi.keyBindings.keyBinding.adventureVisitObject": "Hartă: vizitează obiect",
+	"vcmi.keyBindings.keyBinding.adventureZoomIn": "Hartă: mărește",
+	"vcmi.keyBindings.keyBinding.adventureZoomOut": "Hartă: micșorează",
+	"vcmi.keyBindings.keyBinding.adventureZoomReset": "Hartă: resetare zoom",
+	"vcmi.keyBindings.keyBinding.adventureSearch": "Hartă: caută",
+	"vcmi.keyBindings.keyBinding.adventureSearchContinue": "Hartă: continuă căutarea",
+	"vcmi.keyBindings.keyBinding.battleAutocombat": "Luptă: auto-luptă",
+	"vcmi.keyBindings.keyBinding.battleAutocombatEnd": "Luptă: încheie auto-lupta",
+	"vcmi.keyBindings.keyBinding.battleCastSpell": "Luptă: aruncă vrajă",
+	"vcmi.keyBindings.keyBinding.battleConsoleDown": "Luptă: consolă jos",
+	"vcmi.keyBindings.keyBinding.battleConsoleUp": "Luptă: consolă sus",
+	"vcmi.keyBindings.keyBinding.battleDefend": "Luptă: apără-te",
+	"vcmi.keyBindings.keyBinding.battleOpenActiveUnit": "Luptă: deschide unitatea activă",
+	"vcmi.keyBindings.keyBinding.battleOpenHoveredUnit": "Luptă: deschide unitatea deasupra cursorului",
+	"vcmi.keyBindings.keyBinding.battleRetreat": "Luptă: retragere",
+	"vcmi.keyBindings.keyBinding.battleToggleQuickSpell": "Luptă: comută vraja rapidă",
+	"vcmi.keyBindings.keyBinding.battleSpellShortcut0": "Luptă: scurtătură vrajă 0",
+	"vcmi.keyBindings.keyBinding.battleSpellShortcut1": "Luptă: scurtătură vrajă 1",
+	"vcmi.keyBindings.keyBinding.battleSpellShortcut2": "Luptă: scurtătură vrajă 2",
+	"vcmi.keyBindings.keyBinding.battleSpellShortcut3": "Luptă: scurtătură vrajă 3",
+	"vcmi.keyBindings.keyBinding.battleSpellShortcut4": "Luptă: scurtătură vrajă 4",
+	"vcmi.keyBindings.keyBinding.battleSpellShortcut5": "Luptă: scurtătură vrajă 5",
+	"vcmi.keyBindings.keyBinding.battleSpellShortcut6": "Luptă: scurtătură vrajă 6",
+	"vcmi.keyBindings.keyBinding.battleSpellShortcut7": "Luptă: scurtătură vrajă 7",
+	"vcmi.keyBindings.keyBinding.battleSpellShortcut8": "Luptă: scurtătură vrajă 8",
+	"vcmi.keyBindings.keyBinding.battleSpellShortcut9": "Luptă: scurtătură vrajă 9",
+	"vcmi.keyBindings.keyBinding.battleSpellShortcut10": "Luptă: scurtătură vrajă 10",
+	"vcmi.keyBindings.keyBinding.battleSpellShortcut11": "Luptă: scurtătură vrajă 11",
+	"vcmi.keyBindings.keyBinding.battleSurrender": "Luptă: predare",
+	"vcmi.keyBindings.keyBinding.battleTacticsEnd": "Luptă: finalizează tactica",
+	"vcmi.keyBindings.keyBinding.battleTacticsNext": "Luptă: unitate tactică următoare",
+	"vcmi.keyBindings.keyBinding.battleToggleHeroesStats": "Luptă: comută statisticile eroilor",
+	"vcmi.keyBindings.keyBinding.battleToggleQueue": "Luptă: comută ordinea unităților",
+	"vcmi.keyBindings.keyBinding.battleUseCreatureSpell": "Luptă: folosește vraja creaturii",
+	"vcmi.keyBindings.keyBinding.battleWait": "Luptă: așteaptă",
+	"vcmi.keyBindings.keyBinding.exchangeArmySwap": "Schimb: inversează armatele",
+	"vcmi.keyBindings.keyBinding.exchangeArmyToLeft": "Schimb: armata spre stânga",
+	"vcmi.keyBindings.keyBinding.exchangeArmyToRight": "Schimb: armata spre dreapta",
+	"vcmi.keyBindings.keyBinding.exchangeArtifactsSwap": "Schimb: inversează artefactele",
+	"vcmi.keyBindings.keyBinding.exchangeArtifactsToLeft": "Schimb: artefacte spre stânga",
+	"vcmi.keyBindings.keyBinding.exchangeArtifactsToRight": "Schimb: artefacte spre dreapta",
+	"vcmi.keyBindings.keyBinding.exchangeBackpackLeft": "Schimb: rucsac stânga",
+	"vcmi.keyBindings.keyBinding.exchangeBackpackRight": "Schimb: rucsac dreapta",
+	"vcmi.keyBindings.keyBinding.exchangeBackpackSwap": "Schimb: inversează rucsacul",
+	"vcmi.keyBindings.keyBinding.exchangeBackpackToLeft": "Schimb: rucsac spre stânga",
+	"vcmi.keyBindings.keyBinding.exchangeBackpackToRight": "Schimb: rucsac spre dreapta",
+	"vcmi.keyBindings.keyBinding.exchangeEquippedSwap": "Schimb: inversează echipamentul",
+	"vcmi.keyBindings.keyBinding.exchangeEquippedToLeft": "Schimb: echipament spre stânga",
+	"vcmi.keyBindings.keyBinding.exchangeEquippedToRight": "Schimb: echipament spre dreapta",
+	"vcmi.keyBindings.keyBinding.gameActivateConsole": "Joc: activează consola",
+	"vcmi.keyBindings.keyBinding.globalAccept": "Global: acceptă",
+	"vcmi.keyBindings.keyBinding.globalBackspace": "Global: șterge caracter",
+	"vcmi.keyBindings.keyBinding.globalCancel": "Global: anulează",
+	"vcmi.keyBindings.keyBinding.globalFullscreen": "Global: ecran complet",
+	"vcmi.keyBindings.keyBinding.globalMoveFocus": "Global: mută focalizarea",
+	"vcmi.keyBindings.keyBinding.globalOptions": "Global: opțiuni",
+	"vcmi.keyBindings.keyBinding.globalReturn": "Global: confirmă",
+	"vcmi.keyBindings.keyBinding.heroArmySplit": "Erou: împarte armata",
+	"vcmi.keyBindings.keyBinding.heroBackpack": "Erou: rucsac",
+	"vcmi.keyBindings.keyBinding.heroCommander": "Erou: comandant",
+	"vcmi.keyBindings.keyBinding.heroCostumeLoad0": "Erou: încarcă echipament 0",
+	"vcmi.keyBindings.keyBinding.heroCostumeLoad1": "Erou: încarcă echipament 1",
+	"vcmi.keyBindings.keyBinding.heroCostumeLoad2": "Erou: încarcă echipament 2",
+	"vcmi.keyBindings.keyBinding.heroCostumeLoad3": "Erou: încarcă echipament 3",
+	"vcmi.keyBindings.keyBinding.heroCostumeLoad4": "Erou: încarcă echipament 4",
+	"vcmi.keyBindings.keyBinding.heroCostumeLoad5": "Erou: încarcă echipament 5",
+	"vcmi.keyBindings.keyBinding.heroCostumeLoad6": "Erou: încarcă echipament 6",
+	"vcmi.keyBindings.keyBinding.heroCostumeLoad7": "Erou: încarcă echipament 7",
+	"vcmi.keyBindings.keyBinding.heroCostumeLoad8": "Erou: încarcă echipament 8",
+	"vcmi.keyBindings.keyBinding.heroCostumeLoad9": "Erou: încarcă echipament 9",
+	"vcmi.keyBindings.keyBinding.heroCostumeSave0": "Erou: salvează echipament 0",
+	"vcmi.keyBindings.keyBinding.heroCostumeSave1": "Erou: salvează echipament 1",
+	"vcmi.keyBindings.keyBinding.heroCostumeSave2": "Erou: salvează echipament 2",
+	"vcmi.keyBindings.keyBinding.heroCostumeSave3": "Erou: salvează echipament 3",
+	"vcmi.keyBindings.keyBinding.heroCostumeSave4": "Erou: salvează echipament 4",
+	"vcmi.keyBindings.keyBinding.heroCostumeSave5": "Erou: salvează echipament 5",
+	"vcmi.keyBindings.keyBinding.heroCostumeSave6": "Erou: salvează echipament 6",
+	"vcmi.keyBindings.keyBinding.heroCostumeSave7": "Erou: salvează echipament 7",
+	"vcmi.keyBindings.keyBinding.heroCostumeSave8": "Erou: salvează echipament 8",
+	"vcmi.keyBindings.keyBinding.heroCostumeSave9": "Erou: salvează echipament 9",
+	"vcmi.keyBindings.keyBinding.heroDismiss": "Erou: concediază",
+	"vcmi.keyBindings.keyBinding.heroLooseFormation": "Erou: formație largă",
+	"vcmi.keyBindings.keyBinding.heroTightFormation": "Erou: formație strânsă",
+	"vcmi.keyBindings.keyBinding.heroToggleTactics": "Erou: comută tactica",
+	"vcmi.keyBindings.keyBinding.highScoresCampaigns": "Clasamente: campanii",
+	"vcmi.keyBindings.keyBinding.highScoresReset": "Clasamente: resetare",
+	"vcmi.keyBindings.keyBinding.highScoresStatistics": "Clasamente: statistici",
+	"vcmi.keyBindings.keyBinding.highScoresScenarios": "Clasamente: scenarii",
+	"vcmi.keyBindings.keyBinding.kingdomHeroesTab": "Regat: fila eroi",
+	"vcmi.keyBindings.keyBinding.kingdomTownsTab": "Regat: fila cetăți",
+	"vcmi.keyBindings.keyBinding.lobbyAdditionalOptions": "Lobby: opțiuni suplimentare",
+	"vcmi.keyBindings.keyBinding.lobbyBeginCampaign": "Lobby: începe campanie",
+	"vcmi.keyBindings.keyBinding.lobbyBeginStandardGame": "Lobby: începe joc standard",
+	"vcmi.keyBindings.keyBinding.lobbyExtraOptions": "Lobby: opțiuni extra",
+	"vcmi.keyBindings.keyBinding.lobbyFlipCoin": "Lobby: aruncă monedă",
+	"vcmi.keyBindings.keyBinding.lobbyInvitePlayers": "Lobby: invită jucători",
+	"vcmi.keyBindings.keyBinding.lobbyLoadGame": "Lobby: încarcă joc",
+	"vcmi.keyBindings.keyBinding.lobbyRandomMap": "Lobby: hartă aleatorie",
+	"vcmi.keyBindings.keyBinding.lobbyRandomTown": "Lobby: cetate aleatorie",
+	"vcmi.keyBindings.keyBinding.lobbyRandomTownVs": "Lobby: cetate aleatorie vs",
+	"vcmi.keyBindings.keyBinding.lobbyHandicap": "Lobby: handicap",
+	"vcmi.keyBindings.keyBinding.lobbyReplayVideo": "Lobby: redă video",
+	"vcmi.keyBindings.keyBinding.lobbySaveGame": "Lobby: salvează joc",
+	"vcmi.keyBindings.keyBinding.lobbySelectScenario": "Lobby: selectează scenariu",
+	"vcmi.keyBindings.keyBinding.lobbyToggleChat": "Lobby: comută chat",
+	"vcmi.keyBindings.keyBinding.lobbyTurnOptions": "Lobby: opțiuni tură",
+	"vcmi.keyBindings.keyBinding.lobbyCampaignSets": "Lobby: seturi campanie",
+	"vcmi.keyBindings.keyBinding.mainMenuBack": "Meniu principal: înapoi",
+	"vcmi.keyBindings.keyBinding.mainMenuCampaign": "Meniu principal: campanie",
+	"vcmi.keyBindings.keyBinding.mainMenuCampaignAb": "Meniu principal: campanie AB",
+	"vcmi.keyBindings.keyBinding.mainMenuCampaignCustom": "Meniu principal: campanie personalizată",
+	"vcmi.keyBindings.keyBinding.mainMenuCampaignRoe": "Meniu principal: campanie RoE",
+	"vcmi.keyBindings.keyBinding.mainMenuCampaignSod": "Meniu principal: campanie SoD",
+	"vcmi.keyBindings.keyBinding.mainMenuCampaignChr": "Meniu principal: campanie Chronicles",
+	"vcmi.keyBindings.keyBinding.mainMenuCampaignHota": "Meniu principal: campanie HotA",
+	"vcmi.keyBindings.keyBinding.mainMenuCampaignWog": "Meniu principal: campanie WoG",
+	"vcmi.keyBindings.keyBinding.mainMenuCampaignVCMI": "Meniu principal: campanie VCMI",
+	"vcmi.keyBindings.keyBinding.mainMenuCredits": "Meniu principal: credite",
+	"vcmi.keyBindings.keyBinding.mainMenuHighScores": "Meniu principal: clasamente",
+	"vcmi.keyBindings.keyBinding.mainMenuHostGame": "Meniu principal: găzduiește joc",
+	"vcmi.keyBindings.keyBinding.mainMenuHotseat": "Meniu principal: hotseat",
+	"vcmi.keyBindings.keyBinding.mainMenuJoinGame": "Meniu principal: alătură-te jocului",
+	"vcmi.keyBindings.keyBinding.mainMenuLoadGame": "Meniu principal: încarcă joc",
+	"vcmi.keyBindings.keyBinding.mainMenuLobby": "Meniu principal: lobby",
+	"vcmi.keyBindings.keyBinding.mainMenuMultiplayer": "Meniu principal: multiplayer",
+	"vcmi.keyBindings.keyBinding.mainMenuNewGame": "Meniu principal: joc nou",
+	"vcmi.keyBindings.keyBinding.mainMenuQuit": "Meniu principal: ieșire",
+	"vcmi.keyBindings.keyBinding.mainMenuSingleplayer": "Meniu principal: singleplayer",
+	"vcmi.keyBindings.keyBinding.mainMenuTutorial": "Meniu principal: tutorial",
+	"vcmi.keyBindings.keyBinding.mapsSizeAll": "Hărți: toate dimensiunile",
+	"vcmi.keyBindings.keyBinding.mapsSizeL": "Hărți: dimensiune L",
+	"vcmi.keyBindings.keyBinding.mapsSizeM": "Hărți: dimensiune M",
+	"vcmi.keyBindings.keyBinding.mapsSizeS": "Hărți: dimensiune S",
+	"vcmi.keyBindings.keyBinding.mapsSizeXl": "Hărți: dimensiune XL",
+	"vcmi.keyBindings.keyBinding.mapsSortChangedate": "Hărți: sortare după dată",
+	"vcmi.keyBindings.keyBinding.mapsSortDefeat": "Hărți: sortare după înfrângere",
+	"vcmi.keyBindings.keyBinding.mapsSortFormat": "Hărți: sortare după format",
+	"vcmi.keyBindings.keyBinding.mapsSortMaps": "Hărți: sortare hărți",
+	"vcmi.keyBindings.keyBinding.mapsSortName": "Hărți: sortare după nume",
+	"vcmi.keyBindings.keyBinding.mapsSortPlayers": "Hărți: sortare după jucători",
+	"vcmi.keyBindings.keyBinding.mapsSortSize": "Hărți: sortare după dimensiune",
+	"vcmi.keyBindings.keyBinding.mapsSortVictory": "Hărți: sortare după victorie",
+	"vcmi.keyBindings.keyBinding.marketArtifactExperience": "Piață: artefact - experiență",
+	"vcmi.keyBindings.keyBinding.marketArtifactResource": "Piață: artefact - resurse",
+	"vcmi.keyBindings.keyBinding.marketCreatureExperience": "Piață: creatură - experiență",
+	"vcmi.keyBindings.keyBinding.marketCreatureResource": "Piață: creatură - resurse",
+	"vcmi.keyBindings.keyBinding.marketDeal": "Piață: tranzacție",
+	"vcmi.keyBindings.keyBinding.marketMaxAmount": "Piață: cantitate maximă",
+	"vcmi.keyBindings.keyBinding.marketResourceArtifact": "Piață: resursă - artefact",
+	"vcmi.keyBindings.keyBinding.marketResourcePlayer": "Piață: resursă - jucător",
+	"vcmi.keyBindings.keyBinding.marketResourceResource": "Piață: resursă - resursă",
+	"vcmi.keyBindings.keyBinding.marketSacrificeAll": "Piață: sacrifică tot",
+	"vcmi.keyBindings.keyBinding.marketSacrificeBackpack": "Piață: sacrifică rucsacul",
+	"vcmi.keyBindings.keyBinding.moveDown": "Mută jos",
+	"vcmi.keyBindings.keyBinding.moveFirst": "Mută primul",
+	"vcmi.keyBindings.keyBinding.moveLast": "Mută ultimul",
+	"vcmi.keyBindings.keyBinding.moveLeft": "Mută stânga",
+	"vcmi.keyBindings.keyBinding.movePageDown": "Mută pagină jos",
+	"vcmi.keyBindings.keyBinding.movePageUp": "Mută pagină sus",
+	"vcmi.keyBindings.keyBinding.moveRight": "Mută dreapta",
+	"vcmi.keyBindings.keyBinding.moveUp": "Mută sus",
+	"vcmi.keyBindings.keyBinding.recruitmentMax": "Recrutare: maxim",
+	"vcmi.keyBindings.keyBinding.recruitmentMin": "Recrutare: minim",
+	"vcmi.keyBindings.keyBinding.recruitmentSwitchLevel": "Recrutare: schimbă nivelul",
+	"vcmi.keyBindings.keyBinding.recruitmentUpgrade": "Recrutare: upgrade",
+	"vcmi.keyBindings.keyBinding.recruitmentUpgradeAll": "Recrutare: upgrade total",
+	"vcmi.keyBindings.keyBinding.selectIndex1": "Selectează indice 1",
+	"vcmi.keyBindings.keyBinding.selectIndex2": "Selectează indice 2",
+	"vcmi.keyBindings.keyBinding.selectIndex3": "Selectează indice 3",
+	"vcmi.keyBindings.keyBinding.selectIndex4": "Selectează indice 4",
+	"vcmi.keyBindings.keyBinding.selectIndex5": "Selectează indice 5",
+	"vcmi.keyBindings.keyBinding.selectIndex6": "Selectează indice 6",
+	"vcmi.keyBindings.keyBinding.selectIndex7": "Selectează indice 7",
+	"vcmi.keyBindings.keyBinding.selectIndex8": "Selectează indice 8",
+	"vcmi.keyBindings.keyBinding.settingsLoadGame": "Setări: încarcă joc",
+	"vcmi.keyBindings.keyBinding.settingsNewGame": "Setări: joc nou",
+	"vcmi.keyBindings.keyBinding.settingsQuitGame": "Setări: ieșire din joc",
+	"vcmi.keyBindings.keyBinding.settingsRestartGame": "Setări: repornește jocul",
+	"vcmi.keyBindings.keyBinding.settingsSaveGame": "Setări: salvează joc",
+	"vcmi.keyBindings.keyBinding.settingsToMainMenu": "Setări: mergi la meniul principal",
+	"vcmi.keyBindings.keyBinding.spectateSkipBattle": "Spectate: sari peste luptă",
+	"vcmi.keyBindings.keyBinding.spectateSkipBattleResult": "Spectate: sari peste rezultatul luptei",
+	"vcmi.keyBindings.keyBinding.spectateTrackHero": "Spectate: urmărește eroul",
+	"vcmi.keyBindings.keyBinding.spellbookTabAdventure": "Tablou vraji: hartă",
+	"vcmi.keyBindings.keyBinding.spellbookTabCombat": "Tablou vraji: luptă",
+	"vcmi.keyBindings.keyBinding.spellbookSearchFocus": "Tablou vraji: caută",
+	"vcmi.keyBindings.keyBinding.townOpenFort": "Cetate: deschide fort",
+	"vcmi.keyBindings.keyBinding.townOpenGarrisonedHero": "Cetate: deschide eroul garnizoanei",
+	"vcmi.keyBindings.keyBinding.townOpenHall": "Cetate: deschide sală",
+	"vcmi.keyBindings.keyBinding.townOpenHero": "Cetate: deschide erou",
+	"vcmi.keyBindings.keyBinding.townOpenHeroExchange": "Cetate: deschide schimb eroi",
+	"vcmi.keyBindings.keyBinding.townOpenMageGuild": "Cetate: deschide ghilda magilor",
+	"vcmi.keyBindings.keyBinding.townOpenMarket": "Cetate: deschide piață",
+	"vcmi.keyBindings.keyBinding.townOpenRecruitment": "Cetate: deschide recrutare",
+	"vcmi.keyBindings.keyBinding.townOpenTavern": "Cetate: deschide tavernă",
+	"vcmi.keyBindings.keyBinding.townOpenThievesGuild": "Cetate: deschide ghilda hoților",
+	"vcmi.keyBindings.keyBinding.townOpenVisitingHero": "Cetate: deschide eroul vizitator",
+	"vcmi.keyBindings.keyBinding.townSwapArmies": "Cetate: schimbă armatele",
+	"vcmi.keyBindings.keyBinding.listHeroUp": "Listează eroul sus",
+	"vcmi.keyBindings.keyBinding.listHeroDown": "Listează eroul jos",
+	"vcmi.keyBindings.keyBinding.listHeroTop": "Listează eroul în vârf",
+	"vcmi.keyBindings.keyBinding.listHeroBottom": "Listează eroul jos",
+	"vcmi.keyBindings.keyBinding.listTownUp": "Listează cetatea sus",
+	"vcmi.keyBindings.keyBinding.listTownDown": "Listează cetatea jos",
+	"vcmi.keyBindings.keyBinding.listTownTop": "Listează cetatea în vârf",
+	"vcmi.keyBindings.keyBinding.listTownBottom": "Listează cetatea jos",
+	"vcmi.keyBindings.keyBinding.mouseCursorX" : "Cursor mouse X",
+	"vcmi.keyBindings.keyBinding.mouseCursorY" : "Cursor mouse Y",
+	"vcmi.keyBindings.keyBinding.mouseSwipeX" : "Glisare mouse X",
+	"vcmi.keyBindings.keyBinding.mouseSwipeY" : "Glisare mouse Y",
+	"vcmi.keyBindings.keyBinding.mouseClickLeft": "Click mouse stânga",
+	"vcmi.keyBindings.keyBinding.mouseClickRight": "Click mouse dreapta",
+	
+	"vcmi.systemOptions.videoGroup" : "Setări video",
+	"vcmi.systemOptions.audioGroup" : "Setări audio",
+	"vcmi.systemOptions.otherGroup" : "Alte setări", // momentan neutilizat
+	"vcmi.systemOptions.townsGroup" : "Ecran cetate",
+	
+	"vcmi.statisticWindow.statistics" : "Statistici",
+	"vcmi.statisticWindow.tsvCopy" : "Date în clipboard",
+	"vcmi.statisticWindow.selectView" : "Selectează vizualizarea",
+	"vcmi.statisticWindow.value" : "Valoare",
+	"vcmi.statisticWindow.title.overview" : "Prezentare generală",
+	"vcmi.statisticWindow.title.resources" : "Resurse",
+	"vcmi.statisticWindow.title.income" : "Venituri",
+	"vcmi.statisticWindow.title.numberOfHeroes" : "Nr. eroi",
+	"vcmi.statisticWindow.title.numberOfTowns" : "Nr. cetăți",
+	"vcmi.statisticWindow.title.numberOfArtifacts" : "Nr. artefacte",
+	"vcmi.statisticWindow.title.numberOfDwellings" : "Nr. locuințe",
+	"vcmi.statisticWindow.title.numberOfMines" : "Nr. mine",
+	"vcmi.statisticWindow.title.armyStrength" : "Forța armatei",
+	"vcmi.statisticWindow.title.experience" : "Experiență",
+	"vcmi.statisticWindow.title.resourcesSpentArmy" : "Costuri armate",
+	"vcmi.statisticWindow.title.resourcesSpentBuildings" : "Costuri clădiri",
+	"vcmi.statisticWindow.title.mapExplored" : "Proporția hartelor explorate",
+	"vcmi.statisticWindow.param.playerName" : "Numele jucătorului",
+	"vcmi.statisticWindow.param.daysSurvived" : "Zile supraviețuite",
+	"vcmi.statisticWindow.param.maxHeroLevel" : "Nivel maxim erou",
+	"vcmi.statisticWindow.param.battleWinRatioHero" : "Rata câștigurilor (vs. erou)",
+	"vcmi.statisticWindow.param.battleWinRatioNeutral" : "Rata câștigurilor (vs. neutral)",
+	"vcmi.statisticWindow.param.battlesHero" : "Bătălii (vs. erou)",
+	"vcmi.statisticWindow.param.battlesNeutral" : "Bătălii (vs. neutral)",
+	"vcmi.statisticWindow.param.maxArmyStrength" : "Forța maximă totală a armatei",
+	"vcmi.statisticWindow.param.tradeVolume" : "Volum tranzacționat",
+	"vcmi.statisticWindow.param.obeliskVisited" : "Obeliscul vizitat",
+	"vcmi.statisticWindow.icon.townCaptured" : "Cetate capturată",
+	"vcmi.statisticWindow.icon.strongestHeroDefeated" : "Cel mai puternic erou al inamicului învins",
+	"vcmi.statisticWindow.icon.grailFound" : "Graal găsit",
+	"vcmi.statisticWindow.icon.defeated" : "Înfrânt",
+	
+	"vcmi.systemOptions.fullscreenBorderless.hover" : "Ecran complet (fără margini)",
+	"vcmi.systemOptions.fullscreenBorderless.help"  : "{Ecran complet fără margini}\n\nDacă este selectat, VCMI va rula în mod ecran complet fără margini. În acest mod, jocul va utiliza întotdeauna aceeași rezoluție ca și desktopul, ignorând rezoluția selectată.",
+	"vcmi.systemOptions.fullscreenExclusive.hover"  : "Ecran complet (exclusiv)",
+	"vcmi.systemOptions.fullscreenExclusive.help"   : "{Ecran complet}\n\nDacă este selectat, VCMI va rula în mod ecran complet exclusiv. În acest mod, jocul va schimba rezoluția monitorului la rezoluția selectată.",
+	"vcmi.systemOptions.resolutionButton.hover" : "Rezoluție: %wx%h",
+	"vcmi.systemOptions.resolutionButton.help"  : "{Selectează rezoluția}\n\nSchimbă rezoluția ecranului din joc.",
+	"vcmi.systemOptions.resolutionMenu.hover"   : "Selectează rezoluția",
+	"vcmi.systemOptions.resolutionMenu.help"    : "Schimbă rezoluția ecranului din joc.",
+	"vcmi.systemOptions.scalingButton.hover"   : "Scalare interfață: %p%",
+	"vcmi.systemOptions.scalingButton.help"    : "{Scalare interfață}\n\nSchimbă scalarea interfeței din joc.",
+	"vcmi.systemOptions.scalingMenu.hover"     : "Selectează scalarea interfeței",
+	"vcmi.systemOptions.scalingMenu.help"      : "Schimbă scalarea interfeței din joc.",
+	"vcmi.systemOptions.longTouchButton.hover"   : "Interval atingere lungă: %d ms", // Nota de traducere: "ms" = "milisecunde"
+	"vcmi.systemOptions.longTouchButton.help"    : "{Interval atingere lungă}\n\nCând folosești ecranul tactil, feronetele vor apărea după atingerea ecranului pentru durata specificată, în milisecunde.",
+	"vcmi.systemOptions.longTouchMenu.hover"     : "Selectează intervalul de atingere lungă",
+	"vcmi.systemOptions.longTouchMenu.help"      : "Schimbă durata intervalului de atingere lungă.",
+	"vcmi.systemOptions.longTouchMenu.entry"     : "%d milisecunde",
+	"vcmi.systemOptions.performanceOverlayButton.hover"  : "Afișează performanța",
+	"vcmi.systemOptions.performanceOverlayButton.help"   : "{Afișează performanța}\n\nComută vizibilitatea suprapunerii cu informații suplimentare, precum cadre pe secundă, timp și nivelul bateriei (dacă este disponibil) în colțul feronetei jocului.",
+	"vcmi.systemOptions.hapticFeedbackButton.hover"  : "Feedback haptic",
+	"vcmi.systemOptions.hapticFeedbackButton.help"   : "{Feedback haptic}\n\nComută feedback-ul haptic pentru intrările tactilă.",
+	"vcmi.systemOptions.enableUiEnhancementsButton.hover"  : "Îmbunătățiri interfață",
+	"vcmi.systemOptions.enableUiEnhancementsButton.help"   : "{Îmbunătățiri interfață}\n\nComută diverse îmbunătățiri ale interfeței pentru calitatea vieții. De exemplu, un buton pentru rucsac etc. Dezactivează pentru o experiență mai clasică.",
+	"vcmi.systemOptions.enableLargeSpellbookButton.hover"  : "Cartea mare de vrăji",
+	"vcmi.systemOptions.enableLargeSpellbookButton.help"   : "{Cartea mare de vrăji}\n\nPermite o carte de vrăji mai mare care încapă mai multe vrăji pe pagină. Animația schimbării paginii din carte nu funcționează cu această setare activată.",
+	"vcmi.systemOptions.audioMuteFocus.hover"  : "Mutare la inactivitate",
+	"vcmi.systemOptions.audioMuteFocus.help"   : "{Mutare la inactivitate}\n\nMută audio când fereastra devine inactivă. Excepții sunt mesajele din joc și sunetul începerii unei noi ture.",
+	"vcmi.systemOptions.enableOverlayButton.hover"  : "Activează suprapunerea",
+	"vcmi.systemOptions.enableOverlayButton.help"   : "{Activează suprapunerea}\n\nActivează suprapunerea pentru a arăta informații suplimentare, cum ar fi numele clădirilor atunci când ții apăsată tasta ALT sau faci gestul cu două degete.",
+	
+	"vcmi.adventureOptions.infoBarPick.hover" : "Afișează mesaje în panoul de informații",
+	"vcmi.adventureOptions.infoBarPick.help" : "{Afișează mesaje în panoul de informații}\n\nDe fiecare dată când este posibil, mesajele jocului despre obiectele hărții vor fi afișate în panoul de informații, în loc să apară într-o fereastră separată.",
+	"vcmi.adventureOptions.numericQuantities.hover" : "Cantități numerice de creaturi",
+	"vcmi.adventureOptions.numericQuantities.help" : "{Cantități numerice de creaturi}\n\nAfișează cantitățile aproximative ale creaturilor inamicii în formatul numeric A-B.",
+	"vcmi.adventureOptions.forceMovementInfo.hover" : "Arată întotdeauna costul mișcării",
+	"vcmi.adventureOptions.forceMovementInfo.help" : "{Arată întotdeauna costul mișcării}\n\nArată întotdeauna datele despre punctele de mișcare în bara de stare (în loc să le vizualizezi doar când ții apăsată tasta ALT).",
+	"vcmi.adventureOptions.showGrid.hover" : "Arată grilă",
+	"vcmi.adventureOptions.showGrid.help" : "{Arată grilă}\n\nArată suprapunerea cu grila, evidențiind granițele între pătratele hărții de aventură.",
+	"vcmi.adventureOptions.borderScroll.hover" : "Derulare la margine",
+	"vcmi.adventureOptions.borderScroll.help" : "{Derulare la margine}\n\nDerulează harta de aventură când cursorul se află lângă marginea feronetei. Poate fi dezactivat prin apăsarea tastei CTRL.",
+	"vcmi.adventureOptions.infoBarCreatureManagement.hover" : "Gestionare creaturi în panoul de informații",
+	"vcmi.adventureOptions.infoBarCreatureManagement.help" : "{Gestionare creaturi în panoul de informații}\n\nPermite aranjarea creaturilor în panoul de informații în loc să se facă cicluri între componentele implicite.",
+	"vcmi.adventureOptions.leftButtonDrag.hover" : "Misca cu click-stâng",
+	"vcmi.adventureOptions.leftButtonDrag.help" : "{Misca cu click-stâng}\n\nCând este activat, mișcarea mouse-ului cu butonul stâng apăsat va trage vizualizarea hărții de aventură.",
+	"vcmi.adventureOptions.rightButtonDrag.hover" : "Misca cu click-drept",
+	"vcmi.adventureOptions.rightButtonDrag.help" : "{Misca cu click-drept}\n\nCând este activat, mișcarea mouse-ului cu butonul drept apăsat va trage vizualizarea hărții de aventură.",
+	"vcmi.adventureOptions.smoothDragging.hover" : "Tragere fluidă a hărții",
+	"vcmi.adventureOptions.smoothDragging.help" : "{Tragere fluidă a hărții}\n\nCând este activat, tragerea hărții va avea un efect modern de estompare la ieșire.",
+	"vcmi.adventureOptions.skipAdventureMapAnimations.hover" : "Sari peste efectele de estompare",
+	"vcmi.adventureOptions.skipAdventureMapAnimations.help" : "{Sari peste efectele de estompare}\n\nCând este activat, sare peste estomparea obiectelor și efectele similare (colectarea de resurse, îmbarcarea pe corabie etc). Face UI-ul mai reactiv în unele cazuri în detrimentul esteticii. Foarte util în jocurile PvP. Pentru viteză maximă de mișcare, sărirea este activă indiferent de această setare.",
+	"vcmi.adventureOptions.mapScrollSpeed1.hover" : "",
+	"vcmi.adventureOptions.mapScrollSpeed5.hover" : "",
+	"vcmi.adventureOptions.mapScrollSpeed6.hover" : "",
+	"vcmi.adventureOptions.mapScrollSpeed1.help" : "Setează viteza de derulare a hărții la foarte lent.",
+	"vcmi.adventureOptions.mapScrollSpeed5.help" : "Setează viteza de derulare a hărții la foarte rapid.",
+	"vcmi.adventureOptions.mapScrollSpeed6.help" : "Setează viteza de derulare a hărții instantaneu.",
+	"vcmi.adventureOptions.hideBackground.hover" : "Ascunde fundalul",
+	"vcmi.adventureOptions.hideBackground.help" : "{Ascunde fundalul}\n\nAscunde harta de aventură din fundal și afișează în schimb o textură.",
+	"vcmi.adventureOptions.minimapShowHeroes.hover" : "Arată eroi pe mini-hartă",
+	"vcmi.adventureOptions.minimapShowHeroes.help" : "{Arată eroi pe mini-hartă}\n\nAfișează un icon pentru toți eroii vizibili pe mini-hartă, făcându-i mai ușor de observat pe hărțile mari",
+	
+	"vcmi.battleOptions.queueSizeLabel.hover" : "Arată ordinea turelor",
+	"vcmi.battleOptions.queueSizeNoneButton.hover" : "OFF",
+	"vcmi.battleOptions.queueSizeAutoButton.hover" : "AUTO",
+	"vcmi.battleOptions.queueSizeSmallButton.hover" : "MIC",
+	"vcmi.battleOptions.queueSizeBigButton.hover" : "MARE",
+	"vcmi.battleOptions.queueSizeNoneButton.help" : "Nu afișa ordinea turelor.",
+	"vcmi.battleOptions.queueSizeAutoButton.help" : "Ajustează automat dimensiunea cozii de ordine a turelor în funcție de rezoluția jocului (dimensiunea MICĂ este folosită când joci pe o rezoluție cu înălțime mai mică de 700 pixeli, dimensiunea MARE este folosită altfel).",
+	"vcmi.battleOptions.queueSizeSmallButton.help" : "Setează dimensiunea cozii la MIC.",
+	"vcmi.battleOptions.queueSizeBigButton.help" : "Setează dimensiunea cozii la MARE (nu este acceptată dacă înălțimea rezoluției jocului este mai mică de 700 pixeli).",
+	"vcmi.battleOptions.animationsSpeed1.hover" : "",
+	"vcmi.battleOptions.animationsSpeed5.hover" : "",
+	"vcmi.battleOptions.animationsSpeed6.hover" : "",
+	"vcmi.battleOptions.animationsSpeed1.help" : "Setează viteza animațiilor la foarte lent.",
+	"vcmi.battleOptions.animationsSpeed5.help" : "Setează viteza animațiilor la foarte rapid.",
+	"vcmi.battleOptions.animationsSpeed6.help" : "Setează viteza animațiilor instantaneu.",
+	"vcmi.battleOptions.movementHighlightOnHover.hover" : "Evidențiază mișcarea la trecerea cursorului",
+	"vcmi.battleOptions.movementHighlightOnHover.help" : "{Evidențiază mișcarea la trecerea cursorului}\n\nEvidențiază raza de mișcare a unității atunci când treci cu cursorul peste ea.",
+	"vcmi.battleOptions.rangeLimitHighlightOnHover.hover" : "Arată limitele razei pentru trăgători",
+	"vcmi.battleOptions.rangeLimitHighlightOnHover.help" : "{Arată limitele razei pentru trăgători la trecerea cursorului}\n\nArată limitele razei de atac ale trăgătorilor atunci când treci cu cursorul peste ei.",
+	"vcmi.battleOptions.showStickyHeroInfoWindows.hover" : "Arată feronetele cu statistici eroi",
+	"vcmi.battleOptions.showStickyHeroInfoWindows.help" : "{Arată feronetele cu statistici eroi}\n\nActivează permanent feronetele cu statistici ale eroilor care afișează statisticile primare și punctele de vrajă.",
+	"vcmi.battleOptions.skipBattleIntroMusic.hover" : "Sari peste muzica de introducere",
+	"vcmi.battleOptions.skipBattleIntroMusic.help" : "{Sari peste muzica de introducere}\n\nPermite acțiuni în timpul muzicii de introducere care se joacă la începutul fiecărei bătălii.",
+	"vcmi.battleOptions.endWithAutocombat.hover" : "Încheie bătălia",
+	"vcmi.battleOptions.endWithAutocombat.help" : "{Încheie bătălia}\n\nAuto-lupta joacă bătălia până la final instantaneu",
+	"vcmi.battleOptions.showQuickSpell.hover" : "Arată panoul cu vrăji rapide",
+	"vcmi.battleOptions.showQuickSpell.help" : "{Arată panoul cu vrăji rapide}\n\nArată panoul pentru selectarea rapidă a vrajelor",
+	"vcmi.battleOptions.showHealthBar.hover" : "Arată bara de viață",
+	"vcmi.battleOptions.showHealthBar.help" : "{Arată bara de viață}\n\nArată bara de viață care indică viața rămasă înainte ca o unitate să moară.",
+	
+	"vcmi.adventureMap.revisitObject.hover" : "Vizitează din nou obiectul",
+	"vcmi.adventureMap.revisitObject.help" : "{Vizitează din nou obiectul}\n\nDacă un erou se află pe un obiect al hărții, acesta poate vizita din nou locația.",
+	
+	"vcmi.battleWindow.pressKeyToSkipIntro" : "Apasă orice tastă pentru a începe bătălia imediat",
+	"vcmi.battleWindow.damageEstimation.melee" : "Atac %CREATURE (%DAMAGE).",
+	"vcmi.battleWindow.damageEstimation.meleeKills" : "Atac %CREATURE (%DAMAGE, %KILLS).",
+	"vcmi.battleWindow.damageEstimation.ranged" : "Trage %CREATURE (%SHOTS, %DAMAGE).",
+	"vcmi.battleWindow.damageEstimation.rangedKills" : "Trage %CREATURE (%SHOTS, %DAMAGE, %KILLS).",
+	"vcmi.battleWindow.damageEstimation.shots" : "%d gloanțe rămase",
+	"vcmi.battleWindow.damageEstimation.shots.1" : "%d glonț rămas",
+	"vcmi.battleWindow.damageEstimation.damage" : "%d daune",
+	"vcmi.battleWindow.damageEstimation.damage.1" : "%d daune",
+	"vcmi.battleWindow.damageEstimation.kills" : "%d vor peri",
+	"vcmi.battleWindow.damageEstimation.kills.1" : "%d va perii",
+	
+	"vcmi.battleWindow.damageRetaliation.will" : "Va răspunde ",
+	"vcmi.battleWindow.damageRetaliation.may" : "Poate răspunde ",
+	"vcmi.battleWindow.damageRetaliation.never" : "Nu va răspunde.",
+	"vcmi.battleWindow.damageRetaliation.damage" : "(%DAMAGE).",
+	"vcmi.battleWindow.damageRetaliation.damageKills" : "(%DAMAGE, %KILLS).",
+	
+	"vcmi.battleWindow.killed" : "Ucide",
+	"vcmi.battleWindow.accurateShot.resultDescription.0" : "%d %s au fost uciși de focuri precise!",
+	"vcmi.battleWindow.accurateShot.resultDescription.1" : "%d %s a fost ucis cu o lovitură precisă!",
+	"vcmi.battleWindow.accurateShot.resultDescription.2" : "%d %s au fost uciși de lovituri precise!",
+	"vcmi.battleWindow.endWithAutocombat" : "Ești sigur că vrei să închei bătălia cu auto-combat?",
+	
+	"vcmi.battleResultsWindow.applyResultsLabel" : "Accepti rezultatul bătăliei?",
+	"vcmi.battleResultsWindow.spellDurationRemaining.0" : "Durata rămasă: %d runde de luptă",
+	"vcmi.battleResultsWindow.spellDurationRemaining.1" : "Durata rămasă: %d rundă de luptă",
+	"vcmi.battleResultsWindow.spellDurationRemaining.2" : "Durata rămasă: %d runde de luptă",
+	
+	"vcmi.credits.website" : "Website",
+	"vcmi.credits.vcmi" : "VCMI",
+	"vcmi.credits.heroes" : "Heroes III",
+	"vcmi.credits.idea" : "Ideea",
+	"vcmi.credits.developing" : "Dezvoltare",
+	"vcmi.credits.testing" : "Testare",
+	"core.credits.createdBy" : "Creat de",
+	"core.credits.executiveProducer" : "Producător Executiv",
+	"core.credits.producer" : "Producător",
+	"core.credits.director" : "Director",
+	"core.credits.designers" : "Designeri",
+	"core.credits.leadProgrammers" : "Programatori șefi",
+	"core.credits.programmers" : "Programatori",
+	"core.credits.installerProgrammer" : "Programator Instalator",
+	"core.credits.leadArtists" : "Artiști șefi",
+	"core.credits.artists" : "Artiști",
+	"core.credits.assetCoordinator" : "Coordonator Resurse",
+	"core.credits.levelDesigners" : "Designeri de nivele",
+	"core.credits.musicProducer" : "Producător Muzical",
+	"core.credits.townThemes" : "Teme pentru cetăți",
+	"core.credits.music" : "Muzică",
+	"core.credits.soundDesign" : "Design Sunet",
+	"core.credits.voiceProduction" : "Producție Vocală",
+	"core.credits.voiceTalent" : "Talente vocale",
+	"core.credits.leadTester" : "Testator Șef",
+	"core.credits.seniorTester" : "Testator Senior",
+	"core.credits.testers" : "Testatori",
+	"core.credits.specialThanks" : "Mulțumiri speciale",
+	"core.credits.visitUsOnTheWeb" : "Vizitează-ne pe web",
+	
+	"vcmi.tutorialWindow.title" : "Introducere în touchscreen",
+	"vcmi.tutorialWindow.decription.RightClick" : "Atinge și ține apăsat pe elementul pe care vrei să faci clic dreapta. Atinge zona liberă pentru a închide.",
+	"vcmi.tutorialWindow.decription.MapPanning" : "Atinge și trage cu un deget pentru a muta harta.",
+	"vcmi.tutorialWindow.decription.MapZooming" : "Aproapează cu două degete pentru a schimba zoom-ul hărții.",
+	"vcmi.tutorialWindow.decription.RadialWheel" : "Fă swipe pentru a deschide roata radială pentru diverse acțiuni, cum ar fi gestionarea creaturilor/eroilor și comenzi pentru cetate.",
+	"vcmi.tutorialWindow.decription.BattleDirection" : "Pentru a ataca dintr-o direcție anume, fă swipe în direcția din care va fi făcut atacul.",
+	"vcmi.tutorialWindow.decription.BattleDirectionAbort" : "Gestul de direcționare a atacului poate fi anulat dacă degetul este destul de departe.",
+	"vcmi.tutorialWindow.decription.AbortSpell" : "Ține apăsat pentru a anula o vrajă.",
+	
+	"vcmi.otherOptions.availableCreaturesAsDwellingLabel.hover" : "Arată creaturile disponibile",
+	"vcmi.otherOptions.availableCreaturesAsDwellingLabel.help" : "{Arată creaturile disponibile}\n\nArată numărul de creaturi disponibile pentru a fi cumpărate în locul creșterii lor în rezumatul cetății (colțul din stânga jos al ecranului cetății).",
+	"vcmi.otherOptions.creatureGrowthAsDwellingLabel.hover" : "Arată creșterea săptămânală a creaturilor",
+	"vcmi.otherOptions.creatureGrowthAsDwellingLabel.help" : "{Arată creșterea săptămânală a creaturilor}\n\nArată creșterea săptămânală a creaturilor în locul cantității disponibile în rezumatul cetății (colțul din stânga jos al ecranului cetății).",
+	"vcmi.otherOptions.compactTownCreatureInfo.hover" : "Informații compacte despre creaturi",
+	"vcmi.otherOptions.compactTownCreatureInfo.help" : "{Informații compacte despre creaturi}\n\nArată informații mai mici pentru creaturile cetății în rezumatul cetății (colțul din stânga jos al ecranului cetății).",
+	
+	"vcmi.townHall.missingBase"             : "Clădirea de bază %s trebuie construită mai întâi",
+	"vcmi.townHall.noCreaturesToRecruit"    : "Nu sunt creaturi disponibile pentru recrutare!",
+	
+	"vcmi.townStructure.bank.borrow" : "Intră în bancă. Un bancher te vede și spune: \"Am făcut o ofertă specială pentru tine. Poți lua un împrumut de 2500 de aur de la noi pentru 5 zile. Va trebui să plătești înapoi 500 de aur în fiecare zi.\"",
+	"vcmi.townStructure.bank.payBack" : "Intră în bancă. Un bancher te vede și spune: \"Ai deja împrumutul tău. Plătește-l înapoi înainte de a lua un altul.\"",
+	
+	"vcmi.townWindow.upgradeAll.notAllUpgradable" : "Nu sunt suficiente resurse pentru a actualiza toate creaturile. Vrei să actualizezi următoarele creaturi?",
+	"vcmi.townWindow.upgradeAll.notUpgradable" : "Nu sunt suficiente resurse pentru a actualiza nicio creatură.",
+	
+	"vcmi.kingdomOverview.secSkillOverflow.hover" : "Mai multe abilități",
+	"vcmi.kingdomOverview.secSkillOverflow.help" : "{Mai multe abilități}\n\nAcest erou are mai multe abilități.\nLe poți vedea pe toate în rezumatul eroului.",
+	
+	"vcmi.logicalExpressions.anyOf"  : "Oricare dintre următoarele:",
+	"vcmi.logicalExpressions.allOf"  : "Toate următoarele:",
+	"vcmi.logicalExpressions.noneOf" : "Niciunul dintre următoarele:",
+	
+	"vcmi.heroWindow.openCommander.hover" : "Deschide fereastra de informații a comandantului",
+	"vcmi.heroWindow.openCommander.help"  : "Afișează detalii despre comandantul acestui erou.",
+	"vcmi.heroWindow.openBackpack.hover" : "Deschide fereastra rucsacului cu artefacte",
+	"vcmi.heroWindow.openBackpack.help"  : "Deschide fereastra care permite gestionarea mai ușoară a rucsacului cu artefacte.",
+	"vcmi.heroWindow.sortBackpackByCost.hover"  : "După valoare",
+	"vcmi.heroWindow.sortBackpackByCost.help"  : "{Sortează după cost}\n\nSortează artefactele din rucsac după cost.",
+	"vcmi.heroWindow.sortBackpackBySlot.hover"  : "După slot",
+	"vcmi.heroWindow.sortBackpackBySlot.help"  : "{Sortează după slot}\n\nSortează artefactele din rucsac după slotul echipat.",
+	"vcmi.heroWindow.sortBackpackByClass.hover"  : "După clasă",
+	"vcmi.heroWindow.sortBackpackByClass.help"  : "{Sortează după clasă}\n\nSortează artefactele din rucsac după clasa artefactului. Tezaur, Minore, Majore, Relicve",
+	"vcmi.heroWindow.fusingArtifact.fusing" : "Posesi toate componentele necesare pentru fuzionarea %s. Vrei să efectuezi fuzionarea? {Toate componentele vor fi consumate la fuzionare.}",
+	"vcmi.heroWindow.lockedartifact.hover" : "Ocupați de %s",
+	
+	"vcmi.tavernWindow.inviteHero"  : "Invită eroul",
+	
+	"vcmi.commanderWindow.artifactMessage" : "Vrei să returnezi acest artefact eroului?",
+	
+	"vcmi.creatureWindow.showBonuses.hover"    : "Comută la vizualizarea bonusurilor",
+	"vcmi.creatureWindow.showBonuses.help"     : "Afișează toate bonusurile active ale comandantului.",
+	"vcmi.creatureWindow.showSkills.hover"     : "Comută la vizualizarea abilităților",
+	"vcmi.creatureWindow.showSkills.help"      : "Afișează toate abilitățile învățate ale comandantului.",
+	"vcmi.creatureWindow.returnArtifact.hover" : "Returnează artefactul",
+	"vcmi.creatureWindow.returnArtifact.help"  : "Apasă acest buton pentru a returna artefactul în rucsacul eroului.",
+	
+	"vcmi.questLog.hideComplete.hover" : "Ascunde quest-urile finalizate",
+	"vcmi.questLog.hideComplete.help"  : "Ascunde toate quest-urile finalizate.",
+	
+	"vcmi.randomMapTab.widgets.randomTemplate"      : "(Aleatoriu)",
+	"vcmi.randomMapTab.widgets.templateLabel"        : "Șablon",
+	"vcmi.randomMapTab.widgets.teamAlignmentsButton" : "Configurați...",
+	"vcmi.randomMapTab.widgets.teamAlignmentsLabel"  : "Aliniamente echipe",
+	"vcmi.randomMapTab.widgets.roadTypesLabel"       : "Tipuri de drumuri",
+	
+	"vcmi.optionsTab.turnOptions.hover" : "Opțiuni de tură",
+	"vcmi.optionsTab.turnOptions.help" : "Selectează opțiunile pentru cronometru și ture simultane",
+	
+	"vcmi.optionsTab.chessFieldBase.hover" : "Crono bază",
+	"vcmi.optionsTab.chessFieldTurn.hover" : "Crono tură",
+	"vcmi.optionsTab.chessFieldBattle.hover" : "Crono bătălie",
+	"vcmi.optionsTab.chessFieldUnit.hover" : "Crono unitate",
+	"vcmi.optionsTab.chessFieldBase.help" : "Folosit când {Cronometrul pentru tură} ajunge la 0. Setat o singură dată la începutul jocului. Când ajunge la zero, se încheie tura curentă. Orice luptă în desfășurare se va încheia cu o pierdere.",
+	"vcmi.optionsTab.chessFieldTurnAccumulate.help" : "Folosit în afacerea de luptă sau când {Cronometrul pentru bătălie} se încheie. Se resetează la fiecare tură. Timpul rămas se adaugă la {Cronometrul de bază} la sfârșitul turei.",
+	"vcmi.optionsTab.chessFieldTurnDiscard.help" : "Folosit în afacerea de luptă sau când {Cronometrul pentru bătălie} se încheie. Se resetează la fiecare tură. Orice timp necheltuit este pierdut.",
+	"vcmi.optionsTab.chessFieldBattle.help" : "Folosit în luptele cu AI sau în luptele PvP când {Cronometrul pentru unitate} se încheie. Se resetează la începutul fiecărei bătălii.",
+	"vcmi.optionsTab.chessFieldUnitAccumulate.help" : "Folosit când selectezi o acțiune de unitate în luptele PvP. Timpul rămas se adaugă la {Cronometrul pentru bătălie} la sfârșitul turei unității.",
+	"vcmi.optionsTab.chessFieldUnitDiscard.help" : "Folosit când selectezi o acțiune de unitate în luptele PvP. Se resetează la începutul fiecărei ture a unității. Orice timp necheltuit este pierdut.",
+	
+	"vcmi.optionsTab.accumulate" : "Acumulare",
+	
+	"vcmi.optionsTab.simturnsTitle" : "Ture simultane",
+	"vcmi.optionsTab.simturnsMin.hover" : "Cel puțin pentru",
+	"vcmi.optionsTab.simturnsMax.hover" : "Cel mult pentru",
+	"vcmi.optionsTab.simturnsAI.hover" : "(Experimental) Ture simultane AI",
+	"vcmi.optionsTab.simturnsMin.help" : "Joacă simultan pentru numărul specificat de zile. Contactele între jucători în această perioadă sunt blocate.",
+	"vcmi.optionsTab.simturnsMax.help" : "Joacă simultan pentru numărul specificat de zile sau până la contactul cu alt jucător.",
+	"vcmi.optionsTab.simturnsAI.help" : "{Ture simultane AI}\nOpțiune experimentală. Permite jucătorilor AI să acționeze în același timp cu jucătorul uman când turele simultane sunt activate.",
+	
+	"vcmi.optionsTab.turnTime.select"     : "Selectează cronometru tură",
+	"vcmi.optionsTab.turnTime.unlimited"  : "Timp nelimitat pentru tură",
+	"vcmi.optionsTab.turnTime.classic.1"  : "Cronometru clasic: 1 minut",
+	"vcmi.optionsTab.turnTime.classic.2"  : "Cronometru clasic: 2 minute",
+	"vcmi.optionsTab.turnTime.classic.5"  : "Cronometru clasic: 5 minute",
+	"vcmi.optionsTab.turnTime.classic.10" : "Cronometru clasic: 10 minute",
+	"vcmi.optionsTab.turnTime.classic.20" : "Cronometru clasic: 20 minute",
+	"vcmi.optionsTab.turnTime.classic.30" : "Cronometru clasic: 30 minute",
+	"vcmi.optionsTab.turnTime.chess.20"   : "Șah: 20:00 + 10:00 + 02:00 + 00:00",
+	"vcmi.optionsTab.turnTime.chess.16"   : "Șah: 16:00 + 08:00 + 01:30 + 00:00",
+	"vcmi.optionsTab.turnTime.chess.8"    : "Șah: 08:00 + 04:00 + 01:00 + 00:00",
+	"vcmi.optionsTab.turnTime.chess.4"    : "Șah: 04:00 + 02:00 + 00:30 + 00:00",
+	"vcmi.optionsTab.turnTime.chess.2"    : "Șah: 02:00 + 01:00 + 00:15 + 00:00",
+	"vcmi.optionsTab.turnTime.chess.1"    : "Șah: 01:00 + 01:00 + 00:00 + 00:00",
+	
+	"vcmi.optionsTab.simturns.select"         : "Selectează ture simultane",
+	"vcmi.optionsTab.simturns.none"           : "Fără ture simultane",
+	"vcmi.optionsTab.simturns.tillContactMax" : "Simture: Până la contact",
+	"vcmi.optionsTab.simturns.tillContact1"   : "Simture: 1 săptămână, pauză la contact",
+	"vcmi.optionsTab.simturns.tillContact2"   : "Simture: 2 săptămâni, pauză la contact",
+	"vcmi.optionsTab.simturns.tillContact4"   : "Simture: 1 lună, pauză la contact",
+	"vcmi.optionsTab.simturns.blocked1"       : "Simture: 1 săptămână, contacte blocate",
+	"vcmi.optionsTab.simturns.blocked2"       : "Simture: 2 săptămâni, contacte blocate",
+	"vcmi.optionsTab.simturns.blocked4"       : "Simture: 1 lună, contacte blocate",
+	
+	"vcmi.campaignSet.chronicles" : "Heroes Chronicles",
+	"vcmi.campaignSet.hota" : "Horn of the Abyss",
+	
+	// Translation note: translate strings below using form that is correct for "0 days", "1 day" and "2 days" in your language
+	// Using this information, VCMI will automatically select correct plural form for every possible amount
+	"vcmi.optionsTab.simturns.days.0" : " %d zile",
+	"vcmi.optionsTab.simturns.days.1" : " %d zi",
+	"vcmi.optionsTab.simturns.days.2" : " %d zile",
+	"vcmi.optionsTab.simturns.weeks.0" : " %d săptămâni",
+	"vcmi.optionsTab.simturns.weeks.1" : " %d săptămână",
+	"vcmi.optionsTab.simturns.weeks.2" : " %d săptămâni",
+	"vcmi.optionsTab.simturns.months.0" : " %d luni",
+	"vcmi.optionsTab.simturns.months.1" : " %d lună",
+	"vcmi.optionsTab.simturns.months.2" : " %d luni",
+	
+	"vcmi.selectionTab.campaignSets.hover" : "Seturi de campanii",
+	"vcmi.selectionTab.campaignSets.help" : "Mai multe campanii grupate ca set",
+	
+	"vcmi.optionsTab.extraOptions.hover" : "Opțiuni suplimentare",
+	"vcmi.optionsTab.extraOptions.help" : "Setări suplimentare pentru joc",
+	
+	"vcmi.optionsTab.cheatAllowed.hover" : "Permite trucuri",
+	"vcmi.optionsTab.unlimitedReplay.hover" : "Repetare nelimitată a bătăliei",
+	"vcmi.optionsTab.cheatAllowed.help" : "{Permite trucuri}\nPermite introducerea trucurilor în timpul jocului.",
+	"vcmi.optionsTab.unlimitedReplay.help" : "{Repetare nelimitată a bătăliei}\nFără limită pentru repetarea bătăliilor.",
+	
+	// Custom victory conditions for H3 campaigns and HotA maps
+	"vcmi.map.victoryCondition.daysPassed.toOthers" : "Inamicul a reușit să supraviețuiască până în această zi. Victorie este a lor!",
+	"vcmi.map.victoryCondition.daysPassed.toSelf" : "Felicitări! Ai reușit să supraviețuiești. Victorie este a ta!",
+	"vcmi.map.victoryCondition.eliminateMonsters.toOthers" : "Inamicul a învins toate monștrii care bântuie această țară și revendică victoria!",
+	"vcmi.map.victoryCondition.eliminateMonsters.toSelf" : "Felicitări! Ai învins toți monștrii care bântuie această țară și poți revendica victoria!",
+	"vcmi.map.victoryCondition.collectArtifacts.message" : "Achiziționează trei artefacte",
+	"vcmi.map.victoryCondition.angelicAlliance.toSelf" : "Felicitări! Toți inamicii tăi au fost înfrânți și ai Alianța Angelică! Victorie este a ta!",
+	"vcmi.map.victoryCondition.angelicAlliance.message" : "Înfrânge toți inamicii și creează Alianța Angelică",
+	"vcmi.map.victoryCondition.angelicAlliancePartLost.toSelf" : "Din păcate, ai pierdut o parte din Alianța Angelică. Totul este pierdut.",
+	
+	// few strings from WoG used by vcmi
+	"vcmi.stackExperience.description" : "» Detalii despre Experiența Stivă «\n\nTipul de creatură ................... : %s\nRangul experienței ................. : %s (%i)\nPuncte de experiență ............... : %i\nPuncte de experiență pentru următorul rang .. : %i\nExperiență maximă pe bătălie ... : %i%% (%i)\nNumărul de creaturi în stivă .... : %i\nMaxim noi recruți\n fără a pierde rangul actual .... : %i\nMultiplicator de experiență ........... : %.2f\nMultiplicator de upgrade .............. : %.2f\nExperiență după Rangul 10 ........ : %i\nMaxim noi recruți pentru a rămâne la\n Rangul 10 dacă la experiență maximă : %i",
+	"vcmi.stackExperience.rank.0" : "De bază",
+	"vcmi.stackExperience.rank.1" : "Novice",
+	"vcmi.stackExperience.rank.2" : "Antrenat",
+	"vcmi.stackExperience.rank.3" : "Calificat",
+	"vcmi.stackExperience.rank.4" : "Dovedit",
+	"vcmi.stackExperience.rank.5" : "Veteran",
+	"vcmi.stackExperience.rank.6" : "Adept",
+	"vcmi.stackExperience.rank.7" : "Expert",
+	"vcmi.stackExperience.rank.8" : "Elit",
+	"vcmi.stackExperience.rank.9" : "Maestru",
+	"vcmi.stackExperience.rank.10" : "As",
+		
+	// Strings for HotA Seer Hut / Quest Guards
+	"core.seerhut.quest.heroClass.complete.0" : "Ah, tu ești %s. Iată un cadou pentru tine. Accepti?",
+	"core.seerhut.quest.heroClass.complete.1" : "Ah, tu ești %s. Iată un cadou pentru tine. Accepti?",
+	"core.seerhut.quest.heroClass.complete.2" : "Ah, tu ești %s. Iată un cadou pentru tine. Accepti?",
+	"core.seerhut.quest.heroClass.complete.3" : "Gărzile observă că ești %s și îți oferă să treci. Accepti?",
+	"core.seerhut.quest.heroClass.complete.4" : "Gărzile observă că ești %s și îți oferă să treci. Accepti?",
+	"core.seerhut.quest.heroClass.complete.5" : "Gărzile observă că ești %s și îți oferă să treci. Accepti?",
+	"core.seerhut.quest.heroClass.description.0" : "Trimite %s la %s",
+	"core.seerhut.quest.heroClass.description.1" : "Trimite %s la %s",
+	"core.seerhut.quest.heroClass.description.2" : "Trimite %s la %s",
+	"core.seerhut.quest.heroClass.description.3" : "Trimite %s pentru a deschide poarta",
+	"core.seerhut.quest.heroClass.description.4" : "Trimite %s pentru a deschide poarta",
+	"core.seerhut.quest.heroClass.description.5" : "Trimite %s pentru a deschide poarta",
+	"core.seerhut.quest.heroClass.hover.0" : "(caută un erou de clasa %s)",
+	"core.seerhut.quest.heroClass.hover.1" : "(caută un erou de clasa %s)",
+	"core.seerhut.quest.heroClass.hover.2" : "(caută un erou de clasa %s)",
+	"core.seerhut.quest.heroClass.hover.3" : "(caută un erou de clasa %s)",
+	"core.seerhut.quest.heroClass.hover.4" : "(caută un erou de clasa %s)",
+	"core.seerhut.quest.heroClass.hover.5" : "(caută un erou de clasa %s)",
+	"core.seerhut.quest.heroClass.receive.0" : "Am un cadou pentru %s.",
+	"core.seerhut.quest.heroClass.receive.1" : "Am un cadou pentru %s.",
+	"core.seerhut.quest.heroClass.receive.2" : "Am un cadou pentru %s.",
+	"core.seerhut.quest.heroClass.receive.3" : "Gărzile de aici spun că doar %s poate trece.",
+	"core.seerhut.quest.heroClass.receive.4" : "Gărzile de aici spun că doar %s poate trece.",
+	"core.seerhut.quest.heroClass.receive.5" : "Gărzile de aici spun că doar %s poate trece.",
+	"core.seerhut.quest.heroClass.visit.0" : "Nu ești %s. Nu am nimic pentru tine. Pleacă!",
+	"core.seerhut.quest.heroClass.visit.1" : "Nu ești %s. Nu am nimic pentru tine. Pleacă!",
+	"core.seerhut.quest.heroClass.visit.2" : "Nu ești %s. Nu am nimic pentru tine. Pleacă!",
+	"core.seerhut.quest.heroClass.visit.3" : "Gărzile de aici vor lăsa doar %s să treacă.",
+	"core.seerhut.quest.heroClass.visit.4" : "Gărzile de aici vor lăsa doar %s să treacă.",
+	"core.seerhut.quest.heroClass.visit.5" : "Gărzile de aici vor lăsa doar %s să treacă.",
+	
+	"core.seerhut.quest.reachDate.complete.0" : "Sunt liber acum. Iată ce am pentru tine. Accepti?",
+	"core.seerhut.quest.reachDate.complete.1" : "Sunt liber acum. Iată ce am pentru tine. Accepti?",
+	"core.seerhut.quest.reachDate.complete.2" : "Sunt liber acum. Iată ce am pentru tine. Accepti?",
+	"core.seerhut.quest.reachDate.complete.3" : "Poți trece acum. Vrei să treci?",
+	"core.seerhut.quest.reachDate.complete.4" : "Poți trece acum. Vrei să treci?",
+	"core.seerhut.quest.reachDate.complete.5" : "Poți trece acum. Vrei să treci?",
+	"core.seerhut.quest.reachDate.description.0" : "Așteaptă până la %s pentru %s",
+	"core.seerhut.quest.reachDate.description.1" : "Așteaptă până la %s pentru %s",
+	"core.seerhut.quest.reachDate.description.2" : "Așteaptă până la %s pentru %s",
+	"core.seerhut.quest.reachDate.description.3" : "Așteaptă până la %s pentru a deschide poarta",
+	"core.seerhut.quest.reachDate.description.4" : "Așteaptă până la %s pentru a deschide poarta",
+	"core.seerhut.quest.reachDate.description.5" : "Așteaptă până la %s pentru a deschide poarta",
+	"core.seerhut.quest.reachDate.hover.0" : "(Nu te întoarce înainte de %s)",
+	"core.seerhut.quest.reachDate.hover.1" : "(Nu te întoarce înainte de %s)",
+	"core.seerhut.quest.reachDate.hover.2" : "(Nu te întoarce înainte de %s)",
+	"core.seerhut.quest.reachDate.hover.3" : "(Nu te întoarce înainte de %s)",
+	"core.seerhut.quest.reachDate.hover.4" : "(Nu te întoarce înainte de %s)",
+	"core.seerhut.quest.reachDate.hover.5" : "(Nu te întoarce înainte de %s)",
+	"core.seerhut.quest.reachDate.receive.0" : "Sunt ocupat. Vino înapoi după %s",
+	"core.seerhut.quest.reachDate.receive.1" : "Sunt ocupat. Vino înapoi după %s",
+	"core.seerhut.quest.reachDate.receive.2" : "Sunt ocupat. Vino înapoi după %s",
+	"core.seerhut.quest.reachDate.receive.3" : "Închis până la %s.",
+	"core.seerhut.quest.reachDate.receive.4" : "Închis până la %s.",
+	"core.seerhut.quest.reachDate.receive.5" : "Închis până la %s.",
+	"core.seerhut.quest.reachDate.visit.0" : "Sunt ocupat. Vino înapoi după %s.",
+	"core.seerhut.quest.reachDate.visit.1" : "Sunt ocupat. Vino înapoi după %s.",
+	"core.seerhut.quest.reachDate.visit.2" : "Sunt ocupat. Vino înapoi după %s.",
+	"core.seerhut.quest.reachDate.visit.3" : "Închis până la %s.",
+	"core.seerhut.quest.reachDate.visit.4" : "Închis până la %s.",
+	"core.seerhut.quest.reachDate.visit.5" : "Închis până la %s.",
+	
+	"mapObject.core.hillFort.object.description" : "Îmbunătățește creaturile. Nivelele 1 - 4 sunt mai ieftine decât în orașul asociat.",
+	
+	"artifact.core.orbOfVulnerability.bonus.noResistance" : "{Orbita Vulnerabilității}\nAnulează rezistența magică naturală a tuturor creaturilor de pe câmpul de luptă",
+	"creatures.core.angel.bonus.raisesMorale" : "{Crește moralul aliaților}\nÎngerii și Arhanghelii cresc moralul aliaților cu 1",
+	"creatures.core.devil.bonus.decreaseLuck" : "{Reduce norocul inamicilor}\nDiavolii și Arhidiavolii reduc norocul inamicilor cu 1",
+	"creatures.core.boneDragon.bonus.decreaseMorale" : "{Reduce moralul inamicilor}\nDragonii de oase și Dragonii fantomă scad moralul unităților inamicilor cu 1",
+	"creatures.core.marksman.bonus.extraAttack" : "{Trage de două ori}\nAceastă unitate poate trage de două ori",
+	"creatures.core.azureDragon.bonus.fearful" : "{Frica}\nUnitățile inamicilor au o șansă de 10% de a îngheța de frică",
+	"creatures.core.azureDragon.bonus.fearless" : "{Fără frică}\nImun la abilitatea Frică",
+	"creatures.core.halfling.bonus.lucky" : "{Norocos}\nNorocul Halflingului nu poate fi scăzut sub +1",
+	"creatures.core.nomad.bonus.sandWalker" : "{Mers pe nisip}\nEroul ignoră penalizarea terenului pe nisip",
+	"creatures.core.rogue.bonus.visionsMonsters" : "{Viziuni Monștri}\nEroul poate vedea informații detaliate despre monștri neutri",
+	"creatures.core.rogue.bonus.visionsHeroes" : "{Viziuni Eroi}\nEroul poate vedea informații detaliate despre eroii inamici",
+	"creatures.core.rogue.bonus.visionsTowns" : "{Viziuni Orașe}\nEroul poate vedea informații detaliate despre orașele inamicilor",
+	
+	"core.bonus.ADDITIONAL_ATTACK.description" : "{Atacuri suplimentare}\nUnitatea poate ataca de încă ${val} ori", // TODO: descriere alternativă pentru efectul melee/ranged
+	"core.bonus.ADDITIONAL_RETALIATION.description" : "{Riposte suplimentare}\nUnitatea poate riposta de ${val} ori suplimentar",
+	"core.bonus.ALWAYS_MAXIMUM_DAMAGE.description" : "{Daune maxime}\nAceastă unitate dă întotdeauna daunele maxime posibile",
+	"core.bonus.ATTACKS_ALL_ADJACENT.description" : "{Atacuri în jurul unității}\nAtacă toate unitățile adiacente în plus față de ținta principală",
+	"core.bonus.BLOCKS_RANGED_RETALIATION.description" : "{Fără ripostă la distanță}\nInamicii nu pot riposta când sunt atacați de această unitate",
+	"core.bonus.BLOCKS_RETALIATION.description" : "{Fără ripostă}\nInamicii nu pot riposta când sunt atacați în lupta corp la corp de această unitate",
+	"core.bonus.CATAPULT.description" : "{Catapultă}\nAceastă unitate poate trage asupra zidurilor în timpul unui asediu de oraș",
+	"core.bonus.CHANGES_SPELL_COST_FOR_ALLY.description" : "{Reducerea costului vrăjii (${val})}\nScade costul vrăjilor pentru erou cu ${val}",
+	"core.bonus.CHANGES_SPELL_COST_FOR_ENEMY.description" : "{Amortizor magic (${val})}\nCrește costul vrăjilor inamicilor cu ${val}",
+	"core.bonus.CHARGE_IMMUNITY.description" : "{Imunitate la bonusul de turnir}\nAceastă unitate nu primește daune suplimentare de la bonusul de turnir",
+	"core.bonus.DEATH_STARE.description" : "{Privire mortală (${val}%)}\nAre o șansă de ${val}% de a ucide instant un singur monstru viu",
+	"core.bonus.DEFENSIVE_STANCE.description" : "{Bonus de apărare}\nCrește apărarea cu +${val} după utilizarea acțiunii de apărare",
+	"core.bonus.DESTRUCTION.description" : "{Distrugere}\nAre o șansă de ${val}% de a ucide unități suplimentare după atac",
+	"core.bonus.DISINTEGRATE.description" : "{Dezintegrate}\nCând această unitate moare, nu va lăsa niciun cadavru în urma sa",
+	"core.bonus.DOUBLE_DAMAGE_CHANCE.description" : "{Lovitura fatală}\nAre o șansă de ${val}% de a da dublu daune de bază când atacă",
+	"core.bonus.DRAGON_NATURE.description" : "{Dragon}\nAceastă creatură este un Dragon",
+	"core.bonus.ENCHANTED.description" : "{Vrăjit}\nEste permanent afectat de ${subtype.spell}",
+	"core.bonus.ENCHANTER.description" : "{Vrăjitor}\nPoate lansa ${subtype.spell} în fiecare tur",
+	"core.bonus.ENEMY_ATTACK_REDUCTION.description" : "{Ignoră atacul (${val}%) }\nCând este atacat, ${val}% din atacul agresorului este ignorat",
+	"core.bonus.ENEMY_DEFENCE_REDUCTION.description" : "{Ignoră apărarea (${val}%) }\nCând atacă, ${val}% din apărarea apărătorului este ignorata",
+	"core.bonus.FEROCITY.description" : "{Ferocitate}\nAtacă de ${val} ori suplimentar dacă a ucis pe cineva",
+	"core.bonus.FIRE_SHIELD.description" : "{Scut de foc (${val}%) }\nUnitatea reflectă ${val} din daunele de corp la corp primite",
+	"core.bonus.FIRST_STRIKE.description.bonusSubtype.damageTypeMelee" : "{Lovitura de început}\nUnitatea ripostează înainte de a fi atacată în lupta corp la corp",
+	"core.bonus.FIRST_STRIKE.description.bonusSubtype.damageTypeRanged" : "{Lovitura de început}\nUnitatea ripostează înainte de a fi atacată de o unitate cu atac la distanță",
+	"core.bonus.FIRST_STRIKE.description" : "{Lovitura de început}\nUnitatea ripostează înainte de a fi atacată",
+	"core.bonus.FLYING.description.bonusSubtype.movementTeleporting" : "{Teleportare}\nAceastă unitate se teleporteaza în orice hex și ignoră obstacolele pe câmpul de luptă",
+	"core.bonus.FLYING.description" : "{Poate Zbura}\nAceastă unitate zboară când se mișcă și va ignora obstacolele de pe câmpul de luptă",
+	"core.bonus.FREE_SHOOTING.description" : "{Trage de aproape}\nAtacurile la distanță ale acestei unități nu pot fi blocate de inamicii adiacenți",
+	"core.bonus.GARGOYLE.description" : "{Gargoyle}\nAceastă unitate nu poate fi înviată din morți sau vindecată",
+	"core.bonus.GENERAL_DAMAGE_REDUCTION.description.bonusSubtype.damageTypeMelee" : "{Reducerea daunei (${val}%) }\nReduce daunele fizice din atacurile corp la corp cu ${val}%",
+	"core.bonus.GENERAL_DAMAGE_REDUCTION.description.bonusSubtype.damageTypeRanged" : "{Reducerea daunei (${val}%) }\nReduce daunele fizice din atacurile la distanță cu ${val}%",
+	"core.bonus.GENERAL_DAMAGE_REDUCTION.description" : "{Reducerea daunei (${val}%) }\nReduce daunele fizice din atacurile la distanță sau corp la corp cu ${val}%",
+	"core.bonus.HATE.description" : "{Ură față de ${subtype.creature}}\nFace ${val}% daune suplimentare creaturilor ${subtype.creature}",
+	"core.bonus.HEALER.description" : "{Vindecător}\nVindecă unitățile aliate",
+	"core.bonus.HP_REGENERATION.description" : "{Regenerare}\nVindecă ${val} puncte de viață în fiecare rundă",
+	"core.bonus.INVINCIBLE.description" : "{Invincibil}\nNu poate fi afectat de nimic",
+	"core.bonus.JOUSTING.description" : "{Bonus de turnir}\nMișcarea înainte de un atac crește daunele cu ${val}% pentru fiecare hex parcurs",
+	"core.bonus.KING.description.2" : "{Rege Avansat}\nPrimește daune suplimentare de la unitățile afectate de vraja Slayer avansat",
+	"core.bonus.KING.description.3" : "{Rege Expert}\nPrimește daune suplimentare de la unitățile afectate de vraja Slayer expert",
+	"core.bonus.KING.description" : "{Rege}\nPrimește daune suplimentare de la unitățile afectate de vraja Slayer",
+	"core.bonus.LEVEL_SPELL_IMMUNITY.description" : "{Imunitate la vrăji de nivel 1-${val}}\nAceastă unitate nu poate fi țintită de vrăji de nivelurile 1-${val}",
+	"core.bonus.LIFE_DRAIN.description" : "{Drenaj de viață}\nDrănează ${val}% din daunele cauzate",
+	"core.bonus.LIMITED_SHOOTING_RANGE.description" : "{Distanta limitata de atac}\nNu poate folosi un atac împotriva unităților care sunt la peste ${val} hexuri distanță",
+	"core.bonus.MAGIC_MIRROR.description" : "{Oglindă magică}\nAre o șansă de ${val}% de a redirecționa o vrăjire ofensivă către o unitate inamică",
+	"core.bonus.MAGIC_RESISTANCE.description" : "{Rezistență magică (${val}%) }\nAre o șansă de ${val}% de a rezista unei vrăji inamice",
+	"core.bonus.MANA_CHANNELING.description" : "{Canalizare Magică}\nDă eroului tău ${val}% din mana cheltuită de inamic",
+	"core.bonus.MANA_DRAIN.description" : "{Drenează de mana}\nDrenează ${val} mana în fiecare tur de la eroul inamic",
+	"core.bonus.MECHANICAL.description" : "{Mecanic}\nAceastă unitate este imună la efectele care afectează doar ființele vii și poate fi reparată",
+	"core.bonus.MIND_IMMUNITY.description" : "{Imunitate la vrăjile mentale}\nAceastă unitate nu poate fi țintită de vrăjile care afectează mintea sa",
+	"core.bonus.MORE_DAMAGE_FROM_SPELL.description" : "{Vulnerabilă la ${subtype.spell}}\nDaunele primite când este lovită de ${subtype.spell} sunt crescute cu ${val}%",
+	"core.bonus.NO_DISTANCE_PENALTY.description" : "{Fără penalizare de distanță}\nAtacurile la distanță dau daune complete",
+	"core.bonus.NO_MELEE_PENALTY.description" : "{Fără penalizare în lupta corp la corp}\nAceastă unitate nu are penalizare la atac corp la corp.",
+	"core.bonus.NO_MORALE.description" : "{Morale neutră}\nCreatura este imună la efectele morale",
+	"core.bonus.NON_LIVING.description" : "{Non-viu}\nAceastă unitate este imună la efectele care afectează doar ființele vii",
+	"core.bonus.NO_WALL_PENALTY.description" : "{Fără penalizare la ziduri}\nAtacurile la distanță dau daune complete unităților aflate în spatele zidurilor",
+	"core.bonus.PRISM_HEX_ATTACK_BREATH.description" : "{Respirație Prism}\nAtacurile vizează toate unitățile aflate imediat în spatele țintei principale",
+	"core.bonus.RANDOM_SPELLCASTER.description" : "{Vrăjitor aleatoriu}\nPoate lansa o vrajă benefică aleatorie asupra unei unități aliate",
+	"core.bonus.RANGED_RETALIATION.description" : "{Ripostă la distanță}\nPoate efectua o contraripostă la atacurile la distanță",
+	"core.bonus.REBIRTH.description" : "{Reînviere (${val}%) }\n${val}% din această unitate va învia după moarte",
+	"core.bonus.RECEPTIVE.description" : "{Receptiv}\nVrăjile lansate de aliați ignoră imunitățile acestei unități",
+	"core.bonus.RETURN_AFTER_STRIKE.description" : "{Lovire și întoarcere}\nUnitatea se întoarce la poziția inițială după ce efectuează un atac corp la corp",
+	"core.bonus.REVENGE.description" : "{Răzbunare}\nDă daune suplimentare în funcție de sănătatea pierdută a atacatorului în bătălie",
+	"core.bonus.SHOOTER.description" : "{Trage la distanță}\nAceastă unitate poate folosi muniția pentru a efectua atacuri la distanță",
+	"core.bonus.SHOOTS_ALL_ADJACENT.description" : "{Loveste la distantă unitățile adiacente}\nAtacurile la distanță lovesc toate țintele dintr-o zonă mică adiacentă",
+	"core.bonus.SKELETON_TRANSFORMER_TARGET.description" : "{Convertire în schelet}\nConvertitorul de schelete va transforma această unitate într-o ${subtype.creature}",
+	"core.bonus.SOUL_STEAL.description" : "{Furt de suflete}\nCâștigă ${val} creaturi noi pentru fiecare inamic ucis",
+	"core.bonus.SPELL_AFTER_ATTACK.description" : "{Lansează după atac}\nAre o șansă de ${val}% de a lansa ${subtype.spell} după ce atacă",
+	"core.bonus.SPELL_BEFORE_ATTACK.description" : "{Lansează înainte de atac}\nAre o șansă de ${val}% de a lansa ${subtype.spell} înainte de a ataca",
+	"core.bonus.SPELLCASTER.description" : "{Vrăjitor}\nPoate lansa ${subtype.spell}",
+	"core.bonus.SPELL_DAMAGE_REDUCTION.description" : "{Rezistență la vrăji}\nDaunele din toate vrăjile sunt reduse cu ${val}%",
+	"core.bonus.SPELL_DAMAGE_REDUCTION.description.spellSchool.air" : "{Rezistență la vrăjile de Aer}\nDaunele din vrăjile de Aer sunt reduse cu ${val}%",
+	"core.bonus.SPELL_DAMAGE_REDUCTION.description.spellSchool.earth" : "{Rezistență la vrăjile de Pământ}\nDaunele din vrăjile de Pământ sunt reduse cu ${val}%",
+	"core.bonus.SPELL_DAMAGE_REDUCTION.description.spellSchool.fire"  : "{Rezistență la vrăjile de Foc}\nDaunele din vrăjile de Foc sunt reduse cu ${val}%",
+	"core.bonus.SPELL_DAMAGE_REDUCTION.description.spellSchool.water" : "{Rezistență la vrăjile de Apă}\nDaunele din vrăjile de Apă sunt reduse cu ${val}%",
+	"core.bonus.SPELL_IMMUNITY.description" : "{Imunitate la vrăji}\nAceastă unitate nu poate fi afectată de ${subtype.spell}",
+	"core.bonus.SPELL_LIKE_ATTACK.description" : "{Atac asemănător vrăjii}\nAtacă cu ${subtype.spell}",
+	"core.bonus.SPELL_RESISTANCE_AURA.description" : "{Aură de rezistență}\nUnitățile adiacente primesc ${val}% rezistență la magie",
+	"core.bonus.SPELL_SCHOOL_IMMUNITY.description" : "{Imunitate la vrăji}\nAceastă unitate este imună la toate vrăjile",
+	"core.bonus.SPELL_SCHOOL_IMMUNITY.description.spellSchool.air"   : "{Imunitate la magia Aerului}\nImun la toate vrăjile din școala de magie a Aerului",
+	"core.bonus.SPELL_SCHOOL_IMMUNITY.description.spellSchool.earth" : "{Imunitate la magia Pământului}\nImun la toate vrăjile din școala de magie a Pământului",
+	"core.bonus.SPELL_SCHOOL_IMMUNITY.description.spellSchool.fire"  : "{Imunitate la magia Focului}\nImun la toate vrăjile din școala de magie a Focului",
+	"core.bonus.SPELL_SCHOOL_IMMUNITY.description.spellSchool.water" : "{Imunitate la magia Apelor}\nImun la toate vrăjile din școala de magie a Apelor",
+	"core.bonus.SUMMON_GUARDIANS.description" : "{Summon guardians}\nLa începutul bătăliei, invocă ${subtype.creature} (${val}%)",
+	"core.bonus.THREE_HEADED_ATTACK.description" : "{Atac cu trei capete}\nAtacă trei unități adiacente",
+	"core.bonus.TRANSMUTATION.description" : "{Transmutare}\n${val}% șansă de a transforma unitatea atacată într-un tip diferit",
+	"core.bonus.TRANSMUTATION_IMMUNITY.description" : "{Imunitate la Transmutare}\nAceastă unitate nu poate fi transformată într-o altă unitate de atacul inamic",
+	"core.bonus.TWO_HEX_ATTACK_BREATH.description" : "{Atac cu respirație}\nAtacurile acestei unități vor lovi și orice unitate poziționată imediat în spatele țintei",
+	"core.bonus.UNDEAD.description" : "{Non-viu}\nCreatura este Non-viu și este imună la efectele care afectează doar ființele vii",
+	"core.bonus.UNLIMITED_RETALIATIONS.description" : "{Riposte nelimitate}\nAceastă unitate poate riposta la un număr nelimitat de atacuri",
+	"core.bonus.WIDE_BREATH.description" : "{Respirație largă}\nAceastă unitate atacă toate unitățile din jurul țintei",
+	
+	"spell.core.castleMoat.name" : "Șanț",
+	"spell.core.castleMoatTrigger.name" : "Șanț",
+	"spell.core.catapultShot.name" : "Lansare de catapultă",
+	"spell.core.cyclopsShot.name" : "Lansare de asediu",
+	"spell.core.dungeonMoat.name" : "Ulei Fiert",
+	"spell.core.dungeonMoatTrigger.name" : "Ulei Fiert",
+	"spell.core.fireWallTrigger.name" : "Perete de Foc",
+	"spell.core.firstAid.name" : "Prim Ajutor",
+	"spell.core.fortressMoat.name" : "Gudron Fiert",
+	"spell.core.fortressMoatTrigger.name" : "Gudron Fiert",
+	"spell.core.infernoMoat.name" : "Lava",
+	"spell.core.infernoMoatTrigger.name" : "Lava",
+	"spell.core.landMineTrigger.name" : "Mină de Pământ",
+	"spell.core.necropolisMoat.name" : "Cimitirul",
+	"spell.core.necropolisMoatTrigger.name" : "Cimitirul",
+	"spell.core.rampartMoat.name" : "Spini",
+	"spell.core.rampartMoatTrigger.name" : "Spini",
+	"spell.core.strongholdMoat.name" : "Țepi de Lemn",
+	"spell.core.strongholdMoatTrigger.name" : "Țepi de Lemn",
+	"spell.core.summonDemons.name" : "Invocare Demoni",
+	"spell.core.towerMoat.name" : "Mină de Pământ",
+	
+	"spell.core.stoneGaze.description.none" : "{Privire de Piatră}\n\nUnitatea țintă este pietrificată și nu poate să se miște timp de trei runde de luptă. Când este atacată, primește 50% din daunele normale și devine deblocat",
+	"spell.core.poison.description.none" : "{Otravă}\n\nCând este otrăvit, sănătatea maximă a unității țintă scade cu 10% în fiecare rundă de luptă timp de trei runde. După trei runde, creatura nu mai este otrăvită, dar sănătatea maximă rămâne scăzută",
+	"spell.core.bind.description.none" : "{Legare}\n\nUnitatea țintă este legată de pământ, neputând să se miște până când grămada care a legat-o se mișcă sau dispare.",
+	"spell.core.disease.description.none" : "{Boală}\n\nȚinta vie devine bolnavă, iar valorile sale de atac și apărare sunt reduse cu două pentru o perioadă de trei runde",
+	"spell.core.paralyze.description.none" : "{Paralizie}\n\nȚinta este paralizată și nu își va efectua tura în runda de luptă curentă și în următoarele două runde de luptă, decât dacă este atacată între timp. Creaturile paralizate primesc daune complete de la atacuri, dar ripostează doar cu un sfert din forța lor.",
+	"spell.core.age.description.none" : "{Îmbătrânire}\n\nÎmbătrânirea scade sănătatea maximă a fiecărei creaturi din grămada țintă la 50% timp de trei runde de luptă",
+	"spell.core.deathCloud.description.none" : "{Nor de Moarte}\n\nPe lângă daunele normale ale atacului la distanță din hex-ul țintă, norul de moarte afectează și toate cele 6 hex-uri adiacente din jurul țintei, provocând daune tuturor creaturilor vii din raza respectivă",
+	"spell.core.thunderbolt.description.none" : "{Fulger}\n\nCând grămada atacă, există o șansă de 20% ca un fulger să lovească înainte ca inamicul să aibă șansa de a riposta. Dacă se întâmplă, fulgerul va provoca daune egale cu de zece ori numărul de Thunderbirds care atacă",
+	"spell.core.dispelHelpful.description.none" : "{Dispersare vrăji benefice}\n\nÎndepărtează toate efectele vrăjilor de la unitatea țintă.",
+	"spell.core.acidBreath.description.none" : "{Respirație acidă}\n\nRespirația reduce apărarea grămezii țintă cu 3 și are o șansă de 20% de a provoca daune suplimentare de 25 puncte per unitatea care atacă.",
+	
+	"spellSchool.core.air.name" : "Aer",
+	"spellSchool.core.earth.name" : "Pământ",
+	"spellSchool.core.fire.name" : "Foc",
+	"spellSchool.core.water.name" : "Apă"
+}

+ 2 - 0
client/CMakeLists.txt

@@ -52,6 +52,7 @@ set(vcmiclientcommon_SRCS
 	gui/ShortcutHandler.cpp
 	gui/WindowHandler.cpp
 
+	lobby/BattleOnlyMode.cpp
 	lobby/CBonusSelection.cpp
 	lobby/CCampaignInfoScreen.cpp
 	lobby/CLobbyScreen.cpp
@@ -262,6 +263,7 @@ set(vcmiclientcommon_HEADERS
 	gui/TextAlignment.h
 	gui/WindowHandler.h
 
+	lobby/BattleOnlyMode.h
 	lobby/CBonusSelection.h
 	lobby/CCampaignInfoScreen.h
 	lobby/CLobbyScreen.h

+ 3 - 2
client/CPlayerInterface.cpp

@@ -97,6 +97,7 @@
 #include "../lib/mapObjects/MiscObjects.h"
 #include "../lib/mapObjects/ObjectTemplate.h"
 
+#include "../lib/mapping/CMap.h"
 #include "../lib/mapping/CMapHeader.h"
 
 #include "../lib/networkPacks/PacksForClient.h"
@@ -658,7 +659,7 @@ void CPlayerInterface::battleStart(const BattleID & battleID, const CCreatureSet
 {
 	EVENT_HANDLER_CALLED_BY_CLIENT;
 
-	bool useQuickCombat = settings["adventure"]["quickCombat"].Bool();
+	bool useQuickCombat = settings["adventure"]["quickCombat"].Bool() || GAME->map().getMap()->battleOnly;
 	bool forceQuickCombat = settings["adventure"]["forceQuickCombat"].Bool();
 
 	if ((replayAllowed && useQuickCombat) || forceQuickCombat)
@@ -1482,7 +1483,7 @@ void CPlayerInterface::playerBlocked(int reason, bool start)
 {
 	if(reason == PlayerBlocked::EReason::UPCOMING_BATTLE)
 	{
-		if(GAME->server().howManyPlayerInterfaces() > 1 && GAME->interface() != this && GAME->interface()->makingTurn == false)
+		if(GAME->server().howManyPlayerInterfaces() > 1 && GAME->interface() != this && GAME->interface()->makingTurn == false && !GAME->map().getMap()->battleOnly)
 		{
 			//one of our players who isn't last in order got attacked not by our another player (happens for example in hotseat mode)
 			GAME->setInterfaceInstance(this);

+ 7 - 0
client/CServerHandler.cpp

@@ -432,6 +432,13 @@ void CServerHandler::setCampaignBonus(int bonusId) const
 	sendLobbyPack(lscb);
 }
 
+void CServerHandler::setBattleOnlyModeStartInfo(std::shared_ptr<BattleOnlyModeStartInfo> startInfo) const
+{
+	LobbySetBattleOnlyModeStartInfo lsbomsui;
+	lsbomsui.startInfo = startInfo;
+	sendLobbyPack(lsbomsui);
+}
+
 void CServerHandler::setMapInfo(std::shared_ptr<CMapInfo> to, std::shared_ptr<CMapGenOptions> mapGenOpts) const
 {
 	LobbySetMap lsm;

+ 2 - 0
client/CServerHandler.h

@@ -77,6 +77,7 @@ public:
 	virtual void setCampaignState(std::shared_ptr<CampaignState> newCampaign) = 0;
 	virtual void setCampaignMap(CampaignScenarioID mapId) const = 0;
 	virtual void setCampaignBonus(int bonusId) const = 0;
+	virtual void setBattleOnlyModeStartInfo(std::shared_ptr<BattleOnlyModeStartInfo> startInfo) const = 0;
 	virtual void setMapInfo(std::shared_ptr<CMapInfo> to, std::shared_ptr<CMapGenOptions> mapGenOpts = {}) const = 0;
 	virtual void setPlayer(PlayerColor color) const = 0;
 	virtual void setPlayerName(PlayerColor color, const std::string & name) const = 0;
@@ -186,6 +187,7 @@ public:
 	void setCampaignState(std::shared_ptr<CampaignState> newCampaign) override;
 	void setCampaignMap(CampaignScenarioID mapId) const override;
 	void setCampaignBonus(int bonusId) const override;
+	void setBattleOnlyModeStartInfo(std::shared_ptr<BattleOnlyModeStartInfo> startInfo) const override;
 	void setMapInfo(std::shared_ptr<CMapInfo> to, std::shared_ptr<CMapGenOptions> mapGenOpts = {}) const override;
 	void setPlayer(PlayerColor color) const override;
 	void setPlayerName(PlayerColor color, const std::string & name) const override;

+ 1 - 0
client/LobbyClientNetPackVisitors.h

@@ -59,4 +59,5 @@ public:
 	void visitLobbyLoadProgress(LobbyLoadProgress & pack) override;
 	void visitLobbyUpdateState(LobbyUpdateState & pack) override;
 	void visitLobbyShowMessage(LobbyShowMessage & pack) override;
+	void visitLobbySetBattleOnlyModeStartInfo(LobbySetBattleOnlyModeStartInfo & pack) override;
 };

+ 9 - 2
client/NetPacksClient.cpp

@@ -15,6 +15,7 @@
 #include "windows/GUIClasses.h"
 #include "windows/CCastleInterface.h"
 #include "mapView/mapHandler.h"
+#include "mainmenu/CMainMenu.h"
 #include "adventureMap/AdventureMapInterface.h"
 #include "adventureMap/CInGameConsole.h"
 #include "battle/BattleInterface.h"
@@ -400,7 +401,7 @@ void ApplyClientNetPackVisitor::visitPlayerEndsGame(PlayerEndsGame & pack)
 	bool localHumanWinsGame = vstd::contains(cl.playerint, pack.player) && cl.gameInfo().getPlayerState(pack.player)->human && pack.victoryLossCheckResult.victory();
 	bool lastHumanEndsGame = GAME->server().howManyPlayerInterfaces() == 1 && vstd::contains(cl.playerint, pack.player) && cl.gameInfo().getPlayerState(pack.player)->human && !settings["session"]["spectate"].Bool();
 
-	if(lastHumanEndsGame || localHumanWinsGame)
+	if(lastHumanEndsGame || localHumanWinsGame || pack.silentEnd)
 	{
 		assert(adventureInt);
 		if(adventureInt)
@@ -409,7 +410,13 @@ void ApplyClientNetPackVisitor::visitPlayerEndsGame(PlayerEndsGame & pack)
 			adventureInt.reset();
 		}
 
-		GAME->server().showHighScoresAndEndGameplay(pack.player, pack.victoryLossCheckResult.victory(), pack.statistic);
+		if(!pack.silentEnd)
+			GAME->server().showHighScoresAndEndGameplay(pack.player, pack.victoryLossCheckResult.victory(), pack.statistic);
+		else
+		{
+			GAME->server().endGameplay();
+			GAME->mainmenu()->menu->switchToTab("main");
+		}
 	}
 
 	// In auto testing pack.mode we always close client if red pack.player won or lose

+ 13 - 0
client/NetPacksLobbyClient.cpp

@@ -19,6 +19,7 @@
 #include "lobby/ExtraOptionsTab.h"
 #include "lobby/SelectionTab.h"
 #include "lobby/CBonusSelection.h"
+#include "lobby/BattleOnlyMode.h"
 #include "globalLobby/GlobalLobbyWindow.h"
 #include "globalLobby/GlobalLobbyServerSetup.h"
 #include "globalLobby/GlobalLobbyClient.h"
@@ -113,6 +114,9 @@ void ApplyOnLobbyScreenNetPackVisitor::visitLobbyGuiAction(LobbyGuiAction & pack
 	if(!lobby || !handler.isGuest())
 		return;
 
+	if(auto topWindow = ENGINE->windows().topWindow<BattleOnlyModeWindow>())
+		topWindow->close();
+
 	switch(pack.action)
 	{
 	case LobbyGuiAction::NO_TAB:
@@ -133,6 +137,9 @@ void ApplyOnLobbyScreenNetPackVisitor::visitLobbyGuiAction(LobbyGuiAction & pack
 	case LobbyGuiAction::OPEN_EXTRA_OPTIONS:
 		lobby->toggleTab(lobby->tabExtraOptions);
 		break;
+	case LobbyGuiAction::BATTLE_MODE:
+		BattleOnlyMode::openBattleWindow();
+		break;
 	}
 }
 
@@ -232,3 +239,9 @@ void ApplyOnLobbyScreenNetPackVisitor::visitLobbyShowMessage(LobbyShowMessage &
 	lobby->buttonStart->block(false);
 	handler.showServerError(pack.message.toString());
 }
+
+void ApplyOnLobbyScreenNetPackVisitor::visitLobbySetBattleOnlyModeStartInfo(LobbySetBattleOnlyModeStartInfo & pack)
+{
+	if(auto topWindow = ENGINE->windows().topWindow<BattleOnlyModeWindow>())
+		topWindow->applyStartInfo(pack.startInfo);
+}

+ 12 - 3
client/battle/BattleActionsController.cpp

@@ -264,6 +264,7 @@ void BattleActionsController::reorderPossibleActionsPriority(const CStack * stac
 			case PossiblePlayerBattleAction::NO_LOCATION:
 			case PossiblePlayerBattleAction::FREE_LOCATION:
 			case PossiblePlayerBattleAction::OBSTACLE:
+			case PossiblePlayerBattleAction::SACRIFICE:
 				if(!stack->hasBonusOfType(BonusType::NO_SPELLCAST_BY_DEFAULT) && targetStack != nullptr)
 				{
 					PlayerColor stackOwner = owner.getBattle()->battleGetOwner(targetStack);
@@ -652,10 +653,11 @@ bool BattleActionsController::actionIsLegal(PossiblePlayerBattleAction action, c
 		case PossiblePlayerBattleAction::WALK_AND_ATTACK:
 		case PossiblePlayerBattleAction::ATTACK_AND_RETURN:
 			{
-				if (owner.fieldController->isTileAttackable(targetHex)) // move isTileAttackable to be part of battleCanAttack?
+				auto activeStack = owner.stacksController->getActiveStack();
+				if (targetStack && targetStack != activeStack && owner.fieldController->isTileAttackable(targetHex)) // move isTileAttackable to be part of battleCanAttack?
 				{
 					BattleHex attackFromHex = owner.fieldController->fromWhichHexAttack(targetHex);
-					if(owner.getBattle()->battleCanAttack(owner.stacksController->getActiveStack(), targetStack, attackFromHex))
+					if(owner.getBattle()->battleCanAttack(activeStack, targetStack, attackFromHex))
 						return true;
 				}
 				return false;
@@ -698,7 +700,14 @@ bool BattleActionsController::actionIsLegal(PossiblePlayerBattleAction action, c
 			return selectedStack && isCastingPossibleHere(action.spell().toSpell(), selectedStack, targetHex);
 
 		case PossiblePlayerBattleAction::SACRIFICE: //choose our living stack to sacrifice
-			return targetStack && targetStack != selectedStack && targetStackOwned && targetStack->alive();
+		{
+			if(!targetStack)
+				return false;
+
+			auto unit = targetStack->acquire();
+			return targetStack != selectedStack && targetStackOwned && targetStack->alive()
+					&& unit->isLiving() && !unit->hasBonusOfType(BonusType::MECHANICAL);
+		}
 
 		case PossiblePlayerBattleAction::OBSTACLE:
 		case PossiblePlayerBattleAction::FREE_LOCATION:

+ 1 - 1
client/battle/BattleFieldController.cpp

@@ -819,7 +819,7 @@ bool BattleFieldController::isTileAttackable(const BattleHex & number) const
 
 	for (auto & elem : occupiableHexes)
 	{
-		if (BattleHex::mutualPosition(elem, number) != BattleHex::EDir::NONE || elem == number)
+		if (BattleHex::mutualPosition(elem, number) != BattleHex::EDir::NONE)
 			return true;
 	}
 	return false;

+ 1 - 1
client/battle/BattleProjectileController.cpp

@@ -161,7 +161,7 @@ const CCreature & BattleProjectileController::getShooter(const CStack * stack) c
 	if(creature->getId() == CreatureID::ARROW_TOWERS)
 		creature = owner.siegeController->getTurretCreature(stack->initialPosition);
 
-	if(creature->animation.missileFrameAngles.empty())
+	if(creature->animation.missileFrameAngles.empty() && creature->animation.projectileRay.empty())
 	{
 		logAnim->error("Mod error: Creature '%s' on the Archer's tower is not a shooter. Mod should be fixed. Trying to use archer's data instead...", creature->getNameSingularTranslated());
 		creature = CreatureID(CreatureID::ARCHER).toCreature();

+ 12 - 1
client/battle/BattleResultWindow.cpp

@@ -12,6 +12,9 @@
 
 #include "BattleWindow.h"
 
+#include "../GameInstance.h"
+#include "../Client.h"
+#include "../CServerHandler.h"
 #include "../CPlayerInterface.h"
 #include "../GameEngine.h"
 #include "../gui/Shortcut.h"
@@ -23,6 +26,7 @@
 #include "../widgets/VideoWidget.h"
 
 #include "../../lib/CStack.h"
+#include "../../lib/CPlayerState.h"
 #include "../../lib/ConditionalWait.h"
 #include "../../lib/GameLibrary.h"
 #include "../../lib/StartInfo.h"
@@ -45,7 +49,14 @@ BattleResultWindow::BattleResultWindow(const BattleResult & br, CPlayerInterface
 	exit = std::make_shared<CButton>(Point(384, 505), AnimationPath::builtin("iok6432.def"), std::make_pair("", ""), [this](){ bExitf();}, EShortcut::GLOBAL_ACCEPT);
 	exit->setBorderColor(Colors::METALLIC_GOLD);
 
-	if(allowReplay || owner.cb->getStartInfo()->extraOptionsInfo.unlimitedReplay)
+	auto battle = owner.cb->getBattle(br.battleID);
+	const auto * attackerPlayer = GAME->server().client->gameInfo().getPlayerState(battle->sideToPlayer(BattleSide::ATTACKER));
+	const auto * defenderPlayer = GAME->server().client->gameInfo().getPlayerState(battle->sideToPlayer(BattleSide::DEFENDER));
+	bool isAttackerHuman = attackerPlayer && attackerPlayer->isHuman();
+	bool isDefenderHuman = defenderPlayer && defenderPlayer->isHuman();
+	bool onlyOnePlayerHuman = isAttackerHuman != isDefenderHuman;
+
+	if((allowReplay || owner.cb->getStartInfo()->extraOptionsInfo.unlimitedReplay) && onlyOnePlayerHuman)
 	{
 		repeat = std::make_shared<CButton>(Point(24, 505), AnimationPath::builtin("icn6432.def"), std::make_pair("", ""), [this](){ bRepeatf();}, EShortcut::GLOBAL_CANCEL);
 		repeat->setBorderColor(Colors::METALLIC_GOLD);

+ 3 - 0
client/battle/BattleWindow.cpp

@@ -51,6 +51,7 @@
 #include "../../lib/entities/artifact/CArtHandler.h"
 #include "../../lib/filesystem/ResourcePath.h"
 #include "../../lib/gameState/InfoAboutArmy.h"
+#include "../../lib/mapping/CMapHeader.h"
 #include "../../lib/mapObjects/CGHeroInstance.h"
 #include "../../lib/texts/CGeneralTextHandler.h"
 
@@ -851,6 +852,8 @@ void BattleWindow::endWithAutocombat()
 
 void BattleWindow::showAll(Canvas & to)
 {
+	if(owner.curInt->cb->getMapHeader()->battleOnly)
+		to.fillTexture(ENGINE->renderHandler().loadImage(ImagePath::builtin("DiBoxBck"), EImageBlitMode::OPAQUE));
 	CIntObject::showAll(to);
 
 	if (ENGINE->screenDimensions().x != 800 || ENGINE->screenDimensions().y !=600)

+ 1 - 1
client/gui/CursorHandler.h

@@ -132,7 +132,7 @@ class CursorHandler final
 	Point pos;
 	float frameTime;
 	int32_t currentCursorIndex;
-	int32_t currentFrame;
+	int32_t currentFrame {};
 	Cursor::ShowType showType;
 	bool showing;
 

+ 517 - 0
client/lobby/BattleOnlyMode.cpp

@@ -0,0 +1,517 @@
+/*
+ * BattleOnlyMode.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+#include "StdInc.h"
+#include "BattleOnlyMode.h"
+
+#include "../CServerHandler.h"
+#include "../GameEngine.h"
+#include "../GameInstance.h"
+
+#include "../render/IRenderHandler.h"
+#include "../render/CAnimation.h"
+#include "../render/Canvas.h"
+#include "../render/CanvasImage.h"
+#include "../gui/Shortcut.h"
+#include "../gui/WindowHandler.h"
+#include "../widgets/Buttons.h"
+#include "../widgets/GraphicalPrimitiveCanvas.h"
+#include "../widgets/TextControls.h"
+#include "../widgets/CTextInput.h"
+#include "../widgets/Images.h"
+#include "../windows/GUIClasses.h"
+#include "../windows/CHeroOverview.h"
+#include "../windows/CCreatureWindow.h"
+
+#include "../../lib/GameLibrary.h"
+#include "../../lib/gameState/CGameState.h"
+#include "../../lib/networkPacks/PacksForLobby.h"
+#include "../../lib/StartInfo.h"
+#include "../../lib/VCMIDirs.h"
+#include "../../lib/CRandomGenerator.h"
+#include "../../lib/callback/EditorCallback.h"
+#include "../../lib/entities/hero/CHero.h"
+#include "../../lib/entities/hero/CHeroClass.h"
+#include "../../lib/entities/hero/CHeroHandler.h"
+#include "../../lib/entities/faction/CTown.h"
+#include "../../lib/entities/faction/CTownHandler.h"
+#include "../../lib/mapObjects/CGHeroInstance.h"
+#include "../../lib/mapObjects/CGTownInstance.h"
+#include "../../lib/mapObjectConstructors/AObjectTypeHandler.h"
+#include "../../lib/mapObjectConstructors/CObjectClassesHandler.h"
+#include "../../lib/mapping/CMap.h"
+#include "../../lib/mapping/CMapInfo.h"
+#include "../../lib/mapping/CMapEditManager.h"
+#include "../../lib/mapping/CMapService.h"
+#include "../../lib/mapping/MapFormat.h"
+#include "../../lib/texts/CGeneralTextHandler.h"
+#include "../../lib/texts/MetaString.h"
+#include "../../lib/texts/TextOperations.h"
+#include "../../lib/filesystem/Filesystem.h"
+
+void BattleOnlyMode::openBattleWindow()
+{
+	GAME->server().sendGuiAction(LobbyGuiAction::BATTLE_MODE);
+	ENGINE->windows().createAndPushWindow<BattleOnlyModeWindow>();
+}
+
+BattleOnlyModeWindow::BattleOnlyModeWindow()
+	: CWindowObject(BORDERED)
+	, startInfo(std::make_shared<BattleOnlyModeStartInfo>())
+	, disabledColor(GAME->server().isHost() ? Colors::WHITE : Colors::ORANGE)
+{
+	OBJECT_CONSTRUCTION;
+
+	pos.w = 519;
+	pos.h = 238;
+
+	updateShadow();
+	center();
+
+	init();
+
+	backgroundTexture = std::make_shared<FilledTexturePlayerColored>(Rect(0, 0, pos.w, pos.h));
+	backgroundTexture->setPlayerColor(PlayerColor(1));
+	buttonOk = std::make_shared<CButton>(Point(191, 203), AnimationPath::builtin("MuBchck"), CButton::tooltip(), [this](){ startBattle(); }, EShortcut::GLOBAL_ACCEPT);
+	buttonOk->block(true);
+	buttonAbort = std::make_shared<CButton>(Point(265, 203), AnimationPath::builtin("MuBcanc"), CButton::tooltip(), [this](){
+		GAME->server().sendGuiAction(LobbyGuiAction::NO_TAB);
+		close();
+	}, EShortcut::GLOBAL_CANCEL);
+	buttonAbort->block(true);
+	title = std::make_shared<CLabel>(260, 20, FONT_BIG, ETextAlignment::CENTER, Colors::YELLOW, LIBRARY->generaltexth->translate("vcmi.lobby.battleOnlyMode"));
+
+	battlefieldSelector = std::make_shared<CButton>(Point(29, 174), AnimationPath::builtin("GSPButtonClear"), CButton::tooltip(), [this](){
+		std::vector<std::string> texts;
+		std::vector<std::shared_ptr<IImage>> images;
+
+		auto & terrains = LIBRARY->terrainTypeHandler->objects;
+		for (const auto & terrain : terrains)
+		{
+			if(!terrain->isPassable())
+				continue;
+
+			texts.push_back(terrain->getNameTranslated());
+
+			const auto & patterns = LIBRARY->terviewh->getTerrainViewPatterns(terrain->getId());
+			TerrainViewPattern pattern;
+			for(auto & p : patterns)
+				if(p[0].id == "n1")
+					pattern = p[0];
+			auto image = ENGINE->renderHandler().loadImage(terrain->tilesFilename, pattern.mapping[0].first, 0, EImageBlitMode::OPAQUE);
+			image->scaleTo(Point(23, 23), EScalingAlgorithm::NEAREST);
+			images.push_back(image);
+		}
+
+		auto factions = LIBRARY->townh->getDefaultAllowed();
+		for (const auto & faction : factions)
+		{
+			texts.push_back(faction.toFaction()->getNameTranslated());
+
+			auto image = ENGINE->renderHandler().loadImage(AnimationPath::builtin("ITPA"), faction.toFaction()->town->clientInfo.icons[true][false] + 2, 0, EImageBlitMode::OPAQUE);
+			image->scaleTo(Point(35, 23), EScalingAlgorithm::NEAREST);
+			images.push_back(image);
+		}
+
+		ENGINE->windows().createAndPushWindow<CObjectListWindow>(texts, nullptr, LIBRARY->generaltexth->translate("vcmi.lobby.battleOnlyModeBattlefield"), LIBRARY->generaltexth->translate("vcmi.lobby.battleOnlyModeBattlefieldSelect"), [this, terrains, factions](int index){
+			if(terrains.size() > index)
+			{
+				startInfo->selectedTerrain = terrains[index]->getId();
+				startInfo->selectedTown = std::nullopt;
+			}
+			else
+			{
+				startInfo->selectedTerrain = std::nullopt;
+				auto it = std::next(factions.begin(), index - terrains.size());
+				if (it != factions.end())
+    				startInfo->selectedTown = *it;
+			}
+			onChange();
+		}, (startInfo->selectedTerrain ? static_cast<int>(*startInfo->selectedTerrain) : static_cast<int>(*startInfo->selectedTown + terrains.size())), images, true, true);
+	});
+	battlefieldSelector->block(GAME->server().isGuest());
+	buttonReset = std::make_shared<CButton>(Point(289, 174), AnimationPath::builtin("GSPButtonClear"), CButton::tooltip(), [this](){
+		if(GAME->server().isHost())
+		{
+			startInfo->selectedTerrain = TerrainId::DIRT;
+			startInfo->selectedTown = std::nullopt;
+			startInfo->selectedHero[0] = std::nullopt;
+			startInfo->selectedArmy[0].fill(CStackBasicDescriptor(CreatureID::NONE, 1));
+			for(size_t i=0; i<GameConstants::ARMY_SIZE; i++)
+				heroSelector1->selectedArmyInput.at(i)->disable();
+		}
+		startInfo->selectedHero[1] = std::nullopt;
+		startInfo->selectedArmy[1].fill(CStackBasicDescriptor(CreatureID::NONE, 1));
+		for(size_t i=0; i<GameConstants::ARMY_SIZE; i++)
+			heroSelector2->selectedArmyInput.at(i)->disable();
+		onChange();
+	});
+	buttonReset->setTextOverlay(LIBRARY->generaltexth->translate("vcmi.lobby.battleOnlyModeReset"), EFonts::FONT_SMALL, Colors::WHITE);
+
+	heroSelector1 = std::make_shared<BattleOnlyModeHeroSelector>(0, *this, Point(0, 40));
+	heroSelector2 = std::make_shared<BattleOnlyModeHeroSelector>(1, *this, Point(260, 40));
+
+	heroSelector1->setInputEnabled(GAME->server().isHost());
+
+	onChange();
+}
+
+void BattleOnlyModeWindow::init()
+{
+	map = std::make_unique<CMap>(nullptr);
+	map->version = EMapFormat::VCMI;
+	map->creationDateTime = std::time(nullptr);
+	map->width = 10;
+	map->height = 10;
+	map->mapLevels = 1;
+	map->battleOnly = true;
+	map->name = MetaString::createFromTextID("vcmi.lobby.battleOnlyMode");
+
+	cb = std::make_unique<EditorCallback>(map.get());
+}
+
+void BattleOnlyModeWindow::onChange()
+{
+	GAME->server().setBattleOnlyModeStartInfo(startInfo);
+}
+
+void BattleOnlyModeWindow::update()
+{
+	setTerrainButtonText();
+	setOkButtonEnabled();
+	
+	heroSelector1->setHeroIcon();
+	heroSelector1->setCreatureIcons();
+	heroSelector2->setHeroIcon();
+	heroSelector2->setCreatureIcons();
+	redraw();
+}
+
+void BattleOnlyModeWindow::applyStartInfo(std::shared_ptr<BattleOnlyModeStartInfo> si)
+{
+	startInfo = si;
+	update();
+}
+
+void BattleOnlyModeWindow::setTerrainButtonText()
+{
+	battlefieldSelector->setTextOverlay(LIBRARY->generaltexth->translate("vcmi.lobby.battleOnlyModeBattlefield") + ":   " + (startInfo->selectedTerrain ? (*startInfo->selectedTerrain).toEntity(LIBRARY)->getNameTranslated() : (*startInfo->selectedTown).toEntity(LIBRARY)->getNameTranslated()), EFonts::FONT_SMALL, disabledColor);
+}
+
+void BattleOnlyModeWindow::setOkButtonEnabled()
+{
+	bool army2Empty = std::all_of(startInfo->selectedArmy[1].begin(), startInfo->selectedArmy[1].end(), [](const auto x) { return x.getId() == CreatureID::NONE; });
+
+	bool canStart = (startInfo->selectedTerrain || startInfo->selectedTown);
+	canStart &= (startInfo->selectedHero[0] && ((startInfo->selectedHero[1]) || (startInfo->selectedTown && !army2Empty)));
+	buttonOk->block(!canStart || GAME->server().isGuest());
+	buttonAbort->block(GAME->server().isGuest());
+}
+
+std::shared_ptr<IImage> drawBlackBox(Point size, std::string text, ColorRGBA color)
+{
+	auto image = ENGINE->renderHandler().createImage(size, CanvasScalingPolicy::AUTO);
+	Canvas canvas = image->getCanvas();
+	canvas.drawColor(Rect(0, 0, size.x, size.y), Colors::BLACK);
+	canvas.drawText(Point(size.x / 2, size.y / 2), FONT_TINY, color, ETextAlignment::CENTER, text);
+	return image;
+}
+
+BattleOnlyModeHeroSelector::BattleOnlyModeHeroSelector(int id, BattleOnlyModeWindow& p, Point position)
+: parent(p)
+, id(id)
+{
+	OBJECT_CONSTRUCTION;
+
+	pos.x += position.x;
+	pos.y += position.y;
+
+	backgroundImage = std::make_shared<CPicture>(ImagePath::builtin("heroSlotsBlue"), Point(3, 4));
+
+	for(size_t i=0; i<GameConstants::PRIMARY_SKILLS; i++)
+	{
+		auto image = std::make_shared<CAnimImage>(AnimationPath::builtin("PSKIL32"), i, 0, 78 + i * 36, 26);
+		primSkills.push_back(image);
+		primSkillsBorder.push_back(std::make_shared<GraphicalPrimitiveCanvas>(Rect(78 + i * 36, 26, 32, 32)));
+		primSkillsBorder.back()->addRectangle(Point(0, 0), Point(32, 32), ColorRGBA(44, 108, 255));
+		primSkillsInput.push_back(std::make_shared<CTextInput>(Rect(78 + i * 36, 58, 32, 16), EFonts::FONT_SMALL, ETextAlignment::CENTER, false));
+		primSkillsInput.back()->setColor(id == 1 ? Colors::WHITE : parent.disabledColor);
+		primSkillsInput.back()->setFilterNumber(0, 100);
+		primSkillsInput.back()->setText("0");
+		primSkillsInput.back()->setCallback([this, i, id](const std::string & text){
+			parent.startInfo->primSkillLevel[id][i] = std::stoi(primSkillsInput[i]->getText());
+			parent.onChange();
+		});
+	}
+
+	creatureImage.resize(GameConstants::ARMY_SIZE);
+	for(size_t i=0; i<GameConstants::ARMY_SIZE; i++)
+	{
+		selectedArmyInput.push_back(std::make_shared<CTextInput>(Rect(5 + i * 36, 113, 32, 16), EFonts::FONT_SMALL, ETextAlignment::CENTER, false));
+		selectedArmyInput.back()->setColor(id == 1 ? Colors::WHITE : parent.disabledColor);
+		selectedArmyInput.back()->setFilterNumber(1, 10000000, 3);
+		selectedArmyInput.back()->setText("1");
+		selectedArmyInput.back()->setCallback([this, i, id](const std::string & text){
+			if(parent.startInfo->selectedArmy[id][i].getId() != CreatureID::NONE)
+			{
+				parent.startInfo->selectedArmy[id][i].setCount(TextOperations::parseMetric<int>(text));
+				parent.onChange();
+				selectedArmyInput[i]->enable();
+			}
+			else
+				selectedArmyInput[i]->disable();
+		});
+	}
+
+	setHeroIcon();
+	setCreatureIcons();
+}
+
+void BattleOnlyModeHeroSelector::setHeroIcon()
+{
+	OBJECT_CONSTRUCTION;
+
+	if(!parent.startInfo->selectedHero[id])
+	{
+		heroImage = std::make_shared<CPicture>(drawBlackBox(Point(58, 64), LIBRARY->generaltexth->translate("vcmi.lobby.battleOnlyModeSelect"), id == 1 ? Colors::WHITE : parent.disabledColor), Point(6, 7));
+		heroLabel = std::make_shared<CLabel>(160, 16, FONT_SMALL, ETextAlignment::CENTER, id == 1 ? Colors::WHITE : parent.disabledColor, LIBRARY->generaltexth->translate("core.genrltxt.507"));
+		for(size_t i=0; i<GameConstants::PRIMARY_SKILLS; i++)
+			primSkillsInput[i]->setText("0");
+	}
+	else
+	{
+		heroImage = std::make_shared<CPicture>(ENGINE->renderHandler().loadAnimation(AnimationPath::builtin("PortraitsLarge"), EImageBlitMode::COLORKEY)->getImage((*parent.startInfo->selectedHero[id]).toHeroType()->imageIndex), Point(6, 7));
+		heroLabel = std::make_shared<CLabel>(160, 16, FONT_SMALL, ETextAlignment::CENTER, id == 1 ? Colors::WHITE : parent.disabledColor, (*parent.startInfo->selectedHero[id]).toHeroType()->getNameTranslated());
+		for(size_t i=0; i<GameConstants::PRIMARY_SKILLS; i++)
+			primSkillsInput[i]->setText(std::to_string(parent.startInfo->primSkillLevel[id][i]));
+	}
+
+	heroImage->addLClickCallback([this](){
+		auto allowedSet = LIBRARY->heroh->getDefaultAllowed();
+		std::vector<HeroTypeID> heroes(allowedSet.begin(), allowedSet.end());
+		std::sort(heroes.begin(), heroes.end(), [](auto a, auto b) {
+			auto heroA = a.toHeroType();
+			auto heroB = b.toHeroType();
+			if(heroA->heroClass->faction != heroB->heroClass->faction)
+				return heroA->heroClass->faction < heroB->heroClass->faction;
+			if(heroA->heroClass->getId() != heroB->heroClass->getId())
+				return heroA->heroClass->getId() < heroB->heroClass->getId();
+			return heroA->getNameTranslated() < heroB->getNameTranslated();
+		});
+
+		int selectedIndex = !parent.startInfo->selectedHero[id] ? 0 : (1 + std::distance(heroes.begin(), std::find_if(heroes.begin(), heroes.end(), [this](auto heroID) {
+			return heroID == (*parent.startInfo->selectedHero[id]);
+    	})));
+		
+		std::vector<std::string> texts;
+		std::vector<std::shared_ptr<IImage>> images;
+		// Add "no hero" option
+		texts.push_back(LIBRARY->generaltexth->translate("core.genrltxt.507"));
+		images.push_back(nullptr);
+		for (const auto & h : heroes)
+		{
+			texts.push_back(h.toHeroType()->getNameTranslated());
+
+			auto image = ENGINE->renderHandler().loadImage(AnimationPath::builtin("PortraitsSmall"), h.toHeroType()->imageIndex, 0, EImageBlitMode::OPAQUE);
+			image->scaleTo(Point(35, 23), EScalingAlgorithm::NEAREST);
+			images.push_back(image);
+		}
+		auto window = std::make_shared<CObjectListWindow>(texts, nullptr, LIBRARY->generaltexth->translate("vcmi.lobby.battleOnlyModeHeroSelect"), LIBRARY->generaltexth->translate("vcmi.lobby.battleOnlyModeHeroSelect"), [this, heroes](int index){
+			if(index == 0)
+			{
+				parent.startInfo->selectedHero[id] = std::nullopt;
+				parent.onChange();
+				return;
+			}
+			index--;
+
+			parent.startInfo->selectedHero[id] = heroes[index];
+
+			for(size_t i=0; i<GameConstants::PRIMARY_SKILLS; i++)
+				parent.startInfo->primSkillLevel[id][i] = 0;
+			parent.onChange();
+		}, selectedIndex, images, true, true);
+		window->onPopup = [heroes](int index) {
+			if(index == 0)
+				return;
+			index--;
+
+			ENGINE->windows().createAndPushWindow<CHeroOverview>(heroes.at(index));
+		};
+		ENGINE->windows().pushWindow(window);
+	});
+
+	heroImage->addRClickCallback([this](){
+		if(!parent.startInfo->selectedHero[id])
+			return;
+		
+		ENGINE->windows().createAndPushWindow<CHeroOverview>(parent.startInfo->selectedHero[id]->toHeroType()->getId());
+	});
+}
+
+void BattleOnlyModeHeroSelector::setCreatureIcons()
+{
+	OBJECT_CONSTRUCTION;
+
+	for(int i = 0; i < creatureImage.size(); i++)
+	{
+		if(parent.startInfo->selectedArmy[id][i].getId() == CreatureID::NONE)
+		{
+			creatureImage[i] = std::make_shared<CPicture>(drawBlackBox(Point(32, 32), LIBRARY->generaltexth->translate("vcmi.lobby.battleOnlyModeSelect"), id == 1 ? Colors::WHITE : parent.disabledColor), Point(6 + i * 36, 78));
+			selectedArmyInput[i]->disable();
+		}
+		else
+		{
+			auto unit = parent.startInfo->selectedArmy[id][i];
+			auto creatureID = unit.getId();
+			creatureImage[i] = std::make_shared<CPicture>(ENGINE->renderHandler().loadAnimation(AnimationPath::builtin("CPRSMALL"), EImageBlitMode::COLORKEY)->getImage(LIBRARY->creh->objects.at(creatureID)->getIconIndex()), Point(6 + i * 36, 78));
+			selectedArmyInput[i]->setText(TextOperations::formatMetric(unit.getCount(), 3));
+			selectedArmyInput[i]->enable();
+		}
+
+		creatureImage[i]->addLClickCallback([this, i](){
+			auto allowedSet = LIBRARY->creh->getDefaultAllowed();
+			std::vector<CreatureID> creatures(allowedSet.begin(), allowedSet.end());
+			std::sort(creatures.begin(), creatures.end(), [](auto a, auto b) {
+				auto creatureA = a.toCreature();
+				auto creatureB = b.toCreature();
+				if(creatureA->getFactionID() != creatureB->getFactionID())
+					return creatureA->getFactionID() < creatureB->getFactionID();
+				if(creatureA->getLevel() != creatureB->getLevel())
+					return creatureA->getLevel() < creatureB->getLevel();
+				if(creatureA->upgrades.size() != creatureB->upgrades.size())
+					return creatureA->upgrades.size() > creatureB->upgrades.size();
+				return creatureA->getNameSingularTranslated() < creatureB->getNameSingularTranslated();
+			});
+
+			int selectedIndex = parent.startInfo->selectedArmy[id][i].getId() == CreatureID::NONE ? 0 : (1 + std::distance(creatures.begin(), std::find_if(creatures.begin(), creatures.end(), [this, i](auto creatureID) {
+				return creatureID == parent.startInfo->selectedArmy[id][i].getId();
+			})));
+			
+			std::vector<std::string> texts;
+			std::vector<std::shared_ptr<IImage>> images;
+			// Add "no creature" option
+			texts.push_back(LIBRARY->generaltexth->translate("core.genrltxt.507"));
+			images.push_back(nullptr);
+			for (const auto & c : creatures)
+			{
+				texts.push_back(c.toCreature()->getNameSingularTranslated());
+
+				auto image = ENGINE->renderHandler().loadImage(AnimationPath::builtin("CPRSMALL"), c.toCreature()->getIconIndex(), 0, EImageBlitMode::OPAQUE);
+				image->scaleTo(Point(23, 23), EScalingAlgorithm::NEAREST);
+				images.push_back(image);
+			}
+			auto window = std::make_shared<CObjectListWindow>(texts, nullptr, LIBRARY->generaltexth->translate("vcmi.lobby.battleOnlyModeCreatureSelect"), LIBRARY->generaltexth->translate("vcmi.lobby.battleOnlyModeCreatureSelect"), [this, creatures, i](int index){
+				if(index == 0)
+				{
+					parent.startInfo->selectedArmy[id][i] = CStackBasicDescriptor(CreatureID::NONE, 1);
+					parent.onChange();
+					return;
+				}
+				index--;
+
+				auto creature = creatures.at(index).toCreature();
+				parent.startInfo->selectedArmy[id][i] = CStackBasicDescriptor(creature->getId(), 100);
+				parent.onChange();
+			}, selectedIndex, images, true, true);
+			window->onPopup = [creatures](int index) {
+				if(index == 0)
+					return;
+				index--;
+
+				ENGINE->windows().createAndPushWindow<CStackWindow>(creatures.at(index).toCreature(), true);
+			};
+			ENGINE->windows().pushWindow(window);
+		});
+
+		creatureImage[i]->addRClickCallback([this, i](){
+			if(parent.startInfo->selectedArmy[id][i].getId() == CreatureID::NONE)
+				return;
+			
+			ENGINE->windows().createAndPushWindow<CStackWindow>(LIBRARY->creh->objects.at(parent.startInfo->selectedArmy[id][i].getId()).get(), true);
+		});
+	}
+}
+
+void BattleOnlyModeWindow::startBattle()
+{
+	auto rng = &CRandomGenerator::getDefault();
+	
+	map->initTerrain();
+	map->getEditManager()->clearTerrain(rng);
+
+	map->getEditManager()->getTerrainSelection().selectAll();
+	map->getEditManager()->drawTerrain(!startInfo->selectedTerrain ? TerrainId::DIRT : *startInfo->selectedTerrain, 0, rng);
+
+	map->players[0].canComputerPlay = true;
+	map->players[0].canHumanPlay = true;
+	map->players[1] = map->players[0];
+
+	auto knownHeroes = LIBRARY->objtypeh->knownSubObjects(Obj::HERO);
+
+	auto addHero = [&, this](int sel, PlayerColor color, const int3 & position)
+	{
+		auto factory = LIBRARY->objtypeh->getHandlerFor(Obj::HERO, (*startInfo->selectedHero[sel]).toHeroType()->heroClass->getId());
+		auto templates = factory->getTemplates();
+		auto obj = std::dynamic_pointer_cast<CGHeroInstance>(factory->create(cb.get(), templates.front()));
+		obj->setHeroType(*startInfo->selectedHero[sel]);
+
+		obj->setOwner(color);
+		obj->pos = position;
+		for(size_t i=0; i<GameConstants::PRIMARY_SKILLS; i++)
+			obj->pushPrimSkill(PrimarySkill(i), startInfo->primSkillLevel[sel][i]);
+		obj->clearSlots();
+		for(int slot = 0; slot < GameConstants::ARMY_SIZE; slot++)
+			if(startInfo->selectedArmy[sel][slot].getId() != CreatureID::NONE)
+				obj->setCreature(SlotID(slot), startInfo->selectedArmy[sel][slot].getId(), startInfo->selectedArmy[sel][slot].getCount());
+		map->getEditManager()->insertObject(obj);
+	};
+
+	addHero(0, PlayerColor(0), int3(5, 6, 0));
+	if(!startInfo->selectedTown)
+		addHero(1, PlayerColor(1), int3(5, 5, 0));
+	else
+	{
+		auto factory = LIBRARY->objtypeh->getHandlerFor(Obj::TOWN, *startInfo->selectedTown);
+		auto templates = factory->getTemplates();
+		auto obj = factory->create(cb.get(), templates.front());
+		auto townObj = std::dynamic_pointer_cast<CGTownInstance>(obj);
+		obj->setOwner(PlayerColor(1));
+		obj->pos = int3(5, 5, 0);
+		for (const auto & building : townObj->getTown()->getAllBuildings())
+			townObj->addBuilding(building);
+		if(!startInfo->selectedHero[1])
+		{
+			for(int slot = 0; slot < GameConstants::ARMY_SIZE; slot++)
+				if(startInfo->selectedArmy[1][slot].getId() != CreatureID::NONE)
+					townObj->getArmy()->setCreature(SlotID(slot), startInfo->selectedArmy[1][slot].getId(), startInfo->selectedArmy[1][slot].getCount());
+		}
+		else
+			addHero(1, PlayerColor(1), int3(5, 5, 0));
+
+		map->getEditManager()->insertObject(townObj);
+	}
+
+	auto path = VCMIDirs::get().userDataPath() / "Maps";
+	boost::filesystem::create_directories(path);
+	const std::string fileName = "BattleOnlyMode.vmap";
+	const auto fullPath = path / fileName;
+	CMapService mapService;
+	mapService.saveMap(map, fullPath);
+	CResourceHandler::get()->updateFilteredFiles([&](const std::string & mount) { return true; });
+
+	auto mapInfo = std::make_shared<CMapInfo>();
+	mapInfo->mapInit("Maps/BattleOnlyMode");
+	GAME->server().setMapInfo(mapInfo);
+	ExtraOptionsInfo extraOptions;
+	extraOptions.unlimitedReplay = true;
+	GAME->server().setExtraOptionsInfo(extraOptions);
+	GAME->server().sendStartGame();
+}

+ 92 - 0
client/lobby/BattleOnlyMode.h

@@ -0,0 +1,92 @@
+/*
+ * BattleOnlyMode.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+#pragma once
+
+#include "../windows/CWindowObject.h"
+#include "../../lib/constants/EntityIdentifiers.h"
+
+
+VCMI_LIB_NAMESPACE_BEGIN
+class CGHeroInstance;
+class CCreatureSet;
+class CMap;
+class EditorCallback;
+class BattleOnlyModeStartInfo;
+VCMI_LIB_NAMESPACE_END
+
+class FilledTexturePlayerColored;
+class CButton;
+class CPicture;
+class CLabel;
+class BattleOnlyModeWindow;
+class CAnimImage;
+class GraphicalPrimitiveCanvas;
+class CTextInput;
+class TransparentFilledRectangle;
+
+class BattleOnlyMode
+{
+public:
+	static void openBattleWindow();
+};
+
+class BattleOnlyModeHeroSelector : public CIntObject
+{
+private:
+	BattleOnlyModeWindow& parent;
+
+	std::shared_ptr<CPicture> backgroundImage;
+	std::shared_ptr<CPicture> heroImage;
+	std::shared_ptr<CLabel> heroLabel;
+	std::vector<std::shared_ptr<CPicture>> creatureImage;
+
+	int id;
+public:
+	std::vector<std::shared_ptr<CAnimImage>> primSkills;
+	std::vector<std::shared_ptr<GraphicalPrimitiveCanvas>> primSkillsBorder;
+	std::vector<std::shared_ptr<CTextInput>> primSkillsInput;
+
+	std::vector<std::shared_ptr<CTextInput>> selectedArmyInput;
+
+	void setHeroIcon();
+	void setCreatureIcons();
+	BattleOnlyModeHeroSelector(int id, BattleOnlyModeWindow& parent, Point position);
+};
+
+class BattleOnlyModeWindow : public CWindowObject
+{
+	friend class BattleOnlyModeHeroSelector;
+private:
+	std::shared_ptr<BattleOnlyModeStartInfo> startInfo;
+	std::unique_ptr<CMap> map;
+	std::shared_ptr<EditorCallback> cb;
+
+	std::shared_ptr<FilledTexturePlayerColored> backgroundTexture;
+	std::shared_ptr<CButton> buttonOk;
+	std::shared_ptr<CButton> buttonAbort;
+	std::shared_ptr<CLabel> title;
+
+	std::shared_ptr<CButton> battlefieldSelector;
+	std::shared_ptr<CButton> buttonReset;
+	std::shared_ptr<BattleOnlyModeHeroSelector> heroSelector1;
+	std::shared_ptr<BattleOnlyModeHeroSelector> heroSelector2;
+
+	ColorRGBA disabledColor;
+
+	void init();
+	void onChange();
+	void update();
+	void setTerrainButtonText();
+	void setOkButtonEnabled();
+	void startBattle();
+public:
+	BattleOnlyModeWindow();
+	void applyStartInfo(std::shared_ptr<BattleOnlyModeStartInfo> si);
+};

+ 16 - 4
client/lobby/RandomMapTab.cpp

@@ -172,14 +172,26 @@ RandomMapTab::RandomMapTab():
 		{
 			std::vector<std::string> texts;
 			texts.push_back(readText(variables["randomTemplate"]));
-			for(auto & t : getTemplates())
-				texts.push_back(t->getName());
+
+			auto selectedTemplate = mapGenOptions->getMapTemplate();
+			const auto& templates = getTemplates();
+			for(int i = 0; i < templates.size(); i++)
+			{
+				if(selectedTemplate)
+				{
+					if(templates[i]->getId() == selectedTemplate->getId())
+						templateIndex = i + 1;
+				}
+				else
+					templateIndex = 0;
+
+				texts.push_back(templates[i]->getName());
+			}
 
 			ENGINE->windows().popWindows(1);
 			ENGINE->windows().createAndPushWindow<CObjectListWindow>(texts, nullptr, LIBRARY->generaltexth->translate("vcmi.lobby.templatesSelect.hover"), LIBRARY->generaltexth->translate("vcmi.lobby.templatesSelect.help"), [this](int index){
 				widget<ComboBox>("templateList")->setItem(index);
-				templateIndex = index;
-			}, templateIndex, std::vector<std::shared_ptr<IImage>>(), true);
+			}, templateIndex, std::vector<std::shared_ptr<IImage>>(), true, true);
 		});
 	}
 	

+ 11 - 0
client/lobby/SelectionTab.cpp

@@ -12,6 +12,7 @@
 #include "SelectionTab.h"
 #include "CSelectionBase.h"
 #include "CLobbyScreen.h"
+#include "BattleOnlyMode.h"
 
 #include "../CPlayerInterface.h"
 #include "../CServerHandler.h"
@@ -241,6 +242,13 @@ SelectionTab::SelectionTab(ESelectionScreen Type)
 		sortByDate->setOverlay(std::make_shared<CPicture>(ImagePath::builtin("lobby/selectionTabSortDate")));
 		buttonsSortBy.push_back(sortByDate);
 
+		if(tabType == ESelectionScreen::newGame)
+		{
+			buttonBattleOnlyMode = std::make_shared<CButton>(Point(23, 18), AnimationPath::builtin("lobby/battleButton"), CButton::tooltip("", LIBRARY->generaltexth->translate("vcmi.lobby.battleOnlyMode")), [tabTitle, tabTitleDelete](){
+				BattleOnlyMode::openBattleWindow();
+			});
+		}
+
 		if(tabType == ESelectionScreen::loadGame || tabType == ESelectionScreen::newGame)
 		{
 			buttonDeleteMode = std::make_shared<CButton>(Point(367, 18), AnimationPath::builtin("lobby/deleteButton"), CButton::tooltip("", LIBRARY->generaltexth->translate("vcmi.lobby.deleteMode")), [this, tabTitle, tabTitleDelete](){
@@ -315,6 +323,8 @@ void SelectionTab::toggleMode()
 	{
 		if(slider)
 			slider->block(true);
+		if(buttonBattleOnlyMode)
+			buttonBattleOnlyMode->block(true);
 	}
 	else
 	{
@@ -325,6 +335,7 @@ void SelectionTab::toggleMode()
 				inputName->disable();
 				auto files = getFiles("Maps/", EResType::MAP);
 				files.erase(ResourcePath("Maps/Tutorial.tut", EResType::MAP));
+				files.erase(ResourcePath("Maps/BattleOnlyMode.vmap", EResType::MAP));
 				parseMaps(files);
 				break;
 			}

+ 2 - 0
client/lobby/SelectionTab.h

@@ -128,6 +128,8 @@ private:
 	std::shared_ptr<CButton> buttonDeleteMode;
 	bool deleteMode;
 
+	std::shared_ptr<CButton> buttonBattleOnlyMode;
+
 	bool enableUiEnhancements;
 	std::shared_ptr<CButton> buttonCampaignSet;
 

+ 3 - 1
client/netlag/PackRollbackGeneratorVisitor.cpp

@@ -52,9 +52,11 @@ void PackRollbackGeneratorVisitor::visitRebalanceStacks(RebalanceStacks & pack)
 	const auto * srcArmy = dynamic_cast<const CArmedInstance *>(srcObject);
 	const auto * dstArmy = dynamic_cast<const CArmedInstance *>(dstObject);
 
+	const auto * artifact = srcArmy->getStack(pack.srcSlot).getSlot(ArtifactPosition::CREATURE_SLOT);
+
 	if (srcArmy->getStack(pack.srcSlot).getTotalExperience() != 0 ||
 	   dstArmy->getStack(pack.srcSlot).getTotalExperience() != 0 ||
-	   srcArmy->getStack(pack.srcSlot).getSlot(ArtifactPosition::CREATURE_SLOT)->artifactID.hasValue())
+	   (artifact && artifact->artifactID.hasValue()))
 	{
 		// TODO: rollback creature artifacts & stack experience
 		return;

+ 89 - 11
client/render/AssetGenerator.cpp

@@ -93,6 +93,14 @@ void AssetGenerator::initialize()
 	
 	animationFiles[AnimationPath::builtin("SPRITES/GSPButtonClear")] = createGSPButtonClear();
 
+	for (PlayerColor color(-1); color < PlayerColor::PLAYER_LIMIT; ++color)
+	{
+		std::string name = "TownPortalBackgroundBlue" + (color == -1 ? "" : "-" + color.toString());
+		imageFiles[ImagePath::builtin(name)] = [this, color](){ return createGateListColored(std::max(PlayerColor(0), color), PlayerColor(1)); };
+	}
+
+	imageFiles[ImagePath::builtin("heroSlotsBlue.png")] = [this](){ return createHeroSlotsColored(PlayerColor(1));};
+
 	createPaletteShiftedSprites();
 }
 
@@ -129,6 +137,22 @@ void AssetGenerator::addAnimationFile(const AnimationPath & path, AnimationLayou
 	animationFiles[path] = anim;
 }
 
+auto getColorFilters()
+{
+	auto filterSettings = LIBRARY->settingsHandler->getFullConfig()["interface"]["playerColoredBackground"];
+	static const std::array<ColorFilter, PlayerColor::PLAYER_LIMIT_I> filters = {
+		ColorFilter::genRangeShifter( filterSettings["red"   ].convertTo<std::vector<float>>() ),
+		ColorFilter::genRangeShifter( filterSettings["blue"  ].convertTo<std::vector<float>>() ),
+		ColorFilter::genRangeShifter( filterSettings["tan"   ].convertTo<std::vector<float>>() ),
+		ColorFilter::genRangeShifter( filterSettings["green" ].convertTo<std::vector<float>>() ),
+		ColorFilter::genRangeShifter( filterSettings["orange"].convertTo<std::vector<float>>() ),
+		ColorFilter::genRangeShifter( filterSettings["purple"].convertTo<std::vector<float>>() ),
+		ColorFilter::genRangeShifter( filterSettings["teal"  ].convertTo<std::vector<float>>() ),
+		ColorFilter::genRangeShifter( filterSettings["pink"  ].convertTo<std::vector<float>>() )
+	};
+	return filters;
+}
+
 AssetGenerator::CanvasPtr AssetGenerator::createAdventureOptionsCleanBackground() const
 {
 	auto locator = ImageLocator(ImagePath::builtin("ADVOPTBK"), EImageBlitMode::OPAQUE);
@@ -208,17 +232,7 @@ AssetGenerator::CanvasPtr AssetGenerator::createPlayerColoredBackground(const Pl
 	std::shared_ptr<IImage> texture = ENGINE->renderHandler().loadImage(locator);
 
 	// transform to make color of brown DIBOX.PCX texture match color of specified player
-	auto filterSettings = LIBRARY->settingsHandler->getFullConfig()["interface"]["playerColoredBackground"];
-	static const std::array<ColorFilter, PlayerColor::PLAYER_LIMIT_I> filters = {
-		ColorFilter::genRangeShifter( filterSettings["red"   ].convertTo<std::vector<float>>() ),
-		ColorFilter::genRangeShifter( filterSettings["blue"  ].convertTo<std::vector<float>>() ),
-		ColorFilter::genRangeShifter( filterSettings["tan"   ].convertTo<std::vector<float>>() ),
-		ColorFilter::genRangeShifter( filterSettings["green" ].convertTo<std::vector<float>>() ),
-		ColorFilter::genRangeShifter( filterSettings["orange"].convertTo<std::vector<float>>() ),
-		ColorFilter::genRangeShifter( filterSettings["purple"].convertTo<std::vector<float>>() ),
-		ColorFilter::genRangeShifter( filterSettings["teal"  ].convertTo<std::vector<float>>() ),
-		ColorFilter::genRangeShifter( filterSettings["pink"  ].convertTo<std::vector<float>>() )
-	};
+	static const std::array<ColorFilter, PlayerColor::PLAYER_LIMIT_I> filters = getColorFilters();
 
 	assert(player.isValidPlayer());
 	if (!player.isValidPlayer())
@@ -884,3 +898,67 @@ AssetGenerator::AnimationLayoutMap AssetGenerator::createGSPButtonClear()
 
 	return layout;
 }
+
+AssetGenerator::CanvasPtr AssetGenerator::createGateListColored(PlayerColor color, PlayerColor backColor) const
+{
+	auto locator = ImageLocator(ImagePath::builtin("TpGate"), EImageBlitMode::COLORKEY);
+	std::shared_ptr<IImage> img = ENGINE->renderHandler().loadImage(locator);
+	img->playerColored(color);
+	std::shared_ptr<IImage> imgColored = ENGINE->renderHandler().loadImage(locator);
+	static const std::array<ColorFilter, PlayerColor::PLAYER_LIMIT_I> filters = getColorFilters();
+	imgColored->adjustPalette(filters[backColor.getNum()], 0);
+
+	auto image = ENGINE->renderHandler().createImage(img->dimensions(), CanvasScalingPolicy::IGNORE);
+	Canvas canvas = image->getCanvas();
+
+	canvas.draw(imgColored, Point(0, 0));
+
+	std::vector<Rect> keepOriginalRects = {
+		Rect(0, 0, 14, 393),
+		Rect(293, 0, 13, 393),
+		Rect(0, 393, 8, 76),
+		Rect(299, 393, 6, 76),
+		Rect(0, 0, 306, 16),
+		Rect(0, 383, 306, 10),
+		Rect(0, 441, 306, 2),
+		Rect(0, 462, 306, 7),
+		// Edges
+		Rect(14, 15, 2, 5),
+		Rect(16, 15, 3, 2),
+		Rect(16, 17, 1, 1),
+		Rect(14, 379, 3, 4),
+		Rect(16, 381, 2, 2),
+		Rect(16, 380, 1, 1),
+		Rect(289, 16, 2, 2),
+		Rect(291, 16, 2, 4),
+		Rect(289, 381, 2, 2),
+		Rect(291, 379, 2, 4)
+	};
+	for(auto & rect : keepOriginalRects)
+		canvas.draw(img, Point(rect.x, rect.y), rect);
+
+	std::vector<Rect> blackRect = {
+		Rect(14, 401, 66, 32),
+		Rect(227, 401, 66, 32)
+	};
+	for(auto & rect : blackRect)
+		canvas.drawBorder(rect, Colors::BLACK);
+
+	return image;
+}
+
+AssetGenerator::CanvasPtr AssetGenerator::createHeroSlotsColored(PlayerColor backColor) const
+{
+	auto locator = ImageLocator(AnimationPath::builtin("OVSLOT"), 4, 0, EImageBlitMode::COLORKEY);
+	std::shared_ptr<IImage> img = ENGINE->renderHandler().loadImage(locator);
+	static const std::array<ColorFilter, PlayerColor::PLAYER_LIMIT_I> filters = getColorFilters();
+	img->adjustPalette(filters[backColor.getNum()], 0);
+
+	auto image = ENGINE->renderHandler().createImage(Point(260, 150), CanvasScalingPolicy::IGNORE);
+	Canvas canvas = image->getCanvas();
+	canvas.draw(img, Point(0, 0), Rect(3, 4, 253, 107));
+	for(int i = 0; i<7; i++)
+		canvas.draw(img, Point(1 + i * 36, 108), Rect(76, 57, 35, 17));
+
+	return image;
+}

+ 2 - 0
client/render/AssetGenerator.h

@@ -66,6 +66,8 @@ private:
 	CanvasPtr createCreatureInfoPanelElement(CreatureInfoPanelElement element) const;
 	CanvasPtr createQuestWindow() const;
 	AnimationLayoutMap createGSPButtonClear();
+	CanvasPtr createGateListColored(PlayerColor color, PlayerColor backColor) const;
+	CanvasPtr createHeroSlotsColored(PlayerColor backColor) const;
 
 	void createPaletteShiftedSprites();
 	void generatePaletteShiftedAnimation(const AnimationPath & source, const std::vector<PaletteAnimation> & animation);

+ 2 - 0
client/render/CanvasImage.cpp

@@ -65,6 +65,8 @@ Rect CanvasImage::contentRect() const
 
 Point CanvasImage::dimensions() const
 {
+	if (scalingPolicy != CanvasScalingPolicy::IGNORE)
+		return Point(surface->w, surface->h) / ENGINE->screenHandler().getScalingFactor();
 	return {surface->w, surface->h};
 }
 

+ 59 - 32
client/widgets/CTextInput.cpp

@@ -200,9 +200,9 @@ void CTextInput::setFilterFilename()
 	onTextFiltering = std::bind(&CTextInput::filenameFilter, _1, _2);
 }
 
-void CTextInput::setFilterNumber(int minValue, int maxValue)
+void CTextInput::setFilterNumber(int minValue, int maxValue, int metricDigits)
 {
-	onTextFiltering = std::bind(&CTextInput::numberFilter, _1, _2, minValue, maxValue);
+	onTextFiltering = std::bind(&CTextInput::numberFilter, _1, _2, minValue, maxValue, metricDigits);
 }
 
 std::string CTextInput::getVisibleText() const
@@ -256,6 +256,10 @@ void CTextInput::keyPressed(EShortcut key)
 
 	if(redrawNeeded)
 	{
+		std::string oldText = currentText;
+		if(onTextFiltering)
+			onTextFiltering(currentText, oldText);
+
 		updateLabel();
 		if(onTextEdited)
 			onTextEdited(currentText);
@@ -295,9 +299,9 @@ void CTextInput::textInputted(const std::string & enteredText)
 	if(onTextFiltering)
 		onTextFiltering(currentText, oldText);
 
+	updateLabel();
 	if(currentText != oldText)
 	{
-		updateLabel();
 		if(onTextEdited)
 			onTextEdited(currentText);
 	}
@@ -321,40 +325,63 @@ void CTextInput::filenameFilter(std::string & text, const std::string &oldText)
 		text.erase(pos, 1);
 }
 
-void CTextInput::numberFilter(std::string & text, const std::string & oldText, int minValue, int maxValue)
+std::optional<char> getMetricSuffix(const std::string& text)
+{
+	const std::string suffixes = "kKmMgGtTpPeE";
+	std::vector<char> found;
+
+	// Collect all suffixes in the string
+	for (char c : text) {
+		if (suffixes.find(c) != std::string::npos) {
+			// Normalize: 'k' lowercase, others uppercase
+			found.push_back((c == 'k' || c == 'K') ? 'k' : static_cast<char>(std::toupper(c)));
+		}
+	}
+
+	if (found.empty()) return std::nullopt;            // No suffix
+	if (found.size() == 1) return found[0];           // Single suffix
+	// More than one suffix
+	bool allSame = std::all_of(found.begin(), found.end(), [&](char c){ return c == found[0]; });
+	if (allSame) return std::nullopt;                 // Multiple but identical → nullopt
+	return found.back();                               // Multiple different → last suffix
+}
+
+
+void CTextInput::numberFilter(std::string & text, const std::string & oldText, int minValue, int maxValue, int metricDigits)
 {
 	assert(minValue < maxValue);
 
-	if(text.empty())
-		text = "0";
+	bool isNegative = std::count_if(text.begin(), text.end(), [](char c){ return c == '-'; }) == 1 && minValue < 0;
+	auto suffix = getMetricSuffix(text);
+	if(metricDigits == 0)
+		suffix = std::nullopt;
 
-	size_t pos = 0;
-	if(text[0] == '-') //allow '-' sign as first symbol only
-		pos++;
+	// Remove all non-digit characters
+	text.erase(std::remove_if(text.begin(), text.end(), [](char c){ return !isdigit(c); }), text.end());
 
-	while(pos < text.size())
-	{
-		if(text[pos] < '0' || text[pos] > '9')
-		{
-			text = oldText;
-			return; //new text is not number.
-		}
-		pos++;
-	}
-	try
-	{
-		int value = boost::lexical_cast<int>(text);
-		if(value < minValue)
-			text = std::to_string(minValue);
-		else if(value > maxValue)
-			text = std::to_string(maxValue);
-	}
-	catch(boost::bad_lexical_cast &)
-	{
-		//Should never happen. Unless I missed some cases
-		logGlobal->warn("Warning: failed to convert %s to number!", text);
-		text = oldText;
-	}
+	// Remove leading zeros
+	size_t firstNonZero = text.find_first_not_of('0');
+	if (firstNonZero > 0)
+		text.erase(0, firstNonZero);
+
+	if (text.empty())
+		text = "0";
+
+	// Add negative sign
+	text = (isNegative ? "-" : "") + text;
+
+	// Restore suffix if it exists
+	if (suffix)
+		text += *suffix;
+
+	// Clamp value
+	int value = TextOperations::parseMetric<int>(text);
+	if (metricDigits)
+		text = (isNegative && value == 0 ? "-" : "") + TextOperations::formatMetric(value, metricDigits);
+	if (value < minValue)
+		text = metricDigits ? TextOperations::formatMetric(minValue, metricDigits) : std::to_string(minValue);
+	else if (value > maxValue)
+		text = metricDigits ? TextOperations::formatMetric(maxValue, metricDigits) : std::to_string(maxValue);
 }
 
 void CTextInput::activate()

+ 2 - 2
client/widgets/CTextInput.h

@@ -66,7 +66,7 @@ protected:
 	static void filenameFilter(std::string & text, const std::string & oldText);
 	//Filter that will allow only input of numbers in range min-max (min-max are allowed)
 	//min-max should be set via something like std::bind
-	static void numberFilter(std::string & text, const std::string & oldText, int minValue, int maxValue);
+	static void numberFilter(std::string & text, const std::string & oldText, int minValue, int maxValue, int metricDigits);
 
 	std::string getVisibleText() const;
 	void createLabel(bool giveFocusToInput);
@@ -99,7 +99,7 @@ public:
 	/// Enables filtering entered text that ensures that text is valid filename (existing or not)
 	void setFilterFilename();
 	/// Enable filtering entered text that ensures that text is valid number in provided range [min, max]
-	void setFilterNumber(int minValue, int maxValue);
+	void setFilterNumber(int minValue, int maxValue, int metricDigits=0);
 
 	void setFont(EFonts Font);
 	void setColor(const ColorRGBA & Color);

+ 15 - 4
client/widgets/Images.cpp

@@ -46,7 +46,7 @@ CPicture::CPicture(std::shared_ptr<IImage> image, const Point & position)
 	pos.w = bg->width();
 	pos.h = bg->height();
 
-	addUsedEvents(SHOW_POPUP);
+	addUsedEvents(LCLICK | SHOW_POPUP);
 }
 
 CPicture::CPicture( const ImagePath &bmpname, int x, int y )
@@ -75,7 +75,7 @@ CPicture::CPicture( const ImagePath & bmpname, const Point & position, EImageBli
 		pos.w = pos.h = 0;
 	}
 
-	addUsedEvents(SHOW_POPUP);
+	addUsedEvents(LCLICK | SHOW_POPUP);
 }
 
 CPicture::CPicture( const ImagePath & bmpname, const Point & position )
@@ -89,7 +89,7 @@ CPicture::CPicture(const ImagePath & bmpname, const Rect &SrcRect, int x, int y)
 	pos.w = srcRect->w;
 	pos.h = srcRect->h;
 
-	addUsedEvents(SHOW_POPUP);
+	addUsedEvents(LCLICK | SHOW_POPUP);
 }
 
 CPicture::CPicture(std::shared_ptr<IImage> image, const Rect &SrcRect, int x, int y)
@@ -99,7 +99,7 @@ CPicture::CPicture(std::shared_ptr<IImage> image, const Rect &SrcRect, int x, in
 	pos.w = srcRect->w;
 	pos.h = srcRect->h;
 
-	addUsedEvents(SHOW_POPUP);
+	addUsedEvents(LCLICK | SHOW_POPUP);
 }
 
 void CPicture::show(Canvas & to)
@@ -137,11 +137,22 @@ void CPicture::setPlayerColor(PlayerColor player)
 	bg->playerColored(player);
 }
 
+void CPicture::addLClickCallback(const std::function<void()> & callback)
+{
+	lCallback = callback;
+}
+
 void CPicture::addRClickCallback(const std::function<void()> & callback)
 {
 	rCallback = callback;
 }
 
+void CPicture::clickPressed(const Point & cursorPosition)
+{
+	if(lCallback)
+		lCallback();
+}
+
 void CPicture::showPopupWindow(const Point & cursorPosition)
 {
 	if(rCallback)

+ 3 - 0
client/widgets/Images.h

@@ -27,6 +27,7 @@ enum class EImageBlitMode : uint8_t;
 class CPicture : public CIntObject
 {
 	std::shared_ptr<IImage> bg;
+	std::function<void()> lCallback;
 	std::function<void()> rCallback;
 
 public:
@@ -60,10 +61,12 @@ public:
 	void scaleTo(Point size);
 	void setPlayerColor(PlayerColor player);
 
+	void addLClickCallback(const std::function<void()> & callback);
 	void addRClickCallback(const std::function<void()> & callback);
 
 	void show(Canvas & to) override;
 	void showAll(Canvas & to) override;
+	void clickPressed(const Point & cursorPosition) override;
 	void showPopupWindow(const Point & cursorPosition) override;
 };
 

+ 5 - 3
client/widgets/MiscWidgets.cpp

@@ -623,13 +623,15 @@ void MoraleLuckBox::set(const AFactionMember * node)
 	else if(morale && node && node->getBonusBearer()->hasBonusOfType(BonusType::NO_MORALE))
 	{
 		auto noMorale = node->getBonusBearer()->getBonus(Selector::type()(BonusType::NO_MORALE));
-		text += "\n" + noMorale->Description(GAME->interface()->cb.get());
+		if(GAME->interface())
+			text += "\n" + noMorale->Description(GAME->interface()->cb.get());
 		component.value = 0;
 	}
 	else if (!morale && node && node->getBonusBearer()->hasBonusOfType(BonusType::NO_LUCK))
 	{
 		auto noLuck = node->getBonusBearer()->getBonus(Selector::type()(BonusType::NO_LUCK));
-		text += "\n" + noLuck->Description(GAME->interface()->cb.get());
+		if(GAME->interface())
+			text += "\n" + noLuck->Description(GAME->interface()->cb.get());
 		component.value = 0;
 	}
 	else
@@ -637,7 +639,7 @@ void MoraleLuckBox::set(const AFactionMember * node)
 		std::string addInfo = "";
 		for(auto & bonus : * modifierList)
 		{
-			if(bonus->val) {
+			if(GAME->interface() && bonus->val) {
 				const std::string& description = bonus->Description(GAME->interface()->cb.get());
 				//arraytxt already contains \n
 				if (description.size() && description[0] != '\n')

+ 25 - 1
client/windows/CCastleInterface.cpp

@@ -2184,8 +2184,16 @@ void CMageGuildScreen::updateSpells(ObjectInstanceID tID)
 		uint32_t spellCount = town->spellsAtLevel(i+1,false); //spell at level with -1 hmmm?
 		for(uint32_t j=0; j<spellCount; j++)
 		{
-			if(i<town->mageGuildLevel() && town->spells[i].size()>j)
+			if (town->hasBuilt(BuildingSubID::AURORA_BOREALIS))
+			{
+				std::string auroraBorealisName = town->getTown()->getSpecialBuilding(BuildingSubID::AURORA_BOREALIS)->getNameTranslated();
+
+				auroraBorealisScrolls.push_back(std::make_shared<ScrollAllSpells>(positions[i][j], auroraBorealisName));
+			}
+			else if(i<town->mageGuildLevel() && town->spells[i].size()>j)
+			{
 				spells.push_back(std::make_shared<Scroll>(positions[i][j], town->spells[i][j].toSpell(), townId));
+			}
 			else
 				emptyScrolls.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("TPMAGES.DEF"), 1, 0, positions[i][j].x, positions[i][j].y));
 		}
@@ -2194,6 +2202,22 @@ void CMageGuildScreen::updateSpells(ObjectInstanceID tID)
 	redraw();
 }
 
+CMageGuildScreen::ScrollAllSpells::ScrollAllSpells(Point position, const std::string & buildingName)
+{
+	constexpr int auroraBorealisImageIndex = 70;
+
+	OBJECT_CONSTRUCTION;
+	pos += position;
+	image = std::make_shared<CAnimImage>(AnimationPath::builtin("SPELLSCR"), auroraBorealisImageIndex);
+	pos = image->pos;
+
+	MetaString description;
+	description.appendTextID("core.genrltxt.714");
+	description.replaceRawString(buildingName);
+
+	text = std::make_shared<LRClickableAreaWText>(Rect(Point(), pos.dimensions()), description.toString(), description.toString() );
+}
+
 CMageGuildScreen::Scroll::Scroll(Point position, const CSpell *Spell, ObjectInstanceID townId)
 	: spell(Spell), townId(townId)
 {

+ 12 - 0
client/windows/CCastleInterface.h

@@ -37,6 +37,7 @@ class CGarrisonInt;
 class CComponent;
 class CComponentBox;
 class LRClickableArea;
+class LRClickableAreaWText;
 class CTextInputWithConfirm;
 
 /// Building "button"
@@ -394,10 +395,21 @@ class CMageGuildScreen : public CStatusbarWindow
 		void showPopupWindow(const Point & cursorPosition) override;
 		void hover(bool on) override;
 	};
+
+	class ScrollAllSpells : public CIntObject
+	{
+		std::shared_ptr<CAnimImage> image;
+		std::shared_ptr<LRClickableAreaWText> text;
+
+	public:
+		ScrollAllSpells(Point position, const std::string & buildingName);
+	};
+
 	std::shared_ptr<CPicture> window;
 	std::shared_ptr<CButton> exit;
 	std::vector<std::shared_ptr<Scroll>> spells;
 	std::vector<std::shared_ptr<CAnimImage>> emptyScrolls;
+	std::vector<std::shared_ptr<ScrollAllSpells>> auroraBorealisScrolls;
 
 	std::shared_ptr<CMinorResDataBar> resdatabar;
 

+ 3 - 3
client/windows/CCreatureWindow.cpp

@@ -428,7 +428,7 @@ CStackWindow::ButtonsSection::ButtonsSection(CStackWindow * owner, int yOffset)
 			};
 
 			std::string tooltipText = "vcmi.creatureWindow." + btnIDs[buttonIndex];
-			parent->switchButtons[buttonIndex] = std::make_shared<CButton>(Point(302 + (int)buttonIndex*40, 5), AnimationPath::builtin("stackWindow/upgradeButton"), CButton::tooltipLocalized(tooltipText), onSwitch);
+			parent->switchButtons[buttonIndex] = std::make_shared<CButton>(Point(342, 5), AnimationPath::builtin("stackWindow/upgradeButton"), CButton::tooltipLocalized(tooltipText), onSwitch);
 			parent->switchButtons[buttonIndex]->setOverlay(std::make_shared<CAnimImage>(AnimationPath::builtin("stackWindow/switchModeIcons"), buttonIndex));
 		}
 		parent->switchButtons[parent->activeTab]->disable();
@@ -952,8 +952,8 @@ void CStackWindow::initSections()
 {
 	OBJECT_CONSTRUCTION;
 
-	bool showArt = GAME->interface()->cb->getSettings().getBoolean(EGameSettings::MODULE_STACK_ARTIFACT) && info->commander == nullptr && info->stackNode;
-	bool showExp = (GAME->interface()->cb->getSettings().getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE) || info->commander != nullptr) && info->stackNode;
+	bool showArt = GAME->interface() && GAME->interface()->cb->getSettings().getBoolean(EGameSettings::MODULE_STACK_ARTIFACT) && info->commander == nullptr && info->stackNode;
+	bool showExp = ((GAME->interface() && GAME->interface()->cb->getSettings().getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE)) || info->commander != nullptr) && info->stackNode;
 
 	mainSection = std::make_shared<MainSection>(this, pos.h, showExp, showArt);
 

+ 4 - 3
client/windows/CHeroOverview.cpp

@@ -214,8 +214,8 @@ void CHeroOverview::genControls()
 	{
 		secSkills.push_back(std::make_shared<CSecSkillPlace>(Point(302, 7 * borderOffset + yOffset + 186 + i * (32 + borderOffset)),
 															 CSecSkillPlace::ImageSize::SMALL, skill.first, skill.second));
-		labelSecSkillsNames.push_back(std::make_shared<CLabel>(334 + 2 * borderOffset, 8 * borderOffset + yOffset + 186 + i * (32 + borderOffset) - 5, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, LIBRARY->generaltexth->levels[skill.second - 1]));
-		labelSecSkillsNames.push_back(std::make_shared<CLabel>(334 + 2 * borderOffset, 8 * borderOffset + yOffset + 186 + i * (32 + borderOffset) + 10, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, (*LIBRARY->skillh)[skill.first]->getNameTranslated()));
+		labelSecSkillsNames.push_back(std::make_shared<CLabel>(334 + 2 * borderOffset, 8 * borderOffset + yOffset + 186 + i * (32 + borderOffset) - 5, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, LIBRARY->generaltexth->levels[skill.second - 1], 90));
+		labelSecSkillsNames.push_back(std::make_shared<CLabel>(334 + 2 * borderOffset, 8 * borderOffset + yOffset + 186 + i * (32 + borderOffset) + 10, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, (*LIBRARY->skillh)[skill.first]->getNameTranslated(), 90));
 		i++;
 	}
 
@@ -240,7 +240,8 @@ void CHeroOverview::genControls()
 		}
 
 		imageSpells.push_back(std::make_shared<CAnimImage>(AnimationPath::builtin("SPELLBON"), (*LIBRARY->spellh)[spell]->getIconIndex(), Rect(302 + (292 / 2) + 2 * borderOffset, 7 * borderOffset + yOffset + 186 + i * (32 + borderOffset), 32, 32), 0));
-		labelSpellsNames.push_back(std::make_shared<CLabel>(302 + (292 / 2) + 3 * borderOffset + 32 + borderOffset, 8 * borderOffset + yOffset + 186 + i * (32 + borderOffset) + 3, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, (*LIBRARY->spellh)[spell]->getNameTranslated()));
+		Rect labelPos(302 + (292 / 2) + 2 * borderOffset + 32 + borderOffset + 5, 7 * borderOffset + yOffset + 186 + i * (32 + borderOffset), (292 / 2) - 32 - 3 * borderOffset - 10, 32);
+		labelSpellsNames.push_back(std::make_shared<CMultiLineLabel>(labelPos, FONT_SMALL, ETextAlignment::CENTERLEFT, Colors::WHITE, (*LIBRARY->spellh)[spell]->getNameTranslated()));
 		i++;
 	}
 }

+ 2 - 2
client/windows/CHeroOverview.h

@@ -58,7 +58,7 @@ class CHeroOverview : public CWindowObject
 
     std::shared_ptr<CLabel> labelSpellTitle;
     std::vector<std::shared_ptr<CAnimImage>> imageSpells;
-    std::vector<std::shared_ptr<CLabel>> labelSpellsNames;
+    std::vector<std::shared_ptr<CMultiLineLabel>> labelSpellsNames;
 
     std::shared_ptr<CLabel> labelSecSkillTitle;
     std::vector<std::shared_ptr<CSecSkillPlace>> secSkills;
@@ -69,4 +69,4 @@ class CHeroOverview : public CWindowObject
 
 public:
     CHeroOverview(const HeroTypeID & h);
-};
+};

+ 4 - 0
client/windows/CSpellWindow.cpp

@@ -34,6 +34,7 @@
 #include "../widgets/Buttons.h"
 #include "../widgets/VideoWidget.h"
 #include "../adventureMap/AdventureMapInterface.h"
+#include "../eventsSDL/InputHandler.h"
 
 #include "../../lib/CConfigHandler.h"
 #include "../../lib/GameConstants.h"
@@ -99,6 +100,7 @@ CSpellWindow::InteractiveArea::InteractiveArea(const Rect & myRect, const std::f
 
 void CSpellWindow::InteractiveArea::clickPressed(const Point & cursorPosition)
 {
+	ENGINE->input().hapticFeedback();
 	onLeft();
 }
 
@@ -687,6 +689,8 @@ void CSpellWindow::SpellArea::clickPressed(const Point & cursorPosition)
 {
 	if(mySpell)
 	{
+		ENGINE->input().hapticFeedback();
+
 		if(owner->onSpellSelect)
 		{
 			owner->onSpellSelect(mySpell->id);

+ 3 - 1
client/windows/CWindowObject.cpp

@@ -86,7 +86,9 @@ std::shared_ptr<CPicture> CWindowObject::createBg(const ImagePath & imageName, b
 		return nullptr;
 
 	auto image = std::make_shared<CPicture>(imageName, Point(0,0), EImageBlitMode::OPAQUE);
-	if(playerColored && GAME->interface())
+	if(!GAME->interface())
+		image->setPlayerColor(PlayerColor(1)); // in main menu we use blue
+	else if(playerColored)
 		image->setPlayerColor(GAME->interface()->playerID);
 	return image;
 }

+ 23 - 18
client/windows/GUIClasses.cpp

@@ -1535,8 +1535,9 @@ CObjectListWindow::CItem::CItem(CObjectListWindow * _parent, size_t _id, std::st
 	index(_id)
 {
 	OBJECT_CONSTRUCTION;
-	if(parent->images.size() > index)
-		icon = std::make_shared<CPicture>(parent->images[index], Point(1, 1));
+	auto imgIndex = parent->itemsVisible[index].first;
+	if(parent->images.size() > index && parent->images[imgIndex])
+		icon = std::make_shared<CPicture>(parent->images[imgIndex], Point(1, 1));
 	border = std::make_shared<CPicture>(ImagePath::builtin("TPGATES"));
 	pos = border->pos;
 
@@ -1577,12 +1578,13 @@ void CObjectListWindow::CItem::clickDouble(const Point & cursorPosition)
 
 void CObjectListWindow::CItem::showPopupWindow(const Point & cursorPosition)
 {
+	int where = parent->itemsVisible[index].first;
 	if(parent->onPopup)
-		parent->onPopup(index);
+		parent->onPopup(where);
 }
 
-CObjectListWindow::CObjectListWindow(const std::vector<int> & _items, std::shared_ptr<CIntObject> titleWidget_, std::string _title, std::string _descr, std::function<void(int)> Callback, size_t initialSelection, std::vector<std::shared_ptr<IImage>> images, bool searchBoxEnabled)
-	: CWindowObject(PLAYER_COLORED, ImagePath::builtin("TPGATE")),
+CObjectListWindow::CObjectListWindow(const std::vector<int> & _items, std::shared_ptr<CIntObject> titleWidget_, std::string _title, std::string _descr, std::function<void(int)> Callback, size_t initialSelection, std::vector<std::shared_ptr<IImage>> images, bool searchBoxEnabled, bool blue)
+	: CWindowObject(PLAYER_COLORED, ImagePath::builtin(blue ? "TownPortalBackgroundBlue" : "TPGATE")),
 	onSelect(Callback),
 	selected(initialSelection),
 	images(images)
@@ -1601,12 +1603,12 @@ CObjectListWindow::CObjectListWindow(const std::vector<int> & _items, std::share
 	}
 	itemsVisible = items;
 
-	init(titleWidget_, _title, _descr, searchBoxEnabled);
+	init(titleWidget_, _title, _descr, searchBoxEnabled, blue);
 	list->scrollTo(std::min(static_cast<int>(initialSelection + 4), static_cast<int>(items.size() - 1))); // 4 is for centering (list have 9 elements)
 }
 
-CObjectListWindow::CObjectListWindow(const std::vector<std::string> & _items, std::shared_ptr<CIntObject> titleWidget_, std::string _title, std::string _descr, std::function<void(int)> Callback, size_t initialSelection, std::vector<std::shared_ptr<IImage>> images, bool searchBoxEnabled)
-	: CWindowObject(PLAYER_COLORED, ImagePath::builtin("TPGATE")),
+CObjectListWindow::CObjectListWindow(const std::vector<std::string> & _items, std::shared_ptr<CIntObject> titleWidget_, std::string _title, std::string _descr, std::function<void(int)> Callback, size_t initialSelection, std::vector<std::shared_ptr<IImage>> images, bool searchBoxEnabled, bool blue)
+	: CWindowObject(PLAYER_COLORED, ImagePath::builtin(blue ? "TownPortalBackgroundBlue" : "TPGATE")),
 	onSelect(Callback),
 	selected(initialSelection),
 	images(images)
@@ -1625,17 +1627,17 @@ CObjectListWindow::CObjectListWindow(const std::vector<std::string> & _items, st
 	}
 	itemsVisible = items;
 
-	init(titleWidget_, _title, _descr, searchBoxEnabled);
+	init(titleWidget_, _title, _descr, searchBoxEnabled, blue);
 	list->scrollTo(std::min(static_cast<int>(initialSelection + 4), static_cast<int>(items.size() - 1))); // 4 is for centering (list have 9 elements)
 }
 
-void CObjectListWindow::init(std::shared_ptr<CIntObject> titleWidget_, std::string _title, std::string _descr, bool searchBoxEnabled)
+void CObjectListWindow::init(std::shared_ptr<CIntObject> titleWidget_, std::string _title, std::string _descr, bool searchBoxEnabled, bool blue)
 {
 	titleWidget = titleWidget_;
 
 	title = std::make_shared<CLabel>(152, 27, FONT_BIG, ETextAlignment::CENTER, Colors::YELLOW, _title);
 	descr = std::make_shared<CLabel>(145, 133, FONT_SMALL, ETextAlignment::CENTER, Colors::WHITE, _descr);
-	exit = std::make_shared<CButton>( Point(228, 402), AnimationPath::builtin("ICANCEL.DEF"), CButton::tooltip(), std::bind(&CObjectListWindow::exitPressed, this), EShortcut::GLOBAL_CANCEL);
+	exit = std::make_shared<CButton>( Point(228, 402), AnimationPath::builtin(blue ? "MuBcanc" : "ICANCEL.DEF"), CButton::tooltip(), std::bind(&CObjectListWindow::exitPressed, this), EShortcut::GLOBAL_CANCEL);
 
 	if(titleWidget)
 	{
@@ -1644,10 +1646,10 @@ void CObjectListWindow::init(std::shared_ptr<CIntObject> titleWidget_, std::stri
 		titleWidget->pos.y = 75 + pos.y - titleWidget->pos.h/2;
 	}
 	list = std::make_shared<CListBox>(std::bind(&CObjectListWindow::genItem, this, _1),
-		Point(14, 151), Point(0, 25), 9, itemsVisible.size(), 0, 1, Rect(262, -32, 256, 256) );
+		Point(14, 151), Point(0, 25), 9, itemsVisible.size(), 0, 1 + (blue ? 4 : 0), Rect(262, -32, 256, 256) );
 	list->setRedrawParent(true);
 
-	ok = std::make_shared<CButton>(Point(15, 402), AnimationPath::builtin("IOKAY.DEF"), CButton::tooltip(), std::bind(&CObjectListWindow::elementSelected, this), EShortcut::GLOBAL_ACCEPT);
+	ok = std::make_shared<CButton>(Point(15, 402), AnimationPath::builtin(blue ? "MuBchck" : "IOKAY.DEF"), CButton::tooltip(), std::bind(&CObjectListWindow::elementSelected, this), EShortcut::GLOBAL_ACCEPT);
 	ok->block(!list->size());
 
 	if(!searchBoxEnabled)
@@ -1655,8 +1657,8 @@ void CObjectListWindow::init(std::shared_ptr<CIntObject> titleWidget_, std::stri
 
 	Rect r(50, 90, pos.w - 100, 16);
 	const ColorRGBA rectangleColor = ColorRGBA(0, 0, 0, 75);
-	const ColorRGBA borderColor = ColorRGBA(128, 100, 75);
-	const ColorRGBA grayedColor = ColorRGBA(158, 130, 105);
+	const ColorRGBA borderColor = blue ? ColorRGBA(75, 84, 128) : ColorRGBA(128, 100, 75);
+	const ColorRGBA grayedColor = blue ? ColorRGBA(105, 127, 159) : ColorRGBA(158, 130, 105);
 	searchBoxRectangle = std::make_shared<TransparentFilledRectangle>(r.resize(1), rectangleColor, borderColor);
 	searchBoxDescription = std::make_shared<CLabel>(r.center().x, r.center().y, FONT_SMALL, ETextAlignment::CENTER, grayedColor, LIBRARY->generaltexth->translate("vcmi.spellBook.search"));
 
@@ -1676,9 +1678,12 @@ void CObjectListWindow::trimTextIfTooWide(std::string & text, bool preserveCount
 	{
 		auto posBrace = text.find_last_of("(");
 		auto posClosing = text.find_last_of(")");
-		std::string objCount = text.substr(posBrace, posClosing - posBrace) + ')';
-		suffix += " ";
-		suffix += objCount;
+		if (posBrace != std::string::npos && posClosing != std::string::npos && posClosing > posBrace)
+		{
+			std::string objCount = text.substr(posBrace, posClosing - posBrace) + ')';
+			suffix += " ";
+			suffix += objCount;
+		}
 	}
 
 	const auto & font = ENGINE->renderHandler().loadFont(FONT_SMALL);

+ 3 - 3
client/windows/GUIClasses.h

@@ -205,7 +205,7 @@ class CObjectListWindow : public CWindowObject
 	std::vector< std::pair<int, std::string> > items; //all items present in list
 	std::vector< std::pair<int, std::string> > itemsVisible; //visible items present in list
 
-	void init(std::shared_ptr<CIntObject> titleWidget_, std::string _title, std::string _descr, bool searchBoxEnabled);
+	void init(std::shared_ptr<CIntObject> titleWidget_, std::string _title, std::string _descr, bool searchBoxEnabled, bool blue);
 	void trimTextIfTooWide(std::string & text, bool preserveCountSuffix) const; // trim item's text to fit within window's width
 	void itemsSearchCallback(const std::string & text);
 	void exitPressed();
@@ -219,8 +219,8 @@ public:
 	/// Callback will be called when OK button is pressed, returns id of selected item. initState = initially selected item
 	/// Image can be nullptr
 	///item names will be taken from map objects
-	CObjectListWindow(const std::vector<int> &_items, std::shared_ptr<CIntObject> titleWidget_, std::string _title, std::string _descr, std::function<void(int)> Callback, size_t initialSelection = 0, std::vector<std::shared_ptr<IImage>> images = {}, bool searchBoxEnabled = false);
-	CObjectListWindow(const std::vector<std::string> &_items, std::shared_ptr<CIntObject> titleWidget_, std::string _title, std::string _descr, std::function<void(int)> Callback, size_t initialSelection = 0, std::vector<std::shared_ptr<IImage>> images = {}, bool searchBoxEnabled = false);
+	CObjectListWindow(const std::vector<int> &_items, std::shared_ptr<CIntObject> titleWidget_, std::string _title, std::string _descr, std::function<void(int)> Callback, size_t initialSelection = 0, std::vector<std::shared_ptr<IImage>> images = {}, bool searchBoxEnabled = false, bool blue = false);
+	CObjectListWindow(const std::vector<std::string> &_items, std::shared_ptr<CIntObject> titleWidget_, std::string _title, std::string _descr, std::function<void(int)> Callback, size_t initialSelection = 0, std::vector<std::shared_ptr<IImage>> images = {}, bool searchBoxEnabled = false, bool blue = false);
 
 	std::shared_ptr<CIntObject> genItem(size_t index);
 	void elementSelected();//call callback and close this window

+ 10 - 2
config/bonuses.json

@@ -20,7 +20,11 @@
 	"ATTACKS_ALL_ADJACENT":
 	{
 	},
-	
+
+	"ALWAYS_MAXIMUM_DAMAGE":
+	{
+	},
+
 	"BASE_TILE_MOVEMENT_COST":
 	{
 		"blockDescriptionPropagation": true
@@ -334,7 +338,11 @@
 	{
 		"blockDescriptionPropagation": true
 	},
-	
+
+	"MORE_DAMAGE_FROM_SPELL":
+	{
+	},
+
 	"MOVEMENT":
 	{
 		"blockDescriptionPropagation": true

+ 1 - 1
config/factions/conflux.json

@@ -196,7 +196,7 @@
 						"earthMagic"
 					]
 				},
-				"grail":          { },
+				"grail":          { "type" : "auroraBorealis" },
 				"extraTownHall":  { },
 				"extraCityHall":  { },
 				"extraCapitol":   { },

+ 1 - 1
config/factions/inferno.json

@@ -205,7 +205,7 @@
 				},
 				"horde2":         { "upgrades" : "dwellingLvl3" },
 				"horde2Upgr":     { "upgrades" : "dwellingUpLvl3", "requires" : [ "horde2" ] },
-				"grail":          { },
+				"grail":          { "type" : "deityOfFire" },
 
 				"dwellingLvl1":   { "requires" : [ "fort" ] },
 				"dwellingLvl2":   { "requires" : [ "dwellingLvl1" ] },

+ 1 - 1
config/schemas/townBuilding.json

@@ -36,7 +36,7 @@
 		},
 		"type" : {
 			"type" : "string",
-			"enum" : [ "mysticPond", "castleGate", "portalOfSummoning", "library", "escapeTunnel", "treasury", "bank" ],
+			"enum" : [ "mysticPond", "castleGate", "portalOfSummoning", "library", "escapeTunnel", "treasury", "bank", "auroraBorealis", "deityOfFire" ],
 			"description" : "Subtype for some special buildings"
 		},
 		"mode" : {

+ 19 - 7
config/terrainViewPatterns.json

@@ -124,7 +124,7 @@
 			"data" :
 			[
 				"N", "N", "S",
-				"N", "N", "D",
+				"N", "N", "D,N",
 				"D,N", "D", "D,N"
 			],
 			"mapping" : { "normal" : "44", "hota" : "72" }
@@ -197,8 +197,8 @@
 			"data" :
 			[
 				"N", "N", "N",
-				"N", "N", "s3-1,m7-1,m8-1",
-				"N", "s2-1,m7-1,m8-1", "T"
+				"N", "N", "s3-1,m7-1,m8-1,s1-1",
+				"N", "s2-1,m7-1,m8-1,s1-1", "T"
 			],
 			"minPoints" : 2,
 			"mapping" : { "normal" : "12-15, 32-35", "dirt" : "12-15", "water" : "12-15", "rock": "4D:24-31", "hota" : "22-27,56-61" }
@@ -229,11 +229,23 @@
 			"id" : "s1",
 			"data" :
 			[
-				"?", "?", "?",
-				"?", "N", "N",
-				"T", "N", "N"
+				"?", "S-1,?", "?",
+				"S-1,?", "N", "N",
+				"?", "N", "N"
 			],
-			"mapping" : { "normal" : "0-3, 20-23", "dirt" : "0-3", "water" : "0-3", "rock": "4D:8-15", "hota" : "0-5,34-39" }
+			"minPoints" : 1,
+			"mapping" : { "normal" : "20-23", "dirt" : "0-3", "water" : "0-3", "rock": "4D:8-15", "hota" : "34-39" }
+		},
+		{
+			"id" : "s7",
+			"data" :
+			[
+				"?", "D-1,?", "?",
+				"D-1,?", "N", "N",
+				"?", "N", "N"
+			],
+			"minPoints" : 1,
+			"mapping" : { "normal" : "0-3", "rock": "4D:8-15", "hota" : "0-5" }
 		}
 	],
 	"terrainType" :

+ 13 - 6
docs/developers/Building_Windows.md

@@ -100,12 +100,19 @@ call "C:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\devenv
 4. Right click on `BUILD_ALL` project. This `BUILD_ALL` project should be in `CMakePredefinedTargets` tree in Solution Explorer. You can also build individual targets if you want.
 5. VCMI will be built in `%VCMI_DIR%/build/bin/<config>` folder where `<config>` is e.g. `RelWithDebInfo`. To launch the built executables from a file manager, use respective `bat` files, e.g. `VCMI_launcher.bat`.
 
-### Compile VCMI with MinGW via MSYS2
-
-- Install MSYS2 from <https://www.msys2.org/>
-- Start the `MSYS MinGW x64`-shell
-- Install dependencies: `pacman -S mingw-w64-x86_64-SDL2 mingw-w64-x86_64-SDL2_image mingw-w64-x86_64-SDL2_mixer mingw-w64-x86_64-SDL2_ttf mingw-w64-x86_64-boost mingw-w64-x86_64-gcc mingw-w64-x86_64-ninja mingw-w64-x86_64-qt5-static mingw-w64-x86_64-qt5-tools mingw-w64-x86_64-tbb`
-- Generate and build solution from VCMI-root dir: `cmake --preset windows-mingw-release && cmake --build --preset windows-mingw-release`
+### Compile VCMI with MinGW64 or UCRT64 via MSYS2
+
+1. Install MSYS2 from <https://www.msys2.org/>
+2. Open the correct shell
+   - For MinGW64 (MSVCRT): start `MSYS2 MinGW x64`
+   - For UCRT64: start `MSYS2 UCRT64`
+
+   (Sanity check: `echo $MSYSTEM` should be MINGW64 or UCRT64; don’t mix them.)
+3. Update MSYS2 packages: `pacman -Syu`
+4. Install dependencies
+   - For MinGW64 (MSVCRT): `pacman -S mingw-w64-x86_64-SDL2 mingw-w64-x86_64-SDL2_image mingw-w64-x86_64-SDL2_mixer mingw-w64-x86_64-SDL2_ttf mingw-w64-x86_64-boost mingw-w64-x86_64-gcc mingw-w64-x86_64-ninja mingw-w64-x86_64-qt5-static mingw-w64-x86_64-qt5-tools mingw-w64-x86_64-tbb`
+   - For UCRT64: `pacman -S --needed mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-gcc mingw-w64-ucrt-x86_64-ninja mingw-w64-ucrt-x86_64-boost mingw-w64-ucrt-x86_64-minizip mingw-w64-ucrt-x86_64-ffmpeg mingw-w64-ucrt-x86_64-SDL2_image mingw-w64-ucrt-x86_64-SDL2_mixer mingw-w64-ucrt-x86_64-SDL2_ttf mingw-w64-ucrt-x86_64-qt5-static mingw-w64-ucrt-x86_64-tbb`
+5. Generate and build solution from VCMI-root dir: `cmake --preset windows-mingw-release && cmake --build --preset windows-mingw-release`
 
 **NOTE:** This will link Qt5 statically to `VCMI_launcher.exe` and `VCMI_Mapeditor.exe`. See [PR #3421](https://github.com/vcmi/vcmi/pull/3421) for some background.
 

+ 18 - 1
docs/modders/Bonus/Bonus_Types.md

@@ -543,9 +543,26 @@ When affected unit is attacked from behind, it will receive more damage when att
 
 Affected unit will deal more damage when attacking specific creature
 
-- subtype - identifier of hated creature, ie. "creature.genie"
+- subtype - identifier of hated creature, ie. `genie`
 - val - additional damage, percentage
 
+### HATES_TRAIT
+
+Affected unit will deal more damage when attacking unit that has specific bonus. Note that this bonus has no assigned description. To make it visible in creature window UI, make sure to provide custom description for such bonus.
+
+- subtype - identifier of hated bonus, ie. `UNDEAD`
+- val - additional damage, percentage
+
+Example: Unit deals 50% more damage to any target that has UNDEAD bonus
+
+```json
+	"hatesUndead" : {
+		"type" : "HATES_TRAIT",
+		"subtype" : "UNDEAD",
+		"val" : 50
+	}
+```
+
 ### SPELL_LIKE_ATTACK
 
 Affected unit ranged attack will use animation and range of specified spell (Magog, Lich)

+ 2 - 4
docs/modders/Entities_Format/Town_Building_Format.md

@@ -238,15 +238,13 @@ Building requirements can be described using logical expressions:
 Following Heroes III buildings can be used as unique buildings for a town. Their functionality should be identical to a corresponding H3 building. H3 buildings that are not present in this list contain no hardcoded functionality. See vcmi json configuration to see how such buildings can be implemented in a mod.
 
 - `mysticPond`
-- `artifactMerchant`
-- `freelancersGuild`
-- `magicUniversity`
 - `castleGate`
-- `creatureTransformer`
 - `portalOfSummoning`
 - `library`
 - `escapeTunnel`
 - `treasury`
+- `auroraBorealis`
+- `deityOfFire`
 
 #### Buildings from other Heroes III mods
 

+ 2 - 2
docs/players/Installation_macOS.md

@@ -6,8 +6,8 @@
   - manually: <https://github.com/vcmi/vcmi/releases/latest>
   - via Homebrew: `brew install --cask --no-quarantine vcmi/vcmi/vcmi`
 - Daily builds (might be unstable)
-  - [Intel (x86_64) builds](https://builds.vcmi.download/branch/develop/macos-arm/)
-  - [Apple Silicon (arm64) builds](https://builds.vcmi.download/branch/develop/macos-intel/)
+  - [Intel (x86_64) builds](https://builds.vcmi.download/branch/develop/macos-intel/)
+  - [Apple Silicon (arm64) builds](https://builds.vcmi.download/branch/develop/macos-arm/)
 
 If the app doesn't open, right-click the app bundle - select *Open* menu item - press *Open* button. On macOS 15 Sequoia and later there will be no *Open* button, instead you'll see the following dialog:
 

+ 1 - 1
launcher/lib/innoextract

@@ -1 +1 @@
-Subproject commit 98bb55798a77c0346b12a1dbb53fe4d3e0379d66
+Subproject commit 96e9566a35fb51ebf13ffbdadfd49a93c1ae5c1a

+ 8 - 4
launcher/modManager/cmodlistview_moc.cpp

@@ -1110,8 +1110,10 @@ void CModListView::installMaps(QStringList maps)
 		}
 		else
 		{
-			QString fileName = map.section('/', -1, -1);
-			if (QFile::exists(destDir + fileName))
+		    QString srcPath = Helper::getRealPath(map);
+		    QString fileName = QFileInfo(srcPath).fileName();
+		    QString destFile = destDir + fileName;
+			if (QFile::exists(destFile))
 				conflictCount++;
 		}
 	}
@@ -1198,9 +1200,11 @@ void CModListView::installMaps(QStringList maps)
 		else
 		{
 			// Single map file
-			QString fileName = map.section('/', -1, -1);
+			QString srcPath = Helper::getRealPath(map);
+			QString fileName = QFileInfo(srcPath).fileName();
 			QString destFile = destDir + fileName;
-			logGlobal->info("Importing map '%s'", map.toStdString());
+
+			logGlobal->info("Importing map '%s'", srcPath.toStdString());
 
 			if (QFile::exists(destFile))
 			{

+ 26 - 1
launcher/modManager/modstateitemmodel_moc.cpp

@@ -276,7 +276,7 @@ bool CModFilterModel::filterMatchesCategory(const QModelIndex & source) const
 			return !mod.isInstalled();
 		case ModFilterMask::INSTALLED:
 			return mod.isInstalled();
-		case ModFilterMask::UPDATEABLE:
+		case ModFilterMask::UPDATABLE:
 			return mod.isUpdateAvailable();
 		case ModFilterMask::ENABLED:
 			return mod.isInstalled() && base->model->isModEnabled(modID);
@@ -320,6 +320,31 @@ bool CModFilterModel::filterAcceptsRow(int source_row, const QModelIndex & sourc
 	return false;
 }
 
+bool CModFilterModel::lessThan(const QModelIndex & source_left, const QModelIndex & source_right) const
+{
+	if(source_left.column() != ModFields::STATUS_ENABLED)
+		return QSortFilterProxyModel::lessThan(source_left, source_right);
+
+	const auto leftMod = base->model->getMod(base->modIndexToName(source_left));
+	const auto rightMod = base->model->getMod(base->modIndexToName(source_right));
+
+	const auto isLeftEnabled = base->model->isModEnabled(leftMod.getID());
+	const auto isRightEnabled = base->model->isModEnabled(rightMod.getID());
+	if(!isLeftEnabled && isRightEnabled)
+		return true;
+	if(isLeftEnabled && !isRightEnabled)
+		return false;
+
+	const auto isLeftInstalled = leftMod.isInstalled();
+	const auto isRightInstalled = rightMod.isInstalled();
+	if(!isLeftInstalled && isRightInstalled)
+		return true;
+	if(isLeftInstalled && !isRightInstalled)
+		return false;
+
+	return QSortFilterProxyModel::lessThan(source_left.siblingAtColumn(ModFields::NAME), source_right.siblingAtColumn(ModFields::NAME));
+}
+
 CModFilterModel::CModFilterModel(ModStateItemModel * model, QObject * parent)
 	: QSortFilterProxyModel(parent), base(model), filterMask(ModFilterMask::ALL)
 {

+ 3 - 1
launcher/modManager/modstateitemmodel_moc.h

@@ -32,7 +32,7 @@ enum class ModFilterMask : uint8_t
 	ALL,
 	AVAILABLE,
 	INSTALLED,
-	UPDATEABLE,
+	UPDATABLE,
 	ENABLED,
 	DISABLED
 };
@@ -97,6 +97,8 @@ class CModFilterModel final : public QSortFilterProxyModel
 
 	bool filterAcceptsRow(int source_row, const QModelIndex & source_parent) const override;
 
+	bool lessThan(const QModelIndex & source_left, const QModelIndex & source_right) const override;
+
 public:
 	void setTypeFilter(ModFilterMask filterMask);
 

File diff suppressed because it is too large
+ 355 - 176
launcher/translation/belarusian.ts


File diff suppressed because it is too large
+ 355 - 176
launcher/translation/bulgarian.ts


+ 36 - 26
launcher/translation/chinese.ts

@@ -365,65 +365,74 @@ Install successfully downloaded?</source>
         <translation>正在安装模组 %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1128"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1130"/>
         <source>Map exists</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">地图已存在</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1129"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1131"/>
         <source>Map &apos;%1&apos; already exists. Do you want to overwrite it?</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">地图 &apos;%1&apos; 已存在。要覆盖吗?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1138"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1140"/>
         <source>Yes to All</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">全部是</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1139"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1141"/>
         <source>No to All</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">全部否</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1226"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1230"/>
         <source>Import complete</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">导入完成</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1226"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1230"/>
         <source>%1 map(s) successfully imported.</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">已成功导入 %1 张地图。</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1229"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1233"/>
         <source>Import failed</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">导入失败</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1229"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1233"/>
         <source>Failed to import the following maps:
 %1</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">无法导入以下地图:
+%1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1255"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1259"/>
         <source>Operation failed</source>
         <translation>操作失败</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1256"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1260"/>
         <source>Encountered errors:
 </source>
         <translation>遇到问题:
 </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1292"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1296"/>
         <source>screenshots</source>
         <translation>截图</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1298"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1302"/>
         <source>Screenshot %1</source>
         <translation>截图 %1</translation>
     </message>
@@ -1371,7 +1380,7 @@ Bin (%n字节):
         <location filename="../languages.cpp" line="25"/>
         <source>Czech</source>
         <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
-        <translation>捷克语</translation>
+        <translation type="unfinished">捷克语</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="26"/>
@@ -1382,25 +1391,25 @@ Bin (%n字节):
         <location filename="../languages.cpp" line="27"/>
         <source>English</source>
         <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
-        <translation>英语</translation>
+        <translation type="unfinished">英语</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="28"/>
         <source>Finnish</source>
         <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
-        <translation>芬兰语</translation>
+        <translation type="unfinished">芬兰语</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="29"/>
         <source>French</source>
         <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
-        <translation>法语</translation>
+        <translation type="unfinished">法语</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="30"/>
         <source>German</source>
         <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
-        <translation>德语</translation>
+        <translation type="unfinished">德语</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="31"/>
@@ -1731,7 +1740,8 @@ Bin (%n字节):
     <message>
         <location filename="../modManager/modstateitemmodel_moc.cpp" line="57"/>
         <source>Resources</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">资源</translation>
     </message>
 </context>
 <context>

+ 31 - 21
launcher/translation/czech.ts

@@ -362,65 +362,74 @@ Nainstalovat úspěšně stažené?</translation>
         <translation>Instalování modifikace %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1128"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1130"/>
         <source>Map exists</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Mapa existuje</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1129"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1131"/>
         <source>Map &apos;%1&apos; already exists. Do you want to overwrite it?</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Mapa &apos;%1&apos; již existuje. Chcete ji přepsat?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1138"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1140"/>
         <source>Yes to All</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Ano pro všechny</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1139"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1141"/>
         <source>No to All</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Ne pro všechny</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1226"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1230"/>
         <source>Import complete</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Import dokončen</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1226"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1230"/>
         <source>%1 map(s) successfully imported.</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Úspěšně importováno %1 map.</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1229"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1233"/>
         <source>Import failed</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Import se nezdařil</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1229"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1233"/>
         <source>Failed to import the following maps:
 %1</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Nepodařilo se importovat následující mapy:
+%1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1255"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1259"/>
         <source>Operation failed</source>
         <translation>Operace selhala</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1256"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1260"/>
         <source>Encountered errors:
 </source>
         <translation>Vyskytly se chyby:
 </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1292"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1296"/>
         <source>screenshots</source>
         <translation>snímky obrazovky</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1298"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1302"/>
         <source>Screenshot %1</source>
         <translation>Snímek obrazovky %1</translation>
     </message>
@@ -1730,7 +1739,8 @@ Bin (%n bajtů):
     <message>
         <location filename="../modManager/modstateitemmodel_moc.cpp" line="57"/>
         <source>Resources</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Zdroje</translation>
     </message>
 </context>
 <context>

+ 12 - 12
launcher/translation/english.ts

@@ -356,64 +356,64 @@ Install successfully downloaded?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1128"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1130"/>
         <source>Map exists</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1129"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1131"/>
         <source>Map &apos;%1&apos; already exists. Do you want to overwrite it?</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1138"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1140"/>
         <source>Yes to All</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1139"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1141"/>
         <source>No to All</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1226"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1230"/>
         <source>Import complete</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1226"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1230"/>
         <source>%1 map(s) successfully imported.</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1229"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1233"/>
         <source>Import failed</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1229"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1233"/>
         <source>Failed to import the following maps:
 %1</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1255"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1259"/>
         <source>Operation failed</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1256"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1260"/>
         <source>Encountered errors:
 </source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1292"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1296"/>
         <source>screenshots</source>
         <translation type="unfinished"></translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1298"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1302"/>
         <source>Screenshot %1</source>
         <translation type="unfinished"></translation>
     </message>

File diff suppressed because it is too large
+ 355 - 176
launcher/translation/finnish.ts


+ 69 - 41
launcher/translation/french.ts

@@ -363,65 +363,74 @@ Installer les téchargements réussis?</translation>
         <translation>Installer le mod %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1128"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1130"/>
         <source>Map exists</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">La carte existe</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1129"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1131"/>
         <source>Map &apos;%1&apos; already exists. Do you want to overwrite it?</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">La carte &apos;%1&apos; existe déjà. Voulez-vous l’écraser ?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1138"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1140"/>
         <source>Yes to All</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Oui pour tous</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1139"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1141"/>
         <source>No to All</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Non pour tous</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1226"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1230"/>
         <source>Import complete</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Importation terminée</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1226"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1230"/>
         <source>%1 map(s) successfully imported.</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Importation réussie de %1 carte(s).</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1229"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1233"/>
         <source>Import failed</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Échec de l’importation</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1229"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1233"/>
         <source>Failed to import the following maps:
 %1</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Échec de l’importation des cartes suivantes :
+%1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1255"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1259"/>
         <source>Operation failed</source>
         <translation>Opération échouée</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1256"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1260"/>
         <source>Encountered errors:
 </source>
         <translation>Erreurs rencontrées:
 </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1292"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1296"/>
         <source>screenshots</source>
         <translation>captures d&apos;écran</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1298"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1302"/>
         <source>Screenshot %1</source>
         <translation>Impression écran %1</translation>
     </message>
@@ -509,12 +518,14 @@ Installer les téchargements réussis?</translation>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="82"/>
         <source>Config editor</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Éditeur de configuration</translation>
     </message>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="89"/>
         <source>Open editor</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Ouvrir l’éditeur</translation>
     </message>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="102"/>
@@ -616,7 +627,8 @@ Mode Plein Écran Exclusif - le jeu couvrira entièrement votre écran et utilis
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="1515"/>
         <source>Ignore mute switch</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Ignorer l’interrupteur de sourdine</translation>
     </message>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="693"/>
@@ -913,37 +925,43 @@ Mode Plein Écran Exclusif - le jeu couvrira entièrement votre écran et utilis
     <message>
         <location filename="../settingsView/configeditordialog_moc.ui" line="50"/>
         <source>Save</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Enregistrer</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.ui" line="73"/>
         <source>File:</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Fichier :</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.ui" line="86"/>
         <source>Close</source>
-        <translation type="unfinished">Fermer</translation>
+        <translation>Fermer</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="27"/>
         <source>Config editor</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Éditeur de configuration</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="69"/>
         <source>Unsaved changes</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Modifications non enregistrées</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="69"/>
         <source>Do you want to discard changes?</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Voulez-vous abandonner les modifications ?</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="123"/>
         <source>JSON file is not valid!</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Le fichier JSON n’est pas valide !</translation>
     </message>
 </context>
 <context>
@@ -1204,7 +1222,8 @@ Veuillez sélectionner le répertoire contenant Heroes III: Complete Edition ou
     <message>
         <location filename="../firstLaunch/firstlaunch_moc.cpp" line="372"/>
         <source>Failed to open file: %1</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Échec de l’ouverture du fichier : %1</translation>
     </message>
     <message>
         <location filename="../firstLaunch/firstlaunch_moc.cpp" line="441"/>
@@ -1360,12 +1379,14 @@ Bin (%n octets):
     <message>
         <location filename="../languages.cpp" line="23"/>
         <source>Belarusian</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Biélorusse</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="24"/>
         <source>Bulgarian</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Bulgare</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="25"/>
@@ -1400,7 +1421,8 @@ Bin (%n octets):
     <message>
         <location filename="../languages.cpp" line="31"/>
         <source>Greek</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Grec</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="32"/>
@@ -1415,7 +1437,8 @@ Bin (%n octets):
     <message>
         <location filename="../languages.cpp" line="34"/>
         <source>Japanese</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Japonais</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="35"/>
@@ -1425,7 +1448,8 @@ Bin (%n octets):
     <message>
         <location filename="../languages.cpp" line="36"/>
         <source>Norwegian</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Norvégien</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="37"/>
@@ -1440,7 +1464,8 @@ Bin (%n octets):
     <message>
         <location filename="../languages.cpp" line="39"/>
         <source>Romanian</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Roumain</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="40"/>
@@ -1710,7 +1735,7 @@ Bin (%n octets):
     <message>
         <location filename="../modManager/modstateitemmodel_moc.cpp" line="54"/>
         <source>Campaigns</source>
-        <translation type="unfinished">Campagnes</translation>
+        <translation>Campagnes</translation>
     </message>
     <message>
         <location filename="../modManager/modstateitemmodel_moc.cpp" line="55"/>
@@ -1725,7 +1750,8 @@ Bin (%n octets):
     <message>
         <location filename="../modManager/modstateitemmodel_moc.cpp" line="57"/>
         <source>Resources</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Ressources</translation>
     </message>
 </context>
 <context>
@@ -2011,13 +2037,15 @@ Pour résoudre ce problème, veuillez copier manuellement les fichiers de donné
         <location filename="../startGame/StartGameTab.cpp" line="407"/>
         <location filename="../startGame/StartGameTab.cpp" line="416"/>
         <source>Preset import failed</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Échec de l’importation du préréglage</translation>
     </message>
     <message>
         <location filename="../startGame/StartGameTab.cpp" line="407"/>
         <location filename="../startGame/StartGameTab.cpp" line="416"/>
         <source>Failed to import preset - data in clipboard does not looks like mod preset!</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Échec de l’importation du préréglage - les données du presse-papiers ne ressemblent pas à un préréglage de mod !</translation>
     </message>
     <message>
         <location filename="../startGame/StartGameTab.cpp" line="432"/>

+ 31 - 21
launcher/translation/german.ts

@@ -362,65 +362,74 @@ Installation erfolgreich heruntergeladen?</translation>
         <translation>Installation von Mod %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1128"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1130"/>
         <source>Map exists</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Karte vorhanden</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1129"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1131"/>
         <source>Map &apos;%1&apos; already exists. Do you want to overwrite it?</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Karte &apos;%1&apos; existiert bereits. Möchten Sie sie überschreiben?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1138"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1140"/>
         <source>Yes to All</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Ja für alle</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1139"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1141"/>
         <source>No to All</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Nein für alle</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1226"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1230"/>
         <source>Import complete</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Import abgeschlossen</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1226"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1230"/>
         <source>%1 map(s) successfully imported.</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">%1 Karte(n) erfolgreich importiert.</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1229"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1233"/>
         <source>Import failed</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Import fehlgeschlagen</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1229"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1233"/>
         <source>Failed to import the following maps:
 %1</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Die folgenden Karten konnten nicht importiert werden:
+%1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1255"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1259"/>
         <source>Operation failed</source>
         <translation>Operation fehlgeschlagen</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1256"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1260"/>
         <source>Encountered errors:
 </source>
         <translation>Aufgetretene Fehler:
 </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1292"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1296"/>
         <source>screenshots</source>
         <translation>Screenshots</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1298"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1302"/>
         <source>Screenshot %1</source>
         <translation>Screenshot %1</translation>
     </message>
@@ -1725,7 +1734,8 @@ Bin (%n Bytes):
     <message>
         <location filename="../modManager/modstateitemmodel_moc.cpp" line="57"/>
         <source>Resources</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Ressourcen</translation>
     </message>
 </context>
 <context>

File diff suppressed because it is too large
+ 355 - 176
launcher/translation/greek.ts


+ 69 - 41
launcher/translation/hungarian.ts

@@ -365,65 +365,74 @@ Sikeresen letöltött telepítés?</translation>
         <translation>%1 mod telepítése</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1128"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1130"/>
         <source>Map exists</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Térkép létezik</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1129"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1131"/>
         <source>Map &apos;%1&apos; already exists. Do you want to overwrite it?</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">A(z) &apos;%1&apos; térkép már létezik. Felül szeretnéd írni?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1138"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1140"/>
         <source>Yes to All</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Igen mindet</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1139"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1141"/>
         <source>No to All</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Nem mindet</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1226"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1230"/>
         <source>Import complete</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Importálás befejezve</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1226"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1230"/>
         <source>%1 map(s) successfully imported.</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">%1 térkép sikeresen importálva.</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1229"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1233"/>
         <source>Import failed</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Importálás sikertelen</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1229"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1233"/>
         <source>Failed to import the following maps:
 %1</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">A következő térképek importálása nem sikerült:
+%1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1255"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1259"/>
         <source>Operation failed</source>
         <translation>Művelet sikertelen</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1256"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1260"/>
         <source>Encountered errors:
 </source>
         <translation>Talált hibák:
 </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1292"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1296"/>
         <source>screenshots</source>
         <translation>képernyőképek</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1298"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1302"/>
         <source>Screenshot %1</source>
         <translation>Képernyőkép %1</translation>
     </message>
@@ -516,12 +525,14 @@ Sikeresen letöltött telepítés?</translation>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="82"/>
         <source>Config editor</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Konfigurációs szerkesztő</translation>
     </message>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="89"/>
         <source>Open editor</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Szerkesztő megnyitása</translation>
     </message>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="102"/>
@@ -624,7 +635,8 @@ Exkluzív teljes képernyő - a játék teljes képernyős módban fut, és az 
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="1515"/>
         <source>Ignore mute switch</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Némító kapcsoló figyelmen kívül hagyása</translation>
     </message>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="693"/>
@@ -916,37 +928,43 @@ Exkluzív teljes képernyő - a játék teljes képernyős módban fut, és az 
     <message>
         <location filename="../settingsView/configeditordialog_moc.ui" line="50"/>
         <source>Save</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Mentés</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.ui" line="73"/>
         <source>File:</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Fájl:</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.ui" line="86"/>
         <source>Close</source>
-        <translation type="unfinished">Bezárás</translation>
+        <translation>Bezárás</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="27"/>
         <source>Config editor</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Konfigurációs szerkesztő</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="69"/>
         <source>Unsaved changes</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Nem mentett változtatások</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="69"/>
         <source>Do you want to discard changes?</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Elveted a változtatásokat?</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="123"/>
         <source>JSON file is not valid!</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">A JSON fájl érvénytelen!</translation>
     </message>
 </context>
 <context>
@@ -1212,7 +1230,8 @@ Kérjük, válassza ki a Heroes III: Complete Edition vagy Heroes III: Shadow of
     <message>
         <location filename="../firstLaunch/firstlaunch_moc.cpp" line="372"/>
         <source>Failed to open file: %1</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Nem sikerült megnyitni a fájlt: %1</translation>
     </message>
     <message>
         <location filename="../firstLaunch/firstlaunch_moc.cpp" line="467"/>
@@ -1357,12 +1376,14 @@ Bin (%n bájt):
     <message>
         <location filename="../languages.cpp" line="23"/>
         <source>Belarusian</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Belarusz</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="24"/>
         <source>Bulgarian</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Bolgár</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="25"/>
@@ -1397,7 +1418,8 @@ Bin (%n bájt):
     <message>
         <location filename="../languages.cpp" line="31"/>
         <source>Greek</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Görög</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="32"/>
@@ -1412,7 +1434,8 @@ Bin (%n bájt):
     <message>
         <location filename="../languages.cpp" line="34"/>
         <source>Japanese</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Japán</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="35"/>
@@ -1422,7 +1445,8 @@ Bin (%n bájt):
     <message>
         <location filename="../languages.cpp" line="36"/>
         <source>Norwegian</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Norvég</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="37"/>
@@ -1437,7 +1461,8 @@ Bin (%n bájt):
     <message>
         <location filename="../languages.cpp" line="39"/>
         <source>Romanian</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Román</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="40"/>
@@ -1708,7 +1733,7 @@ Bin (%n bájt):
     <message>
         <location filename="../modManager/modstateitemmodel_moc.cpp" line="54"/>
         <source>Campaigns</source>
-        <translation type="unfinished">Kampányok</translation>
+        <translation>Kampányok</translation>
     </message>
     <message>
         <location filename="../modManager/modstateitemmodel_moc.cpp" line="55"/>
@@ -1723,7 +1748,8 @@ Bin (%n bájt):
     <message>
         <location filename="../modManager/modstateitemmodel_moc.cpp" line="57"/>
         <source>Resources</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Erőforrások</translation>
     </message>
 </context>
 <context>
@@ -2007,13 +2033,15 @@ A probléma megoldásához kérjük, manuálisan másolja a hiányzó adatfájlo
         <location filename="../startGame/StartGameTab.cpp" line="407"/>
         <location filename="../startGame/StartGameTab.cpp" line="416"/>
         <source>Preset import failed</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Előbeállítás importja sikertelen</translation>
     </message>
     <message>
         <location filename="../startGame/StartGameTab.cpp" line="407"/>
         <location filename="../startGame/StartGameTab.cpp" line="416"/>
         <source>Failed to import preset - data in clipboard does not looks like mod preset!</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Az előbeállítás importja nem sikerült – a vágólapon lévő adatok nem tűnnek mod előbeállításnak!</translation>
     </message>
     <message>
         <location filename="../startGame/StartGameTab.cpp" line="432"/>

+ 69 - 41
launcher/translation/italian.ts

@@ -362,64 +362,73 @@ Installazione scaricata con successo?</translation>
         <translation>Installazione del mod %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1128"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1130"/>
         <source>Map exists</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">La mappa esiste</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1129"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1131"/>
         <source>Map &apos;%1&apos; already exists. Do you want to overwrite it?</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">La mappa &apos;%1&apos; esiste già. Vuoi sovrascriverla?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1138"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1140"/>
         <source>Yes to All</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Sì a tutto</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1139"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1141"/>
         <source>No to All</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">No a tutto</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1226"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1230"/>
         <source>Import complete</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Importazione completata</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1226"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1230"/>
         <source>%1 map(s) successfully imported.</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">%1 mappe importate correttamente.</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1229"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1233"/>
         <source>Import failed</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Importazione non riuscita</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1229"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1233"/>
         <source>Failed to import the following maps:
 %1</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Impossibile importare le seguenti mappe:
+%1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1255"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1259"/>
         <source>Operation failed</source>
         <translation>Operazione fallita</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1256"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1260"/>
         <source>Encountered errors:
 </source>
         <translation>Errori riscontrati:</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1292"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1296"/>
         <source>screenshots</source>
         <translation>screenshot</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1298"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1302"/>
         <source>Screenshot %1</source>
         <translation>Screenshot %1</translation>
     </message>
@@ -512,12 +521,14 @@ Installazione scaricata con successo?</translation>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="82"/>
         <source>Config editor</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Editor di configurazione</translation>
     </message>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="89"/>
         <source>Open editor</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Apri editor</translation>
     </message>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="102"/>
@@ -620,7 +631,8 @@ Modalità Schermo Intero Esclusiva - il gioco coprirà l&apos;intero schermo e u
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="1515"/>
         <source>Ignore mute switch</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Ignora interruttore silenzioso</translation>
     </message>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="693"/>
@@ -912,37 +924,43 @@ Modalità Schermo Intero Esclusiva - il gioco coprirà l&apos;intero schermo e u
     <message>
         <location filename="../settingsView/configeditordialog_moc.ui" line="50"/>
         <source>Save</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Salva</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.ui" line="73"/>
         <source>File:</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">File:</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.ui" line="86"/>
         <source>Close</source>
-        <translation type="unfinished">Chiudi</translation>
+        <translation>Chiudi</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="27"/>
         <source>Config editor</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Editor di configurazione</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="69"/>
         <source>Unsaved changes</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Modifiche non salvate</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="69"/>
         <source>Do you want to discard changes?</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Vuoi scartare le modifiche?</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="123"/>
         <source>JSON file is not valid!</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Il file JSON non è valido!</translation>
     </message>
 </context>
 <context>
@@ -1208,7 +1226,8 @@ Seleziona la directory con Heroes III: Complete Edition o Heroes III: Shadow of
     <message>
         <location filename="../firstLaunch/firstlaunch_moc.cpp" line="372"/>
         <source>Failed to open file: %1</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Impossibile aprire il file: %1</translation>
     </message>
     <message>
         <location filename="../firstLaunch/firstlaunch_moc.cpp" line="467"/>
@@ -1359,12 +1378,14 @@ Bin (%n byte):
     <message>
         <location filename="../languages.cpp" line="23"/>
         <source>Belarusian</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Bielorusso</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="24"/>
         <source>Bulgarian</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Bulgaro</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="25"/>
@@ -1399,7 +1420,8 @@ Bin (%n byte):
     <message>
         <location filename="../languages.cpp" line="31"/>
         <source>Greek</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Greco</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="32"/>
@@ -1414,7 +1436,8 @@ Bin (%n byte):
     <message>
         <location filename="../languages.cpp" line="34"/>
         <source>Japanese</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Giapponese</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="35"/>
@@ -1424,7 +1447,8 @@ Bin (%n byte):
     <message>
         <location filename="../languages.cpp" line="36"/>
         <source>Norwegian</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Norvegese</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="37"/>
@@ -1439,7 +1463,8 @@ Bin (%n byte):
     <message>
         <location filename="../languages.cpp" line="39"/>
         <source>Romanian</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Rumeno</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="40"/>
@@ -1709,7 +1734,7 @@ Bin (%n byte):
     <message>
         <location filename="../modManager/modstateitemmodel_moc.cpp" line="54"/>
         <source>Campaigns</source>
-        <translation type="unfinished">Campagne</translation>
+        <translation>Campagne</translation>
     </message>
     <message>
         <location filename="../modManager/modstateitemmodel_moc.cpp" line="55"/>
@@ -1724,7 +1749,8 @@ Bin (%n byte):
     <message>
         <location filename="../modManager/modstateitemmodel_moc.cpp" line="57"/>
         <source>Resources</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Risorse</translation>
     </message>
 </context>
 <context>
@@ -2010,13 +2036,15 @@ Per risolvere questo problema, copia manualmente i file dati mancanti da Heroes
         <location filename="../startGame/StartGameTab.cpp" line="407"/>
         <location filename="../startGame/StartGameTab.cpp" line="416"/>
         <source>Preset import failed</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Importazione del preset non riuscita</translation>
     </message>
     <message>
         <location filename="../startGame/StartGameTab.cpp" line="407"/>
         <location filename="../startGame/StartGameTab.cpp" line="416"/>
         <source>Failed to import preset - data in clipboard does not looks like mod preset!</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Impossibile importare il preset: i dati negli appunti non sembrano un preset di mod!</translation>
     </message>
     <message>
         <location filename="../startGame/StartGameTab.cpp" line="432"/>

File diff suppressed because it is too large
+ 185 - 174
launcher/translation/japanese.ts


File diff suppressed because it is too large
+ 355 - 176
launcher/translation/korean.ts


File diff suppressed because it is too large
+ 355 - 176
launcher/translation/norwegian.ts


+ 42 - 41
launcher/translation/polish.ts

@@ -362,65 +362,66 @@ Zainstalować pomyślnie pobrane?</translation>
         <translation>Instalowanie modyfikacji %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1128"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1130"/>
         <source>Map exists</source>
-        <translation type="unfinished"></translation>
+        <translation>Mapa istnieje</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1129"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1131"/>
         <source>Map &apos;%1&apos; already exists. Do you want to overwrite it?</source>
-        <translation type="unfinished"></translation>
+        <translation>Mapa &apos;%1&apos; już istnieje. Czy chcesz ją nadpisać?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1138"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1140"/>
         <source>Yes to All</source>
-        <translation type="unfinished"></translation>
+        <translation>Tak dla wszystkich</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1139"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1141"/>
         <source>No to All</source>
-        <translation type="unfinished"></translation>
+        <translation>Nie dla wszystkich</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1226"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1230"/>
         <source>Import complete</source>
-        <translation type="unfinished"></translation>
+        <translation>Import zakończony</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1226"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1230"/>
         <source>%1 map(s) successfully imported.</source>
-        <translation type="unfinished"></translation>
+        <translation>Pomyślnie zaimportowano %1 map.</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1229"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1233"/>
         <source>Import failed</source>
-        <translation type="unfinished"></translation>
+        <translation>Import nie powiódł się</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1229"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1233"/>
         <source>Failed to import the following maps:
 %1</source>
-        <translation type="unfinished"></translation>
+        <translation>Nie udało się zaimportować następujących map:
+%1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1255"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1259"/>
         <source>Operation failed</source>
         <translation>Operacja nieudana</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1256"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1260"/>
         <source>Encountered errors:
 </source>
         <translation>Napotkane błędy:
 </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1292"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1296"/>
         <source>screenshots</source>
         <translation>zrzuty ekranu</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1298"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1302"/>
         <source>Screenshot %1</source>
         <translation>Zrzut ekranu %1</translation>
     </message>
@@ -518,12 +519,12 @@ Zainstalować pomyślnie pobrane?</translation>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="82"/>
         <source>Config editor</source>
-        <translation type="unfinished"></translation>
+        <translation>Edytor konfiguracji</translation>
     </message>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="89"/>
         <source>Open editor</source>
-        <translation type="unfinished"></translation>
+        <translation>Otwórz edytor</translation>
     </message>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="102"/>
@@ -625,7 +626,7 @@ Fullscreen Exclusive Mode - the game will cover the entirety of your screen and
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="1515"/>
         <source>Ignore mute switch</source>
-        <translation type="unfinished"></translation>
+        <translation>Ignoruj przełącznik wyciszenia</translation>
     </message>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="693"/>
@@ -912,37 +913,37 @@ Fullscreen Exclusive Mode - the game will cover the entirety of your screen and
     <message>
         <location filename="../settingsView/configeditordialog_moc.ui" line="50"/>
         <source>Save</source>
-        <translation type="unfinished"></translation>
+        <translation>Zapisz</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.ui" line="73"/>
         <source>File:</source>
-        <translation type="unfinished"></translation>
+        <translation>Plik:</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.ui" line="86"/>
         <source>Close</source>
-        <translation type="unfinished">Zamknij</translation>
+        <translation>Zamknij</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="27"/>
         <source>Config editor</source>
-        <translation type="unfinished"></translation>
+        <translation>Edytor konfiguracji</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="69"/>
         <source>Unsaved changes</source>
-        <translation type="unfinished"></translation>
+        <translation>Niezapisane zmiany</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="69"/>
         <source>Do you want to discard changes?</source>
-        <translation type="unfinished"></translation>
+        <translation>Czy chcesz odrzucić zmiany?</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="123"/>
         <source>JSON file is not valid!</source>
-        <translation type="unfinished"></translation>
+        <translation>Plik JSON jest nieprawidłowy!</translation>
     </message>
 </context>
 <context>
@@ -1204,7 +1205,7 @@ Wybierz katalog z Heroes III: Complete Edition lub Heroes III: Shadow of Death.<
     <message>
         <location filename="../firstLaunch/firstlaunch_moc.cpp" line="372"/>
         <source>Failed to open file: %1</source>
-        <translation type="unfinished"></translation>
+        <translation>Nie udało się otworzyć pliku: %1</translation>
     </message>
     <message>
         <location filename="../firstLaunch/firstlaunch_moc.cpp" line="441"/>
@@ -1363,12 +1364,12 @@ Bin (%n bytes):
     <message>
         <location filename="../languages.cpp" line="23"/>
         <source>Belarusian</source>
-        <translation type="unfinished"></translation>
+        <translation>Białoruski</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="24"/>
         <source>Bulgarian</source>
-        <translation type="unfinished"></translation>
+        <translation>Bułgarski</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="25"/>
@@ -1403,7 +1404,7 @@ Bin (%n bytes):
     <message>
         <location filename="../languages.cpp" line="31"/>
         <source>Greek</source>
-        <translation type="unfinished"></translation>
+        <translation>Grecki</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="32"/>
@@ -1418,7 +1419,7 @@ Bin (%n bytes):
     <message>
         <location filename="../languages.cpp" line="34"/>
         <source>Japanese</source>
-        <translation type="unfinished"></translation>
+        <translation>Japoński</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="35"/>
@@ -1428,7 +1429,7 @@ Bin (%n bytes):
     <message>
         <location filename="../languages.cpp" line="36"/>
         <source>Norwegian</source>
-        <translation type="unfinished"></translation>
+        <translation>Norweski</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="37"/>
@@ -1443,7 +1444,7 @@ Bin (%n bytes):
     <message>
         <location filename="../languages.cpp" line="39"/>
         <source>Romanian</source>
-        <translation type="unfinished"></translation>
+        <translation>Rumuński</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="40"/>
@@ -1713,7 +1714,7 @@ Bin (%n bytes):
     <message>
         <location filename="../modManager/modstateitemmodel_moc.cpp" line="54"/>
         <source>Campaigns</source>
-        <translation type="unfinished">Kampanie</translation>
+        <translation>Kampanie</translation>
     </message>
     <message>
         <location filename="../modManager/modstateitemmodel_moc.cpp" line="55"/>
@@ -1728,7 +1729,7 @@ Bin (%n bytes):
     <message>
         <location filename="../modManager/modstateitemmodel_moc.cpp" line="57"/>
         <source>Resources</source>
-        <translation type="unfinished"></translation>
+        <translation>Zasoby</translation>
     </message>
 </context>
 <context>
@@ -2017,13 +2018,13 @@ Aby rozwiązać ten problem, zainstaluj grę ponownie i ponownie zaimportuj plik
         <location filename="../startGame/StartGameTab.cpp" line="407"/>
         <location filename="../startGame/StartGameTab.cpp" line="416"/>
         <source>Preset import failed</source>
-        <translation type="unfinished"></translation>
+        <translation>Import presetu nie powiódł się</translation>
     </message>
     <message>
         <location filename="../startGame/StartGameTab.cpp" line="407"/>
         <location filename="../startGame/StartGameTab.cpp" line="416"/>
         <source>Failed to import preset - data in clipboard does not looks like mod preset!</source>
-        <translation type="unfinished"></translation>
+        <translation>Nie udało się zaimportować presetu – dane w schowku nie wyglądają na preset modów!</translation>
     </message>
     <message>
         <location filename="../startGame/StartGameTab.cpp" line="432"/>

+ 31 - 21
launcher/translation/portuguese.ts

@@ -362,65 +362,74 @@ O download da instalação foi bem-sucedido?</translation>
         <translation>Instalando mod %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1128"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1130"/>
         <source>Map exists</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">O mapa existe</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1129"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1131"/>
         <source>Map &apos;%1&apos; already exists. Do you want to overwrite it?</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">O mapa &apos;%1&apos; já existe. Pretende substituí-lo?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1138"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1140"/>
         <source>Yes to All</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Sim para todos</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1139"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1141"/>
         <source>No to All</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Não para todos</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1226"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1230"/>
         <source>Import complete</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Importação concluída</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1226"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1230"/>
         <source>%1 map(s) successfully imported.</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">%1 mapa(s) importado(s) com êxito.</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1229"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1233"/>
         <source>Import failed</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Falha na importação</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1229"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1233"/>
         <source>Failed to import the following maps:
 %1</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Falha ao importar os seguintes mapas:
+%1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1255"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1259"/>
         <source>Operation failed</source>
         <translation>Falha na operação</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1256"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1260"/>
         <source>Encountered errors:
 </source>
         <translation>Erros encontrados:
 </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1292"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1296"/>
         <source>screenshots</source>
         <translation>capturas de tela</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1298"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1302"/>
         <source>Screenshot %1</source>
         <translation>Captura de tela %1</translation>
     </message>
@@ -1725,7 +1734,8 @@ Bin (%n bytes):
     <message>
         <location filename="../modManager/modstateitemmodel_moc.cpp" line="57"/>
         <source>Resources</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Recursos</translation>
     </message>
 </context>
 <context>

File diff suppressed because it is too large
+ 178 - 164
launcher/translation/romanian.ts


+ 89 - 48
launcher/translation/russian.ts

@@ -362,65 +362,74 @@ Install successfully downloaded?</source>
         <translation>Установка мода %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1128"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1130"/>
         <source>Map exists</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Карта существует</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1129"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1131"/>
         <source>Map &apos;%1&apos; already exists. Do you want to overwrite it?</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Карта &apos;%1&apos; уже существует. Перезаписать?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1138"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1140"/>
         <source>Yes to All</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Да для всех</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1139"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1141"/>
         <source>No to All</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Нет для всех</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1226"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1230"/>
         <source>Import complete</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Импорт завершён</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1226"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1230"/>
         <source>%1 map(s) successfully imported.</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">%1 карта(ы) успешно импортирована(ы).</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1229"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1233"/>
         <source>Import failed</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Сбой импорта</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1229"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1233"/>
         <source>Failed to import the following maps:
 %1</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Не удалось импортировать следующие карты:
+%1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1255"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1259"/>
         <source>Operation failed</source>
         <translation>Операция не удалась</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1256"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1260"/>
         <source>Encountered errors:
 </source>
         <translation>Возникли ошибки:
 </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1292"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1296"/>
         <source>screenshots</source>
         <translation>скриншоты</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1298"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1302"/>
         <source>Screenshot %1</source>
         <translation>Скриншот %1</translation>
     </message>
@@ -548,12 +557,14 @@ Install successfully downloaded?</source>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="82"/>
         <source>Config editor</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Редактор конфигурации</translation>
     </message>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="89"/>
         <source>Open editor</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Открыть редактор</translation>
     </message>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="102"/>
@@ -655,7 +666,8 @@ Fullscreen Exclusive Mode - the game will cover the entirety of your screen and
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="1515"/>
         <source>Ignore mute switch</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Игнорировать переключатель без звука</translation>
     </message>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="693"/>
@@ -912,37 +924,43 @@ Fullscreen Exclusive Mode - the game will cover the entirety of your screen and
     <message>
         <location filename="../settingsView/configeditordialog_moc.ui" line="50"/>
         <source>Save</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Сохранить</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.ui" line="73"/>
         <source>File:</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Файл:</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.ui" line="86"/>
         <source>Close</source>
-        <translation type="unfinished">Закрыть</translation>
+        <translation>Закрыть</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="27"/>
         <source>Config editor</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Редактор конфигурации</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="69"/>
         <source>Unsaved changes</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Несохранённые изменения</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="69"/>
         <source>Do you want to discard changes?</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Отменить внесённые изменения?</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="123"/>
         <source>JSON file is not valid!</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Файл JSON недействителен!</translation>
     </message>
 </context>
 <context>
@@ -1208,7 +1226,8 @@ Please select the directory with Heroes III: Complete Edition or Heroes III: Sha
     <message>
         <location filename="../firstLaunch/firstlaunch_moc.cpp" line="372"/>
         <source>Failed to open file: %1</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Не удалось открыть файл: %1</translation>
     </message>
     <message>
         <location filename="../firstLaunch/firstlaunch_moc.cpp" line="467"/>
@@ -1279,12 +1298,17 @@ error reason: </source>
 Exe (%n bytes):
 %1</source>
         <comment>param is hash</comment>
-        <translation>
-            <numerusform>SHA1 хэш предоставленных файлов:
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">
+            <numerusform>Хеш SHA1 предоставленных файлов:
+Exe (%n байт):
+%1</numerusform>
+            <numerusform>Хеш SHA1 предоставленных файлов:
+Exe (%n байт):
+%1</numerusform>
+            <numerusform>Хеш SHA1 предоставленных файлов:
 Exe (%n байт):
 %1</numerusform>
-            <numerusform></numerusform>
-            <numerusform></numerusform>
         </translation>
     </message>
     <message numerus="yes">
@@ -1293,12 +1317,20 @@ Exe (%n байт):
 Bin (%n bytes):
 %1</source>
         <comment>param is hash</comment>
-        <translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">
+            <numerusform>
+
+Bin (%n байт):
+%1</numerusform>
             <numerusform>
+
+Bin (%n байт):
+%1</numerusform>
+            <numerusform>
+
 Bin (%n байт):
 %1</numerusform>
-            <numerusform></numerusform>
-            <numerusform></numerusform>
         </translation>
     </message>
     <message>
@@ -1357,12 +1389,14 @@ Bin (%n байт):
     <message>
         <location filename="../languages.cpp" line="23"/>
         <source>Belarusian</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Белорусский</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="24"/>
         <source>Bulgarian</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Болгарский</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="25"/>
@@ -1397,7 +1431,8 @@ Bin (%n байт):
     <message>
         <location filename="../languages.cpp" line="31"/>
         <source>Greek</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Греческий</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="32"/>
@@ -1412,7 +1447,8 @@ Bin (%n байт):
     <message>
         <location filename="../languages.cpp" line="34"/>
         <source>Japanese</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Японский</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="35"/>
@@ -1422,7 +1458,8 @@ Bin (%n байт):
     <message>
         <location filename="../languages.cpp" line="36"/>
         <source>Norwegian</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Норвежский</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="37"/>
@@ -1437,7 +1474,8 @@ Bin (%n байт):
     <message>
         <location filename="../languages.cpp" line="39"/>
         <source>Romanian</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Румынский</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="40"/>
@@ -1708,7 +1746,7 @@ Bin (%n байт):
     <message>
         <location filename="../modManager/modstateitemmodel_moc.cpp" line="54"/>
         <source>Campaigns</source>
-        <translation type="unfinished">Кампании</translation>
+        <translation>Кампании</translation>
     </message>
     <message>
         <location filename="../modManager/modstateitemmodel_moc.cpp" line="55"/>
@@ -1723,7 +1761,8 @@ Bin (%n байт):
     <message>
         <location filename="../modManager/modstateitemmodel_moc.cpp" line="57"/>
         <source>Resources</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Ресурсы</translation>
     </message>
 </context>
 <context>
@@ -2013,13 +2052,15 @@ To resolve this problem, please copy missing data files from Heroes III to VCMI
         <location filename="../startGame/StartGameTab.cpp" line="407"/>
         <location filename="../startGame/StartGameTab.cpp" line="416"/>
         <source>Preset import failed</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Сбой импорта пресета</translation>
     </message>
     <message>
         <location filename="../startGame/StartGameTab.cpp" line="407"/>
         <location filename="../startGame/StartGameTab.cpp" line="416"/>
         <source>Failed to import preset - data in clipboard does not looks like mod preset!</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Не удалось импортировать пресет — данные в буфере обмена не похожи на пресет мода!</translation>
     </message>
     <message>
         <location filename="../startGame/StartGameTab.cpp" line="432"/>

+ 69 - 41
launcher/translation/spanish.ts

@@ -365,65 +365,74 @@ Instalar lo correctamente descargado?</translation>
         <translation>Instalando mod %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1128"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1130"/>
         <source>Map exists</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">El mapa existe</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1129"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1131"/>
         <source>Map &apos;%1&apos; already exists. Do you want to overwrite it?</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">El mapa &apos;%1&apos; ya existe. ¿Quieres sobrescribirlo?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1138"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1140"/>
         <source>Yes to All</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Sí para todo</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1139"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1141"/>
         <source>No to All</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">No para todo</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1226"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1230"/>
         <source>Import complete</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Importación completa</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1226"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1230"/>
         <source>%1 map(s) successfully imported.</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Se importaron correctamente %1 mapa(s).</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1229"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1233"/>
         <source>Import failed</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Error de importación</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1229"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1233"/>
         <source>Failed to import the following maps:
 %1</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">No se pudieron importar los siguientes mapas:
+%1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1255"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1259"/>
         <source>Operation failed</source>
         <translation>Operación fallida</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1256"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1260"/>
         <source>Encountered errors:
 </source>
         <translation>Errores encontrados:
 </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1292"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1296"/>
         <source>screenshots</source>
         <translation>capturas de pantalla</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1298"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1302"/>
         <source>Screenshot %1</source>
         <translation>Captura de pantalla %1</translation>
     </message>
@@ -521,12 +530,14 @@ Instalar lo correctamente descargado?</translation>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="82"/>
         <source>Config editor</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Editor de configuración</translation>
     </message>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="89"/>
         <source>Open editor</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Abrir editor</translation>
     </message>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="102"/>
@@ -629,7 +640,8 @@ Modo Exclusivo de Pantalla Completa - el juego cubrirá toda tu pantalla y usar
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="1515"/>
         <source>Ignore mute switch</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Ignorar el interruptor de silencio</translation>
     </message>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="693"/>
@@ -916,37 +928,43 @@ Modo Exclusivo de Pantalla Completa - el juego cubrirá toda tu pantalla y usar
     <message>
         <location filename="../settingsView/configeditordialog_moc.ui" line="50"/>
         <source>Save</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Guardar</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.ui" line="73"/>
         <source>File:</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Archivo:</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.ui" line="86"/>
         <source>Close</source>
-        <translation type="unfinished">Cerrar</translation>
+        <translation>Cerrar</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="27"/>
         <source>Config editor</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Editor de configuración</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="69"/>
         <source>Unsaved changes</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Cambios no guardados</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="69"/>
         <source>Do you want to discard changes?</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">¿Deseas descartar los cambios?</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="123"/>
         <source>JSON file is not valid!</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">¡El archivo JSON no es válido!</translation>
     </message>
 </context>
 <context>
@@ -1212,7 +1230,8 @@ Por favor, selecciona el directorio con Heroes III: Complete Edition o Heroes II
     <message>
         <location filename="../firstLaunch/firstlaunch_moc.cpp" line="372"/>
         <source>Failed to open file: %1</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">No se pudo abrir el archivo: %1</translation>
     </message>
     <message>
         <location filename="../firstLaunch/firstlaunch_moc.cpp" line="467"/>
@@ -1363,12 +1382,14 @@ Bin (%n bytes):
     <message>
         <location filename="../languages.cpp" line="23"/>
         <source>Belarusian</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Bielorruso</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="24"/>
         <source>Bulgarian</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Búlgaro</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="25"/>
@@ -1403,7 +1424,8 @@ Bin (%n bytes):
     <message>
         <location filename="../languages.cpp" line="31"/>
         <source>Greek</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Griego</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="32"/>
@@ -1418,7 +1440,8 @@ Bin (%n bytes):
     <message>
         <location filename="../languages.cpp" line="34"/>
         <source>Japanese</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Japonés</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="35"/>
@@ -1428,7 +1451,8 @@ Bin (%n bytes):
     <message>
         <location filename="../languages.cpp" line="36"/>
         <source>Norwegian</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Noruego</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="37"/>
@@ -1443,7 +1467,8 @@ Bin (%n bytes):
     <message>
         <location filename="../languages.cpp" line="39"/>
         <source>Romanian</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Rumano</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="40"/>
@@ -1713,7 +1738,7 @@ Bin (%n bytes):
     <message>
         <location filename="../modManager/modstateitemmodel_moc.cpp" line="54"/>
         <source>Campaigns</source>
-        <translation type="unfinished">Campañas</translation>
+        <translation>Campañas</translation>
     </message>
     <message>
         <location filename="../modManager/modstateitemmodel_moc.cpp" line="55"/>
@@ -1728,7 +1753,8 @@ Bin (%n bytes):
     <message>
         <location filename="../modManager/modstateitemmodel_moc.cpp" line="57"/>
         <source>Resources</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Recursos</translation>
     </message>
 </context>
 <context>
@@ -2014,13 +2040,15 @@ Para resolver este problema, copia manualmente los archivos de datos faltantes d
         <location filename="../startGame/StartGameTab.cpp" line="407"/>
         <location filename="../startGame/StartGameTab.cpp" line="416"/>
         <source>Preset import failed</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Error al importar el preajuste</translation>
     </message>
     <message>
         <location filename="../startGame/StartGameTab.cpp" line="407"/>
         <location filename="../startGame/StartGameTab.cpp" line="416"/>
         <source>Failed to import preset - data in clipboard does not looks like mod preset!</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Error al importar el preajuste: los datos del portapapeles no parecen un preajuste de mod.</translation>
     </message>
     <message>
         <location filename="../startGame/StartGameTab.cpp" line="432"/>

+ 14 - 13
launcher/translation/swedish.ts

@@ -362,66 +362,66 @@ Installation framgångsrikt nedladdad?</translation>
         <translation>Installerar modd %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1128"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1130"/>
         <source>Map exists</source>
         <translation>Kartan existerar</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1129"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1131"/>
         <source>Map &apos;%1&apos; already exists. Do you want to overwrite it?</source>
         <translation>Kartan ’%1’ finns redan. Vill du skriva över den?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1138"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1140"/>
         <source>Yes to All</source>
         <translation>Ja till alla</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1139"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1141"/>
         <source>No to All</source>
         <translation>Nej till alla</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1226"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1230"/>
         <source>Import complete</source>
         <translation>Importen är klar</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1226"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1230"/>
         <source>%1 map(s) successfully imported.</source>
         <translation>%1 karta/kartor importerades utan problem.</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1229"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1233"/>
         <source>Import failed</source>
         <translation>Importen misslyckades</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1229"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1233"/>
         <source>Failed to import the following maps:
 %1</source>
         <translation>Det gick inte att importera följande kartor:
 %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1255"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1259"/>
         <source>Operation failed</source>
         <translation>Åtgärden misslyckades</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1256"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1260"/>
         <source>Encountered errors:
 </source>
         <translation>Fel påträffades:
 </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1292"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1296"/>
         <source>screenshots</source>
         <translation>skärmbilder</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1298"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1302"/>
         <source>Screenshot %1</source>
         <translation>Skärmbild %1</translation>
     </message>
@@ -1726,7 +1726,8 @@ Bin (%n byte):
     <message>
         <location filename="../modManager/modstateitemmodel_moc.cpp" line="57"/>
         <source>Resources</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Resurser</translation>
     </message>
 </context>
 <context>

File diff suppressed because it is too large
+ 355 - 176
launcher/translation/turkish.ts


+ 71 - 42
launcher/translation/ukrainian.ts

@@ -362,65 +362,74 @@ Install successfully downloaded?</source>
         <translation>Встановлення модифікації %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1128"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1130"/>
         <source>Map exists</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Карта існує</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1129"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1131"/>
         <source>Map &apos;%1&apos; already exists. Do you want to overwrite it?</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Карта &apos;%1&apos; вже існує. Перезаписати?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1138"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1140"/>
         <source>Yes to All</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Так для всіх</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1139"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1141"/>
         <source>No to All</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Ні для всіх</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1226"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1230"/>
         <source>Import complete</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Імпорт завершено</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1226"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1230"/>
         <source>%1 map(s) successfully imported.</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Успішно імпортовано %1 карт.</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1229"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1233"/>
         <source>Import failed</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Не вдалося імпортувати</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1229"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1233"/>
         <source>Failed to import the following maps:
 %1</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Не вдалося імпортувати такі карти:
+%1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1255"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1259"/>
         <source>Operation failed</source>
         <translation>Операція завершилася невдало</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1256"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1260"/>
         <source>Encountered errors:
 </source>
         <translation>Виникли помилки:
 </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1292"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1296"/>
         <source>screenshots</source>
         <translation>знімки екрану</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1298"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1302"/>
         <source>Screenshot %1</source>
         <translation>Знімок екрану %1</translation>
     </message>
@@ -496,7 +505,8 @@ Install successfully downloaded?</source>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="288"/>
         <source>Haptic Feedback</source>
-        <translation></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Тактильний відгук</translation>
     </message>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="392"/>
@@ -518,12 +528,14 @@ Install successfully downloaded?</source>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="82"/>
         <source>Config editor</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Редактор конфігурації</translation>
     </message>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="89"/>
         <source>Open editor</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Відкрити редактор</translation>
     </message>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="102"/>
@@ -625,7 +637,8 @@ Fullscreen Exclusive Mode - the game will cover the entirety of your screen and
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="1515"/>
         <source>Ignore mute switch</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Ігнорувати перемикач вимкнення звуку</translation>
     </message>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="693"/>
@@ -912,37 +925,43 @@ Fullscreen Exclusive Mode - the game will cover the entirety of your screen and
     <message>
         <location filename="../settingsView/configeditordialog_moc.ui" line="50"/>
         <source>Save</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Зберегти</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.ui" line="73"/>
         <source>File:</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Файл:</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.ui" line="86"/>
         <source>Close</source>
-        <translation type="unfinished">Закрити</translation>
+        <translation>Закрити</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="27"/>
         <source>Config editor</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Редактор конфігурації</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="69"/>
         <source>Unsaved changes</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Незбережені зміни</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="69"/>
         <source>Do you want to discard changes?</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Бажаєте скасувати зміни?</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="123"/>
         <source>JSON file is not valid!</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Файл JSON недійсний!</translation>
     </message>
 </context>
 <context>
@@ -1203,7 +1222,8 @@ Please select the directory with Heroes III: Complete Edition or Heroes III: Sha
     <message>
         <location filename="../firstLaunch/firstlaunch_moc.cpp" line="372"/>
         <source>Failed to open file: %1</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Не вдалося відкрити файл: %1</translation>
     </message>
     <message>
         <location filename="../firstLaunch/firstlaunch_moc.cpp" line="441"/>
@@ -1365,12 +1385,14 @@ Bin (%n байтів):
     <message>
         <location filename="../languages.cpp" line="23"/>
         <source>Belarusian</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Білоруська</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="24"/>
         <source>Bulgarian</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Болгарська</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="25"/>
@@ -1405,7 +1427,8 @@ Bin (%n байтів):
     <message>
         <location filename="../languages.cpp" line="31"/>
         <source>Greek</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Грецька</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="32"/>
@@ -1420,7 +1443,8 @@ Bin (%n байтів):
     <message>
         <location filename="../languages.cpp" line="34"/>
         <source>Japanese</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Японська</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="35"/>
@@ -1430,7 +1454,8 @@ Bin (%n байтів):
     <message>
         <location filename="../languages.cpp" line="36"/>
         <source>Norwegian</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Норвезька</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="37"/>
@@ -1445,7 +1470,8 @@ Bin (%n байтів):
     <message>
         <location filename="../languages.cpp" line="39"/>
         <source>Romanian</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Румунська</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="40"/>
@@ -1716,7 +1742,7 @@ Bin (%n байтів):
     <message>
         <location filename="../modManager/modstateitemmodel_moc.cpp" line="54"/>
         <source>Campaigns</source>
-        <translation type="unfinished">Кампанії</translation>
+        <translation>Кампанії</translation>
     </message>
     <message>
         <location filename="../modManager/modstateitemmodel_moc.cpp" line="55"/>
@@ -1731,7 +1757,8 @@ Bin (%n байтів):
     <message>
         <location filename="../modManager/modstateitemmodel_moc.cpp" line="57"/>
         <source>Resources</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Ресурси</translation>
     </message>
 </context>
 <context>
@@ -2021,13 +2048,15 @@ To resolve this problem, please copy missing data files from Heroes III to VCMI
         <location filename="../startGame/StartGameTab.cpp" line="407"/>
         <location filename="../startGame/StartGameTab.cpp" line="416"/>
         <source>Preset import failed</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Не вдалося імпортувати пресет</translation>
     </message>
     <message>
         <location filename="../startGame/StartGameTab.cpp" line="407"/>
         <location filename="../startGame/StartGameTab.cpp" line="416"/>
         <source>Failed to import preset - data in clipboard does not looks like mod preset!</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Не вдалося імпортувати пресет — дані в буфері обміну не схожі на пресет моду!</translation>
     </message>
     <message>
         <location filename="../startGame/StartGameTab.cpp" line="432"/>

+ 69 - 41
launcher/translation/vietnamese.ts

@@ -365,65 +365,74 @@ Cài đặt đã tải xuống thành công?</translation>
         <translation>Cài mod %1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1128"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1130"/>
         <source>Map exists</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Bản đồ đã tồn tại</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1129"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1131"/>
         <source>Map &apos;%1&apos; already exists. Do you want to overwrite it?</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Bản đồ &apos;%1&apos; đã tồn tại. Bạn có muốn ghi đè không?</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1138"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1140"/>
         <source>Yes to All</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Có cho tất cả</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1139"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1141"/>
         <source>No to All</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Không cho tất cả</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1226"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1230"/>
         <source>Import complete</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Nhập xong</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1226"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1230"/>
         <source>%1 map(s) successfully imported.</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Đã nhập thành công %1 bản đồ.</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1229"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1233"/>
         <source>Import failed</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Nhập thất bại</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1229"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1233"/>
         <source>Failed to import the following maps:
 %1</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Không thể nhập các bản đồ sau:
+%1</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1255"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1259"/>
         <source>Operation failed</source>
         <translation>Không mở được</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1256"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1260"/>
         <source>Encountered errors:
 </source>
         <translation>Đã có lỗi:
 </translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1292"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1296"/>
         <source>screenshots</source>
         <translation>hình ảnh</translation>
     </message>
     <message>
-        <location filename="../modManager/cmodlistview_moc.cpp" line="1298"/>
+        <location filename="../modManager/cmodlistview_moc.cpp" line="1302"/>
         <source>Screenshot %1</source>
         <translation>Hình ảnh %1</translation>
     </message>
@@ -519,12 +528,14 @@ Cài đặt đã tải xuống thành công?</translation>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="82"/>
         <source>Config editor</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Trình chỉnh sửa cấu hình</translation>
     </message>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="89"/>
         <source>Open editor</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Mở trình chỉnh sửa</translation>
     </message>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="102"/>
@@ -631,7 +642,8 @@ Toàn màn hình riêng biệt - Sử dụng kích thước màn hình do bạn
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="1515"/>
         <source>Ignore mute switch</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Bỏ qua công tắc tắt tiếng</translation>
     </message>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="693"/>
@@ -934,37 +946,43 @@ Toàn màn hình riêng biệt - Sử dụng kích thước màn hình do bạn
     <message>
         <location filename="../settingsView/configeditordialog_moc.ui" line="50"/>
         <source>Save</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Lưu</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.ui" line="73"/>
         <source>File:</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Tệp:</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.ui" line="86"/>
         <source>Close</source>
-        <translation type="unfinished">Đóng</translation>
+        <translation>Đóng</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="27"/>
         <source>Config editor</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Trình chỉnh sửa cấu hình</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="69"/>
         <source>Unsaved changes</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Thay đổi chưa lưu</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="69"/>
         <source>Do you want to discard changes?</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Bạn có muốn hủy các thay đổi không?</translation>
     </message>
     <message>
         <location filename="../settingsView/configeditordialog_moc.cpp" line="123"/>
         <source>JSON file is not valid!</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Tệp JSON không hợp lệ!</translation>
     </message>
 </context>
 <context>
@@ -1232,7 +1250,8 @@ Hãy chọn thư mục có Heroes III: Complete Edition hoặc Heroes III: Shado
     <message>
         <location filename="../firstLaunch/firstlaunch_moc.cpp" line="372"/>
         <source>Failed to open file: %1</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Không mở được tệp: %1</translation>
     </message>
     <message>
         <location filename="../firstLaunch/firstlaunch_moc.cpp" line="467"/>
@@ -1375,12 +1394,14 @@ Bin (%n bytes):
     <message>
         <location filename="../languages.cpp" line="23"/>
         <source>Belarusian</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Tiếng Belarus</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="24"/>
         <source>Bulgarian</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Tiếng Bulgaria</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="25"/>
@@ -1415,7 +1436,8 @@ Bin (%n bytes):
     <message>
         <location filename="../languages.cpp" line="31"/>
         <source>Greek</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Tiếng Hy Lạp</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="32"/>
@@ -1430,7 +1452,8 @@ Bin (%n bytes):
     <message>
         <location filename="../languages.cpp" line="34"/>
         <source>Japanese</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Tiếng Nhật</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="35"/>
@@ -1440,7 +1463,8 @@ Bin (%n bytes):
     <message>
         <location filename="../languages.cpp" line="36"/>
         <source>Norwegian</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Tiếng Na Uy</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="37"/>
@@ -1455,7 +1479,8 @@ Bin (%n bytes):
     <message>
         <location filename="../languages.cpp" line="39"/>
         <source>Romanian</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Tiếng Romania</translation>
     </message>
     <message>
         <location filename="../languages.cpp" line="40"/>
@@ -1727,7 +1752,7 @@ Bin (%n bytes):
     <message>
         <location filename="../modManager/modstateitemmodel_moc.cpp" line="54"/>
         <source>Campaigns</source>
-        <translation type="unfinished">Chiến dịch</translation>
+        <translation>Chiến dịch</translation>
     </message>
     <message>
         <location filename="../modManager/modstateitemmodel_moc.cpp" line="55"/>
@@ -1743,7 +1768,8 @@ Bin (%n bytes):
     <message>
         <location filename="../modManager/modstateitemmodel_moc.cpp" line="57"/>
         <source>Resources</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Tài nguyên</translation>
     </message>
 </context>
 <context>
@@ -2047,13 +2073,15 @@ To resolve this problem, please copy missing data files from Heroes III to VCMI
         <location filename="../startGame/StartGameTab.cpp" line="407"/>
         <location filename="../startGame/StartGameTab.cpp" line="416"/>
         <source>Preset import failed</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Nhập preset thất bại</translation>
     </message>
     <message>
         <location filename="../startGame/StartGameTab.cpp" line="407"/>
         <location filename="../startGame/StartGameTab.cpp" line="416"/>
         <source>Failed to import preset - data in clipboard does not looks like mod preset!</source>
-        <translation type="unfinished"></translation>
+        <translatorcomment>AI-generated, needs review by native speaker; delete this comment afterwards</translatorcomment>
+        <translation type="unfinished">Không thể nhập preset - dữ liệu trong bảng tạm không giống preset của mod!</translation>
     </message>
     <message>
         <location filename="../startGame/StartGameTab.cpp" line="432"/>

+ 4 - 0
lib/CMakeLists.txt

@@ -869,6 +869,10 @@ if(WIN32)
 			OUTPUT_NAME "VCMI_lib"
 			PROJECT_LABEL "VCMI_lib"
 	)
+	if (MINGW)
+		# Link Windows system libs: WinSock2 (ws2_32) + socket extensions (mswsock) + Debug Help API (dbghelp)
+		target_link_libraries(vcmi PRIVATE ws2_32 mswsock dbghelp)
+	endif()
 endif()
 
 # Use '-Wa,-mbig-obj' for files that generate very large object files

+ 9 - 0
lib/StartInfo.cpp

@@ -241,4 +241,13 @@ TeamID LobbyInfo::getPlayerTeamId(const PlayerColor & color)
 		return TeamID::NO_TEAM;
 }
 
+BattleOnlyModeStartInfo::BattleOnlyModeStartInfo()
+	: selectedTerrain(TerrainId::DIRT)
+	, selectedTown(std::nullopt)
+{
+	for(auto & element : primSkillLevel)
+		for(size_t i=0; i<GameConstants::PRIMARY_SKILLS; i++)
+			element[i] = 0;
+}
+
 VCMI_LIB_NAMESPACE_END

+ 23 - 0
lib/StartInfo.h

@@ -18,6 +18,7 @@
 #include "serializer/GameConnectionID.h"
 #include "serializer/Serializeable.h"
 #include "serializer/PlayerConnectionID.h"
+#include "mapObjects/army/CStackBasicDescriptor.h"
 #include "ResourceSet.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
@@ -239,5 +240,27 @@ struct DLL_LINKAGE LobbyInfo : public LobbyState
 	TeamID getPlayerTeamId(const PlayerColor & color);
 };
 
+class DLL_LINKAGE BattleOnlyModeStartInfo : public Serializeable
+{
+public:
+	std::optional<TerrainId> selectedTerrain;
+	std::optional<FactionID> selectedTown;
+
+	std::array<std::optional<HeroTypeID>, 2> selectedHero;
+	std::array<std::array<CStackBasicDescriptor, 7>, 2> selectedArmy;
+
+	std::array<std::array<int, GameConstants::PRIMARY_SKILLS>, 2> primSkillLevel;
+
+	BattleOnlyModeStartInfo();
+
+	template <typename Handler> void serialize(Handler &h)
+	{
+		h & selectedTerrain;
+		h & selectedTown;
+		h & selectedHero;
+		h & selectedArmy;
+		h & primSkillLevel;
+	}
+};
 
 VCMI_LIB_NAMESPACE_END

+ 8 - 6
lib/battle/CBattleInfoCallback.cpp

@@ -280,8 +280,11 @@ std::vector<PossiblePlayerBattleAction> CBattleInfoCallback::getClientActionsFor
 		if(stack->hasBonusOfType(BonusType::RETURN_AFTER_STRIKE))
 			allowedActionList.push_back(PossiblePlayerBattleAction::ATTACK_AND_RETURN);
 
-		allowedActionList.push_back(PossiblePlayerBattleAction::ATTACK); //all active stacks can attack
-		allowedActionList.push_back(PossiblePlayerBattleAction::WALK_AND_ATTACK); //not all stacks can always walk, but we will check this elsewhere
+		if (stack->isMeleeAttacker()) //not all stacks can actually attack or walk and attack, check this elsewhere
+		{
+			allowedActionList.push_back(PossiblePlayerBattleAction::ATTACK);
+			allowedActionList.push_back(PossiblePlayerBattleAction::WALK_AND_ATTACK);
+		}
 
 		if(stack->canMove() && stack->getMovementRange(0)) //probably no reason to try move war machines or bound stacks
 			allowedActionList.push_back(PossiblePlayerBattleAction::MOVE_STACK);
@@ -683,6 +686,9 @@ bool CBattleInfoCallback::battleCanAttack(const battle::Unit * stack, const batt
 	if(!battleMatchOwner(stack, target))
 		return false;
 
+	if (!stack->isMeleeAttacker())
+		return false;
+
 	if (stack->getPosition() != dest)
 	{
 		for (const auto & obstacle : battleGetAllObstacles())
@@ -695,10 +701,6 @@ bool CBattleInfoCallback::battleCanAttack(const battle::Unit * stack, const batt
 		}
 	}
 
-	auto id = stack->unitType()->getId();
-	if (id == CreatureID::FIRST_AID_TENT || id == CreatureID::CATAPULT)
-		return false;
-
 	return target->alive();
 }
 

+ 16 - 2
lib/battle/DamageCalculator.cpp

@@ -285,13 +285,26 @@ double DamageCalculator::getAttackFromBackFactor() const
 	return 0;
 }
 
-double DamageCalculator::getAttackHateFactor() const
+double DamageCalculator::getAttackHateCreatureFactor() const
 {
 	//assume that unit have only few HATE features and cache them all
 	auto allHateEffects = info.attacker->getBonusesOfType(BonusType::HATE);
 	return allHateEffects->valOfBonuses(Selector::subtype()(BonusSubtypeID(info.defender->creatureId()))) / 100.0;
 }
 
+double DamageCalculator::getAttackHateTraitFactor() const
+{
+	//assume that unit have only few HATE features and cache them all
+	auto allHateEffects = info.attacker->getBonusesOfType(BonusType::HATES_TRAIT);
+
+	auto selector = [this](const Bonus* hateBonus) -> bool
+	{
+		return info.defender->hasBonusOfType(hateBonus->subtype.as<BonusTypeID>().toEnum());
+	};
+
+	return allHateEffects->valOfBonuses(selector) / 100.0;
+}
+
 double DamageCalculator::getAttackRevengeFactor() const
 {
 	if(info.attacker->hasBonusOfType(BonusType::REVENGE)) //HotA Haspid ability
@@ -475,7 +488,8 @@ std::vector<double> DamageCalculator::getAttackFactors() const
 		getAttackFromBackFactor(),
 		getAttackDeathBlowFactor(),
 		getAttackDoubleDamageFactor(),
-		getAttackHateFactor(),
+		getAttackHateCreatureFactor(),
+		getAttackHateTraitFactor(),
 		getAttackRevengeFactor()
 	};
 }

+ 2 - 1
lib/battle/DamageCalculator.h

@@ -50,7 +50,8 @@ class DLL_LINKAGE DamageCalculator
 	double getAttackJoustingFactor() const;
 	double getAttackDeathBlowFactor() const;
 	double getAttackDoubleDamageFactor() const;
-	double getAttackHateFactor() const;
+	double getAttackHateCreatureFactor() const;
+	double getAttackHateTraitFactor() const;
 	double getAttackRevengeFactor() const;
 	double getAttackFromBackFactor() const;
 

+ 10 - 0
lib/battle/Unit.cpp

@@ -38,6 +38,16 @@ bool Unit::isTurret() const
 	return creatureIndex() == CreatureID::ARROW_TOWERS;
 }
 
+bool Unit::isMeleeAttacker() const
+{
+	//exclude war machines
+	if (hasBonusOfType(BonusType::SIEGE_WEAPON))
+		return false;
+
+	//TODO consider that a mod may introduce a melee war machine. Possibly a new bonus type NO_MELEE_ATTACK is needed.
+	return true;
+}
+
 std::string Unit::getDescription() const
 {
 	boost::format fmt("Unit %d of side %d");

+ 1 - 0
lib/battle/Unit.h

@@ -97,6 +97,7 @@ public:
 	virtual bool canShootBlocked() const = 0;
 	virtual bool canShoot() const = 0;
 	virtual bool isShooter() const = 0;
+	bool isMeleeAttacker() const;
 
 	/// returns initial size of this unit
 	virtual int32_t getCount() const = 0;

+ 17 - 0
lib/bonuses/BonusCustomTypes.cpp

@@ -10,6 +10,8 @@
 
 #include "StdInc.h"
 #include "BonusCustomTypes.h"
+#include "CBonusTypeHandler.h"
+#include "GameLibrary.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -75,4 +77,19 @@ std::string BonusCustomSource::encode(const si32 index)
 	return std::to_string(index);
 }
 
+std::string BonusTypeID::encode(int32_t index)
+{
+	if (index == static_cast<int32_t>(BonusType::NONE))
+		return "";
+	return LIBRARY->bth->bonusToString(static_cast<BonusType>(index));
+}
+
+si32 BonusTypeID::decode(const std::string & identifier)
+{
+	if (identifier.empty())
+		return RiverId::NO_RIVER.getNum();
+
+	return resolveIdentifier("bonus", identifier);
+}
+
 VCMI_LIB_NAMESPACE_END

+ 23 - 2
lib/bonuses/BonusCustomTypes.h

@@ -11,6 +11,7 @@
 
 #include "../constants/EntityIdentifiers.h"
 #include "../constants/VariantIdentifier.h"
+#include "BonusEnum.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -77,7 +78,27 @@ public:
 	static BonusCustomSubtype creatureLevel(int level);
 };
 
-using BonusSubtypeID = VariantIdentifier<BonusCustomSubtype, SpellID, CreatureID, PrimarySkill, TerrainId, GameResID, SpellSchool>;
-using BonusSourceID = VariantIdentifier<BonusCustomSource, SpellID, CreatureID, ArtifactID, ArtifactInstanceID, CampaignScenarioID, SecondarySkill, HeroTypeID, Obj, ObjectInstanceID, BuildingTypeUniqueID, BattleField>;
+class DLL_LINKAGE BonusTypeID : public EntityIdentifier<BonusTypeID>
+{
+public:
+	using EntityIdentifier<BonusTypeID>::EntityIdentifier;
+	using EnumType = BonusType;
+
+	static std::string encode(int32_t index);
+	static si32 decode(const std::string & identifier);
+
+	constexpr EnumType toEnum() const
+	{
+		return static_cast<EnumType>(EntityIdentifier::num);
+	}
+
+	constexpr BonusTypeID(const EnumType & enumValue)
+	{
+		EntityIdentifier::num = static_cast<int32_t>(enumValue);
+	}
+};
+
+using BonusSubtypeID = VariantIdentifier<BonusCustomSubtype, SpellID, CreatureID, PrimarySkill, TerrainId, GameResID, SpellSchool, BonusTypeID>;
+using BonusSourceID = VariantIdentifier<BonusCustomSource, SpellID, CreatureID, ArtifactID, CampaignScenarioID, SecondarySkill, HeroTypeID, Obj, ObjectInstanceID, BuildingTypeUniqueID, BattleField, ArtifactInstanceID>;
 
 VCMI_LIB_NAMESPACE_END

+ 1 - 0
lib/bonuses/BonusEnum.h

@@ -194,6 +194,7 @@ class JsonNode;
 	BONUS_NAME(TRANSMUTATION_IMMUNITY) /*blocks TRANSMUTATION bonus*/\
 	BONUS_NAME(COMBAT_MANA_BONUS) /* Additional mana per combat */ \
 	BONUS_NAME(SPECIFIC_SPELL_RANGE) /* value used for allowed spell range, subtype - spell id */\
+	BONUS_NAME(HATES_TRAIT) /* affected unit deals additional damage to units with specific bonus. subtype - bonus, val - damage bonus percent */ \
 	/* end of list */
 
 

+ 3 - 1
lib/constants/Enumerations.h

@@ -31,7 +31,9 @@ namespace BuildingSubID
 		PORTAL_OF_SUMMONING,
 		ESCAPE_TUNNEL,
 		TREASURY,
-		BANK
+		BANK,
+		AURORA_BOREALIS,
+		DEITY_OF_FIRE
 	};
 }
 

+ 3 - 1
lib/constants/StringConstants.h

@@ -135,7 +135,9 @@ namespace MappedKeys
 		{ "library", BuildingSubID::LIBRARY },
 		{ "escapeTunnel", BuildingSubID::ESCAPE_TUNNEL },
 		{ "treasury", BuildingSubID::TREASURY },
-		{ "bank", BuildingSubID::BANK }
+		{ "bank", BuildingSubID::BANK },
+		{ "auroraBorealis", BuildingSubID::AURORA_BOREALIS },
+		{ "deityOfFire", BuildingSubID::DEITY_OF_FIRE }
 	};
 
 	static const std::map<std::string, EMarketMode> MARKET_NAMES_TO_TYPES =

+ 16 - 12
lib/gameState/CGameState.cpp

@@ -1240,17 +1240,20 @@ bool CGameState::checkForVictory(const PlayerColor & player, const EventConditio
 		case EventCondition::HAVE_CREATURES:
 		{
 			//check if in players armies there is enough creatures
-			int total = 0; //creature counter
-			for(auto ai : map->getObjects<CArmedInstance>())
-			{
-				if(ai->getOwner() == player)
-				{
-					for(const auto & elem : ai->Slots()) //iterate through army
-						if(elem.second->getId() == condition.objectType.as<CreatureID>()) //it's searched creature
-							total += elem.second->getCount();
-				}
-			}
-			return total >= condition.value;
+			// NOTE: only heroes & towns are checked, in line with H3.
+			// Garrisons, mines, and guards of owned dwellings(!) are excluded
+			int totalCreatures = 0;
+			for (const auto & hero : p->getHeroes())
+				for(const auto & elem : hero->Slots()) //iterate through army
+					if(elem.second->getId() == condition.objectType.as<CreatureID>()) //it's searched creature
+						totalCreatures += elem.second->getCount();
+
+			for (const auto & town : p->getTowns())
+				for(const auto & elem : town->Slots()) //iterate through army
+					if(elem.second->getId() == condition.objectType.as<CreatureID>()) //it's searched creature
+						totalCreatures += elem.second->getCount();
+
+			return totalCreatures >= condition.value;
 		}
 		case EventCondition::HAVE_RESOURCES:
 		{
@@ -1624,18 +1627,19 @@ void CGameState::loadGame(CLoadFile & file)
 	logGlobal->info("Loading game state...");
 
 	CMapHeader dummyHeader;
-	StartInfo dummyStartInfo;
 	ActiveModsInSaveList dummyActiveMods;
 
 	file.load(dummyHeader);
 	if (file.hasFeature(ESerializationVersion::NO_RAW_POINTERS_IN_SERIALIZER))
 	{
+		StartInfo dummyStartInfo;
 		file.load(dummyStartInfo);
 		file.load(dummyActiveMods);
 		file.load(*this);
 	}
 	else
 	{
+		auto dummyStartInfo = std::make_shared<StartInfo>();
 		bool dummyA = false;
 		uint32_t dummyB = 0;
 		uint16_t dummyC = 0;

+ 0 - 2
lib/gameState/CGameStateCampaign.h

@@ -81,11 +81,9 @@ public:
 		{
 			bool dummyA = false;
 			uint32_t dummyB = 0;
-			uint16_t dummyC = 0;
 
 			h & dummyA;
 			h & dummyB;
-			h & dummyC;
 		}
 	}
 };

+ 8 - 0
lib/json/JsonBonus.cpp

@@ -91,6 +91,14 @@ static void loadBonusSubtype(BonusSubtypeID & subtype, BonusType type, const Jso
 			});
 			break;
 		}
+		case BonusType::HATES_TRAIT:
+		{
+			LIBRARY->identifiers()->requestIdentifier( "bonus", node, [&subtype](int32_t identifier)
+			{
+				subtype = BonusType(identifier);
+			});
+			break;
+		}
 		case BonusType::NO_TERRAIN_PENALTY:
 		{
 			LIBRARY->identifiers()->requestIdentifier( "terrain", node, [&subtype](int32_t identifier)

+ 0 - 22
lib/mapObjects/CGHeroInstance.cpp

@@ -1345,28 +1345,6 @@ void CGHeroInstance::restoreBonusSystem(CGameState & gs)
 	}
 }
 
-void CGHeroInstance::attachToBonusSystem(CGameState & gs)
-{
-	CArmedInstance::attachToBonusSystem(gs);
-	if (boardedBoat.hasValue())
-	{
-		auto boat = gs.getObjInstance(boardedBoat);
-		if (boat)
-			attachTo(dynamic_cast<CGBoat&>(*boat));
-	}
-}
-
-void CGHeroInstance::detachFromBonusSystem(CGameState & gs)
-{
-	CArmedInstance::detachFromBonusSystem(gs);
-	if (boardedBoat.hasValue())
-	{
-		auto boat = gs.getObjInstance(boardedBoat);
-		if (boat)
-			detachFrom(dynamic_cast<CGBoat&>(*boat));
-	}
-}
-
 CBonusSystemNode & CGHeroInstance::whereShouldBeAttached(CGameState & gs)
 {
 	if(visitedTown.hasValue())

+ 0 - 2
lib/mapObjects/CGHeroInstance.h

@@ -311,8 +311,6 @@ public:
 
 	void afterAddToMap(CMap * map) override;
 	void afterRemoveFromMap(CMap * map) override;
-	void attachToBonusSystem(CGameState & gs) override;
-	void detachFromBonusSystem(CGameState & gs) override;
 	void restoreBonusSystem(CGameState & gs) override;
 
 	void updateFrom(const JsonNode & data) override;

+ 0 - 7
lib/mapObjects/CGTownInstance.cpp

@@ -905,13 +905,6 @@ bool CGTownInstance::hasBuilt(const BuildingID & buildingID) const
 	return vstd::contains(builtBuildings, buildingID);
 }
 
-bool CGTownInstance::hasBuilt(const BuildingID & buildingID, FactionID townID) const
-{
-	if (townID == getTown()->faction->getId() || townID == FactionID::ANY)
-		return hasBuilt(buildingID);
-	return false;
-}
-
 void CGTownInstance::addBuilding(const BuildingID & buildingID)
 {
 	if(buildingID == BuildingID::NONE)

+ 0 - 1
lib/mapObjects/CGTownInstance.h

@@ -165,7 +165,6 @@ public:
 	bool hasBuilt(BuildingSubID::EBuildingSubID buildingID) const;
 	//checks if building is constructed and town has same subID
 	bool hasBuilt(const BuildingID & buildingID) const;
-	bool hasBuilt(const BuildingID & buildingID, FactionID townID) const;
 	void addBuilding(const BuildingID & buildingID);
 	void removeBuilding(const BuildingID & buildingID);
 	void removeAllBuildings();

+ 54 - 22
lib/mapping/CDrawRoadsOperation.cpp

@@ -20,7 +20,8 @@
 
 VCMI_LIB_NAMESPACE_BEGIN
 
-const std::vector<CDrawLinesOperation::LinePattern> CDrawLinesOperation::patterns =
+template <typename T>
+const std::vector<typename CDrawLinesOperation<T>::LinePattern> CDrawLinesOperation<T>::patterns =
 {
 	//single tile. fall-back pattern
 	{
@@ -156,34 +157,47 @@ static bool ruleIsAny(const std::string & rule)
 #endif
 
 ///CDrawLinesOperation
-CDrawLinesOperation::CDrawLinesOperation(CMap * map, CTerrainSelection terrainSel, vstd::RNG * gen):
+template <typename T>
+CDrawLinesOperation<T>::CDrawLinesOperation(CMap * map, CTerrainSelection terrainSel, T lineType, vstd::RNG * gen):
 	CMapOperation(map),
 	terrainSel(std::move(terrainSel)),
+	lineType(lineType),
 	gen(gen)
 {
 }
 
 ///CDrawRoadsOperation
 CDrawRoadsOperation::CDrawRoadsOperation(CMap * map, const CTerrainSelection & terrainSel, RoadId roadType, vstd::RNG * gen):
-	CDrawLinesOperation(map, terrainSel,gen),
-	roadType(roadType)
-{
-}
+	CDrawLinesOperation(map, terrainSel,roadType, gen)
+{}
 
 ///CDrawRiversOperation
 CDrawRiversOperation::CDrawRiversOperation(CMap * map, const CTerrainSelection & terrainSel, RiverId riverType, vstd::RNG * gen):
-	CDrawLinesOperation(map, terrainSel, gen),
-	riverType(riverType)
+	CDrawLinesOperation(map, terrainSel, riverType, gen)
+{}
+
+template <typename T>
+void CDrawLinesOperation<T>::execute()
 {
+	for(const auto & pos : terrainSel.getSelectedItems())
+	{
+		auto identifier = getIdentifier(map->getTile(pos));
+		if (formerState.find(identifier) == formerState.end())
+			formerState.insert({identifier, CTerrainSelection(terrainSel.getMap())});
+		formerState.at(identifier).select(pos);
+	}
+
+	drawLines(terrainSel, lineType);
 }
 
-void CDrawLinesOperation::execute()
+template <typename T>
+void CDrawLinesOperation<T>::drawLines(CTerrainSelection selection, T type)
 {
 	std::set<int3> invalidated;
 
-	for(const auto & pos : terrainSel.getSelectedItems())
+	for(const auto & pos : selection.getSelectedItems())
 	{
-		executeTile(map->getTile(pos));
+		executeTile(map->getTile(pos), type);
 
 		auto rect = extendTileAroundSafely(pos);
 		rect.forEach([&invalidated](const int3 & pos)
@@ -195,17 +209,23 @@ void CDrawLinesOperation::execute()
 	updateTiles(invalidated);
 }
 
-void CDrawLinesOperation::undo()
+template <typename T>
+void CDrawLinesOperation<T>::undo()
 {
-  //TODO
+	for (auto const& typeToSelection : formerState)
+	{
+		drawLines(typeToSelection.second, typeToSelection.first);
+	}
 }
 
-void CDrawLinesOperation::redo()
+template <typename T>
+void CDrawLinesOperation<T>::redo()
 {
-  //TODO
+  drawLines(terrainSel, lineType);
 }
 
-void CDrawLinesOperation::flipPattern(LinePattern& pattern, int flip) const
+template <typename T>
+void CDrawLinesOperation<T>::flipPattern(LinePattern& pattern, int flip) const
 {
 	//todo: use cashing here and also in terrain patterns
 
@@ -233,7 +253,8 @@ void CDrawLinesOperation::flipPattern(LinePattern& pattern, int flip) const
 	}
 }
 
-void CDrawLinesOperation::updateTiles(std::set<int3> & invalidated)
+template <typename T>
+void CDrawLinesOperation<T>::updateTiles(std::set<int3> & invalidated)
 {
 	for(const int3 & coord : invalidated)
 	{
@@ -264,7 +285,8 @@ void CDrawLinesOperation::updateTiles(std::set<int3> & invalidated)
 	}
 }
 
-CDrawLinesOperation::ValidationResult CDrawLinesOperation::validateTile(const LinePattern & pattern, const int3 & pos)
+template <typename T>
+typename CDrawLinesOperation<T>::ValidationResult CDrawLinesOperation<T>::validateTile(const LinePattern & pattern, const int3 & pos)
 {
 	ValidationResult result(false);
 
@@ -342,14 +364,14 @@ std::string CDrawRiversOperation::getLabel() const
 	return "Draw Rivers";
 }
 
-void CDrawRoadsOperation::executeTile(TerrainTile & tile)
+void CDrawRoadsOperation::executeTile(TerrainTile & tile, RoadId type)
 {
-	tile.roadType = roadType;
+	tile.roadType = type;
 }
 
-void CDrawRiversOperation::executeTile(TerrainTile & tile)
+void CDrawRiversOperation::executeTile(TerrainTile & tile, RiverId type)
 {
-	tile.riverType = riverType;
+	tile.riverType = type;
 }
 
 bool CDrawRoadsOperation::canApplyPattern(const LinePattern & pattern) const
@@ -398,4 +420,14 @@ void CDrawRiversOperation::updateTile(TerrainTile & tile, const LinePattern & pa
 	tile.extTileFlags = (tile.extTileFlags & 0b00111111) | (flip << 2);
 }
 
+RiverId CDrawRiversOperation::getIdentifier(TerrainTile & tile) const
+{
+	return tile.riverType;
+}
+
+RoadId CDrawRoadsOperation::getIdentifier(TerrainTile & tile) const
+{
+	return tile.roadType;
+}
+
 VCMI_LIB_NAMESPACE_END

Some files were not shown because too many files changed in this diff