mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Fix: Visiting hero should receive town bonuses during town siege
This commit is contained in:
parent
6f0864b47c
commit
f861d3a509
@ -1322,14 +1322,20 @@ CreatureID CCreatureHandler::pickRandomMonster(CRandomGenerator & rand, int tier
|
|||||||
return CreatureID(r);
|
return CreatureID(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCreatureHandler::addBonusForTier(int tier, std::shared_ptr<Bonus> b)
|
void CCreatureHandler::addBonusForTier(int tier, const std::shared_ptr<Bonus> & b)
|
||||||
{
|
{
|
||||||
assert(vstd::iswithin(tier, 1, 7));
|
assert(vstd::iswithin(tier, 1, 7));
|
||||||
creaturesOfLevel[tier].addNewBonus(b);
|
creaturesOfLevel[tier].addNewBonus(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCreatureHandler::addBonusForAllCreatures(std::shared_ptr<Bonus> b)
|
void CCreatureHandler::addBonusForAllCreatures(const std::shared_ptr<Bonus> & b)
|
||||||
{
|
{
|
||||||
|
const auto & exportedBonuses = allCreatures.getExportedBonusList();
|
||||||
|
for(const auto & bonus : exportedBonuses)
|
||||||
|
{
|
||||||
|
if(bonus->type == b->type && bonus->subtype == b->subtype)
|
||||||
|
return;
|
||||||
|
}
|
||||||
allCreatures.addNewBonus(b);
|
allCreatures.addNewBonus(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,8 +278,8 @@ public:
|
|||||||
|
|
||||||
void deserializationFix();
|
void deserializationFix();
|
||||||
CreatureID pickRandomMonster(CRandomGenerator & rand, int tier = -1) const; //tier <1 - CREATURES_PER_TOWN> or -1 for any
|
CreatureID pickRandomMonster(CRandomGenerator & rand, int tier = -1) const; //tier <1 - CREATURES_PER_TOWN> or -1 for any
|
||||||
void addBonusForTier(int tier, std::shared_ptr<Bonus> b); //tier must be <1-7>
|
void addBonusForTier(int tier, const std::shared_ptr<Bonus> & b); //tier must be <1-7>
|
||||||
void addBonusForAllCreatures(std::shared_ptr<Bonus> b);
|
void addBonusForAllCreatures(const std::shared_ptr<Bonus> & b); //due to CBonusSystem::addNewBonus(const std::shared_ptr<Bonus>& b);
|
||||||
void removeBonusesFromAllCreatures();
|
void removeBonusesFromAllCreatures();
|
||||||
void restoreAllCreaturesNodeType794(); //restore ALL_CREATURES node type for old saves
|
void restoreAllCreaturesNodeType794(); //restore ALL_CREATURES node type for old saves
|
||||||
|
|
||||||
|
@ -377,7 +377,11 @@ JsonNode readBuilding(CLegacyConfigParser & parser)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
TPropagatorPtr CTownHandler::emptyPropagator = std::make_shared<CPropagatorNodeType>();
|
TPropagatorPtr & CTownHandler::emptyPropagator()
|
||||||
|
{
|
||||||
|
static TPropagatorPtr emptyProp(nullptr);
|
||||||
|
return emptyProp;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<JsonNode> CTownHandler::loadLegacyData(size_t dataSize)
|
std::vector<JsonNode> CTownHandler::loadLegacyData(size_t dataSize)
|
||||||
{
|
{
|
||||||
@ -618,7 +622,7 @@ void CTownHandler::addBonusesForVanilaBuilding(CBuilding * building)
|
|||||||
|
|
||||||
std::shared_ptr<Bonus> CTownHandler::createBonus(CBuilding * build, Bonus::BonusType type, int val, int subtype)
|
std::shared_ptr<Bonus> CTownHandler::createBonus(CBuilding * build, Bonus::BonusType type, int val, int subtype)
|
||||||
{
|
{
|
||||||
return createBonus(build, type, val, emptyPropagator, subtype);
|
return createBonus(build, type, val, emptyPropagator(), subtype);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<Bonus> CTownHandler::createBonus(CBuilding * build, Bonus::BonusType type, int val, TPropagatorPtr & prop, int subtype)
|
std::shared_ptr<Bonus> CTownHandler::createBonus(CBuilding * build, Bonus::BonusType type, int val, TPropagatorPtr & prop, int subtype)
|
||||||
@ -657,7 +661,7 @@ void CTownHandler::loadSpecialBuildingBonuses(const JsonNode & source, BonusList
|
|||||||
//JsonUtils::parseBuildingBonus produces UNKNOWN type propagator instead of empty.
|
//JsonUtils::parseBuildingBonus produces UNKNOWN type propagator instead of empty.
|
||||||
if(bonus->propagator != nullptr
|
if(bonus->propagator != nullptr
|
||||||
&& bonus->propagator->getPropagatorType() == CBonusSystemNode::ENodeTypes::UNKNOWN)
|
&& bonus->propagator->getPropagatorType() == CBonusSystemNode::ENodeTypes::UNKNOWN)
|
||||||
bonus->addPropagator(emptyPropagator);
|
bonus->addPropagator(emptyPropagator());
|
||||||
building->addNewBonus(bonus, bonusList);
|
building->addNewBonus(bonus, bonusList);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -388,7 +388,7 @@ class DLL_LINKAGE CTownHandler : public CHandlerBase<FactionID, Faction, CFactio
|
|||||||
const static ETerrainType::EETerrainType defaultEvilTerrain = ETerrainType::EETerrainType::LAVA;
|
const static ETerrainType::EETerrainType defaultEvilTerrain = ETerrainType::EETerrainType::LAVA;
|
||||||
const static ETerrainType::EETerrainType defaultNeutralTerrain = ETerrainType::EETerrainType::ROUGH;
|
const static ETerrainType::EETerrainType defaultNeutralTerrain = ETerrainType::EETerrainType::ROUGH;
|
||||||
|
|
||||||
static TPropagatorPtr emptyPropagator;
|
static TPropagatorPtr & emptyPropagator();
|
||||||
|
|
||||||
void initializeRequirements();
|
void initializeRequirements();
|
||||||
void initializeOverridden();
|
void initializeOverridden();
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
#include "battle/BattleInfo.h"
|
#include "battle/BattleInfo.h"
|
||||||
|
|
||||||
#define FOREACH_PARENT(pname) TNodes lparents; getParents(lparents); for(CBonusSystemNode *pname : lparents)
|
#define FOREACH_PARENT(pname) TNodes lparents; getParents(lparents); for(CBonusSystemNode *pname : lparents)
|
||||||
#define FOREACH_CPARENT(pname) TCNodes lparents; getParents(lparents); for(const CBonusSystemNode *pname : lparents)
|
|
||||||
#define FOREACH_RED_CHILD(pname) TNodes lchildren; getRedChildren(lchildren); for(CBonusSystemNode *pname : lchildren)
|
#define FOREACH_RED_CHILD(pname) TNodes lchildren; getRedChildren(lchildren); for(CBonusSystemNode *pname : lchildren)
|
||||||
#define FOREACH_RED_PARENT(pname) TNodes lparents; getRedParents(lparents); for(CBonusSystemNode *pname : lparents)
|
#define FOREACH_RED_PARENT(pname) TNodes lparents; getRedParents(lparents); for(CBonusSystemNode *pname : lparents)
|
||||||
|
|
||||||
@ -873,26 +872,25 @@ void CBonusSystemNode::getParents(TNodes &out)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBonusSystemNode::getBonusesRec(BonusList &out, const CSelector &selector, const CSelector &limit) const
|
void CBonusSystemNode::getAllParents(TCNodes & out) const /*retrieves list of parent nodes (nodes to inherit bonuses from) */
|
||||||
{
|
{
|
||||||
BonusList beforeUpdate;
|
for(auto & cparent : parents)
|
||||||
FOREACH_CPARENT(p)
|
|
||||||
{
|
{
|
||||||
p->getBonusesRec(beforeUpdate, selector, limit);
|
const CBonusSystemNode * parent = cparent;
|
||||||
|
out.insert(parent);
|
||||||
|
parent->getAllParents(out);
|
||||||
}
|
}
|
||||||
bonuses.getBonuses(beforeUpdate, selector, limit);
|
|
||||||
|
|
||||||
for(auto b : beforeUpdate)
|
|
||||||
out.push_back(update(b));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBonusSystemNode::getAllBonusesRec(BonusList &out) const
|
void CBonusSystemNode::getAllBonusesRec(BonusList &out) const
|
||||||
{
|
{
|
||||||
BonusList beforeUpdate;
|
BonusList beforeUpdate;
|
||||||
FOREACH_CPARENT(p)
|
TCNodes lparents;
|
||||||
{
|
getAllParents(lparents);
|
||||||
p->getAllBonusesRec(beforeUpdate);
|
|
||||||
}
|
for(auto parent : lparents)
|
||||||
|
parent->bonuses.getAllBonuses(beforeUpdate);
|
||||||
|
|
||||||
bonuses.getAllBonuses(beforeUpdate);
|
bonuses.getAllBonuses(beforeUpdate);
|
||||||
|
|
||||||
for(auto b : beforeUpdate)
|
for(auto b : beforeUpdate)
|
||||||
|
@ -769,7 +769,6 @@ private:
|
|||||||
mutable std::map<std::string, TBonusListPtr > cachedRequests;
|
mutable std::map<std::string, TBonusListPtr > cachedRequests;
|
||||||
mutable boost::mutex sync;
|
mutable boost::mutex sync;
|
||||||
|
|
||||||
void getBonusesRec(BonusList &out, const CSelector &selector, const CSelector &limit) const;
|
|
||||||
void getAllBonusesRec(BonusList &out) const;
|
void getAllBonusesRec(BonusList &out) const;
|
||||||
TConstBonusListPtr getAllBonusesWithoutCaching(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = nullptr) const;
|
TConstBonusListPtr getAllBonusesWithoutCaching(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = nullptr) const;
|
||||||
std::shared_ptr<Bonus> update(const std::shared_ptr<Bonus> & b) const;
|
std::shared_ptr<Bonus> update(const std::shared_ptr<Bonus> & b) const;
|
||||||
@ -793,6 +792,7 @@ public:
|
|||||||
void getRedAncestors(TNodes &out);
|
void getRedAncestors(TNodes &out);
|
||||||
void getRedChildren(TNodes &out);
|
void getRedChildren(TNodes &out);
|
||||||
void getRedDescendants(TNodes &out);
|
void getRedDescendants(TNodes &out);
|
||||||
|
void getAllParents(TCNodes & out) const;
|
||||||
std::shared_ptr<Bonus> getBonusLocalFirst(const CSelector &selector);
|
std::shared_ptr<Bonus> getBonusLocalFirst(const CSelector &selector);
|
||||||
|
|
||||||
void attachTo(CBonusSystemNode *parent);
|
void attachTo(CBonusSystemNode *parent);
|
||||||
|
@ -186,38 +186,70 @@ struct RangeGenerator
|
|||||||
std::function<int()> myRand;
|
std::function<int()> myRand;
|
||||||
};
|
};
|
||||||
|
|
||||||
void BattleInfo::addOnlyEnemyArmyBonuses(const BonusList & bonusList, BattleInfo * curB, BattleInfo::BattleSide side)
|
|
||||||
|
std::shared_ptr<Bonus> BattleInfo::makeBonusForEnemy(const std::shared_ptr<Bonus> & b, PlayerColor & enemyColor)
|
||||||
{
|
{
|
||||||
for(auto b : bonusList)
|
auto bCopy = std::make_shared<Bonus>(*b);
|
||||||
|
bCopy->effectRange = Bonus::NO_LIMIT;
|
||||||
|
bCopy->propagator.reset();
|
||||||
|
bCopy->limiter.reset(new StackOwnerLimiter(enemyColor));
|
||||||
|
return bCopy;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BattleInfo::addOnlyEnemyArmyBonuses(const BonusList & bonusList, BattleInfo * curB, BattleInfo::BattleSide enemySide)
|
||||||
|
{
|
||||||
|
for(const auto & b : bonusList) //don't copy shared_ptr object, don't change it
|
||||||
{
|
{
|
||||||
if(b->effectRange != Bonus::ONLY_ENEMY_ARMY)
|
if(b->effectRange != Bonus::ONLY_ENEMY_ARMY)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto bCopy = std::make_shared<Bonus>(*b);
|
auto bCopy = makeBonusForEnemy(b, curB->sides[enemySide].color);
|
||||||
bCopy->effectRange = Bonus::NO_LIMIT;
|
|
||||||
bCopy->propagator.reset();
|
|
||||||
bCopy->limiter.reset(new StackOwnerLimiter(curB->sides[side].color));
|
|
||||||
curB->addNewBonus(bCopy);
|
curB->addNewBonus(bCopy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BattleInfo::setupBonusesFromTown(const CGTownInstance * town, BattleInfo * curB)
|
void BattleInfo::setupBonusesFromTownToEnemy(const CGTownInstance * town, BattleInfo * curB)
|
||||||
{
|
{
|
||||||
assert(town);
|
assert(town);
|
||||||
for(auto building : town->builtBuildings)
|
for(const auto & building : town->builtBuildings)
|
||||||
{
|
{
|
||||||
const auto & bonuses = town->town->buildings.at(building)->buildingBonuses;
|
const auto & bonuses = town->town->buildings.at(building)->buildingBonuses;
|
||||||
addOnlyEnemyArmyBonuses(bonuses, curB, BattleInfo::ATTACKER);
|
addOnlyEnemyArmyBonuses(bonuses, curB, BattleInfo::ATTACKER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BattleInfo::setupBonusesFromUnits(BattleInfo * curB)
|
void BattleInfo::setupBonusesFromTownToBothSides(const CGTownInstance * town, BattleInfo * curB)
|
||||||
|
{
|
||||||
|
assert(town);
|
||||||
|
for(const auto & building : town->builtBuildings)
|
||||||
|
{
|
||||||
|
const auto & bonuses = town->town->buildings.at(building)->buildingBonuses;
|
||||||
|
|
||||||
|
for(const auto & b : bonuses)
|
||||||
|
{
|
||||||
|
if(b->effectRange == Bonus::ONLY_ENEMY_ARMY)
|
||||||
|
{
|
||||||
|
auto bCopy = makeBonusForEnemy(b, curB->sides[BattleInfo::ATTACKER].color);
|
||||||
|
curB->addNewBonus(bCopy);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto bCopy = std::make_shared<Bonus>(*b);
|
||||||
|
bCopy->propagator.reset();
|
||||||
|
bCopy->limiter.reset(new StackOwnerLimiter(curB->sides[BattleInfo::DEFENDER].color));
|
||||||
|
curB->addNewBonus(bCopy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BattleInfo::setupBonusesFromUnitsToEnemy(BattleInfo * curB)
|
||||||
{
|
{
|
||||||
for(int i = 0; i < 2; i++)
|
for(int i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
TNodes nodes;
|
TNodes nodes;
|
||||||
curB->battleGetArmyObject(i)->getRedAncestors(nodes);
|
curB->battleGetArmyObject(i)->getRedAncestors(nodes);
|
||||||
for(CBonusSystemNode * n : nodes)
|
for(auto n : nodes)
|
||||||
{
|
{
|
||||||
const auto & bonuses = n->getExportedBonusList();
|
const auto & bonuses = n->getExportedBonusList();
|
||||||
addOnlyEnemyArmyBonuses(bonuses, curB, (BattleInfo::BattleSide)!i);
|
addOnlyEnemyArmyBonuses(bonuses, curB, (BattleInfo::BattleSide)!i);
|
||||||
@ -595,8 +627,13 @@ BattleInfo * BattleInfo::setupBattle(int3 tile, ETerrainType terrain, BFieldType
|
|||||||
curB->tacticDistance = 0;
|
curB->tacticDistance = 0;
|
||||||
|
|
||||||
if(town)
|
if(town)
|
||||||
setupBonusesFromTown(town, curB);
|
{
|
||||||
setupBonusesFromUnits(curB);
|
if(town->visitingHero == heroes[BattleSide::DEFENDER])
|
||||||
|
setupBonusesFromTownToBothSides(town, curB);
|
||||||
|
else
|
||||||
|
setupBonusesFromTownToEnemy(town, curB);
|
||||||
|
}
|
||||||
|
setupBonusesFromUnitsToEnemy(curB);
|
||||||
return curB;
|
return curB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,8 +138,9 @@ public:
|
|||||||
|
|
||||||
void localInit();
|
void localInit();
|
||||||
|
|
||||||
static void setupBonusesFromTown(const CGTownInstance * town, BattleInfo * curB); //besieged city may contain buildings with negative bonuses for enemy army.
|
static void setupBonusesFromTownToEnemy(const CGTownInstance * town, BattleInfo * curB); //besieged city may contain buildings with negative bonuses for enemy army
|
||||||
static void setupBonusesFromUnits(BattleInfo * curB); //besieged city may contain buildings with negative bonuses for enemy army.
|
static void setupBonusesFromTownToBothSides(const CGTownInstance * town, BattleInfo * curB); //if visiting hero is town defender during siege, he/she should receive bonuses
|
||||||
|
static void setupBonusesFromUnitsToEnemy(BattleInfo * curB);
|
||||||
static BattleInfo * setupBattle(int3 tile, ETerrainType terrain, BFieldType battlefieldType, const CArmedInstance * armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance * town);
|
static BattleInfo * setupBattle(int3 tile, ETerrainType terrain, BFieldType battlefieldType, const CArmedInstance * armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance * town);
|
||||||
|
|
||||||
ui8 whatSide(PlayerColor player) const;
|
ui8 whatSide(PlayerColor player) const;
|
||||||
@ -150,7 +151,8 @@ protected:
|
|||||||
scripting::Pool * getContextPool() const override;
|
scripting::Pool * getContextPool() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void addOnlyEnemyArmyBonuses(const BonusList & bonusList, BattleInfo * curB, BattleInfo::BattleSide side);
|
static void addOnlyEnemyArmyBonuses(const BonusList & bonusList, BattleInfo * curB, BattleInfo::BattleSide enemySide);
|
||||||
|
STRONG_INLINE static std::shared_ptr<Bonus> makeBonusForEnemy(const std::shared_ptr<Bonus> & b, PlayerColor & enemyColor);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user