1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

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.
This commit is contained in:
Konstantin 2023-04-05 18:56:28 +03:00
parent 6d9859932b
commit 0f5f4c69ec
14 changed files with 122 additions and 8 deletions

View File

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

View File

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

20
lib/BasicTypes.cpp Normal file
View File

@ -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;
}

View File

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

View File

@ -25,6 +25,9 @@
#include "serializer/JsonSerializeFormat.h" #include "serializer/JsonSerializeFormat.h"
#include "NetPacksBase.h" #include "NetPacksBase.h"
#include <vcmi/FactionService.h>
#include <vcmi/Faction.h>
VCMI_LIB_NAMESPACE_BEGIN 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() CCommanderInstance::CCommanderInstance()
{ {
init(); init();

View File

@ -14,6 +14,8 @@
#include "CArtHandler.h" #include "CArtHandler.h"
#include "CCreatureHandler.h" #include "CCreatureHandler.h"
#include <vcmi/Entity.h>
VCMI_LIB_NAMESPACE_BEGIN VCMI_LIB_NAMESPACE_BEGIN
class JsonNode; class JsonNode;
@ -61,7 +63,7 @@ public:
void serializeJson(JsonSerializeFormat & handler); 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: protected:
const CArmedInstance *_armyObj; //stack must be part of some army, army must be part of some object 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 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 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; virtual ui64 getPower() const;
CCreature::CreatureQuantityId getQuantityID() const; CCreature::CreatureQuantityId getQuantityID() const;
std::string getQuantityTXT(bool capitalized = true) const; std::string getQuantityTXT(bool capitalized = true) const;

View File

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

View File

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

View File

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

View File

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

View File

@ -18,6 +18,9 @@
#include "../serializer/JsonDeserializer.h" #include "../serializer/JsonDeserializer.h"
#include "../serializer/JsonSerializer.h" #include "../serializer/JsonSerializer.h"
#include <vcmi/Faction.h>
#include <vcmi/FactionService.h>
VCMI_LIB_NAMESPACE_BEGIN VCMI_LIB_NAMESPACE_BEGIN
namespace battle namespace battle
@ -43,6 +46,24 @@ std::string Unit::getDescription() const
return fmt.str(); 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 std::vector<BattleHex> Unit::getSurroundingHexes(BattleHex assumedPosition) const
{ {
BattleHex hex = (assumedPosition != BattleHex::INVALID) ? assumedPosition : getPosition(); //use hypothetical position BattleHex hex = (assumedPosition != BattleHex::INVALID) ? assumedPosition : getPosition(); //use hypothetical position

View File

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

View File

@ -84,6 +84,16 @@ ui32 CGHeroInstance::getTileCost(const TerrainTile & dest, const TerrainTile & f
return static_cast<ui32>(ret); 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 TerrainId CGHeroInstance::getNativeTerrain() const
{ {
// NOTE: in H3 neutral stacks will ignore terrain penalty only if placed as topmost stack(s) in hero army. // 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) 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) if(stackNativeTerrain == ETerrainId::NONE)
continue; continue;

View File

@ -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 // We serialize heroes into JSON for crossover
friend class CCampaignState; friend class CCampaignState;
@ -156,7 +156,9 @@ public:
bool needsLastStack()const override; 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 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; int getLowestCreatureSpeed() const;
si32 manaRegain() const; //how many points of mana can hero regain "naturally" in one day 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 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; std::string nodeName() const override;
si32 manaLimit() const override; si32 manaLimit() const override;
///WithBonuses
const IBonusBearer* getBonusBearer() const override;
CBonusSystemNode * whereShouldBeAttachedOnSiege(const bool isBattleOutsideTown) const; CBonusSystemNode * whereShouldBeAttachedOnSiege(const bool isBattleOutsideTown) const;
CBonusSystemNode * whereShouldBeAttachedOnSiege(CGameState * gs); CBonusSystemNode * whereShouldBeAttachedOnSiege(CGameState * gs);