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:
@@ -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;
|
||||
}
|
||||
|
@@ -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
|
||||
|
||||
|
@@ -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())
|
||||
|
@@ -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)
|
||||
|
@@ -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
|
||||
|
@@ -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)
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
|
@@ -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 (?)
|
||||
|
@@ -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);
|
||||
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user