diff --git a/hch/CArtHandler.cpp b/hch/CArtHandler.cpp index d4c5b78ff..f3416c33f 100644 --- a/hch/CArtHandler.cpp +++ b/hch/CArtHandler.cpp @@ -484,11 +484,11 @@ void CArtHandler::getAllowedArts(std::vector &out, std::vectorvalType = valType; + added->limiter.reset(limiter); if(type == Bonus::MORALE || Bonus::LUCK) - added.description = "\n" + artifacts[aid]->Name() + (val > 0 ? " +" : " ") + boost::lexical_cast(val); + added->description = "\n" + artifacts[aid]->Name() + (val > 0 ? " +" : " ") + boost::lexical_cast(val); artifacts[aid]->addNewBonus(added); } diff --git a/hch/CCreatureHandler.cpp b/hch/CCreatureHandler.cpp index 6aed3a394..f9c739e7b 100644 --- a/hch/CCreatureHandler.cpp +++ b/hch/CCreatureHandler.cpp @@ -126,7 +126,7 @@ CCreature::CCreature() } void CCreature::addBonus(int val, int type, int subtype /*= -1*/) { - Bonus added(Bonus::PERMANENT, type, Bonus::CREATURE_ABILITY, val, idNumber, subtype, Bonus::BASE_NUMBER); + Bonus *added = new Bonus(Bonus::PERMANENT, type, Bonus::CREATURE_ABILITY, val, idNumber, subtype, Bonus::BASE_NUMBER); addNewBonus(added); } // void CCreature::getParents(TCNodes &out, const CBonusSystemNode *root /*= NULL*/) const @@ -364,7 +364,7 @@ void CCreatureHandler::loadCreatures() case '+': //add new ability { int creatureID; - Bonus nsf; + Bonus *nsf = new Bonus(); si32 buf; std::string type; @@ -392,15 +392,15 @@ void CCreatureHandler::loadCreatures() tlog1 << "Error: invalid type " << type << " in cr_abils.txt" << std::endl; break; } - nsf.type = it->second; + nsf->type = it->second; - reader >> buf; nsf.val = buf; - reader >> buf; nsf.subtype = buf; - reader >> buf; nsf.additionalInfo = buf; - nsf.source = Bonus::CREATURE_ABILITY; - nsf.id = cre->idNumber; - nsf.duration = Bonus::ONE_BATTLE; - nsf.turnsRemain = 0; + reader >> buf; nsf->val = buf; + reader >> buf; nsf->subtype = buf; + reader >> buf; nsf->additionalInfo = buf; + nsf->source = Bonus::CREATURE_ABILITY; + nsf->id = cre->idNumber; + nsf->duration = Bonus::ONE_BATTLE; + nsf->turnsRemain = 0; cre->addNewBonus(nsf); break; diff --git a/hch/CObjectHandler.cpp b/hch/CObjectHandler.cpp index a6cbbb272..6280c84ec 100644 --- a/hch/CObjectHandler.cpp +++ b/hch/CObjectHandler.cpp @@ -979,17 +979,17 @@ void CGHeroInstance::initObj() { blockVisit = true; speciality.growthsWithLevel = false; - Bonus bonus; if(!type) return; //TODO support prison for (std::vector::const_iterator it = type->spec.begin(); it != type->spec.end(); it++) { - bonus.val = it->val; - bonus.id = id; //from the hero, speciality has no unique id - bonus.duration = Bonus::PERMANENT; - bonus.source = Bonus::HERO_SPECIAL; + Bonus *bonus = new Bonus(); + bonus->val = it->val; + bonus->id = id; //from the hero, speciality has no unique id + bonus->duration = Bonus::PERMANENT; + bonus->source = Bonus::HERO_SPECIAL; switch (it->type) { case 1:// creature speciality @@ -1010,139 +1010,139 @@ void CGHeroInstance::initObj() } } - bonus.limiter = new CCreatureTypeLimiter (specCreature, true); //with upgrades - bonus.type = Bonus::PRIMARY_SKILL; - bonus.additionalInfo = it->additionalinfo; - bonus.valType = Bonus::ADDITIVE_VALUE; + bonus->limiter.reset(new CCreatureTypeLimiter (specCreature, true)); //with upgrades + bonus->type = Bonus::PRIMARY_SKILL; + bonus->additionalInfo = it->additionalinfo; + bonus->valType = Bonus::ADDITIVE_VALUE; - bonus.subtype = PrimarySkill::ATTACK; + bonus->subtype = PrimarySkill::ATTACK; speciality.addNewBonus(bonus); - bonus.subtype = PrimarySkill::DEFENSE; + bonus->subtype = PrimarySkill::DEFENSE; speciality.addNewBonus(bonus); //values will be calculated later - bonus.type = Bonus::STACKS_SPEED; - bonus.val = 1; //+1 speed + bonus->type = Bonus::STACKS_SPEED; + bonus->val = 1; //+1 speed speciality.addNewBonus(bonus); } break; case 2://secondary skill speciality.growthsWithLevel = true; - bonus.type = Bonus::SPECIAL_SECONDARY_SKILL; //needs to be recalculated with level, based on this value - bonus.valType = Bonus::BASE_NUMBER; // to receive nonzero value - bonus.subtype = it->subtype; //skill id - bonus.val = it->val; //value per level, in percent + bonus->type = Bonus::SPECIAL_SECONDARY_SKILL; //needs to be recalculated with level, based on this value + bonus->valType = Bonus::BASE_NUMBER; // to receive nonzero value + bonus->subtype = it->subtype; //skill id + bonus->val = it->val; //value per level, in percent speciality.addNewBonus(bonus); switch (it->additionalinfo) { case 0: //normal - bonus.valType = Bonus::PERCENT_TO_BASE; + bonus->valType = Bonus::PERCENT_TO_BASE; break; case 1: //when it's navigation or there's no 'base' at all - bonus.valType = Bonus::PERCENT_TO_ALL; + bonus->valType = Bonus::PERCENT_TO_ALL; break; } - bonus.type = Bonus::SECONDARY_SKILL_PREMY; //value will be calculated later + bonus->type = Bonus::SECONDARY_SKILL_PREMY; //value will be calculated later speciality.addNewBonus(bonus); break; case 3://spell damage bonus, level dependant but calculated elsehwere - bonus.type = Bonus::SPECIAL_SPELL_LEV; - bonus.subtype = it->subtype; + bonus->type = Bonus::SPECIAL_SPELL_LEV; + bonus->subtype = it->subtype; speciality.addNewBonus(bonus); break; case 4://creature stat boost switch (it->subtype) { case 1://attack - bonus.type = Bonus::PRIMARY_SKILL; - bonus.subtype = PrimarySkill::ATTACK; + bonus->type = Bonus::PRIMARY_SKILL; + bonus->subtype = PrimarySkill::ATTACK; break; case 2://defense - bonus.type = Bonus::PRIMARY_SKILL; - bonus.subtype = PrimarySkill::DEFENSE; + bonus->type = Bonus::PRIMARY_SKILL; + bonus->subtype = PrimarySkill::DEFENSE; break; case 3: - bonus.type = Bonus::CREATURE_DAMAGE; - bonus.subtype = 0; //both min and max + bonus->type = Bonus::CREATURE_DAMAGE; + bonus->subtype = 0; //both min and max break; case 4://hp - bonus.type = Bonus::STACK_HEALTH; + bonus->type = Bonus::STACK_HEALTH; break; case 5: - bonus.type = Bonus::STACKS_SPEED; + bonus->type = Bonus::STACKS_SPEED; break; default: continue; } - bonus.valType = Bonus::ADDITIVE_VALUE; - bonus.limiter = new CCreatureTypeLimiter (*VLC->creh->creatures[it->additionalinfo], true); + bonus->valType = Bonus::ADDITIVE_VALUE; + bonus->limiter.reset(new CCreatureTypeLimiter (*VLC->creh->creatures[it->additionalinfo], true)); speciality.addNewBonus(bonus); break; case 5://spell damage bonus in percent - bonus.type = Bonus::SPECIFIC_SPELL_DAMAGE; - bonus.valType = Bonus::BASE_NUMBER; // current spell system is screwed - bonus.subtype = it->subtype; //spell id + bonus->type = Bonus::SPECIFIC_SPELL_DAMAGE; + bonus->valType = Bonus::BASE_NUMBER; // current spell system is screwed + bonus->subtype = it->subtype; //spell id speciality.addNewBonus(bonus); break; case 6://damage bonus for bless (Adela) - bonus.type = Bonus::SPECIAL_BLESS_DAMAGE; - bonus.subtype = it->subtype; //spell id if you ever wanted to use it otherwise - bonus.additionalInfo = it->additionalinfo; //damage factor + bonus->type = Bonus::SPECIAL_BLESS_DAMAGE; + bonus->subtype = it->subtype; //spell id if you ever wanted to use it otherwise + bonus->additionalInfo = it->additionalinfo; //damage factor speciality.addNewBonus(bonus); break; case 7://maxed mastery for spell - bonus.type = Bonus::MAXED_SPELL; - bonus.subtype = it->subtype; //spell i + bonus->type = Bonus::MAXED_SPELL; + bonus->subtype = it->subtype; //spell i speciality.addNewBonus(bonus); break; case 8://peculiar spells - enchantments - bonus.type = Bonus::SPECIAL_PECULIAR_ENCHANT; - bonus.subtype = it->subtype; //spell id - bonus.additionalInfo = it->additionalinfo;//0, 1 for Coronius + bonus->type = Bonus::SPECIAL_PECULIAR_ENCHANT; + bonus->subtype = it->subtype; //spell id + bonus->additionalInfo = it->additionalinfo;//0, 1 for Coronius speciality.addNewBonus(bonus); break; case 9://upgrade creatures { std::vector* creatures = &VLC->creh->creatures; - bonus.type = Bonus::SPECIAL_UPGRADE; - bonus.subtype = it->subtype; //base id - bonus.additionalInfo = it->additionalinfo; //target id + bonus->type = Bonus::SPECIAL_UPGRADE; + bonus->subtype = it->subtype; //base id + bonus->additionalInfo = it->additionalinfo; //target id speciality.addNewBonus(bonus); for (std::set::iterator i = (*creatures)[it->subtype]->upgrades.begin(); i != (*creatures)[it->subtype]->upgrades.end(); i++) { - bonus.subtype = *i; //propagate for regular upgrades of base creature + bonus->subtype = *i; //propagate for regular upgrades of base creature speciality.addNewBonus(bonus); } break; } case 10://resource generation - bonus.type = Bonus::GENERATE_RESOURCE; - bonus.subtype = it->subtype; + bonus->type = Bonus::GENERATE_RESOURCE; + bonus->subtype = it->subtype; speciality.addNewBonus(bonus); break; case 11://starting skill with mastery (Adrienne) cb->changeSecSkill(id, it->val, it->additionalinfo); //simply give it and forget break; case 12://army speed - bonus.type = Bonus::STACKS_SPEED; + bonus->type = Bonus::STACKS_SPEED; speciality.addNewBonus(bonus); break; case 13://Dragon bonuses (Mutare) - bonus.type = Bonus::PRIMARY_SKILL; - bonus.valType = Bonus::ADDITIVE_VALUE; + bonus->type = Bonus::PRIMARY_SKILL; + bonus->valType = Bonus::ADDITIVE_VALUE; switch (it->subtype) { case 1: - bonus.subtype = PrimarySkill::ATTACK; + bonus->subtype = PrimarySkill::ATTACK; break; case 2: - bonus.subtype = PrimarySkill::DEFENSE; + bonus->subtype = PrimarySkill::DEFENSE; break; } - bonus.limiter = new HasAnotherBonusLimiter(Bonus::DRAGON_NATURE); + bonus->limiter.reset(new HasAnotherBonusLimiter(Bonus::DRAGON_NATURE)); speciality.addNewBonus(bonus); break; default: @@ -1247,9 +1247,9 @@ void CGHeroInstance::updateSkill(int which, int val) } else { - Bonus bonus(Bonus::PERMANENT, Bonus::SECONDARY_SKILL_PREMY, id, skillVal, ID, which, Bonus::BASE_NUMBER); - bonus.source = Bonus::SECONDARY_SKILL; - addNewBonus (bonus); + Bonus *bonus = new Bonus(Bonus::PERMANENT, Bonus::SECONDARY_SKILL_PREMY, id, skillVal, ID, which, Bonus::BASE_NUMBER); + bonus->source = Bonus::SECONDARY_SKILL; + addNewBonus(bonus); } } } @@ -1506,7 +1506,7 @@ int CGHeroInstance::getSpellCost(const CSpell *sp) const void CGHeroInstance::pushPrimSkill(int which, int val) { - addNewBonus(Bonus(Bonus::PERMANENT, Bonus::PRIMARY_SKILL, Bonus::HERO_BASE_SKILL, val, id, which)); + addNewBonus(new Bonus(Bonus::PERMANENT, Bonus::PRIMARY_SKILL, Bonus::HERO_BASE_SKILL, val, id, which)); } // void CGHeroInstance::getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *root /*= NULL*/) const @@ -2132,7 +2132,7 @@ void CGTownInstance::initObj() //add special bonuses from buildings if(subID == 4 && vstd::contains(builtBuildings, 17)) { - addNewBonus( Bonus(Bonus::PERMANENT, Bonus::DARKNESS, Bonus::TOWN_STRUCTURE, 20, 17) ); + addNewBonus(new Bonus(Bonus::PERMANENT, Bonus::DARKNESS, Bonus::TOWN_STRUCTURE, 20, 17) ); } } diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index ee3b3ac10..16565e16d 100644 --- a/lib/CGameState.cpp +++ b/lib/CGameState.cpp @@ -3435,25 +3435,10 @@ int BattleInfo::calculateSpellDuration( const CSpell * spell, const CGHeroInstan } } -CStack * BattleInfo::generateNewStack(const CStackInstance &base, int stackID, bool attackerOwned, int slot, int /*TerrainTile::EterrainType*/ terrain, int position) const +CStack * BattleInfo::generateNewStack(const CStackInstance &base, int stackID, bool attackerOwned, int slot, int position) const { CStack * ret = new CStack(&base, attackerOwned ? side1 : side2, stackID, attackerOwned, slot); - - //TODO: bonus na bitwę z limiterem - -////////////////////////////////////////////////////////////////////////// - - //native terrain bonuses -// int faction = ret->type->faction; -// if(faction >= 0 && VLC->heroh->nativeTerrains[faction] == terrain) -// { -// ret->addNewBonus(makeFeature(Bonus::STACKS_SPEED, Bonus::ONE_BATTLE, 0, 1, Bonus::TERRAIN_NATIVE)); -// ret->addNewBonus(makeFeature(Bonus::PRIMARY_SKILL, Bonus::ONE_BATTLE, PrimarySkill::ATTACK, 1, Bonus::TERRAIN_NATIVE)); -// ret->addNewBonus(makeFeature(Bonus::PRIMARY_SKILL, Bonus::ONE_BATTLE, PrimarySkill::DEFENSE, 1, Bonus::TERRAIN_NATIVE)); -// } -// -// ret->position = position; - + ret->position = position; return ret; } diff --git a/lib/CGameState.h b/lib/CGameState.h index a24445d19..c54738804 100644 --- a/lib/CGameState.h +++ b/lib/CGameState.h @@ -236,7 +236,7 @@ struct DLL_EXPORT BattleInfo : public CBonusSystemNode void calculateCasualties(std::map *casualties) const; //casualties are array of maps size 2 (attacker, defeneder), maps are (crid => amount) std::set getAttackedCreatures(const CSpell * s, int skillLevel, ui8 attackerOwner, int destinationTile); //calculates stack affected by given spell static int calculateSpellDuration(const CSpell * spell, const CGHeroInstance * caster, int usedSpellPower); - CStack * generateNewStack(const CStackInstance &base, int stackID, bool attackerOwned, int slot, int /*TerrainTile::EterrainType*/ terrain, int position) const; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield + CStack * generateNewStack(const CStackInstance &base, int stackID, bool attackerOwned, int slot, int position) const; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield ui32 getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const; //returns cost of given spell int hexToWallPart(int hex) const; //returns part of destructible wall / gate / keep under given hex or -1 if not found int lineToWallHex(int line) const; //returns hex with wall in given line @@ -278,19 +278,19 @@ public: void stackEffectToFeature(BonusList & sf, const Bonus & sse); std::vector activeSpells() const; //returns vector of active spell IDs sorted by time of cast - static inline Bonus featureGenerator(Bonus::BonusType type, si16 subtype, si32 value, ui16 turnsRemain, si32 additionalInfo = 0, si32 limit = Bonus::NO_LIMIT) + static inline Bonus *featureGenerator(Bonus::BonusType type, si16 subtype, si32 value, ui16 turnsRemain, si32 additionalInfo = 0, si32 limit = Bonus::NO_LIMIT) { - Bonus hb(makeFeature(type, Bonus::N_TURNS, subtype, value, Bonus::SPELL_EFFECT, turnsRemain, additionalInfo)); - hb.effectRange = limit; - hb.source = Bonus::CASTED_SPELL; //right? + Bonus *hb = makeFeature(type, Bonus::N_TURNS, subtype, value, Bonus::SPELL_EFFECT, turnsRemain, additionalInfo); + hb->effectRange = limit; + hb->source = Bonus::CASTED_SPELL; //right? return hb; } - static inline Bonus featureGeneratorVT(Bonus::BonusType type, si16 subtype, si32 value, ui16 turnsRemain, ui8 valType) + static inline Bonus *featureGeneratorVT(Bonus::BonusType type, si16 subtype, si32 value, ui16 turnsRemain, ui8 valType) { - Bonus ret(makeFeature(type, Bonus::N_TURNS, subtype, value, Bonus::SPELL_EFFECT, turnsRemain)); - ret.valType = valType; - ret.source = Bonus::CASTED_SPELL; //right? + Bonus *ret(makeFeature(type, Bonus::N_TURNS, subtype, value, Bonus::SPELL_EFFECT, turnsRemain)); + ret->valType = valType; + ret->source = Bonus::CASTED_SPELL; //right? return ret; } diff --git a/lib/Connection.h b/lib/Connection.h index ef02ec5d9..8be1f008c 100644 --- a/lib/Connection.h +++ b/lib/Connection.h @@ -488,6 +488,12 @@ public: const_cast(data).serialize(*this,version); } template + void saveSerializable(const boost::shared_ptr &data) + { + T *internalPtr = data.get(); + *this << internalPtr; + } + template void saveSerializable(const std::vector &data) { boost::uint32_t length = data.size(); @@ -735,6 +741,13 @@ public: }; + template + void loadSerializable(boost::shared_ptr &data) + { + T *internalPtr; + *this >> internalPtr; + data.reset(internalPtr); + } template void loadSerializable(std::vector &data) { diff --git a/lib/HeroBonus.cpp b/lib/HeroBonus.cpp index f5a7b4b13..71372fe3b 100644 --- a/lib/HeroBonus.cpp +++ b/lib/HeroBonus.cpp @@ -8,6 +8,8 @@ #include #include "CCreatureSet.h" #include +#include +#include "../hch/CHeroHandler.h" #define FOREACH_CONST_PARENT(pname) TCNodes parents; getParents(parents); BOOST_FOREACH(const CBonusSystemNode *pname, parents) #define FOREACH_PARENT(pname) TNodes parents; getParents(parents); BOOST_FOREACH(CBonusSystemNode *pname, parents) @@ -99,49 +101,15 @@ void DLL_EXPORT BonusList::getBonuses(BonusList &out, const CSelector &selector, out.push_back(i); } -namespace HHLP -{ - class SourceComp - { - public: - Bonus::BonusSource src; - SourceComp(Bonus::BonusSource _src) : src(_src) - { - } - bool operator()(const Bonus * bon) - { - return bon->source == src; - } - }; -} - void DLL_EXPORT BonusList::removeSpells(Bonus::BonusSource sourceType) { - std::remove_if(begin(), end(), HHLP::SourceComp(sourceType)); + remove_if(Selector::sourceType(sourceType)); } void BonusList::limit(const CBonusSystemNode &node) { -limit_start: - for(iterator i = begin(); i != end(); i++) - { - Bonus *b = *i; - if(b->limiter && b->limiter->limit(b, node)) - { - iterator toErase = i; - if(i != begin()) - { - i--; - erase(toErase); - } - else - { - erase(toErase); - goto limit_start; - } - } - } + remove_if(boost::bind(&CBonusSystemNode::isLimitedOnUs, node, _1)); } int CBonusSystemNode::valOfBonuses(Bonus::BonusType type, const CSelector &selector) const @@ -358,27 +326,36 @@ void CBonusSystemNode::popBonuses(const CSelector &s) child->popBonuses(s); } -void CBonusSystemNode::addNewBonus(const Bonus &b) -{ - addNewBonus(new Bonus(b)); -} +// void CBonusSystemNode::addNewBonus(const Bonus &b) +// { +// addNewBonus(new Bonus(b)); +// } void CBonusSystemNode::addNewBonus(Bonus *b) { exportedBonuses.push_back(b); - - if(!b->propagator) - bonuses.push_back(b); - else - { - //prop - } + whereToPropagate(b)->bonuses.push_back(b); } void CBonusSystemNode::removeBonus(Bonus *b) { exportedBonuses -= b; - //TODO: prop + CBonusSystemNode *whereIsOurBonus = whereToPropagate(b); + whereIsOurBonus->bonuses -= b; + delNull(b); +} + +CBonusSystemNode * CBonusSystemNode::whereToPropagate(Bonus *b) +{ + if(b->propagator) + return b->propagator->getDestNode(this); + else + return this; +} + +bool CBonusSystemNode::isLimitedOnUs(Bonus *b) const +{ + return b->limiter && b->limiter->limit(b, *this); } int NBonus::valOf(const CBonusSystemNode *obj, Bonus::BonusType type, int subtype /*= -1*/) @@ -445,8 +422,6 @@ Bonus::Bonus(ui8 Dur, ui8 Type, ui8 Src, si32 Val, ui32 ID, std::string Desc, si turnsRemain = 0; valType = ADDITIVE_VALUE; effectRange = NO_LIMIT; - limiter = NULL; - propagator = NULL; boost::algorithm::trim(description); } @@ -456,8 +431,6 @@ Bonus::Bonus(ui8 Dur, ui8 Type, ui8 Src, si32 Val, ui32 ID, si32 Subtype/*=-1*/, additionalInfo = -1; turnsRemain = 0; effectRange = NO_LIMIT; - limiter = NULL; - propagator = NULL; } Bonus::Bonus() @@ -467,8 +440,16 @@ Bonus::Bonus() turnsRemain = 0; valType = ADDITIVE_VALUE; effectRange = NO_LIMIT; - limiter = NULL; - propagator = NULL; +} + +Bonus::~Bonus() +{ +} + +Bonus * Bonus::addLimiter(ILimiter *Limiter) +{ + limiter.reset(Limiter); + return this; } CSelector DLL_EXPORT operator&&(const CSelector &first, const CSelector &second) @@ -525,6 +506,19 @@ namespace Selector } } +const CCreature * retrieveCreature(const CBonusSystemNode *node) +{ + switch(node->nodeType) + { + case CBonusSystemNode::CREATURE: + return (static_cast(node)); + case CBonusSystemNode::STACK: + return (static_cast(node))->type; + default: + return NULL; + } +} + DLL_EXPORT std::ostream & operator<<(std::ostream &out, const BonusList &bonusList) { int i = 0; @@ -621,4 +615,66 @@ bool HasAnotherBonusLimiter::limit( const Bonus *b, const CBonusSystemNode &node IPropagator::~IPropagator() { +} + +CBonusSystemNode * IPropagator::getDestNode(CBonusSystemNode *source) +{ + return source; +} + +CreatureNativeTerrainLimiter::CreatureNativeTerrainLimiter(int TerrainType) + : terrainType(TerrainType) +{ +} + +CreatureNativeTerrainLimiter::CreatureNativeTerrainLimiter() +{ + +} +bool CreatureNativeTerrainLimiter::limit(const Bonus *b, const CBonusSystemNode &node) const +{ + const CCreature *c = retrieveCreature(&node); + return !c || VLC->heroh->nativeTerrains[c->faction] != terrainType; //drop bonus for non-creatures or non-native residents +} + +CreatureFactionLimiter::CreatureFactionLimiter(int Faction) + : faction(Faction) +{ +} + +CreatureFactionLimiter::CreatureFactionLimiter() +{ +} +bool CreatureFactionLimiter::limit(const Bonus *b, const CBonusSystemNode &node) const +{ + const CCreature *c = retrieveCreature(&node); + return !c || c->faction != faction; //drop bonus for non-creatures or non-native residents +} + +CreatureAlignmentLimiter::CreatureAlignmentLimiter() +{ +} + +CreatureAlignmentLimiter::CreatureAlignmentLimiter(si8 Alignment) + : alignment(Alignment) +{ +} + +bool CreatureAlignmentLimiter::limit(const Bonus *b, const CBonusSystemNode &node) const +{ + const CCreature *c = retrieveCreature(&node); + if(!c) + return true; + switch(alignment) + { + case GOOD: + return !c->isGood(); //if not good -> return true (drop bonus) + case NEUTRAL: + return c->isEvil() || c->isGood(); + case EVIL: + return !c->isEvil(); + default: + tlog1 << "Warning: illegal alignment in limiter!\n"; + return true; + } } \ No newline at end of file diff --git a/lib/HeroBonus.h b/lib/HeroBonus.h index 8b24d850d..ad9c3c162 100644 --- a/lib/HeroBonus.h +++ b/lib/HeroBonus.h @@ -4,6 +4,7 @@ #include #include #include +#include /* * HeroBonus.h, part of VCMI engine @@ -229,14 +230,15 @@ struct DLL_EXPORT Bonus si32 additionalInfo; ui8 effectRange; //if not NO_LIMIT, bonus will be ommitted by default - ILimiter *limiter; - IPropagator *propagator; + boost::shared_ptr limiter; + boost::shared_ptr propagator; std::string description; Bonus(ui8 Dur, ui8 Type, ui8 Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype=-1); Bonus(ui8 Dur, ui8 Type, ui8 Src, si32 Val, ui32 ID, si32 Subtype=-1, ui8 ValType = ADDITIVE_VALUE); Bonus(); + ~Bonus(); // //comparison // bool operator==(const HeroBonus &other) @@ -294,6 +296,8 @@ struct DLL_EXPORT Bonus const CSpell * sourceSpell() const; std::string Description() const; + + Bonus *addLimiter(ILimiter *Limiter); //returns this for convenient chain-calls }; struct DLL_EXPORT stackExperience : public Bonus @@ -337,6 +341,7 @@ class DLL_EXPORT IPropagator { public: virtual ~IPropagator(); + virtual CBonusSystemNode *getDestNode(CBonusSystemNode *source); }; class DLL_EXPORT ILimiter @@ -405,9 +410,12 @@ public: void attachTo(const CBonusSystemNode *parent); void detachFrom(const CBonusSystemNode *parent); void addNewBonus(Bonus *b); //b will be deleted with destruction of node - void addNewBonus(const Bonus &b); //b will copied + //void addNewBonus(const Bonus &b); //b will copied void removeBonus(Bonus *b); + bool isLimitedOnUs(Bonus *b) const; //if bonus should be removed from list acquired from this node + CBonusSystemNode *whereToPropagate(Bonus *b); + void popBonuses(const CSelector &s); template void serialize(Handler &h, const int version) @@ -432,16 +440,16 @@ namespace NBonus }; //generates HeroBonus from given data -inline Bonus makeFeature(Bonus::BonusType type, ui8 duration, si16 subtype, si32 value, Bonus::BonusSource source, ui16 turnsRemain = 0, si32 additionalInfo = 0) +inline Bonus* makeFeature(Bonus::BonusType type, ui8 duration, si16 subtype, si32 value, Bonus::BonusSource source, ui16 turnsRemain = 0, si32 additionalInfo = 0) { - Bonus sf; - sf.type = type; - sf.duration = duration; - sf.source = source; - sf.turnsRemain = turnsRemain; - sf.subtype = subtype; - sf.val = value; - sf.additionalInfo = additionalInfo; + Bonus* sf = new Bonus(); + sf->type = type; + sf->duration = duration; + sf->source = source; + sf->turnsRemain = turnsRemain; + sf->subtype = subtype; + sf->val = value; + sf->additionalInfo = additionalInfo; return sf; } @@ -497,7 +505,7 @@ public: } }; -class CWillLastTurns +class DLL_EXPORT CWillLastTurns { public: int turnsRequested; @@ -515,7 +523,7 @@ public: } }; -class CCreatureTypeLimiter : public ILimiter //affect only stacks of given creature (and optionally it's upgrades) +class DLL_EXPORT CCreatureTypeLimiter : public ILimiter //affect only stacks of given creature (and optionally it's upgrades) { public: const CCreature *creature; @@ -532,14 +540,14 @@ public: } }; -class HasAnotherBonusLimiter : public ILimiter //applies only to nodes that have another bonus working +class DLL_EXPORT HasAnotherBonusLimiter : public ILimiter //applies only to nodes that have another bonus working { public: TBonusType type; TBonusSubtype subtype; ui8 isSubtypeRelevant; //check for subtype only if this is true - HasAnotherBonusLimiter(TBonusType bonus); + HasAnotherBonusLimiter(TBonusType bonus = Bonus::NONE); HasAnotherBonusLimiter(TBonusType bonus, TBonusSubtype _subtype); bool limit(const Bonus *b, const CBonusSystemNode &node) const OVERRIDE; @@ -550,6 +558,53 @@ public: } }; +class DLL_EXPORT CreatureNativeTerrainLimiter : public ILimiter //applies only to creatures that are on their native terrain +{ +public: + si8 terrainType; + CreatureNativeTerrainLimiter(); + CreatureNativeTerrainLimiter(int TerrainType); + + bool limit(const Bonus *b, const CBonusSystemNode &node) const OVERRIDE; + + template void serialize(Handler &h, const int version) + { + h & terrainType; + } +}; + +class DLL_EXPORT CreatureFactionLimiter : public ILimiter //applies only to creatures of given faction +{ +public: + si8 faction; + CreatureFactionLimiter(); + CreatureFactionLimiter(int TerrainType); + + bool limit(const Bonus *b, const CBonusSystemNode &node) const OVERRIDE; + + template void serialize(Handler &h, const int version) + { + h & faction; + } +}; + +class DLL_EXPORT CreatureAlignmentLimiter : public ILimiter //applies only to creatures of given alignment +{ +public: + si8 alignment; + CreatureAlignmentLimiter(); + CreatureAlignmentLimiter(si8 Alignment); + + bool limit(const Bonus *b, const CBonusSystemNode &node) const OVERRIDE; + + template void serialize(Handler &h, const int version) + { + h & alignment; + } +}; + +const CCreature *retrieveCreature(const CBonusSystemNode *node); + namespace Selector { extern DLL_EXPORT CSelectFieldEqual type; diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp index 6499d82cb..27ea95b05 100644 --- a/lib/NetPacksLib.cpp +++ b/lib/NetPacksLib.cpp @@ -664,17 +664,17 @@ DLL_EXPORT void NewTurn::applyGs( CGameState *gs ) case DOUBLE_GROWTH: b->val = 100; b->type = Bonus::CREATURE_GROWTH_PERCENT; - b->limiter = new CCreatureTypeLimiter(*VLC->creh->creatures[creatureid], false); + b->limiter.reset(new CCreatureTypeLimiter(*VLC->creh->creatures[creatureid], false)); break; case BONUS_GROWTH: b->val = 5; b->type = Bonus::CREATURE_GROWTH; - b->limiter = new CCreatureTypeLimiter(*VLC->creh->creatures[creatureid], false); + b->limiter.reset(new CCreatureTypeLimiter(*VLC->creh->creatures[creatureid], false)); break; case DEITYOFFIRE: b->val = 15; b->type = Bonus::CREATURE_GROWTH; - b->limiter = new CCreatureTypeLimiter(*VLC->creh->creatures[42], true); + b->limiter.reset(new CCreatureTypeLimiter(*VLC->creh->creatures[42], true)); break; case PLAGUE: b->val = -100; //no basic creatures @@ -985,8 +985,8 @@ DLL_EXPORT void BattleSpellCast::applyGs( CGameState *gs ) creID = 112; //air elemental break; } - const int3 & tile = gs->curB->tile; - TerrainTile::EterrainType ter = gs->map->terrain[tile.x][tile.y][tile.z].tertype; +// const int3 & tile = gs->curB->tile; +// TerrainTile::EterrainType ter = gs->map->terrain[tile.x][tile.y][tile.z].tertype; int pos; //position of stack on the battlefield - to be calculated @@ -1004,7 +1004,7 @@ DLL_EXPORT void BattleSpellCast::applyGs( CGameState *gs ) } } - CStack * summonedStack = gs->curB->generateNewStack(CStackInstance(creID, h->getPrimSkillLevel(2) * VLC->spellh->spells[id].powers[skill], h), gs->curB->stacks.size(), !side, 255, ter, pos); + CStack * summonedStack = gs->curB->generateNewStack(CStackInstance(creID, h->getPrimSkillLevel(2) * VLC->spellh->spells[id].powers[skill], h), gs->curB->stacks.size(), !side, 255, pos); summonedStack->state.insert(SUMMONED); //summonedStack->addNewBonus( makeFeature(HeroBonus::SUMMONED, HeroBonus::ONE_BATTLE, 0, 0, HeroBonus::BONUS_FROM_HERO) ); diff --git a/lib/RegisterTypes.cpp b/lib/RegisterTypes.cpp index c7f01e1dd..2381f7adc 100644 --- a/lib/RegisterTypes.cpp +++ b/lib/RegisterTypes.cpp @@ -75,6 +75,10 @@ void registerTypes1(Serializer &s) //end of objects s.template registerType(); s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); + s.template registerType(); } template DLL_EXPORT diff --git a/lib/map.h b/lib/map.h index 210c42296..6b8effcd6 100644 --- a/lib/map.h +++ b/lib/map.h @@ -314,7 +314,9 @@ struct DLL_EXPORT Mapa : public CMapHeader { h & static_cast(*this); h & rumors & allowedSpell & allowedAbilities & allowedArtifact & allowedHeroes & events & grailPos; - h & monsters & heroesToBeat & artInstances; //hopefully serialization is now automagical? + h & monsters; + h & heroesToBeat; + h & artInstances; //hopefully serialization is now automagical? //TODO: viccondetails if(h.saving) diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 3da69efd4..aa5689e31 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -1478,7 +1478,7 @@ void CGameHandler::setupBattle(BattleInfo * curB, int3 tile, const CArmedInstanc else pos = attackerLoose[army1->stacksCount()-1][k]; - CStack * stack = curB->generateNewStack(i->second, stacks.size(), true, i->first, gs->map->terrain[tile.x][tile.y][tile.z].tertype, pos); + CStack * stack = curB->generateNewStack(i->second, stacks.size(), true, i->first, pos); stacks.push_back(stack); } @@ -1493,7 +1493,7 @@ void CGameHandler::setupBattle(BattleInfo * curB, int3 tile, const CArmedInstanc else pos = defenderLoose[army2->stacksCount()-1][k]; - CStack * stack = curB->generateNewStack(i->second, stacks.size(), false, i->first, gs->map->terrain[tile.x][tile.y][tile.z].tertype, pos); + CStack * stack = curB->generateNewStack(i->second, stacks.size(), false, i->first, pos); stacks.push_back(stack); } @@ -1514,17 +1514,17 @@ void CGameHandler::setupBattle(BattleInfo * curB, int3 tile, const CArmedInstanc { if(hero1->getArt(13)) //ballista { - CStack * stack = curB->generateNewStack(CStackInstance(146, 1, hero1), stacks.size(), true, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 52); + CStack * stack = curB->generateNewStack(CStackInstance(146, 1, hero1), stacks.size(), true, 255, 52); stacks.push_back(stack); } if(hero1->getArt(14)) //ammo cart { - CStack * stack = curB->generateNewStack(CStackInstance(148, 1, hero1), stacks.size(), true, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 18); + CStack * stack = curB->generateNewStack(CStackInstance(148, 1, hero1), stacks.size(), true, 255, 18); stacks.push_back(stack); } if(hero1->getArt(15)) //first aid tent { - CStack * stack = curB->generateNewStack(CStackInstance(147, 1, hero1), stacks.size(), true, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 154); + CStack * stack = curB->generateNewStack(CStackInstance(147, 1, hero1), stacks.size(), true, 255, 154); stacks.push_back(stack); } } @@ -1533,23 +1533,23 @@ void CGameHandler::setupBattle(BattleInfo * curB, int3 tile, const CArmedInstanc //defending hero shouldn't receive ballista (bug #551) if(hero2->getArt(13) && !town) //ballista { - CStack * stack = curB->generateNewStack(CStackInstance(146, 1, hero2), stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 66); + CStack * stack = curB->generateNewStack(CStackInstance(146, 1, hero2), stacks.size(), false, 255, 66); stacks.push_back(stack); } if(hero2->getArt(14)) //ammo cart { - CStack * stack = curB->generateNewStack(CStackInstance(148, 1, hero1), stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 32); + CStack * stack = curB->generateNewStack(CStackInstance(148, 1, hero1), stacks.size(), false, 255, 32); stacks.push_back(stack); } if(hero2->getArt(15)) //first aid tent { - CStack * stack = curB->generateNewStack(CStackInstance(147, 1, hero2), stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 168); + CStack * stack = curB->generateNewStack(CStackInstance(147, 1, hero2), stacks.size(), false, 255, 168); stacks.push_back(stack); } } if(town && hero1 && town->hasFort()) //catapult { - CStack * stack = curB->generateNewStack(CStackInstance(145, 1, hero1), stacks.size(), true, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, 120); + CStack * stack = curB->generateNewStack(CStackInstance(145, 1, hero1), stacks.size(), true, 255, 120); stacks.push_back(stack); } //war machines added @@ -1559,14 +1559,14 @@ void CGameHandler::setupBattle(BattleInfo * curB, int3 tile, const CArmedInstanc case 3: //castle {//lower tower / upper tower - CStack * stack = curB->generateNewStack(CStackInstance(149, 1, hero2), stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, -4); + CStack * stack = curB->generateNewStack(CStackInstance(149, 1, hero2), stacks.size(), false, 255, -4); stacks.push_back(stack); - stack = curB->generateNewStack(CStackInstance(149, 1, hero2), stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, -3); + stack = curB->generateNewStack(CStackInstance(149, 1, hero2), stacks.size(), false, 255, -3); stacks.push_back(stack); } case 2: //citadel {//main tower - CStack * stack = curB->generateNewStack(CStackInstance(149, 1, hero2), stacks.size(), false, 255, gs->map->terrain[tile.x][tile.y][tile.z].tertype, -2); + CStack * stack = curB->generateNewStack(CStackInstance(149, 1, hero2), stacks.size(), false, 255, -2); stacks.push_back(stack); } } @@ -1676,8 +1676,7 @@ void CGameHandler::setupBattle(BattleInfo * curB, int3 tile, const CArmedInstanc } } - //giving terrain premies for heroes & stacks - + //giving terrain overalay premies int bonusSubtype = -1; switch(terType) { @@ -1703,86 +1702,47 @@ void CGameHandler::setupBattle(BattleInfo * curB, int3 tile, const CArmedInstanc } { //common part for cases 9, 14, 15, 16, 17 - const CGHeroInstance * cHero = NULL; - for(int i=0; i<2; ++i) - { - if(i == 0) cHero = hero1; - else cHero = hero2; - - if(cHero == NULL) continue; - - GiveBonus gs; - gs.bonus = Bonus(Bonus::ONE_BATTLE, Bonus::MAGIC_SCHOOL_SKILL, Bonus::OBJECT, 3, -1, "", bonusSubtype); - gs.id = cHero->id; - - sendAndApply(&gs); - } - + curB->addNewBonus(new Bonus(Bonus::ONE_BATTLE, Bonus::MAGIC_SCHOOL_SKILL, Bonus::TERRAIN_OVERLAY, 3, -1, "", bonusSubtype)); break; } case 18: //holy ground { - for(int g=0; gtype->isGood()) - stacks[g]->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, 1, Bonus::TERRAIN_OVERLAY)); - else if (stacks[g]->type->isEvil()) - stacks[g]->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, -1, Bonus::TERRAIN_OVERLAY)); - } + curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, +1, Bonus::TERRAIN_OVERLAY)->addLimiter(new CreatureAlignmentLimiter(GOOD))); + curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, -1, Bonus::TERRAIN_OVERLAY)->addLimiter(new CreatureAlignmentLimiter(EVIL))); break; } case 19: //clover field - { - for(int g=0; gtype->faction == -1) //+2 luck bonus for neutral creatures - { - stacks[g]->addNewBonus(makeFeature(Bonus::LUCK, Bonus::ONE_BATTLE, 0, 2, Bonus::TERRAIN_OVERLAY)); - } - } + { //+2 luck bonus for neutral creatures + curB->addNewBonus(makeFeature(Bonus::LUCK, Bonus::ONE_BATTLE, 0, +2, Bonus::TERRAIN_OVERLAY)->addLimiter(new CreatureFactionLimiter(-1))); break; } case 20: //evil fog { - for(int g=0; gtype->isGood()) - stacks[g]->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, -1, Bonus::TERRAIN_OVERLAY)); - else if (stacks[g]->type->isEvil()) - stacks[g]->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, 1, Bonus::TERRAIN_OVERLAY)); - } + curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, -1, Bonus::TERRAIN_OVERLAY)->addLimiter(new CreatureAlignmentLimiter(GOOD))); + curB->addNewBonus(makeFeature(Bonus::MORALE, Bonus::ONE_BATTLE, 0, +1, Bonus::TERRAIN_OVERLAY)->addLimiter(new CreatureAlignmentLimiter(EVIL))); break; } case 22: //cursed ground { - for(int g=0; gaddNewBonus(makeFeature(Bonus::NO_MORALE, Bonus::ONE_BATTLE, 0, 0, Bonus::TERRAIN_OVERLAY)); - stacks[g]->addNewBonus(makeFeature(Bonus::NO_LUCK, Bonus::ONE_BATTLE, 0, 0, Bonus::TERRAIN_OVERLAY)); - } - - const CGHeroInstance * cHero = NULL; - for(int i=0; i<2; ++i) //blocking spells above level 1 - { - if(i == 0) cHero = hero1; - else cHero = hero2; - - if(cHero == NULL) continue; - - GiveBonus gs; - gs.bonus = Bonus(Bonus::ONE_BATTLE, Bonus::BLOCK_SPELLS_ABOVE_LEVEL, Bonus::OBJECT, 1, -1, "", bonusSubtype); - gs.id = cHero->id; - - sendAndApply(&gs); - } - + curB->addNewBonus(makeFeature(Bonus::NO_MORALE, Bonus::ONE_BATTLE, 0, 0, Bonus::TERRAIN_OVERLAY)); + curB->addNewBonus(makeFeature(Bonus::NO_LUCK, Bonus::ONE_BATTLE, 0, 0, Bonus::TERRAIN_OVERLAY)); + curB->addNewBonus(makeFeature(Bonus::BLOCK_SPELLS_ABOVE_LEVEL, Bonus::ONE_BATTLE, 0, 1, Bonus::TERRAIN_OVERLAY)); break; } } + //overlay premies given - //premies given + //native terrain bonuses + int terrain = this->getTile(tile)->tertype; + if(town) //during siege always take premies for native terrain of faction + terrain = VLC->heroh->nativeTerrains[town->town->typeID]; + ILimiter *nativeTerrain = new CreatureNativeTerrainLimiter(terrain); + curB->addNewBonus(makeFeature(Bonus::STACKS_SPEED, Bonus::ONE_BATTLE, 0, 1, Bonus::TERRAIN_NATIVE)->addLimiter(nativeTerrain)); + curB->addNewBonus(makeFeature(Bonus::PRIMARY_SKILL, Bonus::ONE_BATTLE, PrimarySkill::ATTACK, 1, Bonus::TERRAIN_NATIVE)->addLimiter(nativeTerrain)); + curB->addNewBonus(makeFeature(Bonus::PRIMARY_SKILL, Bonus::ONE_BATTLE, PrimarySkill::DEFENSE, 1, Bonus::TERRAIN_NATIVE)->addLimiter(nativeTerrain)); + ////////////////////////////////////////////////////////////////////////// //send info about battles BattleStart bs;