diff --git a/hch/CObjectHandler.cpp b/hch/CObjectHandler.cpp index a4a8da175..2aa84de8c 100644 --- a/hch/CObjectHandler.cpp +++ b/hch/CObjectHandler.cpp @@ -993,11 +993,6 @@ std::vector > CGHeroInstance::getCurrentLuckModifiers return ret; } -const HeroBonus * CGHeroInstance::getBonus( int from, int id ) const -{ - return bonuses.getBonus(from, id); -} - void CGHeroInstance::setPropertyDer( ui8 what, ui32 val ) { if(what == 3) @@ -1154,19 +1149,6 @@ si32 CGHeroInstance::manaRegain() const return 1 + getSecSkillLevel(8) + valOfBonuses(HeroBonus::MANA_REGENERATION); //1 + Mysticism level } -int CGHeroInstance::valOfBonuses( HeroBonus::BonusType type, int subtype /*= -1*/ ) const -{ - return bonuses.valOfBonuses(type, subtype) + ownerBonuses()->valOfBonuses(type, subtype); -} - -bool CGHeroInstance::hasBonusOfType(HeroBonus::BonusType type, int subtype /*= -1*/) const -{ - if(!this) //to allow calls on NULL and avoid checking duplication - return false; //if hero doesn't exist then bonus neither can - else - return bonuses.hasBonusOfType(type, subtype) || ownerBonuses()->hasBonusOfType(type, subtype); -} - si32 CGHeroInstance::getArtPos(int aid) const { for(std::map::const_iterator i = artifWorn.begin(); i != artifWorn.end(); i++) @@ -1218,21 +1200,6 @@ bool CGHeroInstance::hasArt( ui32 aid ) const return false; } -void CGHeroInstance::getModifiersWDescr( std::vector > &out, HeroBonus::BonusType type, int subtype /*= -1*/ ) const -{ - bonuses.getModifiersWDescr(out, type, subtype); - ownerBonuses()->getModifiersWDescr(out, type, subtype); -} - -const BonusList * CGHeroInstance::ownerBonuses() const -{ - const PlayerState *p = cb->getPlayerState(tempOwner); - if(!p) - return NULL; - else - return &p->bonuses; -} - int CGHeroInstance::getBoatType() const { int alignment = type->heroType / 6; @@ -1261,15 +1228,16 @@ int CGHeroInstance::getSpellCost(const CSpell *sp) const return sp->costs[getSpellSchoolLevel(sp)]; } -int CGHeroInstance::getBonusesCount(int from, int id) const +void CGHeroInstance::getParents(TCNodes &out, const CBonusSystemNode *source) const { - int ret = 0; + const PlayerState *p = cb->getPlayerState(tempOwner); + if(!p) + { + //occurs when initializing starting hero and heroes from the pool + return; + } - BOOST_FOREACH(const HeroBonus &hb, bonuses) - if(hb.source == from && hb.id == id) - ret++; - - return ret; + out.push_back(p); } void CGDwelling::initObj() diff --git a/hch/CObjectHandler.h b/hch/CObjectHandler.h index ea67048e3..2658590d6 100644 --- a/hch/CObjectHandler.h +++ b/hch/CObjectHandler.h @@ -232,7 +232,7 @@ public: } }; -class DLL_EXPORT CGHeroInstance : public CArmedInstance, public IBoatGenerator +class DLL_EXPORT CGHeroInstance : public CArmedInstance, public IBoatGenerator, public CBonusSystemNode { public: ////////////////////////////////////////////////////////////////////////// @@ -273,7 +273,7 @@ public: } } patrol; - BonusList bonuses; + //BonusList bonuses; ////////////////////////////////////////////////////////////////////////// @@ -311,17 +311,8 @@ public: int getCurrentLuck(int stack=-1, bool town=false) const; int getSpellCost(const CSpell *sp) const; //do not use during battles -> bonuses from army would be ignored - const BonusList *ownerBonuses() const; - const HeroBonus *getBonus(int from, int id) const; - int getBonusesCount(int from, int id) const; - int valOfBonuses(HeroBonus::BonusType type, int subtype = -1) const; //subtype -> subtype of bonus, if -1 then any - bool hasBonusOfType(HeroBonus::BonusType type, int subtype = -1) const; //determines if hero has a bonus of given type (and optionally subtype) - void getModifiersWDescr(std::vector > &out, HeroBonus::BonusType type, int subtype = -1) const; //out: pairs - template void getModifiersWDescr(std::vector > &out, const HeroBonus::BonusType (&types)[N]) const //retreive array of types - { - for (int i = 0; i < N; i++) - getModifiersWDescr(out, types[i]); - } + + void getParents(TCNodes &out, const CBonusSystemNode *source = NULL) const; std::vector > getCurrentLuckModifiers(int stack=-1, bool town=false) const; //args as above int getCurrentMorale(int stack=-1, bool town=false) const; //if stack - position of creature, if -1 then morale for hero is calculated; town - if bonuses from town (tavern) should be considered diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index d1e55eb34..b82d77e1a 100644 --- a/lib/CGameState.cpp +++ b/lib/CGameState.cpp @@ -2973,8 +2973,7 @@ bool CGameState::battleCanShoot(int ID, int dest) if(our->hasFeatureOfType(StackFeature::SHOOTER)//it's shooter && our->owner != dst->owner && dst->alive() - && (!curB->isStackBlocked(ID) - || ourHero->hasBonusOfType(HeroBonus::FREE_SHOOTING)) + && (!curB->isStackBlocked(ID) || NBonus::hasOfType(ourHero, HeroBonus::FREE_SHOOTING)) && our->shots ) return true; diff --git a/lib/CGameState.h b/lib/CGameState.h index 80902e217..83861de9b 100644 --- a/lib/CGameState.h +++ b/lib/CGameState.h @@ -105,7 +105,7 @@ struct DLL_EXPORT SThievesGuildInfo }; -struct DLL_EXPORT PlayerState +struct DLL_EXPORT PlayerState : public CBonusSystemNode { public: enum EStatus {INGAME, LOSER, WINNER}; @@ -118,7 +118,6 @@ public: std::vector towns; std::vector availableHeroes; //heroes available in taverns std::vector dwellings; //used for town growth - BonusList bonuses; //player bonuses ui8 status; //0 - in game, 1 - loser, 2 - winner <- uses EStatus enum ui8 daysWithoutCastle; @@ -129,37 +128,6 @@ public: { h & color & serial & human & currentSelection & fogOfWarMap & resources & status; h & heroes & towns & availableHeroes & dwellings & bonuses & status & daysWithoutCastle; - -// ui32 size; -// if(h.saving) //write subids of available heroes -// { -// size = availableHeroes.size(); -// h & size; -// for(size_t i=0; i < size; i++) -// { -// if(availableHeroes[i]) -// { -// h & availableHeroes[i]->subID; -// } -// else -// { -// ui32 none = 0xffffffff; -// h & none; -// } -// } -// } -// else -// { -// ui32 hid; -// h & size; -// for(size_t i=0; i < size; i++) -// { -// //fill availableHeroes with dummy hero instances, holding subids -// h & hid; -// availableHeroes.push_back(new CGHeroInstance); -// availableHeroes[availableHeroes.size()-1]->subID = hid; -// } -// } } }; diff --git a/lib/HeroBonus.cpp b/lib/HeroBonus.cpp index 625422da4..488d087f6 100644 --- a/lib/HeroBonus.cpp +++ b/lib/HeroBonus.cpp @@ -1,5 +1,8 @@ #define VCMI_DLL #include "HeroBonus.h" +#include + +#define FOREACH_PARENT(pname) TCNodes parents; getParents(parents); BOOST_FOREACH(const CBonusSystemNode *pname, parents) int BonusList::valOfBonuses( HeroBonus::BonusType type, int subtype /*= -1*/ ) const /*subtype -> subtype of bonus, if -1 then any */ { @@ -70,4 +73,92 @@ void BonusList::getModifiersWDescr( std::vector > &ou if(i->type == type && i->subtype == subtype) out.push_back(std::make_pair(i->val, i->description)); } +} + +int CBonusSystemNode::valOfBonuses(HeroBonus::BonusType type, int subtype /*= -1*/) const +{ + int ret = bonuses.valOfBonuses(type, subtype); + + FOREACH_PARENT(p) + ret += p->valOfBonuses(type, subtype); + + return ret; +} + +bool CBonusSystemNode::hasBonusOfType(HeroBonus::BonusType type, int subtype /*= -1*/) const +{ + if(!this) //to allow calls on NULL and avoid checking duplication + return false; //if hero doesn't exist then bonus neither can + + if(bonuses.hasBonusOfType(type, subtype)) + return true; + + FOREACH_PARENT(p) + if(p->hasBonusOfType(type, subtype)) + return true; + + return false; +} + +const HeroBonus * CBonusSystemNode::getBonus(int from, int id) const +{ + return bonuses.getBonus(from, id); +} + +void CBonusSystemNode::getModifiersWDescr(std::vector > &out, HeroBonus::BonusType type, int subtype /*= -1 */) const +{ + bonuses.getModifiersWDescr(out, type, subtype); + + FOREACH_PARENT(p) + p->getModifiersWDescr(out, type, subtype); +} + +int CBonusSystemNode::getBonusesCount(int from, int id) const +{ + int ret = 0; + + BOOST_FOREACH(const HeroBonus &hb, bonuses) + if(hb.source == from && hb.id == id) + ret++; + + return ret; +} + +void CBonusSystemNode::getParents(TCNodes &out, const CBonusSystemNode *source) const /*retreives list of parent nodes (nodes to inherit bonuses from) */ +{ + return; +} + +int NBonus::valOf(const CBonusSystemNode *obj, HeroBonus::BonusType type, int subtype /*= -1*/) +{ + if(obj) + return obj->valOfBonuses(type, subtype); + return 0; +} + +bool NBonus::hasOfType(const CBonusSystemNode *obj, HeroBonus::BonusType type, int subtype /*= -1*/) +{ + if(obj) + return obj->hasBonusOfType(type, subtype); + return false; +} + +const HeroBonus * NBonus::get(const CBonusSystemNode *obj, int from, int id) +{ + if(obj) + return obj->getBonus(from, id); + return NULL; +} + +void NBonus::getModifiersWDescr(const CBonusSystemNode *obj, std::vector > &out, HeroBonus::BonusType type, int subtype /*= -1 */) +{ + if(obj) + return obj->getModifiersWDescr(out, type, subtype); +} + +int NBonus::getCount(const CBonusSystemNode *obj, int from, int id) +{ + if(obj) + return obj->getBonusesCount(from, id); + return 0; } \ No newline at end of file diff --git a/lib/HeroBonus.h b/lib/HeroBonus.h index 475f85781..5ef228fe5 100644 --- a/lib/HeroBonus.h +++ b/lib/HeroBonus.h @@ -113,9 +113,13 @@ struct DLL_EXPORT HeroBonus }; +class CBonusSystemNode; + static const HeroBonus::BonusType MORALE_AFFECTING[] = {HeroBonus::MORALE, HeroBonus::MORALE_AND_LUCK}; static const HeroBonus::BonusType LUCK_AFFECTING[] = {HeroBonus::LUCK, HeroBonus::MORALE_AND_LUCK}; typedef std::vector > TModDescr; //modifiers values and their descriptions +typedef std::list TNodes; +typedef std::list TCNodes; class BonusList : public std::list { @@ -129,4 +133,39 @@ public: { h & static_cast&>(*this); } +}; + +class DLL_EXPORT CBonusSystemNode +{ +public: + BonusList bonuses; + + virtual void getParents(TCNodes &out, const CBonusSystemNode *source = NULL) const; //retreives list of parent nodes (nodes to inherit bonuses from), source is the prinary asker + + int valOfBonuses(HeroBonus::BonusType type, int subtype = -1) const; //subtype -> subtype of bonus, if -1 then any + bool hasBonusOfType(HeroBonus::BonusType type, int subtype = -1) const;//determines if hero has a bonus of given type (and optionally subtype) + const HeroBonus * getBonus( int from, int id ) const; + void getModifiersWDescr( std::vector > &out, HeroBonus::BonusType type, int subtype = -1 ) const; //out: pairs + int getBonusesCount(int from, int id) const; + + template void getModifiersWDescr(std::vector > &out, const HeroBonus::BonusType (&types)[N]) const //retreive array of types + { + for (int i = 0; i < N; i++) + getModifiersWDescr(out, types[i]); + } + + template void serialize(Handler &h, const int version) + { + h & bonuses; + } +}; + +namespace NBonus +{ + //set of methods that may be safely called with NULL objs + DLL_EXPORT int valOf(const CBonusSystemNode *obj, HeroBonus::BonusType type, int subtype = -1); //subtype -> subtype of bonus, if -1 then any + DLL_EXPORT bool hasOfType(const CBonusSystemNode *obj, HeroBonus::BonusType type, int subtype = -1);//determines if hero has a bonus of given type (and optionally subtype) + DLL_EXPORT const HeroBonus * get(const CBonusSystemNode *obj, int from, int id ); + DLL_EXPORT void getModifiersWDescr(const CBonusSystemNode *obj, std::vector > &out, HeroBonus::BonusType type, int subtype = -1 ); //out: pairs + DLL_EXPORT int getCount(const CBonusSystemNode *obj, int from, int id); }; \ No newline at end of file diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index a7560083e..2bb839a8f 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -337,7 +337,6 @@ void CGameHandler::startBattle(const CArmedInstance *army1, const CArmedInstance NEW_ROUND; //TODO: pre-tactic stuff, call scripts etc. - //tactic round { NEW_ROUND; @@ -362,7 +361,7 @@ void CGameHandler::startBattle(const CArmedInstance *army1, const CArmedInstance //check for bad morale => freeze if( curB.Morale(next) < 0 && - !((hero1->hasBonusOfType(HeroBonus::BLOCK_MORALE)) || (hero2->hasBonusOfType(HeroBonus::BLOCK_MORALE))) //checking if heroes have (or don't have) morale blocking bonuses) + !(NBonus::hasOfType(hero1, HeroBonus::BLOCK_MORALE) || NBonus::hasOfType(hero2, HeroBonus::BLOCK_MORALE)) //checking if heroes have (or don't have) morale blocking bonuses) ) { if( rand()%24 < (-curB.Morale(next))*2 ) @@ -509,7 +508,7 @@ askInterfaceForMove: && !vstd::contains(next->state,WAITING) && next->alive() && curB.Morale(next) > 0 - && !((hero1->hasBonusOfType(HeroBonus::BLOCK_MORALE)) || (hero2->hasBonusOfType(HeroBonus::BLOCK_MORALE)) ) //checking if heroes have (or don't have) morale blocking bonuses + && !(NBonus::hasOfType(hero1, HeroBonus::BLOCK_MORALE) || NBonus::hasOfType(hero2, HeroBonus::BLOCK_MORALE)) //checking if heroes have (or don't have) morale blocking bonuses ) if(rand()%24 < curB.Morale(next)) //this stack hasn't got morale this turn goto askInterfaceForMove; //move this stack once more @@ -3689,7 +3688,7 @@ bool CGameHandler::makeCustomAction( BattleAction &ba ) || (h->mana < gs->curB->getSpellCost(s, h)) //not enough mana || (ba.additionalInfo < 10) //it's adventure spell (not combat) || (gs->curB->castSpells[ba.side]) //spell has been cast - || (secondHero->hasBonusOfType(HeroBonus::SPELL_IMMUNITY, s->id)) //non - casting hero provides immunity for this spell + || (NBonus::hasOfType(secondHero, HeroBonus::SPELL_IMMUNITY, s->id)) //non - casting hero provides immunity for this spell || (gs->battleMaxSpellLevel() < s->level) //non - casting hero stops caster from casting this spell ) {