Browse Source

vcmi: specialize native terrain entity

Specialize native terrain entity for all object that have
native terrain. Allow creatures to take global bonuses into
account when checking for native terrain.
Konstantin 2 years ago
parent
commit
0f5f4c69ec

+ 1 - 0
cmake_modules/VCMI_lib.cmake

@@ -162,6 +162,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
 
 		${MAIN_LIB_DIR}/vstd/StringUtils.cpp
 
+		${MAIN_LIB_DIR}/BasicTypes.cpp
 		${MAIN_LIB_DIR}/BattleFieldHandler.cpp
 		${MAIN_LIB_DIR}/CAndroidVMHelper.cpp
 		${MAIN_LIB_DIR}/CArtHandler.cpp

+ 1 - 0
include/vcmi/Entity.h

@@ -28,6 +28,7 @@ class DLL_LINKAGE WithNativeTerrain
 public:
 	virtual Identifier<ETerrainId> getNativeTerrain() const = 0;
 	virtual FactionID getFaction() const = 0;
+	virtual bool isItNativeTerrain(Identifier<ETerrainId> terrain) const;
 };
 
 class DLL_LINKAGE Entity

+ 20 - 0
lib/BasicTypes.cpp

@@ -0,0 +1,20 @@
+/*
+ * BasicTypes.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 "GameConstants.h"
+
+#include <vcmi/Entity.h>
+
+bool INativeTerrainProvider::isItNativeTerrain(TerrainId terrain) const
+{
+	auto native = getNativeTerrain();
+	return native == terrain || native == ETerrainId::ANY_TERRAIN;
+}

+ 2 - 2
lib/CCreatureHandler.cpp

@@ -348,9 +348,9 @@ TerrainId CCreature::getNativeTerrain() const
 
 	//this code is used in the CreatureTerrainLimiter::limit to setup battle bonuses
 	//and in the CGHeroInstance::getNativeTerrain() to setup movement bonuses or/and penalties.
-	return hasBonus(selectorNoTerrainPenalty, cachingStringNoTerrainPenalty)
+	return getBonusBearer()->hasBonus(selectorNoTerrainPenalty, cachingStringNoTerrainPenalty)
 		? TerrainId(ETerrainId::ANY_TERRAIN)
-		: VLC->factions()->getByIndex(faction)->getNativeTerrain();
+		: VLC->factions()->getById(getFaction())->getNativeTerrain();
 }
 
 void CCreature::updateFrom(const JsonNode & data)

+ 28 - 0
lib/CCreatureSet.cpp

@@ -25,6 +25,9 @@
 #include "serializer/JsonSerializeFormat.h"
 #include "NetPacksBase.h"
 
+#include <vcmi/FactionService.h>
+#include <vcmi/Faction.h>
+
 VCMI_LIB_NAMESPACE_BEGIN
 
 
@@ -912,6 +915,31 @@ void CStackInstance::serializeJson(JsonSerializeFormat & handler)
 	}
 }
 
+FactionID CStackInstance::getFaction() const
+{
+	if(type)
+		return type->getFaction();
+		
+	return FactionID::NEUTRAL;
+}
+
+const IBonusBearer* CStackInstance::getBonusBearer() const
+{
+	return this;
+}
+
+TerrainId CStackInstance::getNativeTerrain() const
+{
+	const std::string cachingStringNoTerrainPenalty = "type_NO_TERRAIN_PENALTY_sANY";
+	static const auto selectorNoTerrainPenalty = Selector::typeSubtype(Bonus::NO_TERRAIN_PENALTY, static_cast<int>(ETerrainId::ANY_TERRAIN));
+
+	//this code is used in the CreatureTerrainLimiter::limit to setup battle bonuses
+	//and in the CGHeroInstance::getNativeTerrain() to setup movement bonuses or/and penalties.
+	return getBonusBearer()->hasBonus(selectorNoTerrainPenalty, cachingStringNoTerrainPenalty)
+		? TerrainId(ETerrainId::ANY_TERRAIN)
+		: VLC->factions()->getById(getFaction())->getNativeTerrain();
+}
+
 CCommanderInstance::CCommanderInstance()
 {
 	init();

+ 9 - 1
lib/CCreatureSet.h

@@ -14,6 +14,8 @@
 #include "CArtHandler.h"
 #include "CCreatureHandler.h"
 
+#include <vcmi/Entity.h>
+
 VCMI_LIB_NAMESPACE_BEGIN
 
 class JsonNode;
@@ -61,7 +63,7 @@ public:
 	void serializeJson(JsonSerializeFormat & handler);
 };
 
-class DLL_LINKAGE CStackInstance : public CBonusSystemNode, public CStackBasicDescriptor, public CArtifactSet
+class DLL_LINKAGE CStackInstance : public CBonusSystemNode, public CStackBasicDescriptor, public CArtifactSet, public WithBonuses, public WithNativeTerrain
 {
 protected:
 	const CArmedInstance *_armyObj; //stack must be part of some army, army must be part of some object
@@ -92,6 +94,12 @@ public:
 	std::string bonusToString(const std::shared_ptr<Bonus>& bonus, bool description) const override; // how would bonus description look for this particular type of node
 	std::string bonusToGraphics(const std::shared_ptr<Bonus> & bonus) const; //file name of graphics from StackSkills , in future possibly others
 
+	//WithBonuses
+	const IBonusBearer* getBonusBearer() const override;
+	//WithNativeTerrain
+	FactionID getFaction() const override;
+	TerrainId getNativeTerrain() const override;
+
 	virtual ui64 getPower() const;
 	CCreature::CreatureQuantityId getQuantityID() const;
 	std::string getQuantityTXT(bool capitalized = true) const;

+ 6 - 1
lib/CStack.cpp

@@ -78,7 +78,7 @@ void CStack::localInit(BattleInfo * battleInfo)
 		attachTo(*army);
 		attachTo(const_cast<CCreature&>(*type));
 	}
-	nativeTerrain = type->getNativeTerrain(); //save nativeTerrain in the variable on the battle start to avoid dead lock
+	nativeTerrain = getNativeTerrain(); //save nativeTerrain in the variable on the battle start to avoid dead lock
 	CUnitState::localInit(this); //it causes execution of the CStack::isOnNativeTerrain where nativeTerrain will be considered
 	position = initialPosition;
 }
@@ -338,6 +338,11 @@ int32_t CStack::unitBaseAmount() const
 	return baseAmount;
 }
 
+const IBonusBearer* CStack::getBonusBearer() const
+{
+	return this;
+}
+
 bool CStack::unitHasAmmoCart(const battle::Unit * unit) const
 {
 	for(const CStack * st : battle->stacks)

+ 2 - 0
lib/CStack.h

@@ -84,6 +84,8 @@ public:
 
 	void spendMana(ServerCallback * server, const int spellCost) const override;
 
+	const IBonusBearer* getBonusBearer() const override;
+	
 	PlayerColor getOwner() const override
 	{
 		return this->owner;

+ 5 - 0
lib/battle/CUnitState.cpp

@@ -413,6 +413,11 @@ int32_t CUnitState::creatureIconIndex() const
 	return unitType()->getIconIndex();
 }
 
+FactionID CUnitState::getFaction() const
+{
+	return unitType()->getFaction();
+}
+
 int32_t CUnitState::getCasterUnitId() const
 {
 	return static_cast<int32_t>(unitId());

+ 2 - 0
lib/battle/CUnitState.h

@@ -247,6 +247,8 @@ public:
 	void localInit(const IUnitEnvironment * env_);
 	void serializeJson(JsonSerializeFormat & handler);
 
+	FactionID getFaction() const override;
+
 	void afterAttack(bool ranged, bool counter);
 
 	void afterNewRound();

+ 21 - 0
lib/battle/Unit.cpp

@@ -18,6 +18,9 @@
 #include "../serializer/JsonDeserializer.h"
 #include "../serializer/JsonSerializer.h"
 
+#include <vcmi/Faction.h>
+#include <vcmi/FactionService.h>
+
 VCMI_LIB_NAMESPACE_BEGIN
 
 namespace battle
@@ -43,6 +46,24 @@ std::string Unit::getDescription() const
 	return fmt.str();
 }
 
+//TODO: deduplicate these functions
+const IBonusBearer* Unit::getBonusBearer() const
+{
+	return this;
+}
+
+TerrainId Unit::getNativeTerrain() const
+{
+	const std::string cachingStringNoTerrainPenalty = "type_NO_TERRAIN_PENALTY_sANY";
+	static const auto selectorNoTerrainPenalty = Selector::typeSubtype(Bonus::NO_TERRAIN_PENALTY, static_cast<int>(ETerrainId::ANY_TERRAIN));
+
+	//this code is used in the CreatureTerrainLimiter::limit to setup battle bonuses
+	//and in the CGHeroInstance::getNativeTerrain() to setup movement bonuses or/and penalties.
+	return getBonusBearer()->hasBonus(selectorNoTerrainPenalty, cachingStringNoTerrainPenalty)
+		? TerrainId(ETerrainId::ANY_TERRAIN)
+		: VLC->factions()->getById(getFaction())->getNativeTerrain();
+}
+
 std::vector<BattleHex> Unit::getSurroundingHexes(BattleHex assumedPosition) const
 {
 	BattleHex hex = (assumedPosition != BattleHex::INVALID) ? assumedPosition : getPosition(); //use hypothetical position

+ 7 - 1
lib/battle/Unit.h

@@ -10,6 +10,7 @@
 
 #pragma once
 
+#include <vcmi/Entity.h>
 #include <vcmi/spells/Caster.h>
 
 #include "../HeroBonus.h"
@@ -40,7 +41,7 @@ namespace BattlePhases
 
 class CUnitState;
 
-class DLL_LINKAGE Unit : public IUnitInfo, public spells::Caster, public virtual IBonusBearer
+class DLL_LINKAGE Unit : public IUnitInfo, public spells::Caster, public virtual IBonusBearer, public WithBonuses, public WithNativeTerrain
 {
 public:
 	virtual ~Unit();
@@ -126,6 +127,11 @@ public:
 
 	int getRawSurrenderCost() const;
 
+	//WithBonuses
+	const IBonusBearer* getBonusBearer() const override;
+	//WithNativeTerrain
+	TerrainId getNativeTerrain() const override;
+
 	//NOTE: save could possibly be const, but this requires heavy changes to Json serialization,
 	//also this method should be called only after modifying object
 	virtual void save(JsonNode & data) = 0;

+ 11 - 1
lib/mapObjects/CGHeroInstance.cpp

@@ -84,6 +84,16 @@ ui32 CGHeroInstance::getTileCost(const TerrainTile & dest, const TerrainTile & f
 	return static_cast<ui32>(ret);
 }
 
+FactionID CGHeroInstance::getFaction() const
+{
+	return FactionID(type->heroClass->faction);
+}
+
+const IBonusBearer* CGHeroInstance::getBonusBearer() const
+{
+	return this;
+}
+
 TerrainId CGHeroInstance::getNativeTerrain() const
 {
 	// NOTE: in H3 neutral stacks will ignore terrain penalty only if placed as topmost stack(s) in hero army.
@@ -96,7 +106,7 @@ TerrainId CGHeroInstance::getNativeTerrain() const
 
 	for(const auto & stack : stacks)
 	{
-		TerrainId stackNativeTerrain = stack.second->type->getNativeTerrain(); //consider terrain bonuses e.g. Lodestar.
+		TerrainId stackNativeTerrain = stack.second->getNativeTerrain(); //consider terrain bonuses e.g. Lodestar.
 
 		if(stackNativeTerrain == ETerrainId::NONE)
 			continue;

+ 7 - 2
lib/mapObjects/CGHeroInstance.h

@@ -40,7 +40,7 @@ public:
 };
 
 
-class DLL_LINKAGE CGHeroInstance : public CArmedInstance, public IBoatGenerator, public CArtifactSet, public spells::Caster
+class DLL_LINKAGE CGHeroInstance : public CArmedInstance, public IBoatGenerator, public CArtifactSet, public spells::Caster, public WithBonuses, public WithNativeTerrain
 {
 	// We serialize heroes into JSON for crossover
 	friend class CCampaignState;
@@ -156,7 +156,9 @@ public:
 	bool needsLastStack()const override;
 
 	ui32 getTileCost(const TerrainTile & dest, const TerrainTile & from, const TurnInfo * ti) const; //move cost - applying pathfinding skill, road and terrain modifiers. NOT includes diagonal move penalty, last move levelling
-	TerrainId getNativeTerrain() const;
+	//WithNativeTerrain
+	FactionID getFaction() const override;
+	TerrainId getNativeTerrain() const override;
 	int getLowestCreatureSpeed() const;
 	si32 manaRegain() const; //how many points of mana can hero regain "naturally" in one day
 	si32 getManaNewTurn() const; //calculate how much mana this hero is going to have the next day
@@ -246,6 +248,9 @@ public:
 	std::string nodeName() const override;
 	si32 manaLimit() const override;
 
+	///WithBonuses
+	const IBonusBearer* getBonusBearer() const override;
+
 	CBonusSystemNode * whereShouldBeAttachedOnSiege(const bool isBattleOutsideTown) const;
 	CBonusSystemNode * whereShouldBeAttachedOnSiege(CGameState * gs);