mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-13 19:54:17 +02:00
vcmi: move limiters outside of HeroBonus.cpp
This will help for recompilation.
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
#include "../../lib/CGameState.h"
|
||||
#include "../../lib/NetPacksBase.h"
|
||||
#include "../../lib/NetPacks.h"
|
||||
#include "../../lib/bonuses/ILimiter.h"
|
||||
#include "../../lib/serializer/CTypeList.h"
|
||||
#include "../../lib/serializer/BinarySerializer.h"
|
||||
#include "../../lib/serializer/BinaryDeserializer.h"
|
||||
|
@@ -43,6 +43,7 @@
|
||||
#include "../lib/CArtHandler.h"
|
||||
#include "../lib/CGeneralTextHandler.h"
|
||||
#include "../lib/CHeroHandler.h"
|
||||
#include "../lib/bonuses/ILimiter.h"
|
||||
#include "../lib/serializer/CTypeList.h"
|
||||
#include "../lib/serializer/BinaryDeserializer.h"
|
||||
#include "../lib/serializer/BinarySerializer.h"
|
||||
|
@@ -28,6 +28,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
|
||||
${MAIN_LIB_DIR}/battle/Unit.cpp
|
||||
|
||||
${MAIN_LIB_DIR}/bonuses/HeroBonus.cpp
|
||||
${MAIN_LIB_DIR}/bonuses/ILimiter.cpp
|
||||
|
||||
${MAIN_LIB_DIR}/events/ApplyDamage.cpp
|
||||
${MAIN_LIB_DIR}/events/GameResumed.cpp
|
||||
@@ -302,6 +303,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
|
||||
${MAIN_LIB_DIR}/battle/Unit.h
|
||||
|
||||
${MAIN_LIB_DIR}/bonuses/HeroBonus.h
|
||||
${MAIN_LIB_DIR}/bonuses/ILimiter.h
|
||||
|
||||
${MAIN_LIB_DIR}/events/ApplyDamage.h
|
||||
${MAIN_LIB_DIR}/events/GameResumed.h
|
||||
|
@@ -19,6 +19,7 @@
|
||||
#include "CModHandler.h"
|
||||
#include "GameSettings.h"
|
||||
#include "StringConstants.h"
|
||||
#include "bonuses/ILimiter.h"
|
||||
#include "serializer/JsonDeserializer.h"
|
||||
#include "serializer/JsonUpdater.h"
|
||||
#include "mapObjects/CObjectClassesHandler.h"
|
||||
|
@@ -24,6 +24,7 @@
|
||||
#include "CSkillHandler.h"
|
||||
#include "mapObjects/CObjectClassesHandler.h"
|
||||
#include "BattleFieldHandler.h"
|
||||
#include "bonuses/ILimiter.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
|
@@ -18,6 +18,7 @@
|
||||
#include "CModHandler.h"
|
||||
#include "BattleFieldHandler.h"
|
||||
#include "ObstacleHandler.h"
|
||||
#include "bonuses/ILimiter.h"
|
||||
|
||||
#include "serializer/CSerializer.h" // for SAVEGAME_MAGIC
|
||||
#include "serializer/BinaryDeserializer.h"
|
||||
|
@@ -14,6 +14,7 @@
|
||||
#include "ScopeGuard.h"
|
||||
|
||||
#include "bonuses/HeroBonus.h"
|
||||
#include "bonuses/ILimiter.h"
|
||||
#include "filesystem/Filesystem.h"
|
||||
#include "VCMI_Lib.h" //for identifier resolution
|
||||
#include "CModHandler.h"
|
||||
|
@@ -9,6 +9,7 @@
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include "BattleInfo.h"
|
||||
#include "../bonuses/ILimiter.h"
|
||||
#include "../CStack.h"
|
||||
#include "../CHeroHandler.h"
|
||||
#include "../NetPacks.h"
|
||||
|
@@ -10,21 +10,22 @@
|
||||
|
||||
#include "StdInc.h"
|
||||
#include "HeroBonus.h"
|
||||
#include "ILimiter.h"
|
||||
|
||||
#include "VCMI_Lib.h"
|
||||
#include "spells/CSpellHandler.h"
|
||||
#include "CCreatureHandler.h"
|
||||
#include "CCreatureSet.h"
|
||||
#include "CHeroHandler.h"
|
||||
#include "CTownHandler.h"
|
||||
#include "CGeneralTextHandler.h"
|
||||
#include "CSkillHandler.h"
|
||||
#include "CStack.h"
|
||||
#include "CArtHandler.h"
|
||||
#include "CModHandler.h"
|
||||
#include "TerrainHandler.h"
|
||||
#include "StringConstants.h"
|
||||
#include "battle/BattleInfo.h"
|
||||
#include "../VCMI_Lib.h"
|
||||
#include "../spells/CSpellHandler.h"
|
||||
#include "../CCreatureHandler.h"
|
||||
#include "../CCreatureSet.h"
|
||||
#include "../CHeroHandler.h"
|
||||
#include "../CTownHandler.h"
|
||||
#include "../CGeneralTextHandler.h"
|
||||
#include "../CSkillHandler.h"
|
||||
#include "../CStack.h"
|
||||
#include "../CArtHandler.h"
|
||||
#include "../CModHandler.h"
|
||||
#include "../TerrainHandler.h"
|
||||
#include "../StringConstants.h"
|
||||
#include "../battle/BattleInfo.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@@ -69,18 +70,6 @@ const std::map<std::string, Bonus::LimitEffect> bonusLimitEffect =
|
||||
BONUS_ITEM(ONLY_MELEE_FIGHT)
|
||||
};
|
||||
|
||||
const std::map<std::string, TLimiterPtr> bonusLimiterMap =
|
||||
{
|
||||
{"SHOOTER_ONLY", std::make_shared<HasAnotherBonusLimiter>(Bonus::SHOOTER)},
|
||||
{"DRAGON_NATURE", std::make_shared<HasAnotherBonusLimiter>(Bonus::DRAGON_NATURE)},
|
||||
{"IS_UNDEAD", std::make_shared<HasAnotherBonusLimiter>(Bonus::UNDEAD)},
|
||||
{"CREATURE_NATIVE_TERRAIN", std::make_shared<CreatureTerrainLimiter>()},
|
||||
{"CREATURE_FACTION", std::make_shared<AllOfLimiter>(std::initializer_list<TLimiterPtr>{std::make_shared<CreatureLevelLimiter>(), std::make_shared<FactionLimiter>()})},
|
||||
{"SAME_FACTION", std::make_shared<FactionLimiter>()},
|
||||
{"CREATURES_ONLY", std::make_shared<CreatureLevelLimiter>()},
|
||||
{"OPPOSITE_SIDE", std::make_shared<OppositeSideLimiter>()},
|
||||
};
|
||||
|
||||
const std::map<std::string, TPropagatorPtr> bonusPropagatorMap =
|
||||
{
|
||||
{"BATTLE_WIDE", std::make_shared<CPropagatorNodeType>(CBonusSystemNode::BATTLE)},
|
||||
@@ -750,30 +739,6 @@ std::shared_ptr<const Bonus> IBonusBearer::getBonus(const CSelector &selector) c
|
||||
return bonuses->getFirst(Selector::all);
|
||||
}
|
||||
|
||||
const CStack * retrieveStackBattle(const CBonusSystemNode * node)
|
||||
{
|
||||
switch(node->getNodeType())
|
||||
{
|
||||
case CBonusSystemNode::STACK_BATTLE:
|
||||
return dynamic_cast<const CStack *>(node);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const CStackInstance * retrieveStackInstance(const CBonusSystemNode * node)
|
||||
{
|
||||
switch(node->getNodeType())
|
||||
{
|
||||
case CBonusSystemNode::STACK_INSTANCE:
|
||||
return (dynamic_cast<const CStackInstance *>(node));
|
||||
case CBonusSystemNode::STACK_BATTLE:
|
||||
return (dynamic_cast<const CStack *>(node))->base;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
PlayerColor CBonusSystemNode::retrieveNodeOwner(const CBonusSystemNode * node)
|
||||
{
|
||||
return node ? node->getOwner() : PlayerColor::CANNOT_DETERMINE;
|
||||
@@ -1398,7 +1363,7 @@ void CBonusSystemNode::limitBonuses(const BonusList &allBonuses, BonusList &out)
|
||||
for(int i = 0; i < undecided.size(); i++)
|
||||
{
|
||||
auto b = undecided[i];
|
||||
BonusLimitationContext context = {b, *this, out, undecided};
|
||||
BonusLimitationContext context = {*b, *this, out, undecided};
|
||||
auto decision = b->limiter ? b->limiter->limit(context) : ILimiter::EDecision::ACCEPT; //bonuses without limiters will be accepted by default
|
||||
if(decision == ILimiter::EDecision::DISCARD)
|
||||
{
|
||||
@@ -1957,22 +1922,6 @@ namespace Selector
|
||||
DLL_LINKAGE CSelector none([](const Bonus * b){return false;});
|
||||
}
|
||||
|
||||
const CCreature * retrieveCreature(const CBonusSystemNode *node)
|
||||
{
|
||||
switch(node->getNodeType())
|
||||
{
|
||||
case CBonusSystemNode::CREATURE:
|
||||
return (dynamic_cast<const CCreature *>(node));
|
||||
case CBonusSystemNode::STACK_BATTLE:
|
||||
return (dynamic_cast<const CStack *>(node))->unitType();
|
||||
default:
|
||||
const CStackInstance * csi = retrieveStackInstance(node);
|
||||
if(csi)
|
||||
return csi->type;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const BonusList &bonusList)
|
||||
{
|
||||
for (ui32 i = 0; i < bonusList.size(); i++)
|
||||
@@ -2035,168 +1984,6 @@ std::shared_ptr<Bonus> Bonus::addLimiter(const TLimiterPtr & Limiter)
|
||||
return this->shared_from_this();
|
||||
}
|
||||
|
||||
ILimiter::EDecision ILimiter::limit(const BonusLimitationContext &context) const /*return true to drop the bonus */
|
||||
{
|
||||
return ILimiter::EDecision::ACCEPT;
|
||||
}
|
||||
|
||||
std::string ILimiter::toString() const
|
||||
{
|
||||
return typeid(*this).name();
|
||||
}
|
||||
|
||||
JsonNode ILimiter::toJsonNode() const
|
||||
{
|
||||
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
||||
root["type"].String() = toString();
|
||||
return root;
|
||||
}
|
||||
|
||||
ILimiter::EDecision CCreatureTypeLimiter::limit(const BonusLimitationContext &context) const
|
||||
{
|
||||
const CCreature *c = retrieveCreature(&context.node);
|
||||
if(!c)
|
||||
return ILimiter::EDecision::DISCARD;
|
||||
|
||||
auto accept = c->getId() == creature->getId() || (includeUpgrades && creature->isMyUpgrade(c));
|
||||
return accept ? ILimiter::EDecision::ACCEPT : ILimiter::EDecision::DISCARD;
|
||||
//drop bonus if it's not our creature and (we don`t check upgrades or its not our upgrade)
|
||||
}
|
||||
|
||||
CCreatureTypeLimiter::CCreatureTypeLimiter(const CCreature & creature_, bool IncludeUpgrades)
|
||||
: creature(&creature_), includeUpgrades(IncludeUpgrades)
|
||||
{
|
||||
}
|
||||
|
||||
void CCreatureTypeLimiter::setCreature(const CreatureID & id)
|
||||
{
|
||||
creature = VLC->creh->objects[id];
|
||||
}
|
||||
|
||||
std::string CCreatureTypeLimiter::toString() const
|
||||
{
|
||||
boost::format fmt("CCreatureTypeLimiter(creature=%s, includeUpgrades=%s)");
|
||||
fmt % creature->getJsonKey() % (includeUpgrades ? "true" : "false");
|
||||
return fmt.str();
|
||||
}
|
||||
|
||||
JsonNode CCreatureTypeLimiter::toJsonNode() const
|
||||
{
|
||||
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
||||
|
||||
root["type"].String() = "CREATURE_TYPE_LIMITER";
|
||||
root["parameters"].Vector().push_back(JsonUtils::stringNode(creature->getJsonKey()));
|
||||
root["parameters"].Vector().push_back(JsonUtils::boolNode(includeUpgrades));
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
HasAnotherBonusLimiter::HasAnotherBonusLimiter( Bonus::BonusType bonus )
|
||||
: type(bonus), subtype(0), isSubtypeRelevant(false), isSourceRelevant(false), isSourceIDRelevant(false)
|
||||
{
|
||||
}
|
||||
|
||||
HasAnotherBonusLimiter::HasAnotherBonusLimiter( Bonus::BonusType bonus, TBonusSubtype _subtype )
|
||||
: type(bonus), subtype(_subtype), isSubtypeRelevant(true), isSourceRelevant(false), isSourceIDRelevant(false)
|
||||
{
|
||||
}
|
||||
|
||||
HasAnotherBonusLimiter::HasAnotherBonusLimiter(Bonus::BonusType bonus, Bonus::BonusSource src)
|
||||
: type(bonus), source(src), isSubtypeRelevant(false), isSourceRelevant(true), isSourceIDRelevant(false)
|
||||
{
|
||||
}
|
||||
|
||||
HasAnotherBonusLimiter::HasAnotherBonusLimiter(Bonus::BonusType bonus, TBonusSubtype _subtype, Bonus::BonusSource src)
|
||||
: type(bonus), subtype(_subtype), isSubtypeRelevant(true), source(src), isSourceRelevant(true), isSourceIDRelevant(false)
|
||||
{
|
||||
}
|
||||
|
||||
ILimiter::EDecision HasAnotherBonusLimiter::limit(const BonusLimitationContext &context) const
|
||||
{
|
||||
//TODO: proper selector config with parsing of JSON
|
||||
auto mySelector = Selector::type()(type);
|
||||
|
||||
if(isSubtypeRelevant)
|
||||
mySelector = mySelector.And(Selector::subtype()(subtype));
|
||||
if(isSourceRelevant && isSourceIDRelevant)
|
||||
mySelector = mySelector.And(Selector::source(source, sid));
|
||||
else if (isSourceRelevant)
|
||||
mySelector = mySelector.And(Selector::sourceTypeSel(source));
|
||||
|
||||
//if we have a bonus of required type accepted, limiter should accept also this bonus
|
||||
if(context.alreadyAccepted.getFirst(mySelector))
|
||||
return ILimiter::EDecision::ACCEPT;
|
||||
|
||||
//if there are no matching bonuses pending, we can (and must) reject right away
|
||||
if(!context.stillUndecided.getFirst(mySelector))
|
||||
return ILimiter::EDecision::DISCARD;
|
||||
|
||||
//do not accept for now but it may change if more bonuses gets included
|
||||
return ILimiter::EDecision::NOT_SURE;
|
||||
}
|
||||
|
||||
std::string HasAnotherBonusLimiter::toString() const
|
||||
{
|
||||
std::string typeName = vstd::findKey(bonusNameMap, type);
|
||||
if(isSubtypeRelevant)
|
||||
{
|
||||
boost::format fmt("HasAnotherBonusLimiter(type=%s, subtype=%d)");
|
||||
fmt % typeName % subtype;
|
||||
return fmt.str();
|
||||
}
|
||||
else
|
||||
{
|
||||
boost::format fmt("HasAnotherBonusLimiter(type=%s)");
|
||||
fmt % typeName;
|
||||
return fmt.str();
|
||||
}
|
||||
}
|
||||
|
||||
JsonNode HasAnotherBonusLimiter::toJsonNode() const
|
||||
{
|
||||
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
||||
std::string typeName = vstd::findKey(bonusNameMap, type);
|
||||
auto sourceTypeName = vstd::findKey(bonusSourceMap, source);
|
||||
|
||||
root["type"].String() = "HAS_ANOTHER_BONUS_LIMITER";
|
||||
root["parameters"].Vector().push_back(JsonUtils::stringNode(typeName));
|
||||
if(isSubtypeRelevant)
|
||||
root["parameters"].Vector().push_back(JsonUtils::intNode(subtype));
|
||||
if(isSourceRelevant)
|
||||
root["parameters"].Vector().push_back(JsonUtils::stringNode(sourceTypeName));
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
ILimiter::EDecision UnitOnHexLimiter::limit(const BonusLimitationContext &context) const
|
||||
{
|
||||
const auto * stack = retrieveStackBattle(&context.node);
|
||||
if(!stack)
|
||||
return ILimiter::EDecision::DISCARD;
|
||||
|
||||
auto accept = false;
|
||||
for (const auto & hex : stack->getHexes())
|
||||
accept |= !!applicableHexes.count(hex);
|
||||
|
||||
return accept ? ILimiter::EDecision::ACCEPT : ILimiter::EDecision::DISCARD;
|
||||
}
|
||||
|
||||
UnitOnHexLimiter::UnitOnHexLimiter(const std::set<BattleHex> & applicableHexes):
|
||||
applicableHexes(applicableHexes)
|
||||
{
|
||||
}
|
||||
|
||||
JsonNode UnitOnHexLimiter::toJsonNode() const
|
||||
{
|
||||
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
||||
|
||||
root["type"].String() = "UNIT_ON_HEXES";
|
||||
for(const auto & hex : applicableHexes)
|
||||
root["parameters"].Vector().push_back(JsonUtils::intNode(hex));
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
bool IPropagator::shouldBeAttached(CBonusSystemNode *dest)
|
||||
{
|
||||
return false;
|
||||
@@ -2222,302 +2009,6 @@ bool CPropagatorNodeType::shouldBeAttached(CBonusSystemNode *dest)
|
||||
return nodeType == dest->getNodeType();
|
||||
}
|
||||
|
||||
CreatureTerrainLimiter::CreatureTerrainLimiter()
|
||||
: terrainType(ETerrainId::NATIVE_TERRAIN)
|
||||
{
|
||||
}
|
||||
|
||||
CreatureTerrainLimiter::CreatureTerrainLimiter(TerrainId terrain):
|
||||
terrainType(terrain)
|
||||
{
|
||||
}
|
||||
|
||||
ILimiter::EDecision CreatureTerrainLimiter::limit(const BonusLimitationContext &context) const
|
||||
{
|
||||
const CStack *stack = retrieveStackBattle(&context.node);
|
||||
if(stack)
|
||||
{
|
||||
if (terrainType == ETerrainId::NATIVE_TERRAIN && stack->isOnNativeTerrain())//terrainType not specified = native
|
||||
return ILimiter::EDecision::ACCEPT;
|
||||
|
||||
if(terrainType != ETerrainId::NATIVE_TERRAIN && stack->isOnTerrain(terrainType))
|
||||
return ILimiter::EDecision::ACCEPT;
|
||||
|
||||
}
|
||||
return ILimiter::EDecision::DISCARD;
|
||||
//TODO neutral creatues
|
||||
}
|
||||
|
||||
std::string CreatureTerrainLimiter::toString() const
|
||||
{
|
||||
boost::format fmt("CreatureTerrainLimiter(terrainType=%s)");
|
||||
auto terrainName = VLC->terrainTypeHandler->getById(terrainType)->getJsonKey();
|
||||
fmt % (terrainType == ETerrainId::NATIVE_TERRAIN ? "native" : terrainName);
|
||||
return fmt.str();
|
||||
}
|
||||
|
||||
JsonNode CreatureTerrainLimiter::toJsonNode() const
|
||||
{
|
||||
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
||||
|
||||
root["type"].String() = "CREATURE_TERRAIN_LIMITER";
|
||||
auto terrainName = VLC->terrainTypeHandler->getById(terrainType)->getJsonKey();
|
||||
root["parameters"].Vector().push_back(JsonUtils::stringNode(terrainName));
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
FactionLimiter::FactionLimiter(FactionID creatureFaction)
|
||||
: faction(creatureFaction)
|
||||
{
|
||||
}
|
||||
|
||||
ILimiter::EDecision FactionLimiter::limit(const BonusLimitationContext &context) const
|
||||
{
|
||||
const auto * bearer = dynamic_cast<const INativeTerrainProvider*>(&context.node);
|
||||
|
||||
if(bearer)
|
||||
{
|
||||
if(faction != FactionID::DEFAULT)
|
||||
return bearer->getFaction() == faction ? ILimiter::EDecision::ACCEPT : ILimiter::EDecision::DISCARD;
|
||||
|
||||
switch(context.b->source)
|
||||
{
|
||||
case Bonus::CREATURE_ABILITY:
|
||||
return faction == CreatureID(context.b->sid).toCreature()->getFaction() ? ILimiter::EDecision::ACCEPT : ILimiter::EDecision::DISCARD;
|
||||
|
||||
case Bonus::TOWN_STRUCTURE:
|
||||
return faction == FactionID(Bonus::getHighFromSid32(context.b->sid)) ? ILimiter::EDecision::ACCEPT : ILimiter::EDecision::DISCARD;
|
||||
|
||||
//TODO: other sources of bonuses
|
||||
}
|
||||
}
|
||||
return ILimiter::EDecision::DISCARD; //Discard by default
|
||||
}
|
||||
|
||||
std::string FactionLimiter::toString() const
|
||||
{
|
||||
boost::format fmt("FactionLimiter(faction=%s)");
|
||||
fmt % VLC->factions()->getByIndex(faction)->getJsonKey();
|
||||
return fmt.str();
|
||||
}
|
||||
|
||||
JsonNode FactionLimiter::toJsonNode() const
|
||||
{
|
||||
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
||||
|
||||
root["type"].String() = "FACTION_LIMITER";
|
||||
root["parameters"].Vector().push_back(JsonUtils::stringNode(VLC->factions()->getByIndex(faction)->getJsonKey()));
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
CreatureLevelLimiter::CreatureLevelLimiter(uint32_t minLevel, uint32_t maxLevel) :
|
||||
minLevel(minLevel),
|
||||
maxLevel(maxLevel)
|
||||
{
|
||||
}
|
||||
|
||||
ILimiter::EDecision CreatureLevelLimiter::limit(const BonusLimitationContext &context) const
|
||||
{
|
||||
const auto *c = retrieveCreature(&context.node);
|
||||
auto accept = c && (c->getLevel() < maxLevel && c->getLevel() >= minLevel);
|
||||
return accept ? ILimiter::EDecision::ACCEPT : ILimiter::EDecision::DISCARD; //drop bonus for non-creatures or non-native residents
|
||||
}
|
||||
|
||||
std::string CreatureLevelLimiter::toString() const
|
||||
{
|
||||
boost::format fmt("CreatureLevelLimiter(minLevel=%d,maxLevel=%d)");
|
||||
fmt % minLevel % maxLevel;
|
||||
return fmt.str();
|
||||
}
|
||||
|
||||
JsonNode CreatureLevelLimiter::toJsonNode() const
|
||||
{
|
||||
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
||||
|
||||
root["type"].String() = "CREATURE_LEVEL_LIMITER";
|
||||
root["parameters"].Vector().push_back(JsonUtils::intNode(minLevel));
|
||||
root["parameters"].Vector().push_back(JsonUtils::intNode(maxLevel));
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
CreatureAlignmentLimiter::CreatureAlignmentLimiter(EAlignment Alignment)
|
||||
: alignment(Alignment)
|
||||
{
|
||||
}
|
||||
|
||||
ILimiter::EDecision CreatureAlignmentLimiter::limit(const BonusLimitationContext &context) const
|
||||
{
|
||||
const auto * c = retrieveCreature(&context.node);
|
||||
if(c) {
|
||||
if(alignment == EAlignment::GOOD && c->isGood())
|
||||
return ILimiter::EDecision::ACCEPT;
|
||||
if(alignment == EAlignment::EVIL && c->isEvil())
|
||||
return ILimiter::EDecision::ACCEPT;
|
||||
if(alignment == EAlignment::NEUTRAL && !c->isEvil() && !c->isGood())
|
||||
return ILimiter::EDecision::ACCEPT;
|
||||
}
|
||||
|
||||
return ILimiter::EDecision::DISCARD;
|
||||
}
|
||||
|
||||
std::string CreatureAlignmentLimiter::toString() const
|
||||
{
|
||||
boost::format fmt("CreatureAlignmentLimiter(alignment=%s)");
|
||||
fmt % GameConstants::ALIGNMENT_NAMES[vstd::to_underlying(alignment)];
|
||||
return fmt.str();
|
||||
}
|
||||
|
||||
JsonNode CreatureAlignmentLimiter::toJsonNode() const
|
||||
{
|
||||
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
||||
|
||||
root["type"].String() = "CREATURE_ALIGNMENT_LIMITER";
|
||||
root["parameters"].Vector().push_back(JsonUtils::stringNode(GameConstants::ALIGNMENT_NAMES[vstd::to_underlying(alignment)]));
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
RankRangeLimiter::RankRangeLimiter(ui8 Min, ui8 Max)
|
||||
:minRank(Min), maxRank(Max)
|
||||
{
|
||||
}
|
||||
|
||||
RankRangeLimiter::RankRangeLimiter()
|
||||
{
|
||||
minRank = maxRank = -1;
|
||||
}
|
||||
|
||||
ILimiter::EDecision RankRangeLimiter::limit(const BonusLimitationContext &context) const
|
||||
{
|
||||
const CStackInstance * csi = retrieveStackInstance(&context.node);
|
||||
if(csi)
|
||||
{
|
||||
if (csi->getNodeType() == CBonusSystemNode::COMMANDER) //no stack exp bonuses for commander creatures
|
||||
return ILimiter::EDecision::DISCARD;
|
||||
if (csi->getExpRank() > minRank && csi->getExpRank() < maxRank)
|
||||
return ILimiter::EDecision::ACCEPT;
|
||||
}
|
||||
return ILimiter::EDecision::DISCARD;
|
||||
}
|
||||
|
||||
OppositeSideLimiter::OppositeSideLimiter(PlayerColor Owner):
|
||||
owner(std::move(Owner))
|
||||
{
|
||||
}
|
||||
|
||||
ILimiter::EDecision OppositeSideLimiter::limit(const BonusLimitationContext & context) const
|
||||
{
|
||||
auto contextOwner = CBonusSystemNode::retrieveNodeOwner(& context.node);
|
||||
auto decision = (owner == contextOwner || owner == PlayerColor::CANNOT_DETERMINE) ? ILimiter::EDecision::DISCARD : ILimiter::EDecision::ACCEPT;
|
||||
return decision;
|
||||
}
|
||||
|
||||
// Aggregate/Boolean Limiters
|
||||
|
||||
AggregateLimiter::AggregateLimiter(std::vector<TLimiterPtr> limiters):
|
||||
limiters(std::move(limiters))
|
||||
{
|
||||
}
|
||||
|
||||
void AggregateLimiter::add(const TLimiterPtr & limiter)
|
||||
{
|
||||
if(limiter)
|
||||
limiters.push_back(limiter);
|
||||
}
|
||||
|
||||
JsonNode AggregateLimiter::toJsonNode() const
|
||||
{
|
||||
JsonNode result(JsonNode::JsonType::DATA_VECTOR);
|
||||
result.Vector().push_back(JsonUtils::stringNode(getAggregator()));
|
||||
for(const auto & l : limiters)
|
||||
result.Vector().push_back(l->toJsonNode());
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::string AllOfLimiter::aggregator = "allOf";
|
||||
const std::string & AllOfLimiter::getAggregator() const
|
||||
{
|
||||
return aggregator;
|
||||
}
|
||||
|
||||
AllOfLimiter::AllOfLimiter(std::vector<TLimiterPtr> limiters):
|
||||
AggregateLimiter(limiters)
|
||||
{
|
||||
}
|
||||
|
||||
ILimiter::EDecision AllOfLimiter::limit(const BonusLimitationContext & context) const
|
||||
{
|
||||
bool wasntSure = false;
|
||||
|
||||
for(const auto & limiter : limiters)
|
||||
{
|
||||
auto result = limiter->limit(context);
|
||||
if(result == ILimiter::EDecision::DISCARD)
|
||||
return result;
|
||||
if(result == ILimiter::EDecision::NOT_SURE)
|
||||
wasntSure = true;
|
||||
}
|
||||
|
||||
return wasntSure ? ILimiter::EDecision::NOT_SURE : ILimiter::EDecision::ACCEPT;
|
||||
}
|
||||
|
||||
const std::string AnyOfLimiter::aggregator = "anyOf";
|
||||
const std::string & AnyOfLimiter::getAggregator() const
|
||||
{
|
||||
return aggregator;
|
||||
}
|
||||
|
||||
AnyOfLimiter::AnyOfLimiter(std::vector<TLimiterPtr> limiters):
|
||||
AggregateLimiter(limiters)
|
||||
{
|
||||
}
|
||||
|
||||
ILimiter::EDecision AnyOfLimiter::limit(const BonusLimitationContext & context) const
|
||||
{
|
||||
bool wasntSure = false;
|
||||
|
||||
for(const auto & limiter : limiters)
|
||||
{
|
||||
auto result = limiter->limit(context);
|
||||
if(result == ILimiter::EDecision::ACCEPT)
|
||||
return result;
|
||||
if(result == ILimiter::EDecision::NOT_SURE)
|
||||
wasntSure = true;
|
||||
}
|
||||
|
||||
return wasntSure ? ILimiter::EDecision::NOT_SURE : ILimiter::EDecision::DISCARD;
|
||||
}
|
||||
|
||||
const std::string NoneOfLimiter::aggregator = "noneOf";
|
||||
const std::string & NoneOfLimiter::getAggregator() const
|
||||
{
|
||||
return aggregator;
|
||||
}
|
||||
|
||||
NoneOfLimiter::NoneOfLimiter(std::vector<TLimiterPtr> limiters):
|
||||
AggregateLimiter(limiters)
|
||||
{
|
||||
}
|
||||
|
||||
ILimiter::EDecision NoneOfLimiter::limit(const BonusLimitationContext & context) const
|
||||
{
|
||||
bool wasntSure = false;
|
||||
|
||||
for(const auto & limiter : limiters)
|
||||
{
|
||||
auto result = limiter->limit(context);
|
||||
if(result == ILimiter::EDecision::ACCEPT)
|
||||
return ILimiter::EDecision::DISCARD;
|
||||
if(result == ILimiter::EDecision::NOT_SURE)
|
||||
wasntSure = true;
|
||||
}
|
||||
|
||||
return wasntSure ? ILimiter::EDecision::NOT_SURE : ILimiter::EDecision::ACCEPT;
|
||||
}
|
||||
|
||||
// Updaters
|
||||
|
||||
std::shared_ptr<Bonus> Bonus::addUpdater(const TUpdaterPtr & Updater)
|
||||
|
@@ -9,10 +9,8 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "GameConstants.h"
|
||||
#include "JsonNode.h"
|
||||
#include "battle/BattleHex.h"
|
||||
#include <limits>
|
||||
#include "../GameConstants.h"
|
||||
#include "../JsonNode.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
@@ -662,29 +660,6 @@ public:
|
||||
|
||||
DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const BonusList &bonusList);
|
||||
|
||||
struct BonusLimitationContext
|
||||
{
|
||||
std::shared_ptr<const Bonus> b;
|
||||
const CBonusSystemNode & node;
|
||||
const BonusList & alreadyAccepted;
|
||||
const BonusList & stillUndecided;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE ILimiter
|
||||
{
|
||||
public:
|
||||
enum class EDecision : uint8_t {ACCEPT, DISCARD, NOT_SURE};
|
||||
|
||||
virtual ~ILimiter() = default;
|
||||
|
||||
virtual EDecision limit(const BonusLimitationContext &context) const; //0 - accept bonus; 1 - drop bonus; 2 - delay (drops eventually)
|
||||
virtual std::string toString() const;
|
||||
virtual JsonNode toJsonNode() const;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE IBonusBearer
|
||||
{
|
||||
@@ -964,227 +939,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE AggregateLimiter : public ILimiter
|
||||
{
|
||||
protected:
|
||||
std::vector<TLimiterPtr> limiters;
|
||||
virtual const std::string & getAggregator() const = 0;
|
||||
AggregateLimiter(std::vector<TLimiterPtr> limiters = {});
|
||||
public:
|
||||
void add(const TLimiterPtr & limiter);
|
||||
JsonNode toJsonNode() const override;
|
||||
|
||||
template <typename Handler> void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & static_cast<ILimiter&>(*this);
|
||||
h & limiters;
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE AllOfLimiter : public AggregateLimiter
|
||||
{
|
||||
protected:
|
||||
const std::string & getAggregator() const override;
|
||||
public:
|
||||
AllOfLimiter(std::vector<TLimiterPtr> limiters = {});
|
||||
static const std::string aggregator;
|
||||
EDecision limit(const BonusLimitationContext & context) const override;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE AnyOfLimiter : public AggregateLimiter
|
||||
{
|
||||
protected:
|
||||
const std::string & getAggregator() const override;
|
||||
public:
|
||||
AnyOfLimiter(std::vector<TLimiterPtr> limiters = {});
|
||||
static const std::string aggregator;
|
||||
EDecision limit(const BonusLimitationContext & context) const override;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE NoneOfLimiter : public AggregateLimiter
|
||||
{
|
||||
protected:
|
||||
const std::string & getAggregator() const override;
|
||||
public:
|
||||
NoneOfLimiter(std::vector<TLimiterPtr> limiters = {});
|
||||
static const std::string aggregator;
|
||||
EDecision limit(const BonusLimitationContext & context) const override;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CCreatureTypeLimiter : public ILimiter //affect only stacks of given creature (and optionally it's upgrades)
|
||||
{
|
||||
public:
|
||||
const CCreature * creature = nullptr;
|
||||
bool includeUpgrades = false;
|
||||
|
||||
CCreatureTypeLimiter() = default;
|
||||
CCreatureTypeLimiter(const CCreature & creature_, bool IncludeUpgrades);
|
||||
void setCreature(const CreatureID & id);
|
||||
|
||||
EDecision limit(const BonusLimitationContext &context) const override;
|
||||
std::string toString() const override;
|
||||
JsonNode toJsonNode() const override;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<ILimiter&>(*this);
|
||||
h & creature;
|
||||
h & includeUpgrades;
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE HasAnotherBonusLimiter : public ILimiter //applies only to nodes that have another bonus working
|
||||
{
|
||||
public:
|
||||
Bonus::BonusType type;
|
||||
TBonusSubtype subtype;
|
||||
Bonus::BonusSource source;
|
||||
si32 sid;
|
||||
bool isSubtypeRelevant; //check for subtype only if this is true
|
||||
bool isSourceRelevant; //check for bonus source only if this is true
|
||||
bool isSourceIDRelevant; //check for bonus source only if this is true
|
||||
|
||||
HasAnotherBonusLimiter(Bonus::BonusType bonus = Bonus::NONE);
|
||||
HasAnotherBonusLimiter(Bonus::BonusType bonus, TBonusSubtype _subtype);
|
||||
HasAnotherBonusLimiter(Bonus::BonusType bonus, Bonus::BonusSource src);
|
||||
HasAnotherBonusLimiter(Bonus::BonusType bonus, TBonusSubtype _subtype, Bonus::BonusSource src);
|
||||
|
||||
EDecision limit(const BonusLimitationContext &context) const override;
|
||||
std::string toString() const override;
|
||||
JsonNode toJsonNode() const override;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<ILimiter&>(*this);
|
||||
h & type;
|
||||
h & subtype;
|
||||
h & isSubtypeRelevant;
|
||||
h & source;
|
||||
h & isSourceRelevant;
|
||||
h & sid;
|
||||
h & isSourceIDRelevant;
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CreatureTerrainLimiter : public ILimiter //applies only to creatures that are on specified terrain, default native terrain
|
||||
{
|
||||
public:
|
||||
TerrainId terrainType;
|
||||
CreatureTerrainLimiter();
|
||||
CreatureTerrainLimiter(TerrainId terrain);
|
||||
|
||||
EDecision limit(const BonusLimitationContext &context) const override;
|
||||
std::string toString() const override;
|
||||
JsonNode toJsonNode() const override;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<ILimiter&>(*this);
|
||||
h & terrainType;
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CreatureLevelLimiter : public ILimiter //applies only to creatures of given faction
|
||||
{
|
||||
public:
|
||||
uint32_t minLevel;
|
||||
uint32_t maxLevel;
|
||||
//accept all levels by default, accept creatures of minLevel <= creature->getLevel() < maxLevel
|
||||
CreatureLevelLimiter(uint32_t minLevel = std::numeric_limits<uint32_t>::min(), uint32_t maxLevel = std::numeric_limits<uint32_t>::max());
|
||||
|
||||
EDecision limit(const BonusLimitationContext &context) const override;
|
||||
std::string toString() const override;
|
||||
JsonNode toJsonNode() const override;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<ILimiter&>(*this);
|
||||
h & minLevel;
|
||||
h & maxLevel;
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE FactionLimiter : public ILimiter //applies only to creatures of given faction
|
||||
{
|
||||
public:
|
||||
FactionID faction;
|
||||
FactionLimiter(FactionID faction = FactionID::DEFAULT);
|
||||
|
||||
EDecision limit(const BonusLimitationContext &context) const override;
|
||||
std::string toString() const override;
|
||||
JsonNode toJsonNode() const override;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<ILimiter&>(*this);
|
||||
h & faction;
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CreatureAlignmentLimiter : public ILimiter //applies only to creatures of given alignment
|
||||
{
|
||||
public:
|
||||
EAlignment alignment;
|
||||
CreatureAlignmentLimiter(EAlignment Alignment = EAlignment::NEUTRAL);
|
||||
|
||||
EDecision limit(const BonusLimitationContext &context) const override;
|
||||
std::string toString() const override;
|
||||
JsonNode toJsonNode() const override;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<ILimiter&>(*this);
|
||||
h & alignment;
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE OppositeSideLimiter : public ILimiter //applies only to creatures of enemy army during combat
|
||||
{
|
||||
public:
|
||||
PlayerColor owner;
|
||||
OppositeSideLimiter(PlayerColor Owner = PlayerColor::CANNOT_DETERMINE);
|
||||
|
||||
EDecision limit(const BonusLimitationContext &context) const override;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<ILimiter&>(*this);
|
||||
h & owner;
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE RankRangeLimiter : public ILimiter //applies to creatures with min <= Rank <= max
|
||||
{
|
||||
public:
|
||||
ui8 minRank, maxRank;
|
||||
|
||||
RankRangeLimiter();
|
||||
RankRangeLimiter(ui8 Min, ui8 Max = 255);
|
||||
EDecision limit(const BonusLimitationContext &context) const override;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<ILimiter&>(*this);
|
||||
h & minRank;
|
||||
h & maxRank;
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE UnitOnHexLimiter : public ILimiter //works only on selected hexes
|
||||
{
|
||||
public:
|
||||
std::set<BattleHex> applicableHexes;
|
||||
|
||||
UnitOnHexLimiter(const std::set<BattleHex> & applicableHexes = {});
|
||||
EDecision limit(const BonusLimitationContext &context) const override;
|
||||
JsonNode toJsonNode() const override;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<ILimiter&>(*this);
|
||||
h & applicableHexes;
|
||||
}
|
||||
};
|
||||
|
||||
namespace Selector
|
||||
{
|
||||
@@ -1221,7 +975,6 @@ extern DLL_LINKAGE const std::map<std::string, Bonus::ValueType> bonusValueMap;
|
||||
extern DLL_LINKAGE const std::map<std::string, Bonus::BonusSource> bonusSourceMap;
|
||||
extern DLL_LINKAGE const std::map<std::string, ui16> bonusDurationMap;
|
||||
extern DLL_LINKAGE const std::map<std::string, Bonus::LimitEffect> bonusLimitEffect;
|
||||
extern DLL_LINKAGE const std::map<std::string, TLimiterPtr> bonusLimiterMap;
|
||||
extern DLL_LINKAGE const std::map<std::string, TPropagatorPtr> bonusPropagatorMap;
|
||||
extern DLL_LINKAGE const std::map<std::string, TUpdaterPtr> bonusUpdaterMap;
|
||||
extern DLL_LINKAGE const std::set<std::string> deprecatedBonusSet;
|
||||
|
541
lib/bonuses/ILimiter.cpp
Normal file
541
lib/bonuses/ILimiter.cpp
Normal file
@@ -0,0 +1,541 @@
|
||||
/*
|
||||
* ILimiter.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 "ILimiter.h"
|
||||
|
||||
#include "../VCMI_Lib.h"
|
||||
#include "../spells/CSpellHandler.h"
|
||||
#include "../CCreatureHandler.h"
|
||||
#include "../CCreatureSet.h"
|
||||
#include "../CHeroHandler.h"
|
||||
#include "../CTownHandler.h"
|
||||
#include "../CGeneralTextHandler.h"
|
||||
#include "../CSkillHandler.h"
|
||||
#include "../CStack.h"
|
||||
#include "../CArtHandler.h"
|
||||
#include "../CModHandler.h"
|
||||
#include "../TerrainHandler.h"
|
||||
#include "../StringConstants.h"
|
||||
#include "../battle/BattleInfo.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
const std::map<std::string, TLimiterPtr> bonusLimiterMap =
|
||||
{
|
||||
{"SHOOTER_ONLY", std::make_shared<HasAnotherBonusLimiter>(Bonus::SHOOTER)},
|
||||
{"DRAGON_NATURE", std::make_shared<HasAnotherBonusLimiter>(Bonus::DRAGON_NATURE)},
|
||||
{"IS_UNDEAD", std::make_shared<HasAnotherBonusLimiter>(Bonus::UNDEAD)},
|
||||
{"CREATURE_NATIVE_TERRAIN", std::make_shared<CreatureTerrainLimiter>()},
|
||||
{"CREATURE_FACTION", std::make_shared<AllOfLimiter>(std::initializer_list<TLimiterPtr>{std::make_shared<CreatureLevelLimiter>(), std::make_shared<FactionLimiter>()})},
|
||||
{"SAME_FACTION", std::make_shared<FactionLimiter>()},
|
||||
{"CREATURES_ONLY", std::make_shared<CreatureLevelLimiter>()},
|
||||
{"OPPOSITE_SIDE", std::make_shared<OppositeSideLimiter>()},
|
||||
};
|
||||
|
||||
static const CStack * retrieveStackBattle(const CBonusSystemNode * node)
|
||||
{
|
||||
switch(node->getNodeType())
|
||||
{
|
||||
case CBonusSystemNode::STACK_BATTLE:
|
||||
return dynamic_cast<const CStack *>(node);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static const CStackInstance * retrieveStackInstance(const CBonusSystemNode * node)
|
||||
{
|
||||
switch(node->getNodeType())
|
||||
{
|
||||
case CBonusSystemNode::STACK_INSTANCE:
|
||||
return (dynamic_cast<const CStackInstance *>(node));
|
||||
case CBonusSystemNode::STACK_BATTLE:
|
||||
return (dynamic_cast<const CStack *>(node))->base;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static const CCreature * retrieveCreature(const CBonusSystemNode *node)
|
||||
{
|
||||
switch(node->getNodeType())
|
||||
{
|
||||
case CBonusSystemNode::CREATURE:
|
||||
return (dynamic_cast<const CCreature *>(node));
|
||||
case CBonusSystemNode::STACK_BATTLE:
|
||||
return (dynamic_cast<const CStack *>(node))->unitType();
|
||||
default:
|
||||
const CStackInstance * csi = retrieveStackInstance(node);
|
||||
if(csi)
|
||||
return csi->type;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
ILimiter::EDecision ILimiter::limit(const BonusLimitationContext &context) const /*return true to drop the bonus */
|
||||
{
|
||||
return ILimiter::EDecision::ACCEPT;
|
||||
}
|
||||
|
||||
std::string ILimiter::toString() const
|
||||
{
|
||||
return typeid(*this).name();
|
||||
}
|
||||
|
||||
JsonNode ILimiter::toJsonNode() const
|
||||
{
|
||||
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
||||
root["type"].String() = toString();
|
||||
return root;
|
||||
}
|
||||
|
||||
ILimiter::EDecision CCreatureTypeLimiter::limit(const BonusLimitationContext &context) const
|
||||
{
|
||||
const CCreature *c = retrieveCreature(&context.node);
|
||||
if(!c)
|
||||
return ILimiter::EDecision::DISCARD;
|
||||
|
||||
auto accept = c->getId() == creature->getId() || (includeUpgrades && creature->isMyUpgrade(c));
|
||||
return accept ? ILimiter::EDecision::ACCEPT : ILimiter::EDecision::DISCARD;
|
||||
//drop bonus if it's not our creature and (we don`t check upgrades or its not our upgrade)
|
||||
}
|
||||
|
||||
CCreatureTypeLimiter::CCreatureTypeLimiter(const CCreature & creature_, bool IncludeUpgrades)
|
||||
: creature(&creature_), includeUpgrades(IncludeUpgrades)
|
||||
{
|
||||
}
|
||||
|
||||
void CCreatureTypeLimiter::setCreature(const CreatureID & id)
|
||||
{
|
||||
creature = VLC->creh->objects[id];
|
||||
}
|
||||
|
||||
std::string CCreatureTypeLimiter::toString() const
|
||||
{
|
||||
boost::format fmt("CCreatureTypeLimiter(creature=%s, includeUpgrades=%s)");
|
||||
fmt % creature->getJsonKey() % (includeUpgrades ? "true" : "false");
|
||||
return fmt.str();
|
||||
}
|
||||
|
||||
JsonNode CCreatureTypeLimiter::toJsonNode() const
|
||||
{
|
||||
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
||||
|
||||
root["type"].String() = "CREATURE_TYPE_LIMITER";
|
||||
root["parameters"].Vector().push_back(JsonUtils::stringNode(creature->getJsonKey()));
|
||||
root["parameters"].Vector().push_back(JsonUtils::boolNode(includeUpgrades));
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
HasAnotherBonusLimiter::HasAnotherBonusLimiter( Bonus::BonusType bonus )
|
||||
: type(bonus), subtype(0), isSubtypeRelevant(false), isSourceRelevant(false), isSourceIDRelevant(false)
|
||||
{
|
||||
}
|
||||
|
||||
HasAnotherBonusLimiter::HasAnotherBonusLimiter( Bonus::BonusType bonus, TBonusSubtype _subtype )
|
||||
: type(bonus), subtype(_subtype), isSubtypeRelevant(true), isSourceRelevant(false), isSourceIDRelevant(false)
|
||||
{
|
||||
}
|
||||
|
||||
HasAnotherBonusLimiter::HasAnotherBonusLimiter(Bonus::BonusType bonus, Bonus::BonusSource src)
|
||||
: type(bonus), source(src), isSubtypeRelevant(false), isSourceRelevant(true), isSourceIDRelevant(false)
|
||||
{
|
||||
}
|
||||
|
||||
HasAnotherBonusLimiter::HasAnotherBonusLimiter(Bonus::BonusType bonus, TBonusSubtype _subtype, Bonus::BonusSource src)
|
||||
: type(bonus), subtype(_subtype), isSubtypeRelevant(true), source(src), isSourceRelevant(true), isSourceIDRelevant(false)
|
||||
{
|
||||
}
|
||||
|
||||
ILimiter::EDecision HasAnotherBonusLimiter::limit(const BonusLimitationContext &context) const
|
||||
{
|
||||
//TODO: proper selector config with parsing of JSON
|
||||
auto mySelector = Selector::type()(type);
|
||||
|
||||
if(isSubtypeRelevant)
|
||||
mySelector = mySelector.And(Selector::subtype()(subtype));
|
||||
if(isSourceRelevant && isSourceIDRelevant)
|
||||
mySelector = mySelector.And(Selector::source(source, sid));
|
||||
else if (isSourceRelevant)
|
||||
mySelector = mySelector.And(Selector::sourceTypeSel(source));
|
||||
|
||||
//if we have a bonus of required type accepted, limiter should accept also this bonus
|
||||
if(context.alreadyAccepted.getFirst(mySelector))
|
||||
return ILimiter::EDecision::ACCEPT;
|
||||
|
||||
//if there are no matching bonuses pending, we can (and must) reject right away
|
||||
if(!context.stillUndecided.getFirst(mySelector))
|
||||
return ILimiter::EDecision::DISCARD;
|
||||
|
||||
//do not accept for now but it may change if more bonuses gets included
|
||||
return ILimiter::EDecision::NOT_SURE;
|
||||
}
|
||||
|
||||
std::string HasAnotherBonusLimiter::toString() const
|
||||
{
|
||||
std::string typeName = vstd::findKey(bonusNameMap, type);
|
||||
if(isSubtypeRelevant)
|
||||
{
|
||||
boost::format fmt("HasAnotherBonusLimiter(type=%s, subtype=%d)");
|
||||
fmt % typeName % subtype;
|
||||
return fmt.str();
|
||||
}
|
||||
else
|
||||
{
|
||||
boost::format fmt("HasAnotherBonusLimiter(type=%s)");
|
||||
fmt % typeName;
|
||||
return fmt.str();
|
||||
}
|
||||
}
|
||||
|
||||
JsonNode HasAnotherBonusLimiter::toJsonNode() const
|
||||
{
|
||||
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
||||
std::string typeName = vstd::findKey(bonusNameMap, type);
|
||||
auto sourceTypeName = vstd::findKey(bonusSourceMap, source);
|
||||
|
||||
root["type"].String() = "HAS_ANOTHER_BONUS_LIMITER";
|
||||
root["parameters"].Vector().push_back(JsonUtils::stringNode(typeName));
|
||||
if(isSubtypeRelevant)
|
||||
root["parameters"].Vector().push_back(JsonUtils::intNode(subtype));
|
||||
if(isSourceRelevant)
|
||||
root["parameters"].Vector().push_back(JsonUtils::stringNode(sourceTypeName));
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
ILimiter::EDecision UnitOnHexLimiter::limit(const BonusLimitationContext &context) const
|
||||
{
|
||||
const auto * stack = retrieveStackBattle(&context.node);
|
||||
if(!stack)
|
||||
return ILimiter::EDecision::DISCARD;
|
||||
|
||||
auto accept = false;
|
||||
for (const auto & hex : stack->getHexes())
|
||||
accept |= !!applicableHexes.count(hex);
|
||||
|
||||
return accept ? ILimiter::EDecision::ACCEPT : ILimiter::EDecision::DISCARD;
|
||||
}
|
||||
|
||||
UnitOnHexLimiter::UnitOnHexLimiter(const std::set<BattleHex> & applicableHexes):
|
||||
applicableHexes(applicableHexes)
|
||||
{
|
||||
}
|
||||
|
||||
JsonNode UnitOnHexLimiter::toJsonNode() const
|
||||
{
|
||||
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
||||
|
||||
root["type"].String() = "UNIT_ON_HEXES";
|
||||
for(const auto & hex : applicableHexes)
|
||||
root["parameters"].Vector().push_back(JsonUtils::intNode(hex));
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
CreatureTerrainLimiter::CreatureTerrainLimiter()
|
||||
: terrainType(ETerrainId::NATIVE_TERRAIN)
|
||||
{
|
||||
}
|
||||
|
||||
CreatureTerrainLimiter::CreatureTerrainLimiter(TerrainId terrain):
|
||||
terrainType(terrain)
|
||||
{
|
||||
}
|
||||
|
||||
ILimiter::EDecision CreatureTerrainLimiter::limit(const BonusLimitationContext &context) const
|
||||
{
|
||||
const CStack *stack = retrieveStackBattle(&context.node);
|
||||
if(stack)
|
||||
{
|
||||
if (terrainType == ETerrainId::NATIVE_TERRAIN && stack->isOnNativeTerrain())//terrainType not specified = native
|
||||
return ILimiter::EDecision::ACCEPT;
|
||||
|
||||
if(terrainType != ETerrainId::NATIVE_TERRAIN && stack->isOnTerrain(terrainType))
|
||||
return ILimiter::EDecision::ACCEPT;
|
||||
|
||||
}
|
||||
return ILimiter::EDecision::DISCARD;
|
||||
//TODO neutral creatues
|
||||
}
|
||||
|
||||
std::string CreatureTerrainLimiter::toString() const
|
||||
{
|
||||
boost::format fmt("CreatureTerrainLimiter(terrainType=%s)");
|
||||
auto terrainName = VLC->terrainTypeHandler->getById(terrainType)->getJsonKey();
|
||||
fmt % (terrainType == ETerrainId::NATIVE_TERRAIN ? "native" : terrainName);
|
||||
return fmt.str();
|
||||
}
|
||||
|
||||
JsonNode CreatureTerrainLimiter::toJsonNode() const
|
||||
{
|
||||
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
||||
|
||||
root["type"].String() = "CREATURE_TERRAIN_LIMITER";
|
||||
auto terrainName = VLC->terrainTypeHandler->getById(terrainType)->getJsonKey();
|
||||
root["parameters"].Vector().push_back(JsonUtils::stringNode(terrainName));
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
FactionLimiter::FactionLimiter(FactionID creatureFaction)
|
||||
: faction(creatureFaction)
|
||||
{
|
||||
}
|
||||
|
||||
ILimiter::EDecision FactionLimiter::limit(const BonusLimitationContext &context) const
|
||||
{
|
||||
const auto * bearer = dynamic_cast<const INativeTerrainProvider*>(&context.node);
|
||||
|
||||
if(bearer)
|
||||
{
|
||||
if(faction != FactionID::DEFAULT)
|
||||
return bearer->getFaction() == faction ? ILimiter::EDecision::ACCEPT : ILimiter::EDecision::DISCARD;
|
||||
|
||||
switch(context.b.source)
|
||||
{
|
||||
case Bonus::CREATURE_ABILITY:
|
||||
return bearer->getFaction() == CreatureID(context.b.sid).toCreature()->getFaction() ? ILimiter::EDecision::ACCEPT : ILimiter::EDecision::DISCARD;
|
||||
|
||||
case Bonus::TOWN_STRUCTURE:
|
||||
return bearer->getFaction() == FactionID(Bonus::getHighFromSid32(context.b.sid)) ? ILimiter::EDecision::ACCEPT : ILimiter::EDecision::DISCARD;
|
||||
|
||||
//TODO: other sources of bonuses
|
||||
}
|
||||
}
|
||||
return ILimiter::EDecision::DISCARD; //Discard by default
|
||||
}
|
||||
|
||||
std::string FactionLimiter::toString() const
|
||||
{
|
||||
boost::format fmt("FactionLimiter(faction=%s)");
|
||||
fmt % VLC->factions()->getByIndex(faction)->getJsonKey();
|
||||
return fmt.str();
|
||||
}
|
||||
|
||||
JsonNode FactionLimiter::toJsonNode() const
|
||||
{
|
||||
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
||||
|
||||
root["type"].String() = "FACTION_LIMITER";
|
||||
root["parameters"].Vector().push_back(JsonUtils::stringNode(VLC->factions()->getByIndex(faction)->getJsonKey()));
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
CreatureLevelLimiter::CreatureLevelLimiter(uint32_t minLevel, uint32_t maxLevel) :
|
||||
minLevel(minLevel),
|
||||
maxLevel(maxLevel)
|
||||
{
|
||||
}
|
||||
|
||||
ILimiter::EDecision CreatureLevelLimiter::limit(const BonusLimitationContext &context) const
|
||||
{
|
||||
const auto *c = retrieveCreature(&context.node);
|
||||
auto accept = c && (c->getLevel() < maxLevel && c->getLevel() >= minLevel);
|
||||
return accept ? ILimiter::EDecision::ACCEPT : ILimiter::EDecision::DISCARD; //drop bonus for non-creatures or non-native residents
|
||||
}
|
||||
|
||||
std::string CreatureLevelLimiter::toString() const
|
||||
{
|
||||
boost::format fmt("CreatureLevelLimiter(minLevel=%d,maxLevel=%d)");
|
||||
fmt % minLevel % maxLevel;
|
||||
return fmt.str();
|
||||
}
|
||||
|
||||
JsonNode CreatureLevelLimiter::toJsonNode() const
|
||||
{
|
||||
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
||||
|
||||
root["type"].String() = "CREATURE_LEVEL_LIMITER";
|
||||
root["parameters"].Vector().push_back(JsonUtils::intNode(minLevel));
|
||||
root["parameters"].Vector().push_back(JsonUtils::intNode(maxLevel));
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
CreatureAlignmentLimiter::CreatureAlignmentLimiter(EAlignment Alignment)
|
||||
: alignment(Alignment)
|
||||
{
|
||||
}
|
||||
|
||||
ILimiter::EDecision CreatureAlignmentLimiter::limit(const BonusLimitationContext &context) const
|
||||
{
|
||||
const auto * c = retrieveCreature(&context.node);
|
||||
if(c) {
|
||||
if(alignment == EAlignment::GOOD && c->isGood())
|
||||
return ILimiter::EDecision::ACCEPT;
|
||||
if(alignment == EAlignment::EVIL && c->isEvil())
|
||||
return ILimiter::EDecision::ACCEPT;
|
||||
if(alignment == EAlignment::NEUTRAL && !c->isEvil() && !c->isGood())
|
||||
return ILimiter::EDecision::ACCEPT;
|
||||
}
|
||||
|
||||
return ILimiter::EDecision::DISCARD;
|
||||
}
|
||||
|
||||
std::string CreatureAlignmentLimiter::toString() const
|
||||
{
|
||||
boost::format fmt("CreatureAlignmentLimiter(alignment=%s)");
|
||||
fmt % GameConstants::ALIGNMENT_NAMES[vstd::to_underlying(alignment)];
|
||||
return fmt.str();
|
||||
}
|
||||
|
||||
JsonNode CreatureAlignmentLimiter::toJsonNode() const
|
||||
{
|
||||
JsonNode root(JsonNode::JsonType::DATA_STRUCT);
|
||||
|
||||
root["type"].String() = "CREATURE_ALIGNMENT_LIMITER";
|
||||
root["parameters"].Vector().push_back(JsonUtils::stringNode(GameConstants::ALIGNMENT_NAMES[vstd::to_underlying(alignment)]));
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
RankRangeLimiter::RankRangeLimiter(ui8 Min, ui8 Max)
|
||||
:minRank(Min), maxRank(Max)
|
||||
{
|
||||
}
|
||||
|
||||
RankRangeLimiter::RankRangeLimiter()
|
||||
{
|
||||
minRank = maxRank = -1;
|
||||
}
|
||||
|
||||
ILimiter::EDecision RankRangeLimiter::limit(const BonusLimitationContext &context) const
|
||||
{
|
||||
const CStackInstance * csi = retrieveStackInstance(&context.node);
|
||||
if(csi)
|
||||
{
|
||||
if (csi->getNodeType() == CBonusSystemNode::COMMANDER) //no stack exp bonuses for commander creatures
|
||||
return ILimiter::EDecision::DISCARD;
|
||||
if (csi->getExpRank() > minRank && csi->getExpRank() < maxRank)
|
||||
return ILimiter::EDecision::ACCEPT;
|
||||
}
|
||||
return ILimiter::EDecision::DISCARD;
|
||||
}
|
||||
|
||||
OppositeSideLimiter::OppositeSideLimiter(PlayerColor Owner):
|
||||
owner(std::move(Owner))
|
||||
{
|
||||
}
|
||||
|
||||
ILimiter::EDecision OppositeSideLimiter::limit(const BonusLimitationContext & context) const
|
||||
{
|
||||
auto contextOwner = CBonusSystemNode::retrieveNodeOwner(& context.node);
|
||||
auto decision = (owner == contextOwner || owner == PlayerColor::CANNOT_DETERMINE) ? ILimiter::EDecision::DISCARD : ILimiter::EDecision::ACCEPT;
|
||||
return decision;
|
||||
}
|
||||
|
||||
// Aggregate/Boolean Limiters
|
||||
|
||||
AggregateLimiter::AggregateLimiter(std::vector<TLimiterPtr> limiters):
|
||||
limiters(std::move(limiters))
|
||||
{
|
||||
}
|
||||
|
||||
void AggregateLimiter::add(const TLimiterPtr & limiter)
|
||||
{
|
||||
if(limiter)
|
||||
limiters.push_back(limiter);
|
||||
}
|
||||
|
||||
JsonNode AggregateLimiter::toJsonNode() const
|
||||
{
|
||||
JsonNode result(JsonNode::JsonType::DATA_VECTOR);
|
||||
result.Vector().push_back(JsonUtils::stringNode(getAggregator()));
|
||||
for(const auto & l : limiters)
|
||||
result.Vector().push_back(l->toJsonNode());
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::string AllOfLimiter::aggregator = "allOf";
|
||||
const std::string & AllOfLimiter::getAggregator() const
|
||||
{
|
||||
return aggregator;
|
||||
}
|
||||
|
||||
AllOfLimiter::AllOfLimiter(std::vector<TLimiterPtr> limiters):
|
||||
AggregateLimiter(limiters)
|
||||
{
|
||||
}
|
||||
|
||||
ILimiter::EDecision AllOfLimiter::limit(const BonusLimitationContext & context) const
|
||||
{
|
||||
bool wasntSure = false;
|
||||
|
||||
for(const auto & limiter : limiters)
|
||||
{
|
||||
auto result = limiter->limit(context);
|
||||
if(result == ILimiter::EDecision::DISCARD)
|
||||
return result;
|
||||
if(result == ILimiter::EDecision::NOT_SURE)
|
||||
wasntSure = true;
|
||||
}
|
||||
|
||||
return wasntSure ? ILimiter::EDecision::NOT_SURE : ILimiter::EDecision::ACCEPT;
|
||||
}
|
||||
|
||||
const std::string AnyOfLimiter::aggregator = "anyOf";
|
||||
const std::string & AnyOfLimiter::getAggregator() const
|
||||
{
|
||||
return aggregator;
|
||||
}
|
||||
|
||||
AnyOfLimiter::AnyOfLimiter(std::vector<TLimiterPtr> limiters):
|
||||
AggregateLimiter(limiters)
|
||||
{
|
||||
}
|
||||
|
||||
ILimiter::EDecision AnyOfLimiter::limit(const BonusLimitationContext & context) const
|
||||
{
|
||||
bool wasntSure = false;
|
||||
|
||||
for(const auto & limiter : limiters)
|
||||
{
|
||||
auto result = limiter->limit(context);
|
||||
if(result == ILimiter::EDecision::ACCEPT)
|
||||
return result;
|
||||
if(result == ILimiter::EDecision::NOT_SURE)
|
||||
wasntSure = true;
|
||||
}
|
||||
|
||||
return wasntSure ? ILimiter::EDecision::NOT_SURE : ILimiter::EDecision::DISCARD;
|
||||
}
|
||||
|
||||
const std::string NoneOfLimiter::aggregator = "noneOf";
|
||||
const std::string & NoneOfLimiter::getAggregator() const
|
||||
{
|
||||
return aggregator;
|
||||
}
|
||||
|
||||
NoneOfLimiter::NoneOfLimiter(std::vector<TLimiterPtr> limiters):
|
||||
AggregateLimiter(limiters)
|
||||
{
|
||||
}
|
||||
|
||||
ILimiter::EDecision NoneOfLimiter::limit(const BonusLimitationContext & context) const
|
||||
{
|
||||
bool wasntSure = false;
|
||||
|
||||
for(const auto & limiter : limiters)
|
||||
{
|
||||
auto result = limiter->limit(context);
|
||||
if(result == ILimiter::EDecision::ACCEPT)
|
||||
return ILimiter::EDecision::DISCARD;
|
||||
if(result == ILimiter::EDecision::NOT_SURE)
|
||||
wasntSure = true;
|
||||
}
|
||||
|
||||
return wasntSure ? ILimiter::EDecision::NOT_SURE : ILimiter::EDecision::ACCEPT;
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
264
lib/bonuses/ILimiter.h
Normal file
264
lib/bonuses/ILimiter.h
Normal file
@@ -0,0 +1,264 @@
|
||||
/*
|
||||
* ILimiter.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
#include "HeroBonus.h"
|
||||
#include "battle/BattleHex.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
extern DLL_LINKAGE const std::map<std::string, TLimiterPtr> bonusLimiterMap;
|
||||
|
||||
struct BonusLimitationContext
|
||||
{
|
||||
const Bonus & b;
|
||||
const CBonusSystemNode & node;
|
||||
const BonusList & alreadyAccepted;
|
||||
const BonusList & stillUndecided;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE ILimiter
|
||||
{
|
||||
public:
|
||||
enum class EDecision : uint8_t {ACCEPT, DISCARD, NOT_SURE};
|
||||
|
||||
virtual ~ILimiter() = default;
|
||||
|
||||
virtual EDecision limit(const BonusLimitationContext &context) const; //0 - accept bonus; 1 - drop bonus; 2 - delay (drops eventually)
|
||||
virtual std::string toString() const;
|
||||
virtual JsonNode toJsonNode() const;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE AggregateLimiter : public ILimiter
|
||||
{
|
||||
protected:
|
||||
std::vector<TLimiterPtr> limiters;
|
||||
virtual const std::string & getAggregator() const = 0;
|
||||
AggregateLimiter(std::vector<TLimiterPtr> limiters = {});
|
||||
public:
|
||||
void add(const TLimiterPtr & limiter);
|
||||
JsonNode toJsonNode() const override;
|
||||
|
||||
template <typename Handler> void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & static_cast<ILimiter&>(*this);
|
||||
h & limiters;
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE AllOfLimiter : public AggregateLimiter
|
||||
{
|
||||
protected:
|
||||
const std::string & getAggregator() const override;
|
||||
public:
|
||||
AllOfLimiter(std::vector<TLimiterPtr> limiters = {});
|
||||
static const std::string aggregator;
|
||||
EDecision limit(const BonusLimitationContext & context) const override;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE AnyOfLimiter : public AggregateLimiter
|
||||
{
|
||||
protected:
|
||||
const std::string & getAggregator() const override;
|
||||
public:
|
||||
AnyOfLimiter(std::vector<TLimiterPtr> limiters = {});
|
||||
static const std::string aggregator;
|
||||
EDecision limit(const BonusLimitationContext & context) const override;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE NoneOfLimiter : public AggregateLimiter
|
||||
{
|
||||
protected:
|
||||
const std::string & getAggregator() const override;
|
||||
public:
|
||||
NoneOfLimiter(std::vector<TLimiterPtr> limiters = {});
|
||||
static const std::string aggregator;
|
||||
EDecision limit(const BonusLimitationContext & context) const override;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CCreatureTypeLimiter : public ILimiter //affect only stacks of given creature (and optionally it's upgrades)
|
||||
{
|
||||
public:
|
||||
const CCreature * creature = nullptr;
|
||||
bool includeUpgrades = false;
|
||||
|
||||
CCreatureTypeLimiter() = default;
|
||||
CCreatureTypeLimiter(const CCreature & creature_, bool IncludeUpgrades);
|
||||
void setCreature(const CreatureID & id);
|
||||
|
||||
EDecision limit(const BonusLimitationContext &context) const override;
|
||||
std::string toString() const override;
|
||||
JsonNode toJsonNode() const override;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<ILimiter&>(*this);
|
||||
h & creature;
|
||||
h & includeUpgrades;
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE HasAnotherBonusLimiter : public ILimiter //applies only to nodes that have another bonus working
|
||||
{
|
||||
public:
|
||||
Bonus::BonusType type;
|
||||
TBonusSubtype subtype;
|
||||
Bonus::BonusSource source;
|
||||
si32 sid;
|
||||
bool isSubtypeRelevant; //check for subtype only if this is true
|
||||
bool isSourceRelevant; //check for bonus source only if this is true
|
||||
bool isSourceIDRelevant; //check for bonus source only if this is true
|
||||
|
||||
HasAnotherBonusLimiter(Bonus::BonusType bonus = Bonus::NONE);
|
||||
HasAnotherBonusLimiter(Bonus::BonusType bonus, TBonusSubtype _subtype);
|
||||
HasAnotherBonusLimiter(Bonus::BonusType bonus, Bonus::BonusSource src);
|
||||
HasAnotherBonusLimiter(Bonus::BonusType bonus, TBonusSubtype _subtype, Bonus::BonusSource src);
|
||||
|
||||
EDecision limit(const BonusLimitationContext &context) const override;
|
||||
std::string toString() const override;
|
||||
JsonNode toJsonNode() const override;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<ILimiter&>(*this);
|
||||
h & type;
|
||||
h & subtype;
|
||||
h & isSubtypeRelevant;
|
||||
h & source;
|
||||
h & isSourceRelevant;
|
||||
h & sid;
|
||||
h & isSourceIDRelevant;
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CreatureTerrainLimiter : public ILimiter //applies only to creatures that are on specified terrain, default native terrain
|
||||
{
|
||||
public:
|
||||
TerrainId terrainType;
|
||||
CreatureTerrainLimiter();
|
||||
CreatureTerrainLimiter(TerrainId terrain);
|
||||
|
||||
EDecision limit(const BonusLimitationContext &context) const override;
|
||||
std::string toString() const override;
|
||||
JsonNode toJsonNode() const override;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<ILimiter&>(*this);
|
||||
h & terrainType;
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CreatureLevelLimiter : public ILimiter //applies only to creatures of given faction
|
||||
{
|
||||
public:
|
||||
uint32_t minLevel;
|
||||
uint32_t maxLevel;
|
||||
//accept all levels by default, accept creatures of minLevel <= creature->getLevel() < maxLevel
|
||||
CreatureLevelLimiter(uint32_t minLevel = std::numeric_limits<uint32_t>::min(), uint32_t maxLevel = std::numeric_limits<uint32_t>::max());
|
||||
|
||||
EDecision limit(const BonusLimitationContext &context) const override;
|
||||
std::string toString() const override;
|
||||
JsonNode toJsonNode() const override;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<ILimiter&>(*this);
|
||||
h & minLevel;
|
||||
h & maxLevel;
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE FactionLimiter : public ILimiter //applies only to creatures of given faction
|
||||
{
|
||||
public:
|
||||
FactionID faction;
|
||||
FactionLimiter(FactionID faction = FactionID::DEFAULT);
|
||||
|
||||
EDecision limit(const BonusLimitationContext &context) const override;
|
||||
std::string toString() const override;
|
||||
JsonNode toJsonNode() const override;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<ILimiter&>(*this);
|
||||
h & faction;
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CreatureAlignmentLimiter : public ILimiter //applies only to creatures of given alignment
|
||||
{
|
||||
public:
|
||||
EAlignment alignment;
|
||||
CreatureAlignmentLimiter(EAlignment Alignment = EAlignment::NEUTRAL);
|
||||
|
||||
EDecision limit(const BonusLimitationContext &context) const override;
|
||||
std::string toString() const override;
|
||||
JsonNode toJsonNode() const override;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<ILimiter&>(*this);
|
||||
h & alignment;
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE OppositeSideLimiter : public ILimiter //applies only to creatures of enemy army during combat
|
||||
{
|
||||
public:
|
||||
PlayerColor owner;
|
||||
OppositeSideLimiter(PlayerColor Owner = PlayerColor::CANNOT_DETERMINE);
|
||||
|
||||
EDecision limit(const BonusLimitationContext &context) const override;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<ILimiter&>(*this);
|
||||
h & owner;
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE RankRangeLimiter : public ILimiter //applies to creatures with min <= Rank <= max
|
||||
{
|
||||
public:
|
||||
ui8 minRank, maxRank;
|
||||
|
||||
RankRangeLimiter();
|
||||
RankRangeLimiter(ui8 Min, ui8 Max = 255);
|
||||
EDecision limit(const BonusLimitationContext &context) const override;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<ILimiter&>(*this);
|
||||
h & minRank;
|
||||
h & maxRank;
|
||||
}
|
||||
};
|
||||
|
||||
class DLL_LINKAGE UnitOnHexLimiter : public ILimiter //works only on selected hexes
|
||||
{
|
||||
public:
|
||||
std::set<BattleHex> applicableHexes;
|
||||
|
||||
UnitOnHexLimiter(const std::set<BattleHex> & applicableHexes = {});
|
||||
EDecision limit(const BonusLimitationContext &context) const override;
|
||||
JsonNode toJsonNode() const override;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & static_cast<ILimiter&>(*this);
|
||||
h & applicableHexes;
|
||||
}
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
@@ -22,6 +22,7 @@
|
||||
#include "../mapObjects/CommonConstructors.h"
|
||||
#include "../mapObjects/MapObjects.h"
|
||||
#include "../battle/CObstacleInstance.h"
|
||||
#include "../bonuses/ILimiter.h"
|
||||
#include "../CStack.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
@@ -16,6 +16,7 @@
|
||||
|
||||
#include "../../NetPacks.h"
|
||||
#include "../../mapObjects/CGTownInstance.h"
|
||||
#include "../../bonuses/ILimiter.h"
|
||||
#include "../../battle/IBattleState.h"
|
||||
#include "../../battle/CBattleInfoCallback.h"
|
||||
#include "../../serializer/JsonSerializeFormat.h"
|
||||
|
Reference in New Issue
Block a user