Przeglądaj źródła

Merge branch 'develop' into 'lobby'

Ivan Savenko 1 rok temu
rodzic
commit
f2ecd4cf11
100 zmienionych plików z 331 dodań i 221 usunięć
  1. 7 0
      .gitignore
  2. 1 1
      AI/BattleAI/BattleExchangeVariant.cpp
  3. 2 2
      AI/EmptyAI/CEmptyAI.h
  4. 1 1
      AI/Nullkiller/Behaviors/BuildingBehavior.h
  5. 1 1
      AI/Nullkiller/Behaviors/BuyArmyBehavior.h
  6. 1 1
      AI/Nullkiller/Behaviors/CaptureObjectsBehavior.h
  7. 2 2
      AI/Nullkiller/Behaviors/ClusterBehavior.h
  8. 1 1
      AI/Nullkiller/Behaviors/DefenceBehavior.h
  9. 2 2
      AI/Nullkiller/Behaviors/GatherArmyBehavior.h
  10. 2 2
      AI/Nullkiller/Behaviors/RecruitHeroBehavior.h
  11. 2 2
      AI/Nullkiller/Behaviors/StartupBehavior.h
  12. 2 2
      AI/Nullkiller/Behaviors/StayAtTownBehavior.h
  13. 1 1
      AI/Nullkiller/Goals/AdventureSpellCast.h
  14. 1 1
      AI/Nullkiller/Goals/Build.h
  15. 1 1
      AI/Nullkiller/Goals/BuildBoat.h
  16. 1 1
      AI/Nullkiller/Goals/BuildThis.h
  17. 2 2
      AI/Nullkiller/Goals/BuyArmy.h
  18. 4 4
      AI/Nullkiller/Goals/CGoal.h
  19. 3 3
      AI/Nullkiller/Goals/CaptureObject.h
  20. 3 3
      AI/Nullkiller/Goals/CompleteQuest.h
  21. 4 4
      AI/Nullkiller/Goals/Composition.h
  22. 1 1
      AI/Nullkiller/Goals/DigAtTile.h
  23. 1 1
      AI/Nullkiller/Goals/DismissHero.h
  24. 1 1
      AI/Nullkiller/Goals/ExchangeSwapTownHeroes.h
  25. 2 2
      AI/Nullkiller/Goals/ExecuteHeroChain.h
  26. 1 1
      AI/Nullkiller/Goals/GatherArmy.h
  27. 2 2
      AI/Nullkiller/Goals/Invalid.h
  28. 1 1
      AI/Nullkiller/Goals/RecruitHero.h
  29. 1 1
      AI/Nullkiller/Goals/SaveResources.h
  30. 1 1
      AI/Nullkiller/Goals/StayAtTown.h
  31. 1 1
      AI/Nullkiller/Goals/Trade.h
  32. 1 1
      AI/Nullkiller/Markers/ArmyUpgrade.h
  33. 1 1
      AI/Nullkiller/Markers/DefendTown.h
  34. 1 1
      AI/Nullkiller/Markers/HeroExchange.h
  35. 1 1
      AI/Nullkiller/Markers/UnlockCluster.h
  36. 1 1
      AI/Nullkiller/Pathfinding/AINodeStorage.h
  37. 1 1
      AI/Nullkiller/Pathfinding/AIPathfinderConfig.h
  38. 2 2
      AI/Nullkiller/Pathfinding/Actions/AdventureSpellCastMovementActions.h
  39. 1 1
      AI/Nullkiller/Pathfinding/Actions/BattleAction.h
  40. 7 7
      AI/Nullkiller/Pathfinding/Actions/BoatActions.h
  41. 2 2
      AI/Nullkiller/Pathfinding/Actions/QuestAction.h
  42. 1 1
      AI/Nullkiller/Pathfinding/Actions/TownPortalAction.h
  43. 2 2
      AI/Nullkiller/Pathfinding/Actors.h
  44. 1 1
      AI/VCAI/Goals/AdventureSpellCast.h
  45. 1 1
      AI/VCAI/Goals/Build.h
  46. 1 1
      AI/VCAI/Goals/BuildBoat.h
  47. 1 1
      AI/VCAI/Goals/BuildThis.h
  48. 1 1
      AI/VCAI/Goals/BuyArmy.h
  49. 1 1
      AI/VCAI/Goals/CGoal.h
  50. 1 1
      AI/VCAI/Goals/ClearWayTo.h
  51. 1 1
      AI/VCAI/Goals/CollectRes.h
  52. 1 1
      AI/VCAI/Goals/CompleteQuest.h
  53. 1 1
      AI/VCAI/Goals/Conquer.h
  54. 1 1
      AI/VCAI/Goals/DigAtTile.h
  55. 1 1
      AI/VCAI/Goals/Explore.h
  56. 1 1
      AI/VCAI/Goals/FindObj.h
  57. 1 1
      AI/VCAI/Goals/GatherArmy.h
  58. 1 1
      AI/VCAI/Goals/GatherTroops.h
  59. 1 1
      AI/VCAI/Goals/GetArtOfType.h
  60. 1 1
      AI/VCAI/Goals/Invalid.h
  61. 1 1
      AI/VCAI/Goals/RecruitHero.h
  62. 1 1
      AI/VCAI/Goals/Trade.h
  63. 1 1
      AI/VCAI/Goals/VisitHero.h
  64. 1 1
      AI/VCAI/Goals/VisitObj.h
  65. 1 1
      AI/VCAI/Goals/VisitTile.h
  66. 1 1
      AI/VCAI/Goals/Win.h
  67. 1 1
      AI/VCAI/Pathfinding/AINodeStorage.h
  68. 1 1
      AI/VCAI/Pathfinding/AIPathfinderConfig.h
  69. 72 51
      Mods/vcmi/config/vcmi/chinese.json
  70. 24 3
      Mods/vcmi/config/vcmi/spanish.json
  71. 3 3
      client/CServerHandler.cpp
  72. 1 1
      client/Client.h
  73. 12 12
      client/ClientNetPackVisitors.h
  74. 10 3
      client/battle/BattleInterfaceClasses.cpp
  75. 1 1
      client/battle/BattleInterfaceClasses.h
  76. 2 2
      client/eventsSDL/InputHandler.cpp
  77. 5 2
      client/gui/CGuiHandler.cpp
  78. 2 2
      client/gui/CGuiHandler.h
  79. 16 5
      client/lobby/CBonusSelection.cpp
  80. 4 0
      client/lobby/CBonusSelection.h
  81. 1 1
      client/lobby/CSelectionBase.cpp
  82. 8 1
      client/lobby/OptionsTabBase.cpp
  83. 1 1
      client/lobby/OptionsTabBase.h
  84. 1 1
      client/lobby/RandomMapTab.cpp
  85. 1 1
      client/widgets/MiscWidgets.h
  86. 1 1
      client/windows/InfoWindows.h
  87. 3 3
      client/windows/settings/GeneralOptionsTab.cpp
  88. 2 0
      cmake_modules/VCMI_lib.cmake
  89. 3 1
      config/gameConfig.json
  90. 1 0
      config/heroes/tower.json
  91. 9 1
      config/schemas/settings.json
  92. 7 0
      config/widgets/extraOptionsTab.json
  93. 7 5
      docs/developers/Building_Linux.md
  94. 5 5
      launcher/translation/chinese.ts
  95. 1 1
      lib/CArtHandler.h
  96. 1 1
      lib/CCreatureHandler.h
  97. 2 2
      lib/CGameInfoCallback.h
  98. 14 14
      lib/CGameInterface.h
  99. 7 0
      lib/CHeroHandler.cpp
  100. 2 2
      lib/CHeroHandler.h

+ 7 - 0
.gitignore

@@ -1,12 +1,15 @@
 /client/vcmiclient
 /server/vcmiserver
+/launcher/.lupdate
 /launcher/vcmilauncher
+/mapeditor/.lupdate
 /launcher/vcmilauncher_automoc.cpp
 /conan-*
 
 build/
 .cache/*
 out/
+/.qt
 *.dll
 *.exe
 *.depend
@@ -42,6 +45,7 @@ VCMI_VS11.opensdf
 .DS_Store
 CMakeUserPresets.json
 compile_commands.json
+fuzzylite.pc
 
 # Visual Studio
 *.suo
@@ -62,5 +66,8 @@ compile_commands.json
 /deps
 .vs/
 
+# Visual Studio Code
+/.vscode/
+
 # CLion
 .idea/

+ 1 - 1
AI/BattleAI/BattleExchangeVariant.cpp

@@ -843,7 +843,7 @@ bool BattleExchangeEvaluator::checkPositionBlocksOurStacks(HypotheticBattle & hb
 					}
 				}
 
-				if(!reachable && vstd::contains(reachabilityMap[hex], unit))
+				if(!reachable && std::count(reachabilityMap[hex].begin(), reachabilityMap[hex].end(), unit) > 1)
 				{
 					blockingScore += ratio * (enemyUnit ? BLOCKING_OWN_ATTACK_PENALTY : BLOCKING_OWN_MOVE_PENALTY);
 				}

+ 2 - 2
AI/EmptyAI/CEmptyAI.h

@@ -19,8 +19,8 @@ class CEmptyAI : public CGlobalAI
 	std::shared_ptr<CCallback> cb;
 
 public:
-	virtual void saveGame(BinarySerializer & h) override;
-	virtual void loadGame(BinaryDeserializer & h) override;
+	void saveGame(BinarySerializer & h) override;
+	void loadGame(BinaryDeserializer & h) override;
 
 	void initGameInterface(std::shared_ptr<Environment> ENV, std::shared_ptr<CCallback> CB) override;
 	void yourTurn(QueryID queryID) override;

+ 1 - 1
AI/Nullkiller/Behaviors/BuildingBehavior.h

@@ -27,7 +27,7 @@ namespace Goals
 
 		virtual Goals::TGoalVec decompose() const override;
 		virtual std::string toString() const override;
-		virtual bool operator==(const BuildingBehavior & other) const override
+		bool operator==(const BuildingBehavior & other) const override
 		{
 			return true;
 		}

+ 1 - 1
AI/Nullkiller/Behaviors/BuyArmyBehavior.h

@@ -26,7 +26,7 @@ namespace Goals
 
 		virtual Goals::TGoalVec decompose() const override;
 		virtual std::string toString() const override;
-		virtual bool operator==(const BuyArmyBehavior & other) const override
+		bool operator==(const BuyArmyBehavior & other) const override
 		{
 			return true;
 		}

+ 1 - 1
AI/Nullkiller/Behaviors/CaptureObjectsBehavior.h

@@ -65,7 +65,7 @@ namespace Goals
 			return *this;
 		}
 
-		virtual bool operator==(const CaptureObjectsBehavior & other) const override;
+		bool operator==(const CaptureObjectsBehavior & other) const override;
 
 		static Goals::TGoalVec getVisitGoals(const std::vector<AIPath> & paths, const CGObjectInstance * objToVisit = nullptr);
 

+ 2 - 2
AI/Nullkiller/Behaviors/ClusterBehavior.h

@@ -28,10 +28,10 @@ namespace Goals
 		{
 		}
 
-		virtual TGoalVec decompose() const override;
+		TGoalVec decompose() const override;
 		virtual std::string toString() const override;
 
-		virtual bool operator==(const ClusterBehavior & other) const override
+		bool operator==(const ClusterBehavior & other) const override
 		{
 			return true;
 		}

+ 1 - 1
AI/Nullkiller/Behaviors/DefenceBehavior.h

@@ -32,7 +32,7 @@ namespace Goals
 		virtual Goals::TGoalVec decompose() const override;
 		virtual std::string toString() const override;
 
-		virtual bool operator==(const DefenceBehavior & other) const override
+		bool operator==(const DefenceBehavior & other) const override
 		{
 			return true;
 		}

+ 2 - 2
AI/Nullkiller/Behaviors/GatherArmyBehavior.h

@@ -25,10 +25,10 @@ namespace Goals
 		{
 		}
 
-		virtual TGoalVec decompose() const override;
+		TGoalVec decompose() const override;
 		virtual std::string toString() const override;
 
-		virtual bool operator==(const GatherArmyBehavior & other) const override
+		bool operator==(const GatherArmyBehavior & other) const override
 		{
 			return true;
 		}

+ 2 - 2
AI/Nullkiller/Behaviors/RecruitHeroBehavior.h

@@ -25,10 +25,10 @@ namespace Goals
 		{
 		}
 
-		virtual TGoalVec decompose() const override;
+		TGoalVec decompose() const override;
 		virtual std::string toString() const override;
 
-		virtual bool operator==(const RecruitHeroBehavior & other) const override
+		bool operator==(const RecruitHeroBehavior & other) const override
 		{
 			return true;
 		}

+ 2 - 2
AI/Nullkiller/Behaviors/StartupBehavior.h

@@ -25,10 +25,10 @@ namespace Goals
 		{
 		}
 
-		virtual TGoalVec decompose() const override;
+		TGoalVec decompose() const override;
 		virtual std::string toString() const override;
 
-		virtual bool operator==(const StartupBehavior & other) const override
+		bool operator==(const StartupBehavior & other) const override
 		{
 			return true;
 		}

+ 2 - 2
AI/Nullkiller/Behaviors/StayAtTownBehavior.h

@@ -25,10 +25,10 @@ namespace Goals
 		{
 		}
 
-		virtual TGoalVec decompose() const override;
+		TGoalVec decompose() const override;
 		virtual std::string toString() const override;
 
-		virtual bool operator==(const StayAtTownBehavior & other) const override
+		bool operator==(const StayAtTownBehavior & other) const override
 		{
 			return true;
 		}

+ 1 - 1
AI/Nullkiller/Goals/AdventureSpellCast.h

@@ -35,7 +35,7 @@ namespace Goals
 
 		void accept(AIGateway * ai) override;
 		std::string toString() const override;
-		virtual bool operator==(const AdventureSpellCast & other) const override;
+		bool operator==(const AdventureSpellCast & other) const override;
 	};
 }
 

+ 1 - 1
AI/Nullkiller/Goals/Build.h

@@ -32,7 +32,7 @@ namespace Goals
 		TSubgoal whatToDoToAchieve() override;
 		bool fulfillsMe(TSubgoal goal) override;
 
-		virtual bool operator==(const Build & other) const override
+		bool operator==(const Build & other) const override
 		{
 			return true;
 		}

+ 1 - 1
AI/Nullkiller/Goals/BuildBoat.h

@@ -29,7 +29,7 @@ namespace Goals
 
 		void accept(AIGateway * ai) override;
 		std::string toString() const override;
-		virtual bool operator==(const BuildBoat & other) const override;
+		bool operator==(const BuildBoat & other) const override;
 	};
 }
 

+ 1 - 1
AI/Nullkiller/Goals/BuildThis.h

@@ -39,7 +39,7 @@ namespace Goals
 		}
 		BuildThis(BuildingID Bid, const CGTownInstance * tid);
 
-		virtual bool operator==(const BuildThis & other) const override;
+		bool operator==(const BuildThis & other) const override;
 		virtual std::string toString() const override;
 		void accept(AIGateway * ai) override;
 	};

+ 2 - 2
AI/Nullkiller/Goals/BuyArmy.h

@@ -36,11 +36,11 @@ namespace Goals
 			priority = 3;//TODO: evaluate?
 		}
 
-		virtual bool operator==(const BuyArmy & other) const override;
+		bool operator==(const BuyArmy & other) const override;
 
 		virtual std::string toString() const override;
 
-		virtual void accept(AIGateway * ai) override;
+		void accept(AIGateway * ai) override;
 	};
 }
 

+ 4 - 4
AI/Nullkiller/Goals/CGoal.h

@@ -44,7 +44,7 @@ namespace Goals
 			//h & value & resID & objid & aid & tile & hero & town & bid;
 		}
 
-		virtual bool operator==(const AbstractGoal & g) const override
+		bool operator==(const AbstractGoal & g) const override
 		{
 			if(goalType != g.goalType)
 				return false;
@@ -54,7 +54,7 @@ namespace Goals
 
 		virtual bool operator==(const T & other) const = 0;
 
-		virtual TGoalVec decompose() const override
+		TGoalVec decompose() const override
 		{
 			TSubgoal single = decomposeSingle();
 
@@ -90,11 +90,11 @@ namespace Goals
 			return *((T *)this);
 		}
 
-		virtual bool isElementar() const override { return true; }
+		bool isElementar() const override { return true; }
 
 		virtual HeroPtr getHero() const override { return AbstractGoal::hero; }
 
-		virtual int getHeroExchangeCount() const override { return 0; }
+		int getHeroExchangeCount() const override { return 0; }
 	};
 }
 

+ 3 - 3
AI/Nullkiller/Goals/CaptureObject.h

@@ -34,11 +34,11 @@ namespace Goals
 			name = obj->getObjectName();
 		}
 
-		virtual bool operator==(const CaptureObject & other) const override;
+		bool operator==(const CaptureObject & other) const override;
 		virtual Goals::TGoalVec decompose() const override;
 		virtual std::string toString() const override;
-		virtual bool hasHash() const override { return true; }
-		virtual uint64_t getHash() const override;
+		bool hasHash() const override { return true; }
+		uint64_t getHash() const override;
 	};
 }
 

+ 3 - 3
AI/Nullkiller/Goals/CompleteQuest.h

@@ -31,10 +31,10 @@ namespace Goals
 
 		virtual Goals::TGoalVec decompose() const override;
 		virtual std::string toString() const override;
-		virtual bool hasHash() const override { return true; }
-		virtual uint64_t getHash() const override;
+		bool hasHash() const override { return true; }
+		uint64_t getHash() const override;
 
-		virtual bool operator==(const CompleteQuest & other) const override;
+		bool operator==(const CompleteQuest & other) const override;
 
 	private:
 		TGoalVec tryCompleteQuest() const;

+ 4 - 4
AI/Nullkiller/Goals/Composition.h

@@ -26,15 +26,15 @@ namespace Goals
 		{
 		}
 
-		virtual bool operator==(const Composition & other) const override;
+		bool operator==(const Composition & other) const override;
 		virtual std::string toString() const override;
 		void accept(AIGateway * ai) override;
 		Composition & addNext(const AbstractGoal & goal);
 		Composition & addNext(TSubgoal goal);
 		Composition & addNextSequence(const TGoalVec & taskSequence);
-		virtual TGoalVec decompose() const override;
-		virtual bool isElementar() const override;
-		virtual int getHeroExchangeCount() const override;
+		TGoalVec decompose() const override;
+		bool isElementar() const override;
+		int getHeroExchangeCount() const override;
 	};
 }
 

+ 1 - 1
AI/Nullkiller/Goals/DigAtTile.h

@@ -33,7 +33,7 @@ namespace Goals
 		{
 			tile = Tile;
 		}
-		virtual bool operator==(const DigAtTile & other) const override;
+		bool operator==(const DigAtTile & other) const override;
 
 	private:
 		//TSubgoal decomposeSingle() const override;

+ 1 - 1
AI/Nullkiller/Goals/DismissHero.h

@@ -26,7 +26,7 @@ namespace Goals
 
 		void accept(AIGateway * ai) override;
 		std::string toString() const override;
-		virtual bool operator==(const DismissHero & other) const override;
+		bool operator==(const DismissHero & other) const override;
 	};
 }
 

+ 1 - 1
AI/Nullkiller/Goals/ExchangeSwapTownHeroes.h

@@ -31,7 +31,7 @@ namespace Goals
 
 		void accept(AIGateway * ai) override;
 		std::string toString() const override;
-		virtual bool operator==(const ExchangeSwapTownHeroes & other) const override;
+		bool operator==(const ExchangeSwapTownHeroes & other) const override;
 
 		const CGHeroInstance * getGarrisonHero() const { return garrisonHero; }
 		HeroLockedReason getLockingReason() const { return lockingReason; }

+ 2 - 2
AI/Nullkiller/Goals/ExecuteHeroChain.h

@@ -30,10 +30,10 @@ namespace Goals
 		
 		void accept(AIGateway * ai) override;
 		std::string toString() const override;
-		virtual bool operator==(const ExecuteHeroChain & other) const override;
+		bool operator==(const ExecuteHeroChain & other) const override;
 		const AIPath & getPath() const { return chainPath; }
 
-		virtual int getHeroExchangeCount() const override { return chainPath.exchangeCount; }
+		int getHeroExchangeCount() const override { return chainPath.exchangeCount; }
 
 	private:
 		bool moveHeroToTile(const CGHeroInstance * hero, const int3 & tile);

+ 1 - 1
AI/Nullkiller/Goals/GatherArmy.h

@@ -36,7 +36,7 @@ namespace Goals
 		TGoalVec getAllPossibleSubgoals() override;
 		TSubgoal whatToDoToAchieve() override;
 		std::string completeMessage() const override;
-		virtual bool operator==(const GatherArmy & other) const override;
+		bool operator==(const GatherArmy & other) const override;
 	};
 }
 

+ 2 - 2
AI/Nullkiller/Goals/Invalid.h

@@ -32,7 +32,7 @@ namespace Goals
 			return TGoalVec();
 		}
 
-		virtual bool operator==(const Invalid & other) const override
+		bool operator==(const Invalid & other) const override
 		{
 			return true;
 		}
@@ -42,7 +42,7 @@ namespace Goals
 			return "Invalid";
 		}
 
-		virtual void accept(AIGateway * ai) override
+		void accept(AIGateway * ai) override
 		{
 			throw cannotFulfillGoalException("Can not fulfill Invalid goal!");
 		}

+ 1 - 1
AI/Nullkiller/Goals/RecruitHero.h

@@ -38,7 +38,7 @@ namespace Goals
 		{
 		}
 
-		virtual bool operator==(const RecruitHero & other) const override
+		bool operator==(const RecruitHero & other) const override
 		{
 			return true;
 		}

+ 1 - 1
AI/Nullkiller/Goals/SaveResources.h

@@ -28,7 +28,7 @@ namespace Goals
 
 		void accept(AIGateway * ai) override;
 		std::string toString() const override;
-		virtual bool operator==(const SaveResources & other) const override;
+		bool operator==(const SaveResources & other) const override;
 	};
 }
 

+ 1 - 1
AI/Nullkiller/Goals/StayAtTown.h

@@ -26,7 +26,7 @@ namespace Goals
 	public:
 		StayAtTown(const CGTownInstance * town, AIPath & path);
 
-		virtual bool operator==(const StayAtTown & other) const override;
+		bool operator==(const StayAtTown & other) const override;
 		virtual std::string toString() const override;
 		void accept(AIGateway * ai) override;
 		float getMovementWasted() const { return movementWasted; }

+ 1 - 1
AI/Nullkiller/Goals/Trade.h

@@ -34,7 +34,7 @@ namespace Goals
 			value = val;
 			objid = Objid;
 		}
-		virtual bool operator==(const Trade & other) const override;
+		bool operator==(const Trade & other) const override;
 	};
 }
 

+ 1 - 1
AI/Nullkiller/Markers/ArmyUpgrade.h

@@ -29,7 +29,7 @@ namespace Goals
 		ArmyUpgrade(const AIPath & upgradePath, const CGObjectInstance * upgrader, const ArmyUpgradeInfo & upgrade);
 		ArmyUpgrade(const CGHeroInstance * targetMain, const CGObjectInstance * upgrader, const ArmyUpgradeInfo & upgrade);
 
-		virtual bool operator==(const ArmyUpgrade & other) const override;
+		bool operator==(const ArmyUpgrade & other) const override;
 		virtual std::string toString() const override;
 
 		uint64_t getUpgradeValue() const { return upgradeValue; }

+ 1 - 1
AI/Nullkiller/Markers/DefendTown.h

@@ -30,7 +30,7 @@ namespace Goals
 		DefendTown(const CGTownInstance * town, const HitMapInfo & treat, const AIPath & defencePath, bool isCounterAttack = false);
 		DefendTown(const CGTownInstance * town, const HitMapInfo & treat, const CGHeroInstance * defender);
 
-		virtual bool operator==(const DefendTown & other) const override;
+		bool operator==(const DefendTown & other) const override;
 		virtual std::string toString() const override;
 
 		const HitMapInfo & getTreat() const { return treat; }

+ 1 - 1
AI/Nullkiller/Markers/HeroExchange.h

@@ -28,7 +28,7 @@ namespace Goals
 			sethero(targetHero);
 		}
 
-		virtual bool operator==(const HeroExchange & other) const override;
+		bool operator==(const HeroExchange & other) const override;
 		virtual std::string toString() const override;
 
 		uint64_t getReinforcementArmyStrength() const;

+ 1 - 1
AI/Nullkiller/Markers/UnlockCluster.h

@@ -36,7 +36,7 @@ namespace Goals
 			sethero(pathToCenter.targetHero);
 		}
 
-		virtual bool operator==(const UnlockCluster & other) const override;
+		bool operator==(const UnlockCluster & other) const override;
 		virtual std::string toString() const override;
 		std::shared_ptr<ObjectCluster> getCluster() const { return cluster; }
 		const AIPath & getPathToCenter() { return pathToCenter; }

+ 1 - 1
AI/Nullkiller/Pathfinding/AINodeStorage.h

@@ -200,7 +200,7 @@ public:
 		const PathfinderConfig * pathfinderConfig,
 		const CPathfinderHelper * pathfinderHelper) override;
 
-	virtual void commit(CDestinationNodeInfo & destination, const PathNodeInfo & source) override;
+	void commit(CDestinationNodeInfo & destination, const PathNodeInfo & source) override;
 
 	void commit(
 		AIPathNode * destination,

+ 1 - 1
AI/Nullkiller/Pathfinding/AIPathfinderConfig.h

@@ -34,7 +34,7 @@ namespace AIPathfinding
 
 		~AIPathfinderConfig();
 
-		virtual CPathfinderHelper * getOrCreatePathfinderHelper(const PathNodeInfo & source, CGameState * gs) override;
+		CPathfinderHelper * getOrCreatePathfinderHelper(const PathNodeInfo & source, CGameState * gs) override;
 	};
 }
 

+ 2 - 2
AI/Nullkiller/Pathfinding/Actions/AdventureSpellCastMovementActions.h

@@ -29,7 +29,7 @@ namespace AIPathfinding
 	public:
 		AdventureCastAction(SpellID spellToCast, const CGHeroInstance * hero, DayFlags flagsToAdd = DayFlags::NONE);
 
-		virtual void execute(const CGHeroInstance * hero) const override;
+		void execute(const CGHeroInstance * hero) const override;
 
 		virtual void applyOnDestination(
 			const CGHeroInstance * hero,
@@ -38,7 +38,7 @@ namespace AIPathfinding
 			AIPathNode * dstMode,
 			const AIPathNode * srcNode) const override;
 
-		virtual bool canAct(const AIPathNode * source) const override;
+		bool canAct(const AIPathNode * source) const override;
 
 		virtual std::string toString() const override;
 	};

+ 1 - 1
AI/Nullkiller/Pathfinding/Actions/BattleAction.h

@@ -28,7 +28,7 @@ namespace AIPathfinding
 		{
 		}
 
-		virtual void execute(const CGHeroInstance * hero) const override;
+		void execute(const CGHeroInstance * hero) const override;
 
 		virtual std::string toString() const override;
 	};

+ 7 - 7
AI/Nullkiller/Pathfinding/Actions/BoatActions.h

@@ -25,7 +25,7 @@ namespace AIPathfinding
 	class SummonBoatAction : public VirtualBoatAction
 	{
 	public:
-		virtual void execute(const CGHeroInstance * hero) const override;
+		void execute(const CGHeroInstance * hero) const override;
 
 		virtual void applyOnDestination(
 			const CGHeroInstance * hero,
@@ -34,9 +34,9 @@ namespace AIPathfinding
 			AIPathNode * dstMode,
 			const AIPathNode * srcNode) const override;
 
-		virtual bool canAct(const AIPathNode * source) const override;
+		bool canAct(const AIPathNode * source) const override;
 
-		virtual const ChainActor * getActor(const ChainActor * sourceActor) const override;
+		const ChainActor * getActor(const ChainActor * sourceActor) const override;
 
 		virtual std::string toString() const override;
 
@@ -56,17 +56,17 @@ namespace AIPathfinding
 		{
 		}
 
-		virtual bool canAct(const AIPathNode * source) const override;
+		bool canAct(const AIPathNode * source) const override;
 
-		virtual void execute(const CGHeroInstance * hero) const override;
+		void execute(const CGHeroInstance * hero) const override;
 
 		virtual Goals::TSubgoal decompose(const CGHeroInstance * hero) const override;
 
-		virtual const ChainActor * getActor(const ChainActor * sourceActor) const override;
+		const ChainActor * getActor(const ChainActor * sourceActor) const override;
 
 		virtual std::string toString() const override;
 
-		virtual const CGObjectInstance * targetObject() const override;
+		const CGObjectInstance * targetObject() const override;
 	};
 }
 

+ 2 - 2
AI/Nullkiller/Pathfinding/Actions/QuestAction.h

@@ -28,11 +28,11 @@ namespace AIPathfinding
 		{
 		}
 
-		virtual bool canAct(const AIPathNode * node) const override;
+		bool canAct(const AIPathNode * node) const override;
 
 		virtual Goals::TSubgoal decompose(const CGHeroInstance * hero) const override;
 
-		virtual void execute(const CGHeroInstance * hero) const override;
+		void execute(const CGHeroInstance * hero) const override;
 
 		virtual std::string toString() const override;
 	};

+ 1 - 1
AI/Nullkiller/Pathfinding/Actions/TownPortalAction.h

@@ -29,7 +29,7 @@ namespace AIPathfinding
 		{
 		}
 
-		virtual void execute(const CGHeroInstance * hero) const override;
+		void execute(const CGHeroInstance * hero) const override;
 
 		virtual std::string toString() const override;
 	};

+ 2 - 2
AI/Nullkiller/Pathfinding/Actors.h

@@ -28,7 +28,7 @@ class HeroExchangeArmy : public CArmedInstance
 public:
 	TResources armyCost;
 	bool requireBuyArmy;
-	virtual bool needsLastStack() const override;
+	bool needsLastStack() const override;
 	std::shared_ptr<SpecialAction> getActorAction() const;
 
 	HeroExchangeArmy(): CArmedInstance(nullptr, true), requireBuyArmy(false) {}
@@ -126,7 +126,7 @@ public:
 	HeroActor(const ChainActor * carrier, const ChainActor * other, const HeroExchangeArmy * army, const Nullkiller * ai);
 
 protected:
-	virtual ExchangeResult tryExchangeNoLock(const ChainActor * specialActor, const ChainActor * other) const override;
+	ExchangeResult tryExchangeNoLock(const ChainActor * specialActor, const ChainActor * other) const override;
 };
 
 class ObjectActor : public ChainActor

+ 1 - 1
AI/VCAI/Goals/AdventureSpellCast.h

@@ -39,6 +39,6 @@ namespace Goals
 		void accept(VCAI * ai) override;
 		std::string name() const override;
 		std::string completeMessage() const override;
-		virtual bool operator==(const AdventureSpellCast & other) const override;
+		bool operator==(const AdventureSpellCast & other) const override;
 	};
 }

+ 1 - 1
AI/VCAI/Goals/Build.h

@@ -29,7 +29,7 @@ namespace Goals
 		TSubgoal whatToDoToAchieve() override;
 		bool fulfillsMe(TSubgoal goal) override;
 
-		virtual bool operator==(const Build & other) const override
+		bool operator==(const Build & other) const override
 		{
 			return true;
 		}

+ 1 - 1
AI/VCAI/Goals/BuildBoat.h

@@ -32,6 +32,6 @@ namespace Goals
 		void accept(VCAI * ai) override;
 		std::string name() const override;
 		std::string completeMessage() const override;
-		virtual bool operator==(const BuildBoat & other) const override;
+		bool operator==(const BuildBoat & other) const override;
 	};
 }

+ 1 - 1
AI/VCAI/Goals/BuildThis.h

@@ -43,6 +43,6 @@ namespace Goals
 		}
 		TSubgoal whatToDoToAchieve() override;
 		//bool fulfillsMe(TSubgoal goal) override;
-		virtual bool operator==(const BuildThis & other) const override;
+		bool operator==(const BuildThis & other) const override;
 	};
 }

+ 1 - 1
AI/VCAI/Goals/BuyArmy.h

@@ -36,6 +36,6 @@ namespace Goals
 
 		TSubgoal whatToDoToAchieve() override;
 		std::string completeMessage() const override;
-		virtual bool operator==(const BuyArmy & other) const override;
+		bool operator==(const BuyArmy & other) const override;
 	};
 }

+ 1 - 1
AI/VCAI/Goals/CGoal.h

@@ -76,7 +76,7 @@ namespace Goals
 			//h & value & resID & objid & aid & tile & hero & town & bid;
 		}
 
-		virtual bool operator==(const AbstractGoal & g) const override
+		bool operator==(const AbstractGoal & g) const override
 		{
 			if(goalType != g.goalType)
 				return false;

+ 1 - 1
AI/VCAI/Goals/ClearWayTo.h

@@ -40,6 +40,6 @@ namespace Goals
 		TGoalVec getAllPossibleSubgoals() override;
 		TSubgoal whatToDoToAchieve() override;
 		bool fulfillsMe(TSubgoal goal) override;
-		virtual bool operator==(const ClearWayTo & other) const override;
+		bool operator==(const ClearWayTo & other) const override;
 	};
 }

+ 1 - 1
AI/VCAI/Goals/CollectRes.h

@@ -35,6 +35,6 @@ namespace Goals
 		TSubgoal whatToDoToAchieve() override;
 		TSubgoal whatToDoToTrade();
 		bool fulfillsMe(TSubgoal goal) override; //TODO: Trade
-		virtual bool operator==(const CollectRes & other) const override;
+		bool operator==(const CollectRes & other) const override;
 	};
 }

+ 1 - 1
AI/VCAI/Goals/CompleteQuest.h

@@ -30,7 +30,7 @@ namespace Goals
 		TSubgoal whatToDoToAchieve() override;
 		std::string name() const override;
 		std::string completeMessage() const override;
-		virtual bool operator==(const CompleteQuest & other) const override;
+		bool operator==(const CompleteQuest & other) const override;
 
 	private:
 		TGoalVec tryCompleteQuest() const;

+ 1 - 1
AI/VCAI/Goals/Conquer.h

@@ -27,6 +27,6 @@ namespace Goals
 		}
 		TGoalVec getAllPossibleSubgoals() override;
 		TSubgoal whatToDoToAchieve() override;
-		virtual bool operator==(const Conquer & other) const override;
+		bool operator==(const Conquer & other) const override;
 	};
 }

+ 1 - 1
AI/VCAI/Goals/DigAtTile.h

@@ -36,6 +36,6 @@ namespace Goals
 			return TGoalVec();
 		}
 		TSubgoal whatToDoToAchieve() override;
-		virtual bool operator==(const DigAtTile & other) const override;
+		bool operator==(const DigAtTile & other) const override;
 	};
 }

+ 1 - 1
AI/VCAI/Goals/Explore.h

@@ -46,7 +46,7 @@ namespace Goals
 		TSubgoal whatToDoToAchieve() override;
 		std::string completeMessage() const override;
 		bool fulfillsMe(TSubgoal goal) override;
-		virtual bool operator==(const Explore & other) const override;
+		bool operator==(const Explore & other) const override;
 
 	private:
 		TSubgoal exploreNearestNeighbour(HeroPtr h) const;

+ 1 - 1
AI/VCAI/Goals/FindObj.h

@@ -42,6 +42,6 @@ namespace Goals
 		}
 		TSubgoal whatToDoToAchieve() override;
 		bool fulfillsMe(TSubgoal goal) override;
-		virtual bool operator==(const FindObj & other) const override;
+		bool operator==(const FindObj & other) const override;
 	};
 }

+ 1 - 1
AI/VCAI/Goals/GatherArmy.h

@@ -33,6 +33,6 @@ namespace Goals
 		TGoalVec getAllPossibleSubgoals() override;
 		TSubgoal whatToDoToAchieve() override;
 		std::string completeMessage() const override;
-		virtual bool operator==(const GatherArmy & other) const override;
+		bool operator==(const GatherArmy & other) const override;
 	};
 }

+ 1 - 1
AI/VCAI/Goals/GatherTroops.h

@@ -35,7 +35,7 @@ namespace Goals
 		TGoalVec getAllPossibleSubgoals() override;
 		TSubgoal whatToDoToAchieve() override;
 		bool fulfillsMe(TSubgoal goal) override;
-		virtual bool operator==(const GatherTroops & other) const override;
+		bool operator==(const GatherTroops & other) const override;
 
 	private:
 		int getCreaturesCount(const CArmedInstance * army);

+ 1 - 1
AI/VCAI/Goals/GetArtOfType.h

@@ -35,6 +35,6 @@ namespace Goals
 			return TGoalVec();
 		}
 		TSubgoal whatToDoToAchieve() override;
-		virtual bool operator==(const GetArtOfType & other) const override;
+		bool operator==(const GetArtOfType & other) const override;
 	};
 }

+ 1 - 1
AI/VCAI/Goals/Invalid.h

@@ -33,7 +33,7 @@ namespace Goals
 			return iAmElementar();
 		}
 
-		virtual bool operator==(const Invalid & other) const override
+		bool operator==(const Invalid & other) const override
 		{
 			return true;
 		}

+ 1 - 1
AI/VCAI/Goals/RecruitHero.h

@@ -33,7 +33,7 @@ namespace Goals
 
 		TSubgoal whatToDoToAchieve() override;
 
-		virtual bool operator==(const RecruitHero & other) const override
+		bool operator==(const RecruitHero & other) const override
 		{
 			return true;
 		}

+ 1 - 1
AI/VCAI/Goals/Trade.h

@@ -33,6 +33,6 @@ namespace Goals
 			priority = 3; //trading is instant, but picking resources is free
 		}
 		TSubgoal whatToDoToAchieve() override;
-		virtual bool operator==(const Trade & other) const override;
+		bool operator==(const Trade & other) const override;
 	};
 }

+ 1 - 1
AI/VCAI/Goals/VisitHero.h

@@ -37,6 +37,6 @@ namespace Goals
 		TSubgoal whatToDoToAchieve() override;
 		bool fulfillsMe(TSubgoal goal) override;
 		std::string completeMessage() const override;
-		virtual bool operator==(const VisitHero & other) const override;
+		bool operator==(const VisitHero & other) const override;
 	};
 }

+ 1 - 1
AI/VCAI/Goals/VisitObj.h

@@ -27,6 +27,6 @@ namespace Goals
 		TSubgoal whatToDoToAchieve() override;
 		bool fulfillsMe(TSubgoal goal) override;
 		std::string completeMessage() const override;
-		virtual bool operator==(const VisitObj & other) const override;
+		bool operator==(const VisitObj & other) const override;
 	};
 }

+ 1 - 1
AI/VCAI/Goals/VisitTile.h

@@ -32,6 +32,6 @@ namespace Goals
 		TGoalVec getAllPossibleSubgoals() override;
 		TSubgoal whatToDoToAchieve() override;
 		std::string completeMessage() const override;
-		virtual bool operator==(const VisitTile & other) const override;
+		bool operator==(const VisitTile & other) const override;
 	};
 }

+ 1 - 1
AI/VCAI/Goals/Win.h

@@ -31,7 +31,7 @@ namespace Goals
 		}
 		TSubgoal whatToDoToAchieve() override;
 
-		virtual bool operator==(const Win & other) const override
+		bool operator==(const Win & other) const override
 		{
 			return true;
 		}

+ 1 - 1
AI/VCAI/Pathfinding/AINodeStorage.h

@@ -99,7 +99,7 @@ public:
 		const PathfinderConfig * pathfinderConfig,
 		const CPathfinderHelper * pathfinderHelper) override;
 
-	virtual void commit(CDestinationNodeInfo & destination, const PathNodeInfo & source) override;
+	void commit(CDestinationNodeInfo & destination, const PathNodeInfo & source) override;
 
 	const AIPathNode * getAINode(const CGPathNode * node) const;
 	void updateAINode(CGPathNode * node, std::function<void (AIPathNode *)> updater);

+ 1 - 1
AI/VCAI/Pathfinding/AIPathfinderConfig.h

@@ -30,6 +30,6 @@ namespace AIPathfinding
 
 		~AIPathfinderConfig();
 
-		virtual CPathfinderHelper * getOrCreatePathfinderHelper(const PathNodeInfo & source, CGameState * gs) override;
+		CPathfinderHelper * getOrCreatePathfinderHelper(const PathNodeInfo & source, CGameState * gs) override;
 	};
 }

+ 72 - 51
Mods/vcmi/config/vcmi/chinese.json

@@ -20,6 +20,7 @@
 	"vcmi.adventureMap.playerAttacked"         : "玩家遭受攻击: %s",
 	"vcmi.adventureMap.moveCostDetails"        : "移动点数 - 花费: %TURNS 轮 + %POINTS 点移动力, 剩余移动力: %REMAINING",
 	"vcmi.adventureMap.moveCostDetailsNoTurns" : "移动点数 - 花费: %POINTS 点移动力, 剩余移动力: %REMAINING",
+	"vcmi.adventureMap.replayOpponentTurnNotImplemented" : "抱歉,重放对手行动功能目前暂未实现!",
 
 	"vcmi.capitalColors.0" : "红色",
 	"vcmi.capitalColors.1" : "蓝色",
@@ -70,7 +71,9 @@
 	"vcmi.lobby.mapPreview" : "地图预览",
 	"vcmi.lobby.noPreview" : "无地上部分",
 	"vcmi.lobby.noUnderground" : "无地下部分",
+	"vcmi.lobby.sortDate" : "以修改时间排序地图",
 
+	"vcmi.client.errors.invalidMap" : "{非法地图或战役}\n\n启动游戏失败,选择的地图或者战役,无效或被污染。原因:\n%s",
 	"vcmi.client.errors.missingCampaigns" : "{找不到数据文件}\n\n没有找到战役数据文件!你可能使用了不完整或损坏的英雄无敌3数据文件,请重新安装数据文件。",
 	"vcmi.server.errors.existingProcess"     : "一个VCMI进程已经在运行,启动新进程前请结束它。",
 	"vcmi.server.errors.modsToEnable"    : "{需要启用的mod列表}",
@@ -81,9 +84,9 @@
 	"vcmi.server.errors.unknownEntity" : "加载保存失败! 在保存的游戏中发现未知实体'%s'! 保存可能与当前安装的mod版本不兼容!",
 
 	"vcmi.settingsMainWindow.generalTab.hover"   : "常规",
-	"vcmi.settingsMainWindow.generalTab.help"    : "切换到“常规”选项卡 - 设置游戏客户端呈现",
+	"vcmi.settingsMainWindow.generalTab.help"    : "切换到“常规”选项卡 - 配置客户端常规内容",
 	"vcmi.settingsMainWindow.battleTab.hover"    : "战斗",
-	"vcmi.settingsMainWindow.battleTab.help"     : "切换到“战斗”选项卡 - 这些设置允许配置战斗界面和相关内容",
+	"vcmi.settingsMainWindow.battleTab.help"     : "切换到“战斗”选项卡 - 配置游戏战斗界面内容",
 	"vcmi.settingsMainWindow.adventureTab.hover" : "冒险地图",
 	"vcmi.settingsMainWindow.adventureTab.help"  : "切换到“冒险地图”选项卡 - 冒险地图即玩家能操作英雄移动的界面",
 
@@ -93,43 +96,43 @@
 	"vcmi.systemOptions.townsGroup" : "城镇画面",
 
 	"vcmi.systemOptions.fullscreenBorderless.hover" : "全屏 (无边框)",
-	"vcmi.systemOptions.fullscreenBorderless.help"  : "{全屏}\n\n选中时,VCMI将以无边框全屏模式运行。在这种模式下,游戏会使用和桌面一致的分辨率而非设置的分辨率。 ",
+	"vcmi.systemOptions.fullscreenBorderless.help"  : "{全屏}\n\n选中时,VCMI将以无边框全屏模式运行。该模式下,游戏会始终和桌面分辨率保持一致,无视设置的分辨率。 ",
 	"vcmi.systemOptions.fullscreenExclusive.hover"  : "全屏 (独占)",
-	"vcmi.systemOptions.fullscreenExclusive.help"   : "{全屏}\n\n选中时,VCMI将以独占全屏模式运行。在这种模式下,游戏会将显示器分辨率改变为设置值。",
-	"vcmi.systemOptions.resolutionButton.hover" : "分辨率",
-	"vcmi.systemOptions.resolutionButton.help"  : "{分辨率选择}\n\n改变游戏内的分辨率,更改后需要重启游戏使其生效。",
-	"vcmi.systemOptions.resolutionMenu.hover"   : "分辨率选择",
+	"vcmi.systemOptions.fullscreenExclusive.help"   : "{全屏}\n\n选中时,VCMI将以独占全屏模式运行。模式下,游戏会将显示器分辨率改变为设置值。",
+	"vcmi.systemOptions.resolutionButton.hover" : "分辨率: %wx%h",
+	"vcmi.systemOptions.resolutionButton.help"  : "{分辨率选择}\n\n改变游戏内的分辨率。",
+	"vcmi.systemOptions.resolutionMenu.hover"   : "选择分辨率",
 	"vcmi.systemOptions.resolutionMenu.help"    : "修改游戏运行时的分辨率。",
-	"vcmi.systemOptions.scalingButton.hover"   : "界面大小: %p%",
-	"vcmi.systemOptions.scalingButton.help"    : "{界面大小}\n\n改变界面的大小",
-	"vcmi.systemOptions.scalingMenu.hover"     : "选择界面大小",
-	"vcmi.systemOptions.scalingMenu.help"      : "改变游戏界面大小。",
-	"vcmi.systemOptions.longTouchButton.hover"   : "触控间距: %d 毫秒", // Translation note: "ms" = "milliseconds"
-	"vcmi.systemOptions.longTouchButton.help"    : "{触控间距}\n\n使用触摸屏时,触摸屏幕指定持续时间(以毫秒为单位)后将出现弹出窗口。",
-	"vcmi.systemOptions.longTouchMenu.hover"     : "选择触控间距",
-	"vcmi.systemOptions.longTouchMenu.help"      : "改变触控间距。",
+	"vcmi.systemOptions.scalingButton.hover"   : "界面缩放: %p%",
+	"vcmi.systemOptions.scalingButton.help"    : "{界面缩放}\n\n改变用户界面的缩放比例。",
+	"vcmi.systemOptions.scalingMenu.hover"     : "选择界面缩放",
+	"vcmi.systemOptions.scalingMenu.help"      : "改变游戏内界面缩放。",
+	"vcmi.systemOptions.longTouchButton.hover"   : "长触延迟: %d 毫秒", // Translation note: "ms" = "milliseconds"
+	"vcmi.systemOptions.longTouchButton.help"    : "{长触延迟}\n\n使用触摸屏时,长触屏幕一定时间后出现弹出窗口(单位:毫秒)。",
+	"vcmi.systemOptions.longTouchMenu.hover"     : "选择长触延迟",
+	"vcmi.systemOptions.longTouchMenu.help"      : "改变长触延迟。",
 	"vcmi.systemOptions.longTouchMenu.entry"     : "%d 毫秒",
 	"vcmi.systemOptions.framerateButton.hover"  : "显示FPS",
-	"vcmi.systemOptions.framerateButton.help"   : "{显示FPS}\n\n打开/关闭在游戏窗口角落的FPS指示器。",
+	"vcmi.systemOptions.framerateButton.help"   : "{显示FPS}\n\n切换在游戏窗口角落显FPS指示器。",
 	"vcmi.systemOptions.hapticFeedbackButton.hover"  : "触觉反馈",
 	"vcmi.systemOptions.hapticFeedbackButton.help"   : "{触觉反馈}\n\n切换触摸输入的触觉反馈。",
 	"vcmi.systemOptions.enableUiEnhancementsButton.hover"  : "界面增强",
-	"vcmi.systemOptions.enableUiEnhancementsButton.help"   : "{界面增强}\n\n显示所有界面增强内容,如大背包和魔法书等。",
-	"vcmi.systemOptions.enableLargeSpellbookButton.hover"  : "增大魔法书界面",
-	"vcmi.systemOptions.enableLargeSpellbookButton.help"   : "{增大魔法书界面}\n\n可以在魔法书单页中显示更多的魔法,从而获得更好的视觉效果。",
-	"vcmi.systemOptions.audioMuteFocus.hover"  : "切换窗口时静音",
-	"vcmi.systemOptions.audioMuteFocus.help"   : "{切换窗口时静音}\n\n快速切换窗口时将静音,在工作时,切换游戏窗口不会有声音。",
+	"vcmi.systemOptions.enableUiEnhancementsButton.help"   : "{界面增强}\n\n显示所有界面优化增强,如背包按钮等。关闭该项以贴近经典模式。",
+	"vcmi.systemOptions.enableLargeSpellbookButton.hover"  : "扩展魔法书",
+	"vcmi.systemOptions.enableLargeSpellbookButton.help"   : "{扩展魔法书}\n\n启用更大的魔法书界面,每页展示更多魔法,但魔法书翻页特效在该模式下无法呈现。",
+	"vcmi.systemOptions.audioMuteFocus.hover"  : "失去焦点时静音",
+	"vcmi.systemOptions.audioMuteFocus.help"   : "{失去焦点时静音}\n\n当窗口失去焦点时静音,游戏内消息提示和新回合提示除外。",
 
 	"vcmi.adventureOptions.infoBarPick.hover" : "在信息面板显示消息",
-	"vcmi.adventureOptions.infoBarPick.help" : "{在信息面板显示消息}\n\n来自访问地图物件的信息将显示在信息面板,而不是弹出窗口。",
+	"vcmi.adventureOptions.infoBarPick.help" : "{在信息面板显示消息}\n\n尽可能将来自访问地图物件的信息将显示在信息面板,而不是弹出窗口。",
 	"vcmi.adventureOptions.numericQuantities.hover" : "生物数量显示",
 	"vcmi.adventureOptions.numericQuantities.help" : "{生物数量显示}\n\n以数字 A-B 格式显示不准确的敌方生物数量。",
-	"vcmi.adventureOptions.forceMovementInfo.hover" : "在状态栏中显示移动力",
-	"vcmi.adventureOptions.forceMovementInfo.help" : "{在状态栏中显示移动力}\n\n不需要按ALT就可以显示移动力。",
+	"vcmi.adventureOptions.forceMovementInfo.hover" : "总是显示移动花费",
+	"vcmi.adventureOptions.forceMovementInfo.help" : "{总是显示移动花费}\n\n总是在状态栏中显示行动力花费(否则仅在按下ALT时显示)。",
 	"vcmi.adventureOptions.showGrid.hover" : "显示网格",
 	"vcmi.adventureOptions.showGrid.help" : "{显示网格}\n\n显示网格覆盖层,高亮冒险地图物件的边沿。",
-	"vcmi.adventureOptions.borderScroll.hover" : "滚动边界",
-	"vcmi.adventureOptions.borderScroll.help" : "{滚动边界}\n\n当光标靠近窗口边缘时滚动冒险地图。 可以通过按住 CTRL 键来禁用。",
+	"vcmi.adventureOptions.borderScroll.hover" : "边缘滚动",
+	"vcmi.adventureOptions.borderScroll.help" : "{边缘滚动}\n\n当光标靠近窗口边缘时滚动冒险地图。 可以通过按住 CTRL 键来禁用。",
 	"vcmi.adventureOptions.infoBarCreatureManagement.hover" : "信息面板生物管理",
 	"vcmi.adventureOptions.infoBarCreatureManagement.help" : "{信息面板生物管理}\n\n允许在信息面板中重新排列生物,而不是在默认组件之间循环。",
 	"vcmi.adventureOptions.leftButtonDrag.hover" : "左键拖动地图",
@@ -137,13 +140,15 @@
 	"vcmi.adventureOptions.smoothDragging.hover" : "平滑地图拖动",
 	"vcmi.adventureOptions.smoothDragging.help" : "{平滑地图拖动}\n\n启用后,地图拖动会产生柔和的羽化效果。",
 	"vcmi.adventureOptions.skipAdventureMapAnimations.hover" : "关闭淡入淡出特效",
-	"vcmi.adventureOptions.skipAdventureMapAnimations.help" : "{关闭淡入淡出特效}\n\n启用后,跳过物体淡出或类似特效(资源收集,登船等)。设置此项能在渲染开销重时能够加快UI的响应,尤其是在PvP对战中。当移动速度被设置为最大时忽略此项设置。",
+	"vcmi.adventureOptions.skipAdventureMapAnimations.help" : "{关闭淡入淡出特效}\n\n启用后,跳过物体淡出或类似特效(资源收集,登船等)。设置此项能在渲染开销重时能够加快UI的响应,尤其是在PvP对战中。当移动速度被设置为最大时忽略此项设置。",
 	"vcmi.adventureOptions.mapScrollSpeed1.hover": "",
 	"vcmi.adventureOptions.mapScrollSpeed5.hover": "",
 	"vcmi.adventureOptions.mapScrollSpeed6.hover": "",
 	"vcmi.adventureOptions.mapScrollSpeed1.help": "将地图卷动速度设置为非常慢",
 	"vcmi.adventureOptions.mapScrollSpeed5.help": "将地图卷动速度设置为非常快",
 	"vcmi.adventureOptions.mapScrollSpeed6.help": "将地图卷动速度设置为即刻。",
+	"vcmi.adventureOptions.hideBackground.hover" : "隐藏背景",
+	"vcmi.adventureOptions.hideBackground.help" : "{隐藏背景}\n\n隐藏冒险地图背景,以显示贴图代替。",
 
 	"vcmi.battleOptions.queueSizeLabel.hover": "回合顺序指示器",
 	"vcmi.battleOptions.queueSizeNoneButton.hover": "关闭",
@@ -168,6 +173,8 @@
 	"vcmi.battleOptions.showStickyHeroInfoWindows.help": "{显示英雄统计数据窗口}\n\n永久切换并显示主要统计数据和法术点的英雄统计数据窗口。",
 	"vcmi.battleOptions.skipBattleIntroMusic.hover": "跳过战斗开始音乐",
 	"vcmi.battleOptions.skipBattleIntroMusic.help": "{跳过战斗开始音乐}\n\n战斗开始音乐播放期间,你也能够进行操作。",
+	"vcmi.battleOptions.endWithAutocombat.hover": "结束战斗",
+	"vcmi.battleOptions.endWithAutocombat.help": "{结束战斗}\n\n以自动战斗立即结束剩余战斗过程",
 	
 	"vcmi.adventureMap.revisitObject.hover" : "重新访问",
 	"vcmi.adventureMap.revisitObject.help" : "{重新访问}\n\n让当前英雄重新访问地图建筑或城镇。",
@@ -183,17 +190,22 @@
 	"vcmi.battleWindow.damageEstimation.damage.1" : "%d 伤害",
 	"vcmi.battleWindow.damageEstimation.kills" : "%d 将被消灭",
 	"vcmi.battleWindow.damageEstimation.kills.1" : "%d 将被消灭",
+	"vcmi.battleWindow.killed" : "已消灭",
+	"vcmi.battleWindow.accurateShot.resultDescription.0" : "%d %s 死于精准射击",
+	"vcmi.battleWindow.accurateShot.resultDescription.1" : "%d %s 死于精准射击",
+	"vcmi.battleWindow.accurateShot.resultDescription.2" : "%d %s 死于精准射击",
+	"vcmi.battleWindow.endWithAutocombat" : "您确定想以自动战斗立即结束吗?",
 
 	"vcmi.battleResultsWindow.applyResultsLabel" : "接受战斗结果",
 	
 	"vcmi.tutorialWindow.title" : "触摸屏介绍",
-	"vcmi.tutorialWindow.decription.RightClick" : "触摸并按住要右键单击的元素。 触摸可用区域以关闭。",
-	"vcmi.tutorialWindow.decription.MapPanning" : "用一根手指触摸并拖动来移动地图。",
-	"vcmi.tutorialWindow.decription.MapZooming" : "用两根手指捏合可更改地图缩放比例。",
+	"vcmi.tutorialWindow.decription.RightClick" : "长按要右键单击的元素。 触摸其他区域以关闭。",
+	"vcmi.tutorialWindow.decription.MapPanning" : "单指拖拽以移动地图。",
+	"vcmi.tutorialWindow.decription.MapZooming" : "两指开合更改地图缩放比例。",
 	"vcmi.tutorialWindow.decription.RadialWheel" : "滑动可打开径向轮以执行各种操作,例如生物/英雄管理和城镇排序。",
 	"vcmi.tutorialWindow.decription.BattleDirection" : "要从特定方向攻击,请向要进行攻击的方向滑动。",
-	"vcmi.tutorialWindow.decription.BattleDirectionAbort" : "如果手指距离足够远,可以取消攻击方向手势。",
-	"vcmi.tutorialWindow.decription.AbortSpell" : "触摸并按住可取消魔法。",
+	"vcmi.tutorialWindow.decription.BattleDirectionAbort" : "将长触状态的手指拉远足够距离,可以取消攻击方向手势。",
+	"vcmi.tutorialWindow.decription.AbortSpell" : "长触以取消魔法。",
 
 	"vcmi.otherOptions.availableCreaturesAsDwellingLabel.hover" : "显示可招募生物",
 	"vcmi.otherOptions.availableCreaturesAsDwellingLabel.help" : "{显示可招募生物}\n\n在城镇摘要(城镇屏幕的左下角)中显示可招募的生物数量,而不是增长。",
@@ -212,7 +224,7 @@
 	"vcmi.townHall.greetingDefence"         : "在%s中稍待片刻,富有战斗经验的战士会教你防御技巧(防御力+1)。",
 	"vcmi.townHall.hasNotProduced"          : "本周%s并没有产生什么资源。",
 	"vcmi.townHall.hasProduced"             : "本周%s产生了%d个%s。",
-	"vcmi.townHall.greetingCustomBonus"     : "当你的英雄访问%s 时,这个神奇的建筑使你的英雄 +%d %s%s。",
+	"vcmi.townHall.greetingCustomBonus"     : "%s 给予英雄 +%d %s%s。",
 	"vcmi.townHall.greetingCustomUntil"     : "直到下一场战斗。",
 	"vcmi.townHall.greetingInTownMagicWell" : "%s使你的魔法值恢复到最大值。",
 
@@ -225,13 +237,15 @@
 	"vcmi.heroWindow.openBackpack.hover" : "开启宝物背包界面",
 	"vcmi.heroWindow.openBackpack.help"  : "用更大的界面显示所有获得的宝物",
 
+	"vcmi.tavernWindow.inviteHero"  : "邀请英雄",
+
 	"vcmi.commanderWindow.artifactMessage" : "你要把这个宝物还给英雄吗?",
 
 	"vcmi.creatureWindow.showBonuses.hover"    : "属性视图",
 	"vcmi.creatureWindow.showBonuses.help"     : "显示指挥官的所有属性增益",
 	"vcmi.creatureWindow.showSkills.hover"     : "技能视图",
 	"vcmi.creatureWindow.showSkills.help"      : "显示指挥官的所有学习的技能",
-	"vcmi.creatureWindow.returnArtifact.hover" : "交换宝物",
+	"vcmi.creatureWindow.returnArtifact.hover" : "返还宝物",
 	"vcmi.creatureWindow.returnArtifact.help"  : "点击这个按钮将宝物反还到英雄的背包里",
 
 	"vcmi.questLog.hideComplete.hover" : "隐藏完成任务",
@@ -321,6 +335,7 @@
 	"vcmi.map.victoryCondition.collectArtifacts.message" : "获得所有三件宝物",
 	"vcmi.map.victoryCondition.angelicAlliance.toSelf" : "祝贺你!你取得了天使联盟且消灭了所有敌人,取得了胜利!",
 	"vcmi.map.victoryCondition.angelicAlliance.message" : "击败所有敌人并取得天使联盟",
+	"vcmi.map.victoryCondition.angelicAlliancePartLost.toSelf" : "功亏一篑,你已失去了天使联盟的一个组件。彻底的失败。",
 
 	// few strings from WoG used by vcmi
 	"vcmi.stackExperience.description" : "» 经 验 获 得 明 细 «\n\n生物类型 ................... : %s\n经验等级 ................. : %s (%i)\n经验点数 ............... : %i\n下一个等级所需经验 .. : %i\n每次战斗最大获得经验 ... : %i%% (%i)\n获得经验的生物数量 .... : %i\n最大招募数量\n不会丢失经验升级 .... : %i\n经验倍数 ........... : %.2f\n升级倍数 .............. : %.2f\n10级后经验值 ........ : %i\n最大招募数量下\n 升级到10级所需经验数量: %i",
@@ -374,8 +389,10 @@
 	"core.bonus.ENCHANTER.description": "每回合群体施放${subtype.spell}",
 	"core.bonus.ENCHANTED.name": "法术加持",
 	"core.bonus.ENCHANTED.description": "永久处于${subtype.spell}影响",
+	"core.bonus.ENEMY_ATTACK_REDUCTION.name": "忽略攻击 (${val}%)",
+	"core.bonus.ENEMY_ATTACK_REDUCTION.description": "被攻击时,进攻方${val}%的攻击力将被无视。",
 	"core.bonus.ENEMY_DEFENCE_REDUCTION.name": "忽略防御 (${val}%)",
-	"core.bonus.ENEMY_DEFENCE_REDUCTION.description": "当攻击时,目标生物${val}%的防御力将被无视。",
+	"core.bonus.ENEMY_DEFENCE_REDUCTION.description": "发动攻击时,防御方${val}%的防御力将被无视。",
 	"core.bonus.FIRE_IMMUNITY.name": "火系免疫",
 	"core.bonus.FIRE_IMMUNITY.description": "免疫所有火系魔法。",
 	"core.bonus.FIRE_SHIELD.name": "烈火神盾 (${val}%)",
@@ -386,7 +403,9 @@
 	"core.bonus.FEAR.description": "使得敌方一只部队恐惧",
 	"core.bonus.FEARLESS.name": "无惧",
 	"core.bonus.FEARLESS.description": "免疫恐惧特质",
-	"core.bonus.FLYING.name": "飞行兵种",
+	"core.bonus.FEROCITY.name": "凶猛追击",
+	"core.bonus.FEROCITY.description": "杀死任意生物后额外攻击${val}次",
+	"core.bonus.FLYING.name": "飞行能力",
 	"core.bonus.FLYING.description": "以飞行的方式移动(无视障碍)",
 	"core.bonus.FREE_SHOOTING.name": "近身射击",
 	"core.bonus.FREE_SHOOTING.description": "能在近战范围内进行射击",
@@ -396,50 +415,52 @@
 	"core.bonus.GENERAL_DAMAGE_REDUCTION.description": "减少从远程和近战中遭受的物理伤害",
 	"core.bonus.HATE.name": "${subtype.creature}的死敌",
 	"core.bonus.HATE.description": "对${subtype.creature}造成额外${val}%伤害",
-	"core.bonus.HEALER.name": "治疗",
+	"core.bonus.HEALER.name": "治疗",
 	"core.bonus.HEALER.description": "可以治疗友军单位",
 	"core.bonus.HP_REGENERATION.name": "再生",
 	"core.bonus.HP_REGENERATION.description": "每回合恢复${val}点生命值",
-	"core.bonus.JOUSTING.name": "冲锋",
+	"core.bonus.JOUSTING.name": "勇士冲锋",
 	"core.bonus.JOUSTING.description": "每移动一格 +${val}%伤害",
-	"core.bonus.KING.name": "顶级怪物",
+	"core.bonus.KING.name": "王牌",
 	"core.bonus.KING.description": "受${val}级或更高级屠戮成性影响",
 	"core.bonus.LEVEL_SPELL_IMMUNITY.name": "免疫1-${val}级魔法",
 	"core.bonus.LEVEL_SPELL_IMMUNITY.description": "免疫1-${val}级的魔法",
-	"core.bonus.LIMITED_SHOOTING_RANGE.name" : "受限射击距离",
-	"core.bonus.LIMITED_SHOOTING_RANGE.description" : "无法以${val}格外的单位为射击目标",
+	"core.bonus.LIMITED_SHOOTING_RANGE.name": "射程限制",
+	"core.bonus.LIMITED_SHOOTING_RANGE.description": "无法瞄准${val}格以外的单位",
 	"core.bonus.LIFE_DRAIN.name": "吸取生命 (${val}%)",
 	"core.bonus.LIFE_DRAIN.description": "吸取${val}%伤害回复自身",
-	"core.bonus.MANA_CHANNELING.name": "法虹吸${val}%",
+	"core.bonus.MANA_CHANNELING.name": "法虹吸${val}%",
 	"core.bonus.MANA_CHANNELING.description": "使你的英雄有${val}%几率获得敌人施法的魔法值",
-	"core.bonus.MANA_DRAIN.name": "吸取力",
+	"core.bonus.MANA_DRAIN.name": "吸取力",
 	"core.bonus.MANA_DRAIN.description": "每回合吸取${val}魔法值",
 	"core.bonus.MAGIC_MIRROR.name": "魔法神镜 (${val}%)",
 	"core.bonus.MAGIC_MIRROR.description": "${val}%几率将进攻性魔法导向一个敌人单位",
 	"core.bonus.MAGIC_RESISTANCE.name": "魔法抵抗 (${val}%)",
 	"core.bonus.MAGIC_RESISTANCE.description": "${val}%几率抵抗敌人的魔法",
-	"core.bonus.MIND_IMMUNITY.name": "免疫心智",
-	"core.bonus.MIND_IMMUNITY.description": "不受心智魔法影响",
-	"core.bonus.NO_DISTANCE_PENALTY.name": "无视距离惩罚",
-	"core.bonus.NO_DISTANCE_PENALTY.description": "任意距离均造成全额伤害",
+	"core.bonus.MIND_IMMUNITY.name": "免疫心智魔法",
+	"core.bonus.MIND_IMMUNITY.description": "不受心智相关的魔法影响",
+	"core.bonus.NO_DISTANCE_PENALTY.name": "无视射程惩罚",
+	"core.bonus.NO_DISTANCE_PENALTY.description": "任意射程造成全额伤害",
 	"core.bonus.NO_MELEE_PENALTY.name": "无近战惩罚",
 	"core.bonus.NO_MELEE_PENALTY.description": "该生物没有近战伤害惩罚",
 	"core.bonus.NO_MORALE.name": "无士气",
 	"core.bonus.NO_MORALE.description": "生物不受士气影响",
-	"core.bonus.NO_WALL_PENALTY.name": "无城墙影响",
-	"core.bonus.NO_WALL_PENALTY.description": "攻城战中不被城墙阻挡造成全额伤害",
+	"core.bonus.NO_WALL_PENALTY.name": "无城墙惩罚",
+	"core.bonus.NO_WALL_PENALTY.description": "攻城战中无视城墙阻挡,造成全额伤害",
 	"core.bonus.NON_LIVING.name": "无生命",
 	"core.bonus.NON_LIVING.description": "免疫大多数的效果",
 	"core.bonus.RANDOM_SPELLCASTER.name": "随机施法",
 	"core.bonus.RANDOM_SPELLCASTER.description": "可以施放随机魔法",
 	"core.bonus.RANGED_RETALIATION.name": "远程反击",
 	"core.bonus.RANGED_RETALIATION.description": "可以对远程攻击进行反击",
-	"core.bonus.RECEPTIVE.name": "接",
+	"core.bonus.RECEPTIVE.name": "接",
 	"core.bonus.RECEPTIVE.description": "不会免疫有益魔法",
 	"core.bonus.REBIRTH.name": "复生 (${val}%)",
 	"core.bonus.REBIRTH.description": "当整支部队死亡后${val}%会复活",
 	"core.bonus.RETURN_AFTER_STRIKE.name": "攻击后返回",
 	"core.bonus.RETURN_AFTER_STRIKE.description": "近战攻击后回到初始位置",
+	"core.bonus.REVENGE.name": "复仇",
+	"core.bonus.REVENGE.description": "根据攻击者在战斗中失去的生命值造成额外伤害",
 	"core.bonus.SHOOTER.name": "远程攻击",
 	"core.bonus.SHOOTER.description": "生物可以射击",
 	"core.bonus.SHOOTS_ALL_ADJACENT.name": "范围远程攻击",
@@ -471,7 +492,7 @@
 	"core.bonus.TRANSMUTATION.name": "变形术",
 	"core.bonus.TRANSMUTATION.description": "${val}%机会将被攻击单位变成其他生物",
 	"core.bonus.UNDEAD.name": "不死生物",
-	"core.bonus.UNDEAD.description": "该生物属于丧尸",
+	"core.bonus.UNDEAD.description": "该生物属于不死生物",
 	"core.bonus.UNLIMITED_RETALIATIONS.name": "无限反击",
 	"core.bonus.UNLIMITED_RETALIATIONS.description": "每回合可以无限反击敌人",
 	"core.bonus.WATER_IMMUNITY.name": "水系免疫",

+ 24 - 3
Mods/vcmi/config/vcmi/spanish.json

@@ -20,6 +20,7 @@
 	"vcmi.adventureMap.playerAttacked"         : "El jugador ha sido atacado: %s",
 	"vcmi.adventureMap.moveCostDetails"        : "Puntos de movimiento - Coste: %TURNS turnos + %POINTS puntos, Puntos restantes: %REMAINING",
 	"vcmi.adventureMap.moveCostDetailsNoTurns" : "Puntos de movimiento - Coste: %POINTS puntos, Puntos restantes: %REMAINING",
+	"vcmi.adventureMap.replayOpponentTurnNotImplemented" : "Disculpe, la repetición del turno del oponente aún no está implementada.",
 
 	"vcmi.capitalColors.0" : "Rojo",
 	"vcmi.capitalColors.1" : "Azul",
@@ -70,7 +71,9 @@
 	"vcmi.lobby.mapPreview" : "Vista previa del mapa",
 	"vcmi.lobby.noPreview" : "sin vista previa",
 	"vcmi.lobby.noUnderground" : "sin subterráneo",
+	"vcmi.lobby.sortDate" : "Ordena los mapas por la fecha de modificación",
 
+	"vcmi.client.errors.invalidMap" : "{Mapa o Campaña invalido}\n\n¡No se pudo iniciar el juego! El mapa o la campaña seleccionados pueden no ser válidos o estar dañados. Motivo:\n%s",
 	"vcmi.client.errors.missingCampaigns" : "{Archivos de datos faltantes}\n\n¡No se encontraron los archivos de datos de las campañas! Quizás estés utilizando archivos de datos incompletos o dañados de Heroes 3. Por favor, reinstala los datos del juego.",
 	"vcmi.server.errors.existingProcess" : "Otro servidor VCMI está en ejecución. Por favor, termínalo antes de comenzar un nuevo juego.",
 	"vcmi.server.errors.modsToEnable"    : "{Se requieren los siguientes mods}",
@@ -144,6 +147,8 @@
 	"vcmi.adventureOptions.mapScrollSpeed1.help": "Establece la velocidad de desplazamiento del mapa como muy lenta",
 	"vcmi.adventureOptions.mapScrollSpeed5.help": "Establece la velocidad de desplazamiento del mapa como muy rápida",
 	"vcmi.adventureOptions.mapScrollSpeed6.help": "Establece la velocidad de desplazamiento del mapa como instantánea.",
+	"vcmi.adventureOptions.hideBackground.hover" : "Ocultar fondo",
+	"vcmi.adventureOptions.hideBackground.help" : "{Ocultar fondo}\n\nOculta el mapa de aventuras en el fondo y muestra una textura en su lugar..",
 
 	"vcmi.battleOptions.queueSizeLabel.hover": "Mostrar orden de turno de criaturas",
 	"vcmi.battleOptions.queueSizeNoneButton.hover": "APAGADO",
@@ -168,6 +173,8 @@
 	"vcmi.battleOptions.showStickyHeroInfoWindows.help": "{Mostrar ventanas de estadísticas de héroes}\n\nAlternar permanentemente las ventanas de estadísticas de héroes que muestran estadísticas primarias y puntos de hechizo.",
 	"vcmi.battleOptions.skipBattleIntroMusic.hover": "Omitir música de introducción",
 	"vcmi.battleOptions.skipBattleIntroMusic.help": "{Omitir música de introducción}\n\nPermitir acciones durante la música de introducción que se reproduce al comienzo de cada batalla.",
+	"vcmi.battleOptions.endWithAutocombat.hover": "Finaliza la batalla",
+	"vcmi.battleOptions.endWithAutocombat.help": "{Finaliza la batalla}\n\nAutomatiza la batalla y la finaliza al instante",
 
 	"vcmi.adventureMap.revisitObject.hover" : "Revisitar objeto",
 	"vcmi.adventureMap.revisitObject.help" : "{Revisitar objeto}\n\nSi un héroe se encuentra actualmente en un objeto del mapa, puede volver a visitar la ubicación.",
@@ -183,6 +190,11 @@
 	"vcmi.battleWindow.damageEstimation.damage.1" : "%d daño",
 	"vcmi.battleWindow.damageEstimation.kills" : "%d perecerán",
 	"vcmi.battleWindow.damageEstimation.kills.1" : "%d perecerá",
+	"vcmi.battleWindow.killed" : "Eliminados",
+	"vcmi.battleWindow.accurateShot.resultDescription.0" : "%d %s han sido eliminados por disparos certeros",
+	"vcmi.battleWindow.accurateShot.resultDescription.1" : "%d %s ha sido eliminado por un disparo certero",
+	"vcmi.battleWindow.accurateShot.resultDescription.2" : "%d %s han sido eliminados por disparos certeros",
+	"vcmi.battleWindow.endWithAutocombat" : "¿Quieres finalizar la batalla con combate automatizado?",
 
 	"vcmi.battleResultsWindow.applyResultsLabel" : "Aplicar resultado de la batalla",
 
@@ -225,6 +237,8 @@
 	"vcmi.heroWindow.openBackpack.hover" : "Abrir ventana de mochila de artefactos",
 	"vcmi.heroWindow.openBackpack.help"  : "Abre la ventana que facilita la gestión de la mochila de artefactos.",
 
+	"vcmi.tavernWindow.inviteHero"  : "Invitar heroe",
+
 	"vcmi.commanderWindow.artifactMessage" : "¿Quieres devolver este artefacto al héroe?",
 
 	"vcmi.creatureWindow.showBonuses.hover"    : "Cambiar a vista de bonificaciones",
@@ -321,6 +335,7 @@
 	"vcmi.map.victoryCondition.collectArtifacts.message" : "Adquirir tres artefactos",
 	"vcmi.map.victoryCondition.angelicAlliance.toSelf" : "¡Felicidades! Todos tus enemigos han sido derrotados y tienes la Alianza Angelical. ¡La victoria es tuya!",
 	"vcmi.map.victoryCondition.angelicAlliance.message" : "Derrota a todos los enemigos y crea la Alianza Angelical",
+	"vcmi.map.victoryCondition.angelicAlliancePartLost.toSelf" : "Por desgracia, has perdido parte de la Alianza Angélica. Todo se ha perdido.",
 
 	// few strings from WoG used by vcmi
 	"vcmi.stackExperience.description" : "» D e t a l l e s  d e  E x p e r i e n c i a  d e l  G r u p o «\n\nTipo de Criatura ................ : %s\nRango de Experiencia ............ : %s (%i)\nPuntos de Experiencia ............ : %i\nPuntos de Experiencia para el\nSiguiente Rango ............... : %i\nExperiencia Máxima por Batalla .. : %i%% (%i)\nNúmero de Criaturas en el grupo .. : %i\nMáximo de Nuevos Reclutas sin\nPerder el Rango Actual ......... : %i\nMultiplicador de Experiencia .... : %.2f\nMultiplicador de Actualización .. : %.2f\nExperiencia después del Rango 10 : %i\nMáximo de Nuevos Reclutas para\nMantener el Rango 10 si\nEstá en la Experiencia Máxima : %i",
@@ -374,6 +389,8 @@
 	"core.bonus.ENCHANTER.description": "Puede lanzar ${subtype.spell} masivo cada turno",
 	"core.bonus.ENCHANTED.name": "Encantado",
 	"core.bonus.ENCHANTED.description": "Afectado por el hechizo permanente ${subtype.spell}",
+	"core.bonus.ENEMY_ATTACK_REDUCTION.name": "Ignorar ataque (${val}%)",
+	"core.bonus.ENEMY_ATTACK_REDUCTION.description": "Al ser atacado, ${val}% del daño del atacante es ignorado",
 	"core.bonus.ENEMY_DEFENCE_REDUCTION.name": "Ignorar Defensa (${val}%)",
 	"core.bonus.ENEMY_DEFENCE_REDUCTION.description": "Ignora una parte de la defensa al atacar",
 	"core.bonus.FIRE_IMMUNITY.name": "Inmunidad al Fuego",
@@ -386,6 +403,8 @@
 	"core.bonus.FEAR.description": "Causa miedo a un grupo enemigo",
 	"core.bonus.FEARLESS.name": "Inmune al miedo",
 	"core.bonus.FEARLESS.description": "Inmune a la habilidad de miedo",
+	"core.bonus.FEROCITY.name": "Ferocidad",
+	"core.bonus.FEROCITY.description": "Ataca ${val} veces adicionales en caso de eliminar a alguien",
 	"core.bonus.FLYING.name": "Volar",
 	"core.bonus.FLYING.description": "Puede volar (ignora obstáculos)",
 	"core.bonus.FREE_SHOOTING.name": "Disparo cercano",
@@ -416,8 +435,8 @@
 	"core.bonus.MANA_DRAIN.description": "Drena ${val} de maná cada turno",
 	"core.bonus.MAGIC_MIRROR.name": "Espejo mágico (${val}%)",
 	"core.bonus.MAGIC_MIRROR.description": "Tiene una probabilidad del ${val}% de redirigir un hechizo ofensivo al enemigo",
-	"core.bonus.MAGIC_RESISTANCE.name": "Resistencia mágica (${MR}%)",
-	"core.bonus.MAGIC_RESISTANCE.description": "Tiene una probabilidad del ${MR}% de resistir el hechizo del enemigo",
+	"core.bonus.MAGIC_RESISTANCE.name": "Resistencia mágica (${val}%)",
+	"core.bonus.MAGIC_RESISTANCE.description": "Tiene una probabilidad del ${val}% de resistir el hechizo del enemigo",
 	"core.bonus.MIND_IMMUNITY.name": "Inmunidad a hechizos mentales",
 	"core.bonus.MIND_IMMUNITY.description": "Inmune a hechizos de tipo mental",
 	"core.bonus.NO_DISTANCE_PENALTY.name": "Sin penalización por distancia",
@@ -440,10 +459,12 @@
 	"core.bonus.REBIRTH.description": "El ${val}% del grupo resucitará después de la muerte",
 	"core.bonus.RETURN_AFTER_STRIKE.name": "Atacar y volver",
 	"core.bonus.RETURN_AFTER_STRIKE.description": "Regresa después de un ataque cuerpo a cuerpo",
+	"core.bonus.REVENGE.name": "Venganza",
+	"core.bonus.REVENGE.description": "Inflige daño adicional según la salud perdida del atacante en la batalla.",
 	"core.bonus.SHOOTER.name": "A distancia",
 	"core.bonus.SHOOTER.description": "La criatura puede disparar",
 	"core.bonus.SHOOTS_ALL_ADJACENT.name": "Dispara en todas direcciones",
-	"core.bonus.SHOOTS_ALL_ADJACENT.description": "Los ataques a distancia de esta criatura impactan a todos los objetivos en un área pequeña",
+	"core.bonus.SHOOTS_ALL_ADJACENT.description": "Los ataques a distancia de esta criatura impactan a todos los objetivos en un área reducida",
 	"core.bonus.SOUL_STEAL.name": "Roba almas",
 	"core.bonus.SOUL_STEAL.description": "Gana ${val} nuevas criaturas por cada enemigo eliminado",
 	"core.bonus.SPELLCASTER.name": "Lanzador de hechizos",

+ 3 - 3
client/CServerHandler.cpp

@@ -869,14 +869,14 @@ public:
 	{
 	}
 
-	virtual bool callTyped() override { return false; }
+	bool callTyped() override { return false; }
 
-	virtual void visitForLobby(CPackForLobby & lobbyPack) override
+	void visitForLobby(CPackForLobby & lobbyPack) override
 	{
 		handler.visitForLobby(lobbyPack);
 	}
 
-	virtual void visitForClient(CPackForClient & clientPack) override
+	void visitForClient(CPackForClient & clientPack) override
 	{
 		handler.visitForClient(clientPack);
 	}

+ 1 - 1
client/Client.h

@@ -173,7 +173,7 @@ public:
 	void showTeleportDialog(TeleportDialog * iw) override {};
 	void showObjectWindow(const CGObjectInstance * object, EOpenWindowMode window, const CGHeroInstance * visitor, bool addQuery) override {};
 	void giveResource(PlayerColor player, GameResID which, int val) override {};
-	virtual void giveResources(PlayerColor player, TResources resources) override {};
+	void giveResources(PlayerColor player, TResources resources) override {};
 
 	void giveCreatures(const CArmedInstance * objid, const CGHeroInstance * h, const CCreatureSet & creatures, bool remove) override {};
 	void takeCreatures(ObjectInstanceID objid, const std::vector<CStackBasicDescriptor> & creatures) override {};

+ 12 - 12
client/ClientNetPackVisitors.h

@@ -118,16 +118,16 @@ public:
 	{
 	}
 
-	virtual void visitChangeObjPos(ChangeObjPos & pack) override;
-	virtual void visitRemoveObject(RemoveObject & pack) override;
-	virtual void visitTryMoveHero(TryMoveHero & pack) override;
-	virtual void visitGiveHero(GiveHero & pack) override;
-	virtual void visitBattleStart(BattleStart & pack) override;
-	virtual void visitBattleNextRound(BattleNextRound & pack) override;
-	virtual void visitBattleUpdateGateState(BattleUpdateGateState & pack) override;
-	virtual void visitBattleResult(BattleResult & pack) override;
-	virtual void visitBattleStackMoved(BattleStackMoved & pack) override;
-	virtual void visitBattleAttack(BattleAttack & pack) override;
-	virtual void visitStartAction(StartAction & pack) override;
-	virtual void visitSetObjectProperty(SetObjectProperty & pack) override;
+	void visitChangeObjPos(ChangeObjPos & pack) override;
+	void visitRemoveObject(RemoveObject & pack) override;
+	void visitTryMoveHero(TryMoveHero & pack) override;
+	void visitGiveHero(GiveHero & pack) override;
+	void visitBattleStart(BattleStart & pack) override;
+	void visitBattleNextRound(BattleNextRound & pack) override;
+	void visitBattleUpdateGateState(BattleUpdateGateState & pack) override;
+	void visitBattleResult(BattleResult & pack) override;
+	void visitBattleStackMoved(BattleStackMoved & pack) override;
+	void visitBattleAttack(BattleAttack & pack) override;
+	void visitStartAction(StartAction & pack) override;
+	void visitSetObjectProperty(SetObjectProperty & pack) override;
 };

+ 10 - 3
client/battle/BattleInterfaceClasses.cpp

@@ -852,12 +852,19 @@ StackQueue::StackQueue(bool Embedded, BattleInterface & owner)
 	owner(owner)
 {
 	OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE);
+
+	uint32_t queueSize = QUEUE_SIZE_BIG;
+
 	if(embedded)
 	{
-		pos.w = QUEUE_SIZE * 41;
+		int32_t queueSmallOutsideYOffset = 65;
+		bool queueSmallOutside = settings["battle"]["queueSmallOutside"].Bool() && (pos.y - queueSmallOutsideYOffset) >= 0;
+		queueSize = std::clamp(static_cast<int>(settings["battle"]["queueSmallSlots"].Float()), 1, queueSmallOutside ? GH.screenDimensions().x / 41 : 19);
+
+		pos.w = queueSize * 41;
 		pos.h = 49;
 		pos.x += parent->pos.w/2 - pos.w/2;
-		pos.y += 10;
+		pos.y += queueSmallOutside ? -queueSmallOutsideYOffset : 10;
 
 		icons = GH.renderHandler().loadAnimation(AnimationPath::builtin("CPRSMALL"));
 		stateIcons = GH.renderHandler().loadAnimation(AnimationPath::builtin("VCMI/BATTLEQUEUE/STATESSMALL"));
@@ -878,7 +885,7 @@ StackQueue::StackQueue(bool Embedded, BattleInterface & owner)
 	}
 	stateIcons->preload();
 
-	stackBoxes.resize(QUEUE_SIZE);
+	stackBoxes.resize(queueSize);
 	for (int i = 0; i < stackBoxes.size(); i++)
 	{
 		stackBoxes[i] = std::make_shared<StackBox>(this);

+ 1 - 1
client/battle/BattleInterfaceClasses.h

@@ -239,7 +239,7 @@ class StackQueue : public CIntObject
 		std::optional<uint32_t> getBoundUnitID() const;
 	};
 
-	static const int QUEUE_SIZE = 10;
+	static const int QUEUE_SIZE_BIG = 10;
 	std::shared_ptr<CFilledTexture> background;
 	std::vector<std::shared_ptr<StackBox>> stackBoxes;
 	BattleInterface & owner;

+ 2 - 2
client/eventsSDL/InputHandler.cpp

@@ -145,7 +145,7 @@ void InputHandler::preprocessEvent(const SDL_Event & ev)
 			Settings full = settings.write["video"]["fullscreen"];
 			full->Bool() = !full->Bool();
 
-			GH.onScreenResize();
+			GH.onScreenResize(false);
 			return;
 		}
 	}
@@ -163,7 +163,7 @@ void InputHandler::preprocessEvent(const SDL_Event & ev)
 #ifndef VCMI_IOS
 			{
 				boost::mutex::scoped_lock interfaceLock(GH.interfaceMutex);
-				GH.onScreenResize();
+				GH.onScreenResize(false);
 			}
 #endif
 			break;

+ 5 - 2
client/gui/CGuiHandler.cpp

@@ -251,8 +251,11 @@ void CGuiHandler::setStatusbar(std::shared_ptr<IStatusBar> newStatusBar)
 	currentStatusBar = newStatusBar;
 }
 
-void CGuiHandler::onScreenResize()
+void CGuiHandler::onScreenResize(bool resolutionChanged)
 {
-	screenHandler().onScreenResize();
+	if(resolutionChanged)
+	{
+		screenHandler().onScreenResize();
+	}
 	windows().onScreenResize();
 }

+ 2 - 2
client/gui/CGuiHandler.h

@@ -92,8 +92,8 @@ public:
 	void init();
 	void renderFrame();
 
-	/// called whenever user selects different resolution, requiring to center/resize all windows
-	void onScreenResize();
+	/// called whenever SDL_WINDOWEVENT_RESTORED is reported or the user selects a different resolution, requiring to center/resize all windows
+	void onScreenResize(bool resolutionChanged);
 
 	void handleEvents(); //takes events from queue and calls interested objects
 	void fakeMouseMove();

+ 16 - 5
client/lobby/CBonusSelection.cpp

@@ -15,6 +15,7 @@
 #include <vcmi/spells/Service.h>
 
 #include "CSelectionBase.h"
+#include "ExtraOptionsTab.h"
 
 #include "../CGameInfo.h"
 #include "../CMusicHandler.h"
@@ -86,7 +87,7 @@ CBonusSelection::CBonusSelection()
 	labelMapDescription = std::make_shared<CLabel>(481, 253, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::YELLOW, CGI->generaltexth->allTexts[496]);
 	mapDescription = std::make_shared<CTextBox>("", Rect(480, 278, 292, 108), 1);
 
-	labelChooseBonus = std::make_shared<CLabel>(511, 432, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[71]);
+	labelChooseBonus = std::make_shared<CLabel>(475, 432, FONT_SMALL, ETextAlignment::TOPLEFT, Colors::WHITE, CGI->generaltexth->allTexts[71]);
 	groupBonuses = std::make_shared<CToggleGroup>(std::bind(&IServerAPI::setCampaignBonus, CSH, _1));
 
 	flagbox = std::make_shared<CFlagBox>(Rect(486, 407, 335, 23));
@@ -94,17 +95,17 @@ CBonusSelection::CBonusSelection()
 	std::vector<std::string> difficulty;
 	std::string difficultyString = CGI->generaltexth->allTexts[492];
 	boost::split(difficulty, difficultyString, boost::is_any_of(" "));
-	labelDifficulty = std::make_shared<CLabel>(689, 432, FONT_MEDIUM, ETextAlignment::TOPLEFT, Colors::WHITE, difficulty.back());
+	labelDifficulty = std::make_shared<CLabel>(724, settings["general"]["enableUiEnhancements"].Bool() ? 457 : 432, FONT_MEDIUM, ETextAlignment::TOPCENTER, Colors::WHITE, difficulty.back());
 
 	for(size_t b = 0; b < difficultyIcons.size(); ++b)
 	{
-		difficultyIcons[b] = std::make_shared<CAnimImage>(AnimationPath::builtinTODO("GSPBUT" + std::to_string(b + 3) + ".DEF"), 0, 0, 709, 455);
+		difficultyIcons[b] = std::make_shared<CAnimImage>(AnimationPath::builtinTODO("GSPBUT" + std::to_string(b + 3) + ".DEF"), 0, 0, 709, settings["general"]["enableUiEnhancements"].Bool() ? 480 : 455);
 	}
 
 	if(getCampaign()->playerSelectedDifficulty())
 	{
-		buttonDifficultyLeft = std::make_shared<CButton>(Point(694, 508), AnimationPath::builtin("SCNRBLF.DEF"), CButton::tooltip(), std::bind(&CBonusSelection::decreaseDifficulty, this));
-		buttonDifficultyRight = std::make_shared<CButton>(Point(738, 508), AnimationPath::builtin("SCNRBRT.DEF"), CButton::tooltip(), std::bind(&CBonusSelection::increaseDifficulty, this));
+		buttonDifficultyLeft = std::make_shared<CButton>(settings["general"]["enableUiEnhancements"].Bool() ? Point(693, 495) : Point(694, 508), AnimationPath::builtin("SCNRBLF.DEF"), CButton::tooltip(), std::bind(&CBonusSelection::decreaseDifficulty, this));
+		buttonDifficultyRight = std::make_shared<CButton>(settings["general"]["enableUiEnhancements"].Bool() ? Point(739, 495) : Point(738, 508), AnimationPath::builtin("SCNRBRT.DEF"), CButton::tooltip(), std::bind(&CBonusSelection::increaseDifficulty, this));
 	}
 
 	for(auto scenarioID : getCampaign()->allScenarios())
@@ -117,6 +118,16 @@ CBonusSelection::CBonusSelection()
 
 	if (!getCampaign()->getMusic().empty())
 		CCS->musich->playMusic( getCampaign()->getMusic(), true, false);
+
+	if(settings["general"]["enableUiEnhancements"].Bool())
+	{
+		tabExtraOptions = std::make_shared<ExtraOptionsTab>();
+		tabExtraOptions->recActions = UPDATE | SHOWALL | LCLICK | RCLICK_POPUP;
+		tabExtraOptions->recreate(true);
+		tabExtraOptions->setEnabled(false);
+		buttonExtraOptions = std::make_shared<CButton>(Point(643, 431), AnimationPath::builtin("GSPBUT2.DEF"), CGI->generaltexth->zelp[46], [this]{ tabExtraOptions->setEnabled(!tabExtraOptions->isActive()); GH.windows().totalRedraw(); }, EShortcut::NONE);
+		buttonExtraOptions->addTextOverlay(CGI->generaltexth->translate("vcmi.optionsTab.extraOptions.hover"), FONT_SMALL, Colors::WHITE);
+	}
 }
 
 void CBonusSelection::createBonusesIcons()

+ 4 - 0
client/lobby/CBonusSelection.h

@@ -27,6 +27,7 @@ class CAnimImage;
 class CLabel;
 class CFlagBox;
 class ISelectionScreenInfo;
+class ExtraOptionsTab;
 
 /// Campaign screen where you can choose one out of three starting bonuses
 class CBonusSelection : public CWindowObject
@@ -82,4 +83,7 @@ public:
 	std::shared_ptr<CButton> buttonDifficultyLeft;
 	std::shared_ptr<CButton> buttonDifficultyRight;
 	std::shared_ptr<CAnimImage> iconsMapSizes;
+
+	std::shared_ptr<ExtraOptionsTab> tabExtraOptions;
+	std::shared_ptr<CButton> buttonExtraOptions;
 };

+ 1 - 1
client/lobby/CSelectionBase.cpp

@@ -229,7 +229,7 @@ void InfoCard::changeSelection()
 	iconsLossCondition->setFrame(header->defeatIconIndex);
 	labelLossConditionText->setText(header->defeatMessage.toString());
 	flagbox->recreate();
-	labelDifficulty->setText(CGI->generaltexth->arraytxt[142 + mapInfo->mapHeader->difficulty]);
+	labelDifficulty->setText(CGI->generaltexth->arraytxt[142 + vstd::to_underlying(mapInfo->mapHeader->difficulty)]);
 	iconDifficulty->setSelected(SEL->getCurrentDifficulty());
 	if(SEL->screenType == ESelectionScreen::loadGame || SEL->screenType == ESelectionScreen::saveGame)
 		for(auto & button : iconDifficulty->buttons)

+ 8 - 1
client/lobby/OptionsTabBase.cpp

@@ -12,6 +12,7 @@
 #include "CSelectionBase.h"
 
 #include "../widgets/ComboBox.h"
+#include "../widgets/Images.h"
 #include "../widgets/Slider.h"
 #include "../widgets/TextControls.h"
 #include "../CServerHandler.h"
@@ -295,7 +296,7 @@ OptionsTabBase::OptionsTabBase(const JsonPath & configPath)
 	}
 }
 
-void OptionsTabBase::recreate()
+void OptionsTabBase::recreate(bool campaign)
 {
 	auto const & generateSimturnsDurationText = [](int days) -> std::string
 	{
@@ -417,4 +418,10 @@ void OptionsTabBase::recreate()
 		buttonUnlimitedReplay->setSelectedSilent(SEL->getStartInfo()->extraOptionsInfo.unlimitedReplay);
 		buttonUnlimitedReplay->block(SEL->screenType == ESelectionScreen::loadGame);
 	}
+
+	if(auto textureCampaignOverdraw = widget<CFilledTexture>("textureCampaignOverdraw"))
+	{
+		if(!campaign)
+			textureCampaignOverdraw->disable();
+	}
 }

+ 1 - 1
client/lobby/OptionsTabBase.h

@@ -28,5 +28,5 @@ class OptionsTabBase : public InterfaceObjectConfigurable
 public:
 	OptionsTabBase(const JsonPath & configPath);
 
-	void recreate();
+	void recreate(bool campaign = false);
 };

+ 1 - 1
client/lobby/RandomMapTab.cpp

@@ -177,7 +177,7 @@ void RandomMapTab::updateMapInfoByHost()
 	mapInfo->mapHeader->version = EMapFormat::VCMI;
 	mapInfo->mapHeader->name.appendLocalString(EMetaText::GENERAL_TXT, 740);
 	mapInfo->mapHeader->description.appendLocalString(EMetaText::GENERAL_TXT, 741);
-	mapInfo->mapHeader->difficulty = 1; // Normal
+	mapInfo->mapHeader->difficulty = EMapDifficulty::NORMAL;
 	mapInfo->mapHeader->height = mapGenOptions->getHeight();
 	mapInfo->mapHeader->width = mapGenOptions->getWidth();
 	mapInfo->mapHeader->twoLevel = mapGenOptions->getHasTwoLevels();

+ 1 - 1
client/widgets/MiscWidgets.h

@@ -40,7 +40,7 @@ class CHoverableArea: public virtual CIntObject
 public:
 	std::string hoverText;
 
-	virtual void hover (bool on) override;
+	void hover (bool on) override;
 
 	CHoverableArea();
 	virtual ~CHoverableArea();

+ 1 - 1
client/windows/InfoWindows.h

@@ -79,7 +79,7 @@ public:
 class CRClickPopup : public WindowBase
 {
 public:
-	virtual void close() override;
+	void close() override;
 	bool isPopupWindow() const override;
 
 	static std::shared_ptr<WindowBase> createCustomInfoWindow(Point position, const CGObjectInstance * specific);

+ 3 - 3
client/windows/settings/GeneralOptionsTab.cpp

@@ -317,7 +317,7 @@ void GeneralOptionsTab::setGameResolution(int index)
 	widget<CLabel>("resolutionLabel")->setText(resolutionToLabelString(resolution.x, resolution.y));
 
 	GH.dispatchMainThread([](){
-		GH.onScreenResize();
+		GH.onScreenResize(true);
 	});
 }
 
@@ -341,7 +341,7 @@ void GeneralOptionsTab::setFullscreenMode(bool on, bool exclusive)
 	updateResolutionSelector();
 
 	GH.dispatchMainThread([](){
-		GH.onScreenResize();
+		GH.onScreenResize(true);
 	});
 }
 
@@ -400,7 +400,7 @@ void GeneralOptionsTab::setGameScaling(int index)
 	widget<CLabel>("scalingLabel")->setText(scalingToLabelString(scaling));
 
 	GH.dispatchMainThread([](){
-		GH.onScreenResize();
+		GH.onScreenResize(true);
 	});
 }
 

+ 2 - 0
cmake_modules/VCMI_lib.cmake

@@ -155,6 +155,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
 		${MAIN_LIB_DIR}/rmg/Zone.cpp
 		${MAIN_LIB_DIR}/rmg/Functions.cpp
 		${MAIN_LIB_DIR}/rmg/RmgMap.cpp
+		${MAIN_LIB_DIR}/rmg/PenroseTiling.cpp
 		${MAIN_LIB_DIR}/rmg/modificators/Modificator.cpp
 		${MAIN_LIB_DIR}/rmg/modificators/ObjectManager.cpp
 		${MAIN_LIB_DIR}/rmg/modificators/ObjectDistributor.cpp
@@ -532,6 +533,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
 		${MAIN_LIB_DIR}/rmg/RmgMap.h
 		${MAIN_LIB_DIR}/rmg/float3.h
 		${MAIN_LIB_DIR}/rmg/Functions.h
+		${MAIN_LIB_DIR}/rmg/PenroseTiling.h
 		${MAIN_LIB_DIR}/rmg/modificators/Modificator.h
 		${MAIN_LIB_DIR}/rmg/modificators/ObjectManager.h
 		${MAIN_LIB_DIR}/rmg/modificators/ObjectDistributor.h

+ 3 - 1
config/gameConfig.json

@@ -384,7 +384,9 @@
 			// if enabled, pathfinder will take use of one-way monoliths with multiple exits.
 			"useMonolithOneWayRandom" : false,
 			// if enabled and hero has whirlpool protection effect, pathfinder will take use of whirpools
-			"useWhirlpool" : true
+			"useWhirlpool" : true,
+			// if enabled flying will work like in original game, otherwise nerf similar to HotA flying is applied
+			"originalFlyRules" : false
 		},
 		
 		"bonuses" : 

+ 1 - 0
config/heroes/tower.json

@@ -70,6 +70,7 @@
 	"torosar":
 	{
 		"index": 36,
+		"compatibilityIdentifiers" : [ "torosar " ],
 		"class" : "alchemist",
 		"female": false,
 		"spellbook": [ "magicArrow" ],

+ 9 - 1
config/schemas/settings.json

@@ -304,7 +304,7 @@
 			"type" : "object",
 			"additionalProperties" : false,
 			"default" : {},
-			"required" : [ "speedFactor", "mouseShadow", "cellBorders", "stackRange", "movementHighlightOnHover", "rangeLimitHighlightOnHover", "showQueue", "swipeAttackDistance", "queueSize", "stickyHeroInfoWindows", "enableAutocombatSpells", "endWithAutocombat" ],
+			"required" : [ "speedFactor", "mouseShadow", "cellBorders", "stackRange", "movementHighlightOnHover", "rangeLimitHighlightOnHover", "showQueue", "swipeAttackDistance", "queueSize", "stickyHeroInfoWindows", "enableAutocombatSpells", "endWithAutocombat", "queueSmallSlots", "queueSmallOutside" ],
 			"properties" : {
 				"speedFactor" : {
 					"type" : "number",
@@ -354,6 +354,14 @@
 				"endWithAutocombat" : {
 					"type": "boolean",
 					"default": false
+				},
+				"queueSmallSlots" : {
+					"type": "number",
+					"default": 10
+				},
+				"queueSmallOutside" : {
+					"type": "boolean",
+					"default": false
 				}
 			}
 		},

+ 7 - 0
config/widgets/extraOptionsTab.json

@@ -9,6 +9,13 @@
 			"image": "ADVOPTBK",
 			"position": {"x": 0, "y": 6}
 		},
+		{
+			"name": "textureCampaignOverdraw",
+			"type": "texture",
+			"color" : "blue", 
+			"image": "DIBOXBCK",
+			"rect": {"x": 391, "y": 14, "w": 82, "h": 569}
+		},
 		{
 			"name": "labelTitle",
 			"type": "label",

+ 7 - 5
docs/developers/Building_Linux.md

@@ -49,12 +49,14 @@ Information about building packages from the Arch User Repository (AUR) can be f
 
 # Getting the sources
 
-VCMI is still in development. We recommend the following initial directory structure:
+We recommend the following directory structure:
 
     .
     ├── vcmi -> contains sources and is under git control
     └── build -> contains build output, makefiles, object files,...
 
+Out-of-source builds keep the local repository clean so one doesn't have to manually exclude files generated during the build from commits.
+
 You can get latest sources with:
 
 `git clone -b develop --recursive https://github.com/vcmi/vcmi.git`
@@ -65,25 +67,25 @@ You can get latest sources with:
 
 ```sh
 mkdir build && cd build
-cmake ../vcmi
+cmake -S ../vcmi
 ```
 
 # Additional options that you may want to use:
 
 ## To enable debugging:
-`cmake ../vcmi -D CMAKE_BUILD_TYPE=Debug`
+`cmake -S ../vcmi -D CMAKE_BUILD_TYPE=Debug`
 
 **Notice**: The ../vcmi/ is not a typo, it will place makefile scripts into the build dir as the build dir is your working dir when calling CMake.
 
 ## To use ccache:
-`cmake ../vcmi -D ENABLE_CCACHE:BOOL=ON`
+`cmake -S ../vcmi -D ENABLE_CCACHE:BOOL=ON`
 
 ## Trigger build
 
 `cmake --build . -- -j2`
 (-j2 = compile with 2 threads, you can specify any value)
 
-That will generate vcmiclient, vcmiserver, vcmilauncher as well as .so libraries in **build/bin/** directory.
+That will generate vcmiclient, vcmiserver, vcmilauncher as well as .so libraries in the **build/bin/** directory.
 
 # Package building
 

+ 5 - 5
launcher/translation/chinese.ts

@@ -16,7 +16,7 @@
     <message>
         <location filename="../aboutProject/aboutproject_moc.ui" line="36"/>
         <source>VCMI on Github</source>
-        <translation>访问VCMI的GUTHUB</translation>
+        <translation>访问VCMI的Github</translation>
     </message>
     <message>
         <location filename="../aboutProject/aboutproject_moc.ui" line="55"/>
@@ -574,7 +574,7 @@ Install successfully downloaded?</source>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="624"/>
         <source>Renderer</source>
-        <translation type="unfinished"></translation>
+        <translation>渲染器</translation>
     </message>
     <message>
         <location filename="../settingsView/csettingsview_moc.ui" line="246"/>
@@ -824,7 +824,7 @@ Heroes® of Might and Magic® III HD is currently not supported!</source>
     <message>
         <location filename="../firstLaunch/firstlaunch_moc.ui" line="156"/>
         <source>VCMI on Github</source>
-        <translation>访问VCMI的GUTHUB</translation>
+        <translation>访问VCMI的Github</translation>
     </message>
     <message>
         <location filename="../firstLaunch/firstlaunch_moc.ui" line="163"/>
@@ -902,12 +902,12 @@ Heroes® of Might and Magic® III HD is currently not supported!</source>
     <message>
         <location filename="../firstLaunch/firstlaunch_moc.cpp" line="143"/>
         <source>Heroes III installation found!</source>
-        <translation type="unfinished"></translation>
+        <translation>英雄无敌3安装目录已找到!</translation>
     </message>
     <message>
         <location filename="../firstLaunch/firstlaunch_moc.cpp" line="143"/>
         <source>Copy data to VCMI folder?</source>
-        <translation type="unfinished"></translation>
+        <translation>复制数据到VCMI文件夹吗?</translation>
     </message>
 </context>
 <context>

+ 1 - 1
lib/CArtHandler.h

@@ -107,7 +107,7 @@ public:
 	std::string getJsonKey() const override;
 	void registerIcons(const IconRegistar & cb) const override;
 	ArtifactID getId() const override;
-	virtual const IBonusBearer * getBonusBearer() const override;
+	const IBonusBearer * getBonusBearer() const override;
 
 	std::string getDescriptionTranslated() const override;
 	std::string getEventTranslated() const override;

+ 1 - 1
lib/CCreatureHandler.h

@@ -126,7 +126,7 @@ public:
 	std::string getJsonKey() const override;
 	void registerIcons(const IconRegistar & cb) const override;
 	CreatureID getId() const override;
-	virtual const IBonusBearer * getBonusBearer() const override;
+	const IBonusBearer * getBonusBearer() const override;
 
 	int32_t getAdvMapAmountMin() const override;
 	int32_t getAdvMapAmountMax() const override;

+ 2 - 2
lib/CGameInfoCallback.h

@@ -171,7 +171,7 @@ public:
 	virtual void fillUpgradeInfo(const CArmedInstance *obj, SlotID stackPos, UpgradeInfo &out)const;
 
 	//hero
-	virtual const CGHeroInstance * getHero(ObjectInstanceID objid) const override;
+	const CGHeroInstance * getHero(ObjectInstanceID objid) const override;
 	const CGHeroInstance * getHeroWithSubid(int subid) const override;
 	virtual int getHeroCount(PlayerColor player, bool includeGarrisoned) const;
 	virtual bool getHeroInfo(const CGObjectInstance * hero, InfoAboutHero & dest, const CGObjectInstance * selectedObject = nullptr) const;
@@ -183,7 +183,7 @@ public:
 	//virtual const CGObjectInstance * getArmyInstance(ObjectInstanceID oid) const;
 
 	//objects
-	virtual const CGObjectInstance * getObj(ObjectInstanceID objid, bool verbose = true) const override;
+	const CGObjectInstance * getObj(ObjectInstanceID objid, bool verbose = true) const override;
 	virtual std::vector <const CGObjectInstance * > getBlockingObjs(int3 pos)const;
 	virtual std::vector <const CGObjectInstance * > getVisitableObjs(int3 pos, bool verbose = true) const override;
 	virtual std::vector <const CGObjectInstance * > getFlaggableObjects(int3 pos) const;

+ 14 - 14
lib/CGameInterface.h

@@ -144,26 +144,26 @@ public:
 	virtual std::string getBattleAIName() const = 0; //has to return name of the battle AI to be used
 
 	//battle interface
-	virtual void activeStack(const BattleID & battleID, const CStack * stack) override;
-	virtual void yourTacticPhase(const BattleID & battleID, int distance) override;
+	void activeStack(const BattleID & battleID, const CStack * stack) override;
+	void yourTacticPhase(const BattleID & battleID, int distance) override;
 
-	virtual void battleNewRound(const BattleID & battleID) override;
-	virtual void battleCatapultAttacked(const BattleID & battleID, const CatapultAttack & ca) override;
-	virtual void battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side, bool replayAllowed) override;
+	void battleNewRound(const BattleID & battleID) override;
+	void battleCatapultAttacked(const BattleID & battleID, const CatapultAttack & ca) override;
+	void battleStart(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side, bool replayAllowed) override;
 	virtual void battleStacksAttacked(const BattleID & battleID, const std::vector<BattleStackAttacked> & bsa, bool ranged) override;
-	virtual void actionStarted(const BattleID & battleID, const BattleAction &action) override;
-	virtual void battleNewRoundFirst(const BattleID & battleID) override;
-	virtual void actionFinished(const BattleID & battleID, const BattleAction &action) override;
-	virtual void battleStacksEffectsSet(const BattleID & battleID, const SetStackEffect & sse) override;
+	void actionStarted(const BattleID & battleID, const BattleAction &action) override;
+	void battleNewRoundFirst(const BattleID & battleID) override;
+	void actionFinished(const BattleID & battleID, const BattleAction &action) override;
+	void battleStacksEffectsSet(const BattleID & battleID, const SetStackEffect & sse) override;
 	virtual void battleObstaclesChanged(const BattleID & battleID, const std::vector<ObstacleChanges> & obstacles) override;
 	virtual void battleStackMoved(const BattleID & battleID, const CStack * stack, std::vector<BattleHex> dest, int distance, bool teleport) override;
-	virtual void battleAttack(const BattleID & battleID, const BattleAttack *ba) override;
-	virtual void battleSpellCast(const BattleID & battleID, const BattleSpellCast *sc) override;
-	virtual void battleEnd(const BattleID & battleID, const BattleResult *br, QueryID queryID) override;
+	void battleAttack(const BattleID & battleID, const BattleAttack *ba) override;
+	void battleSpellCast(const BattleID & battleID, const BattleSpellCast *sc) override;
+	void battleEnd(const BattleID & battleID, const BattleResult *br, QueryID queryID) override;
 	virtual void battleUnitsChanged(const BattleID & battleID, const std::vector<UnitChanges> & units) override;
 
-	virtual void saveGame(BinarySerializer & h) override;
-	virtual void loadGame(BinaryDeserializer & h) override;
+	void saveGame(BinarySerializer & h) override;
+	void loadGame(BinaryDeserializer & h) override;
 };
 
 VCMI_LIB_NAMESPACE_END

+ 7 - 0
lib/CHeroHandler.cpp

@@ -326,6 +326,8 @@ CHeroClass * CHeroClassHandler::loadFromJson(const std::string & scope, const Js
 	{
 		JsonNode classConf = node["mapObject"];
 		classConf["heroClass"].String() = identifier;
+		if (!node["compatibilityIdentifiers"].isNull())
+			classConf["compatibilityIdentifiers"] = node["compatibilityIdentifiers"];
 		classConf.setMeta(scope);
 		VLC->objtypeh->loadSubObject(identifier, classConf, index, heroClass->getIndex());
 	});
@@ -756,6 +758,9 @@ void CHeroHandler::loadObject(std::string scope, std::string name, const JsonNod
 	objects.emplace_back(object);
 
 	registerObject(scope, "hero", name, object->getIndex());
+
+	for(const auto & compatID : data["compatibilityIdentifiers"].Vector())
+		registerObject(scope, "hero", compatID.String(), object->getIndex());
 }
 
 void CHeroHandler::loadObject(std::string scope, std::string name, const JsonNode & data, size_t index)
@@ -767,6 +772,8 @@ void CHeroHandler::loadObject(std::string scope, std::string name, const JsonNod
 	objects[index] = object;
 
 	registerObject(scope, "hero", name, object->getIndex());
+	for(const auto & compatID : data["compatibilityIdentifiers"].Vector())
+		registerObject(scope, "hero", compatID.String(), object->getIndex());
 }
 
 ui32 CHeroHandler::level (TExpType experience) const

+ 2 - 2
lib/CHeroHandler.h

@@ -31,11 +31,11 @@ class CRandomGenerator;
 class JsonSerializeFormat;
 class BattleField;
 
-enum class EHeroGender : uint8_t
+enum class EHeroGender : int8_t
 {
+	DEFAULT = -1, // from h3m, instance has same gender as hero type
 	MALE = 0,
 	FEMALE = 1,
-	DEFAULT = 0xff // from h3m, instance has same gender as hero type
 };
 
 class DLL_LINKAGE CHero : public HeroType

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików