1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-15 20:03:15 +02:00

* Improved battle and bonus system performance (significantly faster in debug build, tip: use vs 2008, turn of hex field presentation)

* Implemented caching for the bonus system
This commit is contained in:
beegee1
2011-06-25 13:53:15 +00:00
parent a60fd00e22
commit 5fdb5aa494
13 changed files with 233 additions and 131 deletions

View File

@@ -1651,16 +1651,18 @@ void CBattleInterface::show(SDL_Surface * to)
////showing units //a lot of work...
std::vector<const CStack *> stackAliveByHex[BFIELD_SIZE];
//double loop because dead stacks should be printed first
BOOST_FOREACH(const CStack *s, stacks)
for (int i = 0; i < stacks.size(); i++)
{
const CStack *s = stacks[i];
if(creAnims.find(s->ID) == creAnims.end()) //e.g. for summoned but not yet handled stacks
continue;
if(creAnims[s->ID]->getType() != 5 && s->position >= 0) //don't show turrets here
stackAliveByHex[s->position].push_back(s);
}
std::vector<const CStack *> stackDeadByHex[BFIELD_SIZE];
BOOST_FOREACH(const CStack *s, stacks)
for (int i = 0; i < stacks.size(); i++)
{
const CStack *s = stacks[i];
if(creAnims.find(s->ID) == creAnims.end()) //e.g. for summoned but not yet handled stacks
continue;
if(creAnims[s->ID]->getType() == 5)
@@ -3093,9 +3095,9 @@ void CBattleInterface::spellCast( const BattleSpellCast * sc )
boost::algorithm::replace_first(text, "%s", curInt->cb->battleGetStackByID(*sc->affectedCres.begin())->type->nameSing);
}
//The %s shrivel with age, and lose %d hit points."
BonusList bl = curInt->cb->battleGetStackByID(*sc->affectedCres.begin(), false)->getBonuses(Selector::type(Bonus::STACK_HEALTH));
bl.remove_if(Selector::source(Bonus::SPELL_EFFECT, 75));
boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>(bl.totalValue()/2));
boost::shared_ptr<BonusList> bl = curInt->cb->battleGetStackByID(*sc->affectedCres.begin(), false)->getBonuses(Selector::type(Bonus::STACK_HEALTH));
bl->remove_if(Selector::source(Bonus::SPELL_EFFECT, 75));
boost::algorithm::replace_first(text, "%d", boost::lexical_cast<std::string>(bl->totalValue()/2));
}
break;
case 78: //Dispell helpful spells
@@ -3428,8 +3430,8 @@ void CBattleInterface::showAliveStack(const CStack *stack, SDL_Surface * to)
//blitting amount background box
SDL_Surface *amountBG = NULL;
BonusList spellEffects = stack->getSpellBonuses();
if(!spellEffects.size())
boost::shared_ptr<BonusList> spellEffects = stack->getSpellBonuses();
if(!spellEffects->size())
{
amountBG = amountNormal;
}

View File

@@ -1136,19 +1136,22 @@ void CCreaInfo::clickRight(tribool down, bool previousState)
cnt++;//external dwellings count to summ
summ+=AddToString(CGI->generaltexth->allTexts[591],descr,cnt);
BonusList bl;
boost::shared_ptr<BonusList> bl;
const CGHeroInstance *hero = town->garrisonHero;
if (hero)
hero->getBonuses(bl, Selector::type(Bonus::CREATURE_GROWTH) && Selector::subtype(level)
&& Selector::sourceType(Bonus::ARTIFACT), hero);
bl = hero->getAllBonuses(Selector::type(Bonus::CREATURE_GROWTH) && Selector::subtype(level)
&& Selector::sourceType(Bonus::ARTIFACT), 0, hero);
hero = town->visitingHero;
if (hero)
hero->getBonuses(bl, Selector::type(Bonus::CREATURE_GROWTH) && Selector::subtype(level)
&& Selector::sourceType(Bonus::ARTIFACT), hero);
{
boost::shared_ptr<BonusList> blAppend = hero->getAllBonuses(Selector::type(Bonus::CREATURE_GROWTH) && Selector::subtype(level)
&& Selector::sourceType(Bonus::ARTIFACT), 0, hero);
bl->insert(bl->end(), blAppend->begin(), blAppend->end()) ;
}
if (bl.size())
summ+=AddToString (CGI->arth->artifacts[bl.front()->sid]->Name()+" %+d", descr, bl.totalValue());
if (bl->size())
summ+=AddToString (CGI->arth->artifacts[bl->front()->sid]->Name()+" %+d", descr, bl->totalValue());
//TODO: player bonuses

View File

@@ -134,7 +134,7 @@ void CCreatureWindow::init(const CStackInstance *Stack, const CBonusSystemNode *
//Basic graphics - need to calculate size
CBonusSystemNode node = CBonusSystemNode() ;
node.bonuses = stackNode->getBonuses(Selector::durationType(Bonus::PERMANENT));
node.bonuses = *(stackNode->getBonuses(Selector::durationType(Bonus::PERMANENT)));
BonusList bl;
while (node.bonuses.size())

View File

@@ -44,21 +44,25 @@
extern SDL_Surface * screen;
using namespace boost::assign;
void CHeroWithMaybePickedArtifact::getAllBonuses(BonusList &out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= NULL*/) const
const boost::shared_ptr<BonusList> CHeroWithMaybePickedArtifact::getAllBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= NULL*/) const
{
BonusList heroBonuses, bonusesFromPickedUpArtifact;
hero->getAllBonuses(heroBonuses, selector, limit, hero);
boost::shared_ptr<BonusList> out(new BonusList);
boost::shared_ptr<BonusList> heroBonuses = hero->getAllBonuses(selector, limit, hero);
boost::shared_ptr<BonusList> bonusesFromPickedUpArtifact;
CArtifactsOfHero::SCommonPart *cp = cww->artSets.size() ? cww->artSets.front()->commonInfo : NULL;
if(cp && cp->src.art && cp->src.AOH && cp->src.AOH->getHero() == hero)
{
cp->src.art->getAllBonuses(bonusesFromPickedUpArtifact, selector, limit, hero);
bonusesFromPickedUpArtifact = cp->src.art->getAllBonuses(selector, limit, hero);
}
else
bonusesFromPickedUpArtifact = boost::shared_ptr<BonusList>(new BonusList);
BOOST_FOREACH(Bonus *b, bonusesFromPickedUpArtifact)
heroBonuses -= b;
BOOST_FOREACH(Bonus *b, heroBonuses)
out.push_back(b);
BOOST_FOREACH(Bonus *b, *bonusesFromPickedUpArtifact)
*heroBonuses -= b;
BOOST_FOREACH(Bonus *b, *heroBonuses)
out->push_back(b);
return out;
}
CHeroWithMaybePickedArtifact::CHeroWithMaybePickedArtifact(CWindowWithArtifacts *Cww, const CGHeroInstance *Hero)

View File

@@ -46,7 +46,7 @@ public:
CWindowWithArtifacts *cww;
CHeroWithMaybePickedArtifact(CWindowWithArtifacts *Cww, const CGHeroInstance *Hero);
void getAllBonuses(BonusList &out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL) const OVERRIDE;
const boost::shared_ptr<BonusList> getAllBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL) const OVERRIDE;
};
class CHeroWindow: public CWindowWithGarrison, public CWindowWithArtifacts

View File

@@ -352,7 +352,8 @@ void CGuiHandler::run()
setThreadName(-1, "CGuiHandler::run");
try
{
CCS->curh->centerCursor();
if (conf.cc.fullscreen)
CCS->curh->centerCursor();
mainFPSmng->init(); // resets internal clock, needed for FPS manager
while(!terminate)

View File

@@ -476,9 +476,9 @@ TDmgRange BattleInfo::calculateDmgRange( const CStack* attacker, const CStack* d
//calculating total attack/defense skills modifier
if(shooting) //precision handling (etc.)
attackDefenceDifference += attacker->getBonuses(Selector::typeSubtype(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK), Selector::effectRange(Bonus::ONLY_DISTANCE_FIGHT)).totalValue();
attackDefenceDifference += attacker->getBonuses(Selector::typeSubtype(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK), Selector::effectRange(Bonus::ONLY_DISTANCE_FIGHT))->totalValue();
else //bloodlust handling (etc.)
attackDefenceDifference += attacker->getBonuses(Selector::typeSubtype(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK), Selector::effectRange(Bonus::ONLY_MELEE_FIGHT)).totalValue();
attackDefenceDifference += attacker->getBonuses(Selector::typeSubtype(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK), Selector::effectRange(Bonus::ONLY_MELEE_FIGHT))->totalValue();
if(attacker->getEffect(55)) //slayer handling
@@ -1830,23 +1830,23 @@ SpellCasting::ESpellCastProblem BattleInfo::battleIsImmune(const CGHeroInstance
return SpellCasting::STACK_IMMUNE_TO_SPELL;
}
BonusList immunities = subject->getBonuses(Selector::type(Bonus::LEVEL_SPELL_IMMUNITY));
boost::shared_ptr<BonusList> immunities = subject->getBonuses(Selector::type(Bonus::LEVEL_SPELL_IMMUNITY));
if(subject->hasBonusOfType(Bonus::NEGATE_ALL_NATURAL_IMMUNITIES))
{
std::remove_if(immunities.begin(), immunities.end(), NegateRemover);
std::remove_if(immunities->begin(), immunities->end(), NegateRemover);
}
if(subject->hasBonusOfType(Bonus::SPELL_IMMUNITY, spell->id) ||
( immunities.size() > 0 && immunities.totalValue() >= spell->level && spell->level))
( immunities->size() > 0 && immunities->totalValue() >= spell->level && spell->level))
{
return SpellCasting::STACK_IMMUNE_TO_SPELL;
}
//dispel helpful spells
if(spell->id == 78)
{
BonusList spellBon = subject->getSpellBonuses();
boost::shared_ptr<BonusList> spellBon = subject->getSpellBonuses();
bool hasPositiveSpell = false;
BOOST_FOREACH(const Bonus * b, spellBon)
BOOST_FOREACH(const Bonus * b, *spellBon)
{
if(VLC->spellh->spells[b->sid]->positiveness > 0)
{
@@ -2265,17 +2265,13 @@ THex CStack::occupiedHex() const
return THex::INVALID;
}
}
BonusList CStack::getSpellBonuses() const
{
return getBonuses(Selector::sourceTypeSel(Bonus::SPELL_EFFECT));
}
std::vector<si32> CStack::activeSpells() const
{
std::vector<si32> ret;
BonusList spellEffects = getSpellBonuses();
BOOST_FOREACH(const Bonus *it, spellEffects)
boost::shared_ptr<BonusList> spellEffects = getSpellBonuses();
BOOST_FOREACH(const Bonus *it, *spellEffects)
{
if (!vstd::contains(ret, it->sid)) //do not duplicate spells with multiple effects
ret.push_back(it->sid);

View File

@@ -159,7 +159,6 @@ public:
bool moved(int turn = 0) const; //if stack was already moved this turn
bool canMove(int turn = 0) const; //if stack can move
ui32 Speed(int turn = 0) const; //get speed of creature with all modificators
BonusList getSpellBonuses() const;
static void stackEffectToFeature(std::vector<Bonus> & sf, const Bonus & sse);
std::vector<si32> activeSpells() const; //returns vector of active spell IDs sorted by time of cast
const CGHeroInstance *getMyHero() const; //if stack belongs to hero (directly or was by him summoned) returns hero, NULL otherwise

View File

@@ -1678,8 +1678,8 @@ UpgradeInfo CGameState::getUpgradeInfo(const CStackInstance &stack)
t = static_cast<const CGTownInstance *>(stack.armyObj);
else if(h)
{ //hero speciality
BonusList lista = h->speciality.getBonuses(Selector::typeSubtype(Bonus::SPECIAL_UPGRADE, base->idNumber));
BOOST_FOREACH(const Bonus *it, lista)
boost::shared_ptr<BonusList> lista = h->speciality.getBonuses(Selector::typeSubtype(Bonus::SPECIAL_UPGRADE, base->idNumber));
BOOST_FOREACH(const Bonus *it, *lista)
{
ui16 nid = it->additionalInfo;
if (nid != base->idNumber) //in very specific case the upgrade is avaliable by default (?)

View File

@@ -2261,9 +2261,9 @@ void CGTownInstance::deserializationFix()
void CGTownInstance::recreateBuildingsBonuses()
{
BonusList bl;
boost::shared_ptr<BonusList> bl(new BonusList);
exportedBonuses.getBonuses(bl, Selector::sourceType(Bonus::TOWN_STRUCTURE));
BOOST_FOREACH(Bonus *b, bl)
BOOST_FOREACH(Bonus *b, *bl)
removeBonus(b);

View File

@@ -14,7 +14,6 @@
#include "BattleState.h"
#include "CArtHandler.h"
#define FOREACH_CONST_PARENT(pname) TCNodes lparents; getParents(lparents); BOOST_FOREACH(const CBonusSystemNode *pname, lparents)
#define FOREACH_PARENT(pname) TNodes lparents; getParents(lparents); BOOST_FOREACH(CBonusSystemNode *pname, lparents)
#define FOREACH_RED_CHILD(pname) TNodes lchildren; getRedChildren(lchildren); BOOST_FOREACH(CBonusSystemNode *pname, lchildren)
#define FOREACH_RED_PARENT(pname) TNodes lparents; getRedParents(lparents); BOOST_FOREACH(CBonusSystemNode *pname, lparents)
@@ -25,6 +24,9 @@
#define BONUS_LOG_LINE(x) tlog5 << x << std::endl
int CBonusSystemNode::treeChanged = 1;
const bool CBonusSystemNode::cachingEnabled = true;
int DLL_EXPORT BonusList::totalValue() const
{
int base = 0;
@@ -93,17 +95,23 @@ int DLL_EXPORT BonusList::totalValue() const
}
const DLL_EXPORT Bonus * BonusList::getFirst(const CSelector &selector) const
{
BOOST_FOREACH(Bonus *i, *this)
if(selector(i))
return &*i;
for (int i = 0; i < this->size(); i++)
{
const Bonus *b = (*this)[i];
if(selector(b))
return &*b;
}
return NULL;
}
DLL_EXPORT Bonus * BonusList::getFirst(const CSelector &select)
{
BOOST_FOREACH(Bonus *i, *this)
if(select(i))
return &*i;
for (int i = 0; i < this->size(); i++)
{
Bonus *b = (*this)[i];
if(select(b))
return &*b;
}
return NULL;
}
@@ -113,7 +121,7 @@ void DLL_EXPORT BonusList::getModifiersWDescr(TModDescr &out) const
out.push_back(std::make_pair(i->val, i->Description()));
}
void DLL_EXPORT BonusList::getBonuses(BonusList &out, const CSelector &selector) const
void DLL_EXPORT BonusList::getBonuses(boost::shared_ptr<BonusList> out, const CSelector &selector) const
{
// BOOST_FOREACH(Bonus *i, *this)
// if(selector(i) && i->effectRange == Bonus::NO_LIMIT)
@@ -122,11 +130,16 @@ void DLL_EXPORT BonusList::getBonuses(BonusList &out, const CSelector &selector)
getBonuses(out, selector, 0);
}
void DLL_EXPORT BonusList::getBonuses(BonusList &out, const CSelector &selector, const CSelector &limit) const
void DLL_EXPORT BonusList::getBonuses(boost::shared_ptr<BonusList> out, const CSelector &selector, const CSelector &limit, const bool caching /*= false*/) const
{
BOOST_FOREACH(Bonus *i, *this)
if(selector(i) && ((!limit && i->effectRange == Bonus::NO_LIMIT) || (limit && limit(i)))) //add matching bonuses that matches limit predicate or have NO_LIMIT if no given predicate
out.push_back(i);
for (int i = 0; i < this->size(); i++)
{
Bonus *b = (*this)[i];
//add matching bonuses that matches limit predicate or have NO_LIMIT if no given predicate
if(caching || (selector(b) && ((!limit && b->effectRange == Bonus::NO_LIMIT) || (limit && limit(b)))))
out->push_back(b);
}
}
void BonusList::limit(const CBonusSystemNode &node)
@@ -134,10 +147,11 @@ void BonusList::limit(const CBonusSystemNode &node)
remove_if(boost::bind(&CBonusSystemNode::isLimitedOnUs, boost::ref(node), _1));
}
void DLL_EXPORT BonusList::eliminateDuplicates()
{
sort();
unique();
sort( begin(), end() );
erase( unique( begin(), end() ), end() );
}
int IBonusBearer::valOfBonuses(Bonus::BonusType type, const CSelector &selector) const
@@ -156,13 +170,13 @@ int IBonusBearer::valOfBonuses(Bonus::BonusType type, int subtype /*= -1*/) cons
int IBonusBearer::valOfBonuses(const CSelector &selector) const
{
BonusList hlp;
getBonuses(hlp, selector);
return hlp.totalValue();
CSelector limit = 0;
boost::shared_ptr<BonusList> hlp = getAllBonuses(selector, limit, NULL);
return hlp->totalValue();
}
bool IBonusBearer::hasBonus(const CSelector &selector) const
{
return getBonuses(selector).size() > 0;
return getBonuses(selector)->size() > 0;
}
bool IBonusBearer::hasBonusOfType(Bonus::BonusType type, int subtype /*= -1*/) const
@@ -170,6 +184,12 @@ bool IBonusBearer::hasBonusOfType(Bonus::BonusType type, int subtype /*= -1*/) c
CSelector s = Selector::type(type);
if(subtype != -1)
s = s && Selector::subtype(subtype);
else
{
std::string str = "type_";
str += ((char) type);
setCachingStr(str);
}
return hasBonus(s);
}
@@ -181,7 +201,7 @@ void IBonusBearer::getModifiersWDescr(TModDescr &out, Bonus::BonusType type, int
void IBonusBearer::getModifiersWDescr(TModDescr &out, const CSelector &selector) const
{
getBonuses(selector).getModifiersWDescr(out);
getBonuses(selector)->getModifiersWDescr(out);
}
int IBonusBearer::getBonusesCount(int from, int id) const
{
@@ -190,43 +210,17 @@ int IBonusBearer::getBonusesCount(int from, int id) const
int IBonusBearer::getBonusesCount(const CSelector &selector) const
{
return getBonuses(selector).size();
return getBonuses(selector)->size();
}
void IBonusBearer::getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root /*= NULL*/) const
const boost::shared_ptr<BonusList> IBonusBearer::getBonuses(const CSelector &selector) const
{
getBonuses(out, selector, 0, root);
// FOREACH_CONST_PARENT(p)
// p->getBonuses(out, selector, root ? root : this);
//
// bonuses.getBonuses(out, selector);
//
// if(!root)
// out.limit(*this);
return getAllBonuses(selector, 0, NULL);
}
BonusList IBonusBearer::getBonuses(const CSelector &selector) const
const boost::shared_ptr<BonusList> IBonusBearer::getBonuses(const CSelector &selector, const CSelector &limit) const
{
BonusList ret;
getBonuses(ret, selector);
return ret;
}
void IBonusBearer::getBonuses(BonusList &out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= NULL*/) const
{
getAllBonuses(out, selector, limit, root);
out.eliminateDuplicates();
//
// getBonuses(out, selector); //first get all the bonuses
// out.remove_if(std::not1(limit)); //now remove the ones we don't like
// out.limit(*this); //apply bonuses' limiters
}
BonusList IBonusBearer::getBonuses(const CSelector &selector, const CSelector &limit) const
{
BonusList ret;
getBonuses(ret, selector, limit);
return ret;
return getAllBonuses(selector, limit, NULL);
}
bool IBonusBearer::hasBonusFrom(ui8 source, ui32 sourceID) const
@@ -325,6 +319,23 @@ si32 IBonusBearer::magicResistance() const
return valOfBonuses(Selector::type(Bonus::MAGIC_RESISTANCE));
}
void IBonusBearer::setCachingStr(const std::string &request) const
{
}
const boost::shared_ptr<BonusList> IBonusBearer::getSpellBonuses() const
{
std::string str = "source_";
str += (char) Bonus::SPELL_EFFECT;
setCachingStr(str);
return getBonuses(Selector::sourceType(Bonus::SPELL_EFFECT));
}
void CBonusSystemNode::setCachingStr(const std::string &request) const
{
cachingStr = request;
}
Bonus * CBonusSystemNode::getBonus(const CSelector &selector)
{
Bonus *ret = bonuses.getFirst(selector);
@@ -348,30 +359,82 @@ const Bonus * CBonusSystemNode::getBonus( const CSelector &selector ) const
void CBonusSystemNode::getParents(TCNodes &out) const /*retreives list of parent nodes (nodes to inherit bonuses from) */
{
BOOST_FOREACH(const CBonusSystemNode *parent, parents)
for (int i = 0; i < parents.size(); i++)
{
const CBonusSystemNode *parent = parents[i];
out.insert(parent);
}
}
void CBonusSystemNode::getParents(TNodes &out)
{
BOOST_FOREACH(const CBonusSystemNode *parent, parents)
for (int i = 0; i < parents.size(); i++)
{
const CBonusSystemNode *parent = parents[i];
out.insert(const_cast<CBonusSystemNode*>(parent));
}
}
void CBonusSystemNode::getAllBonuses(BonusList &out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= NULL*/) const
void CBonusSystemNode::getAllBonusesRec(boost::shared_ptr<BonusList> out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= NULL*/, const bool caching /*= false*/) const
{
FOREACH_CONST_PARENT(p)
p->getBonuses(out, selector, limit, root ? root : this);
bonuses.getBonuses(out, selector, limit);
TCNodes lparents;
getParents(lparents);
BOOST_FOREACH(const CBonusSystemNode *p, lparents)
p->getAllBonusesRec(out, selector, limit, root ? root : this, caching);
bonuses.getBonuses(out, selector, limit, caching);
if(!root)
out.limit(*this);
out->limit(*this);
}
CBonusSystemNode::CBonusSystemNode()
const boost::shared_ptr<BonusList> CBonusSystemNode::getAllBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= NULL*/) const
{
boost::shared_ptr<BonusList> ret(new BonusList());
if (CBonusSystemNode::cachingEnabled)
{
if (cachedLast != treeChanged)
{
getAllBonusesRec(ret, selector, limit, this, true);
ret->eliminateDuplicates();
cachedBonuses = *ret;
ret->clear();
cachedRequests.clear();
cachedLast = treeChanged;
}
if (cachingStr != "")
{
std::map<std::string, boost::shared_ptr<BonusList>>::iterator it(cachedRequests.find(cachingStr));
if (cachedRequests.size() > 0 && it != cachedRequests.end())
{
ret = it->second;
cachingStr = "";
return ret;
}
}
cachedBonuses.getBonuses(ret, selector, limit, false);
if (!root)
ret->limit(*this);
if (cachingStr != "")
cachedRequests[cachingStr] = ret;
cachingStr = "";
return ret;
}
else
{
getAllBonusesRec(ret, selector, limit, root, false);
ret->eliminateDuplicates();
return ret;
}
}
CBonusSystemNode::CBonusSystemNode() : nodeType(UNKNOWN), cachedLast(0)
{
nodeType = UNKNOWN;
}
CBonusSystemNode::~CBonusSystemNode()
@@ -400,6 +463,7 @@ void CBonusSystemNode::attachTo(CBonusSystemNode *parent)
newRedDescendant(parent);
parent->newChildAttached(this);
CBonusSystemNode::treeChanged++;
}
void CBonusSystemNode::detachFrom(CBonusSystemNode *parent)
@@ -413,13 +477,14 @@ void CBonusSystemNode::detachFrom(CBonusSystemNode *parent)
parents -= parent;
parent->childDetached(this);
CBonusSystemNode::treeChanged++;
}
void CBonusSystemNode::popBonuses(const CSelector &s)
{
BonusList bl;
boost::shared_ptr<BonusList> bl(new BonusList);
exportedBonuses.getBonuses(bl, s);
BOOST_FOREACH(Bonus *b, bl)
BOOST_FOREACH(Bonus *b, *bl)
removeBonus(b);
BOOST_FOREACH(CBonusSystemNode *child, children)
@@ -436,6 +501,7 @@ void CBonusSystemNode::addNewBonus(Bonus *b)
assert(!vstd::contains(exportedBonuses,b));
exportedBonuses.push_back(b);
exportBonus(b);
CBonusSystemNode::treeChanged++;
}
void CBonusSystemNode::removeBonus(Bonus *b)
@@ -446,6 +512,7 @@ void CBonusSystemNode::removeBonus(Bonus *b)
else
bonuses -= b;
delNull(b);
CBonusSystemNode::treeChanged++;
}
bool CBonusSystemNode::isLimitedOnUs(Bonus *b) const
@@ -603,8 +670,10 @@ void CBonusSystemNode::getRedDescendants(TNodes &out)
void CBonusSystemNode::battleTurnPassed()
{
BonusList bonusesCpy = exportedBonuses; //copy, because removing bonuses invalidates iters
BOOST_FOREACH(Bonus *b, bonusesCpy)
for (int i = 0; i < bonusesCpy.size(); i++)
{
Bonus *b = bonusesCpy[i];
if(b->duration & Bonus::N_TURNS)
{
b->turnsRemain--;
@@ -852,10 +921,10 @@ const CCreature * retrieveCreature(const CBonusSystemNode *node)
DLL_EXPORT std::ostream & operator<<(std::ostream &out, const BonusList &bonusList)
{
int i = 0;
BOOST_FOREACH(const Bonus *b, bonusList)
for (int i = 0; i < bonusList.size(); i++)
{
out << "Bonus " << i++ << "\n" << *b << std::endl;
Bonus *b = bonusList[i];
out << "Bonus " << i << "\n" << *b << std::endl;
}
return out;
}

View File

@@ -1,7 +1,6 @@
#pragma once
#include "../global.h"
#include <string>
#include <list>
#include <set>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
@@ -318,14 +317,14 @@ struct DLL_EXPORT Bonus
DLL_EXPORT std::ostream & operator<<(std::ostream &out, const Bonus &bonus);
class BonusList : public std::list<Bonus*>
class BonusList : public std::vector<Bonus*>
{
public:
int DLL_EXPORT totalValue() const; //subtype -> subtype of bonus, if -1 then any
void DLL_EXPORT getBonuses(BonusList &out, const CSelector &selector, const CSelector &limit) const;
void DLL_EXPORT getBonuses(boost::shared_ptr<BonusList> out, const CSelector &selector, const CSelector &limit, const bool caching = false) const;
void DLL_EXPORT getModifiersWDescr(TModDescr &out) const;
void DLL_EXPORT getBonuses(BonusList &out, const CSelector &selector) const;
void DLL_EXPORT getBonuses(boost::shared_ptr<BonusList> out, const CSelector &selector) const;
//special find functions
DLL_EXPORT Bonus * getFirst(const CSelector &select);
@@ -333,10 +332,26 @@ public:
void limit(const CBonusSystemNode &node); //erases bonuses using limitor
void DLL_EXPORT eliminateDuplicates();
// remove_if implementation for STL vector types
template <class Predicate>
void remove_if(Predicate pred)
{
BonusList newList;
for (int i = 0; i < this->size(); i++)
{
Bonus *b = (*this)[i];
if (!pred(b))
newList.push_back(b);
}
this->clear();
this->resize(newList.size());
std::copy(newList.begin(), newList.end(), this->begin());
}
template <typename Handler> void serialize(Handler &h, const int version)
{
h & static_cast<std::list<Bonus*>&>(*this);
h & static_cast<std::vector<Bonus*>&>(*this);
}
};
@@ -382,20 +397,18 @@ public:
class DLL_EXPORT IBonusBearer
{
public:
virtual void getAllBonuses(BonusList &out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL) const = 0;
//new bonusing node interface
// * selector is predicate that tests if HeroBonus matches our criteria
// * root is node on which call was made (NULL will be replaced with this)
//interface
void getBonuses(BonusList &out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL) const; //as above but without duplicates
void getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root = NULL) const;
virtual const boost::shared_ptr<BonusList> getAllBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL) const = 0;
virtual void setCachingStr(const std::string &request) const;
void getModifiersWDescr(TModDescr &out, const CSelector &selector) const; //out: pairs<modifier value, modifier description>
int getBonusesCount(const CSelector &selector) const;
int valOfBonuses(const CSelector &selector) const;
bool hasBonus(const CSelector &selector) const;
BonusList getBonuses(const CSelector &selector, const CSelector &limit) const;
BonusList getBonuses(const CSelector &selector) const;
const boost::shared_ptr<BonusList> getBonuses(const CSelector &selector, const CSelector &limit) const;
const boost::shared_ptr<BonusList> getBonuses(const CSelector &selector) const;
//legacy interface
int valOfBonuses(Bonus::BonusType type, const CSelector &selector) const;
@@ -417,11 +430,24 @@ public:
si32 manaLimit() const; //maximum mana value for this hero (basically 10*knowledge)
int getPrimSkillLevel(int id) const; //0-attack, 1-defence, 2-spell power, 3-knowledge
const boost::shared_ptr<BonusList> getSpellBonuses() const;
};
class DLL_EXPORT CBonusSystemNode : public IBonusBearer
{
static const bool cachingEnabled;
mutable BonusList cachedBonuses;
mutable int cachedLast;
static int treeChanged;
// Setting a value to cachingStr before getting any bonuses caches the result for later requests.
// This string needs to be unique, that's why it has to be setted in the following manner:
// [property key]_[value] => only for selector
mutable std::string cachingStr;
mutable std::map<std::string, boost::shared_ptr<BonusList>> cachedRequests;
void getAllBonusesRec(boost::shared_ptr<BonusList> out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL, const bool caching = false) const;
public:
BonusList bonuses; //wielded bonuses (local or up-propagated here)
BonusList exportedBonuses; //bonuses coming from this node (wielded or propagated away)
@@ -432,11 +458,11 @@ public:
ui8 nodeType;
std::string description;
CBonusSystemNode();
explicit CBonusSystemNode();
virtual ~CBonusSystemNode();
void getAllBonuses(BonusList &out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL) const;
const boost::shared_ptr<BonusList> getAllBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = NULL) const;
void setCachingStr(const std::string &request) const;
void getParents(TCNodes &out) const; //retrieves list of parent nodes (nodes to inherit bonuses from),
const Bonus *getBonus(const CSelector &selector) const;

View File

@@ -4265,7 +4265,8 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
if( attacker->hasBonusOfType(Bonus::SPELL_AFTER_ATTACK) )
{
std::set<ui32> spellsToCast;
BOOST_FOREACH(const Bonus *sf, attacker->getBonuses(Selector::type(Bonus::SPELL_AFTER_ATTACK)))
boost::shared_ptr<BonusList> spells = attacker->getBonuses(Selector::type(Bonus::SPELL_AFTER_ATTACK));
BOOST_FOREACH(const Bonus *sf, *spells)
{
spellsToCast.insert (sf->subtype);
}
@@ -4285,7 +4286,8 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
if(oneOfAttacked == NULL) //all attacked creatures have been killed
return;
int spellLevel = 0;
BOOST_FOREACH(const Bonus *sf, attacker->getBonuses(Selector::typeSubtype(Bonus::SPELL_AFTER_ATTACK, spellID)))
boost::shared_ptr<BonusList> spellsByType = attacker->getBonuses(Selector::typeSubtype(Bonus::SPELL_AFTER_ATTACK, spellID));
BOOST_FOREACH(const Bonus *sf, *spellsByType)
{
amax(spellLevel, sf->additionalInfo % 1000); //pick highest level
meleeRanged = sf->additionalInfo / 1000;
@@ -4333,7 +4335,8 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
}
}
int acidDamage = 0;
BOOST_FOREACH(const Bonus *b, attacker->getBonuses(Selector::type(Bonus::ACID_BREATH)))
boost::shared_ptr<BonusList> acidBreath = attacker->getBonuses(Selector::type(Bonus::ACID_BREATH));
BOOST_FOREACH(const Bonus *b, *acidBreath)
{
if (b->additionalInfo > rand()%100)
acidDamage += b->val;
@@ -4815,9 +4818,8 @@ void CGameHandler::runBattle()
{
if(gs->curB->heroes[i] && gs->curB->heroes[i]->hasBonusOfType(Bonus::OPENING_BATTLE_SPELL))
{
BonusList bl;
gs->curB->heroes[i]->getBonuses(bl, Selector::type(Bonus::OPENING_BATTLE_SPELL));
BOOST_FOREACH (Bonus *b, bl)
boost::shared_ptr<BonusList> bl = gs->curB->heroes[i]->getBonuses(Selector::type(Bonus::OPENING_BATTLE_SPELL));
BOOST_FOREACH (Bonus *b, *bl)
{
handleSpellCasting(b->subtype, 3, -1, 0, gs->curB->heroes[i]->tempOwner, NULL, gs->curB->heroes[1-i], b->val, SpellCasting::HERO_CASTING, NULL);
}