1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-07-15 01:24:45 +02:00

Further work on bonus system.

This commit is contained in:
Michał W. Urbańczyk
2010-11-20 00:03:31 +00:00
parent b2a4d857b5
commit 27f83ea8c3
12 changed files with 325 additions and 250 deletions

View File

@ -484,11 +484,11 @@ void CArtHandler::getAllowedArts(std::vector<CArtifact*> &out, std::vector<CArti
} }
void CArtHandler::giveArtBonus( int aid, Bonus::BonusType type, int val, int subtype, int valType, ILimiter * limiter ) void CArtHandler::giveArtBonus( int aid, Bonus::BonusType type, int val, int subtype, int valType, ILimiter * limiter )
{ {
Bonus added(Bonus::PERMANENT,type,Bonus::ARTIFACT,val,aid,subtype); Bonus *added = new Bonus(Bonus::PERMANENT,type,Bonus::ARTIFACT,val,aid,subtype);
added.valType = valType; added->valType = valType;
added.limiter = limiter; added->limiter.reset(limiter);
if(type == Bonus::MORALE || Bonus::LUCK) if(type == Bonus::MORALE || Bonus::LUCK)
added.description = "\n" + artifacts[aid]->Name() + (val > 0 ? " +" : " ") + boost::lexical_cast<std::string>(val); added->description = "\n" + artifacts[aid]->Name() + (val > 0 ? " +" : " ") + boost::lexical_cast<std::string>(val);
artifacts[aid]->addNewBonus(added); artifacts[aid]->addNewBonus(added);
} }

View File

@ -126,7 +126,7 @@ CCreature::CCreature()
} }
void CCreature::addBonus(int val, int type, int subtype /*= -1*/) 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); addNewBonus(added);
} }
// void CCreature::getParents(TCNodes &out, const CBonusSystemNode *root /*= NULL*/) const // void CCreature::getParents(TCNodes &out, const CBonusSystemNode *root /*= NULL*/) const
@ -364,7 +364,7 @@ void CCreatureHandler::loadCreatures()
case '+': //add new ability case '+': //add new ability
{ {
int creatureID; int creatureID;
Bonus nsf; Bonus *nsf = new Bonus();
si32 buf; si32 buf;
std::string type; std::string type;
@ -392,15 +392,15 @@ void CCreatureHandler::loadCreatures()
tlog1 << "Error: invalid type " << type << " in cr_abils.txt" << std::endl; tlog1 << "Error: invalid type " << type << " in cr_abils.txt" << std::endl;
break; break;
} }
nsf.type = it->second; nsf->type = it->second;
reader >> buf; nsf.val = buf; reader >> buf; nsf->val = buf;
reader >> buf; nsf.subtype = buf; reader >> buf; nsf->subtype = buf;
reader >> buf; nsf.additionalInfo = buf; reader >> buf; nsf->additionalInfo = buf;
nsf.source = Bonus::CREATURE_ABILITY; nsf->source = Bonus::CREATURE_ABILITY;
nsf.id = cre->idNumber; nsf->id = cre->idNumber;
nsf.duration = Bonus::ONE_BATTLE; nsf->duration = Bonus::ONE_BATTLE;
nsf.turnsRemain = 0; nsf->turnsRemain = 0;
cre->addNewBonus(nsf); cre->addNewBonus(nsf);
break; break;

View File

@ -979,17 +979,17 @@ void CGHeroInstance::initObj()
{ {
blockVisit = true; blockVisit = true;
speciality.growthsWithLevel = false; speciality.growthsWithLevel = false;
Bonus bonus;
if(!type) if(!type)
return; //TODO support prison return; //TODO support prison
for (std::vector<SSpecialtyInfo>::const_iterator it = type->spec.begin(); it != type->spec.end(); it++) for (std::vector<SSpecialtyInfo>::const_iterator it = type->spec.begin(); it != type->spec.end(); it++)
{ {
bonus.val = it->val; Bonus *bonus = new Bonus();
bonus.id = id; //from the hero, speciality has no unique id bonus->val = it->val;
bonus.duration = Bonus::PERMANENT; bonus->id = id; //from the hero, speciality has no unique id
bonus.source = Bonus::HERO_SPECIAL; bonus->duration = Bonus::PERMANENT;
bonus->source = Bonus::HERO_SPECIAL;
switch (it->type) switch (it->type)
{ {
case 1:// creature speciality case 1:// creature speciality
@ -1010,139 +1010,139 @@ void CGHeroInstance::initObj()
} }
} }
bonus.limiter = new CCreatureTypeLimiter (specCreature, true); //with upgrades bonus->limiter.reset(new CCreatureTypeLimiter (specCreature, true)); //with upgrades
bonus.type = Bonus::PRIMARY_SKILL; bonus->type = Bonus::PRIMARY_SKILL;
bonus.additionalInfo = it->additionalinfo; bonus->additionalInfo = it->additionalinfo;
bonus.valType = Bonus::ADDITIVE_VALUE; bonus->valType = Bonus::ADDITIVE_VALUE;
bonus.subtype = PrimarySkill::ATTACK; bonus->subtype = PrimarySkill::ATTACK;
speciality.addNewBonus(bonus); speciality.addNewBonus(bonus);
bonus.subtype = PrimarySkill::DEFENSE; bonus->subtype = PrimarySkill::DEFENSE;
speciality.addNewBonus(bonus); speciality.addNewBonus(bonus);
//values will be calculated later //values will be calculated later
bonus.type = Bonus::STACKS_SPEED; bonus->type = Bonus::STACKS_SPEED;
bonus.val = 1; //+1 speed bonus->val = 1; //+1 speed
speciality.addNewBonus(bonus); speciality.addNewBonus(bonus);
} }
break; break;
case 2://secondary skill case 2://secondary skill
speciality.growthsWithLevel = true; speciality.growthsWithLevel = true;
bonus.type = Bonus::SPECIAL_SECONDARY_SKILL; //needs to be recalculated with level, based on this value 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->valType = Bonus::BASE_NUMBER; // to receive nonzero value
bonus.subtype = it->subtype; //skill id bonus->subtype = it->subtype; //skill id
bonus.val = it->val; //value per level, in percent bonus->val = it->val; //value per level, in percent
speciality.addNewBonus(bonus); speciality.addNewBonus(bonus);
switch (it->additionalinfo) switch (it->additionalinfo)
{ {
case 0: //normal case 0: //normal
bonus.valType = Bonus::PERCENT_TO_BASE; bonus->valType = Bonus::PERCENT_TO_BASE;
break; break;
case 1: //when it's navigation or there's no 'base' at all 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; 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); speciality.addNewBonus(bonus);
break; break;
case 3://spell damage bonus, level dependant but calculated elsehwere case 3://spell damage bonus, level dependant but calculated elsehwere
bonus.type = Bonus::SPECIAL_SPELL_LEV; bonus->type = Bonus::SPECIAL_SPELL_LEV;
bonus.subtype = it->subtype; bonus->subtype = it->subtype;
speciality.addNewBonus(bonus); speciality.addNewBonus(bonus);
break; break;
case 4://creature stat boost case 4://creature stat boost
switch (it->subtype) switch (it->subtype)
{ {
case 1://attack case 1://attack
bonus.type = Bonus::PRIMARY_SKILL; bonus->type = Bonus::PRIMARY_SKILL;
bonus.subtype = PrimarySkill::ATTACK; bonus->subtype = PrimarySkill::ATTACK;
break; break;
case 2://defense case 2://defense
bonus.type = Bonus::PRIMARY_SKILL; bonus->type = Bonus::PRIMARY_SKILL;
bonus.subtype = PrimarySkill::DEFENSE; bonus->subtype = PrimarySkill::DEFENSE;
break; break;
case 3: case 3:
bonus.type = Bonus::CREATURE_DAMAGE; bonus->type = Bonus::CREATURE_DAMAGE;
bonus.subtype = 0; //both min and max bonus->subtype = 0; //both min and max
break; break;
case 4://hp case 4://hp
bonus.type = Bonus::STACK_HEALTH; bonus->type = Bonus::STACK_HEALTH;
break; break;
case 5: case 5:
bonus.type = Bonus::STACKS_SPEED; bonus->type = Bonus::STACKS_SPEED;
break; break;
default: default:
continue; continue;
} }
bonus.valType = Bonus::ADDITIVE_VALUE; bonus->valType = Bonus::ADDITIVE_VALUE;
bonus.limiter = new CCreatureTypeLimiter (*VLC->creh->creatures[it->additionalinfo], true); bonus->limiter.reset(new CCreatureTypeLimiter (*VLC->creh->creatures[it->additionalinfo], true));
speciality.addNewBonus(bonus); speciality.addNewBonus(bonus);
break; break;
case 5://spell damage bonus in percent case 5://spell damage bonus in percent
bonus.type = Bonus::SPECIFIC_SPELL_DAMAGE; bonus->type = Bonus::SPECIFIC_SPELL_DAMAGE;
bonus.valType = Bonus::BASE_NUMBER; // current spell system is screwed bonus->valType = Bonus::BASE_NUMBER; // current spell system is screwed
bonus.subtype = it->subtype; //spell id bonus->subtype = it->subtype; //spell id
speciality.addNewBonus(bonus); speciality.addNewBonus(bonus);
break; break;
case 6://damage bonus for bless (Adela) case 6://damage bonus for bless (Adela)
bonus.type = Bonus::SPECIAL_BLESS_DAMAGE; bonus->type = Bonus::SPECIAL_BLESS_DAMAGE;
bonus.subtype = it->subtype; //spell id if you ever wanted to use it otherwise bonus->subtype = it->subtype; //spell id if you ever wanted to use it otherwise
bonus.additionalInfo = it->additionalinfo; //damage factor bonus->additionalInfo = it->additionalinfo; //damage factor
speciality.addNewBonus(bonus); speciality.addNewBonus(bonus);
break; break;
case 7://maxed mastery for spell case 7://maxed mastery for spell
bonus.type = Bonus::MAXED_SPELL; bonus->type = Bonus::MAXED_SPELL;
bonus.subtype = it->subtype; //spell i bonus->subtype = it->subtype; //spell i
speciality.addNewBonus(bonus); speciality.addNewBonus(bonus);
break; break;
case 8://peculiar spells - enchantments case 8://peculiar spells - enchantments
bonus.type = Bonus::SPECIAL_PECULIAR_ENCHANT; bonus->type = Bonus::SPECIAL_PECULIAR_ENCHANT;
bonus.subtype = it->subtype; //spell id bonus->subtype = it->subtype; //spell id
bonus.additionalInfo = it->additionalinfo;//0, 1 for Coronius bonus->additionalInfo = it->additionalinfo;//0, 1 for Coronius
speciality.addNewBonus(bonus); speciality.addNewBonus(bonus);
break; break;
case 9://upgrade creatures case 9://upgrade creatures
{ {
std::vector<CCreature*>* creatures = &VLC->creh->creatures; std::vector<CCreature*>* creatures = &VLC->creh->creatures;
bonus.type = Bonus::SPECIAL_UPGRADE; bonus->type = Bonus::SPECIAL_UPGRADE;
bonus.subtype = it->subtype; //base id bonus->subtype = it->subtype; //base id
bonus.additionalInfo = it->additionalinfo; //target id bonus->additionalInfo = it->additionalinfo; //target id
speciality.addNewBonus(bonus); speciality.addNewBonus(bonus);
for (std::set<ui32>::iterator i = (*creatures)[it->subtype]->upgrades.begin(); for (std::set<ui32>::iterator i = (*creatures)[it->subtype]->upgrades.begin();
i != (*creatures)[it->subtype]->upgrades.end(); i++) 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); speciality.addNewBonus(bonus);
} }
break; break;
} }
case 10://resource generation case 10://resource generation
bonus.type = Bonus::GENERATE_RESOURCE; bonus->type = Bonus::GENERATE_RESOURCE;
bonus.subtype = it->subtype; bonus->subtype = it->subtype;
speciality.addNewBonus(bonus); speciality.addNewBonus(bonus);
break; break;
case 11://starting skill with mastery (Adrienne) case 11://starting skill with mastery (Adrienne)
cb->changeSecSkill(id, it->val, it->additionalinfo); //simply give it and forget cb->changeSecSkill(id, it->val, it->additionalinfo); //simply give it and forget
break; break;
case 12://army speed case 12://army speed
bonus.type = Bonus::STACKS_SPEED; bonus->type = Bonus::STACKS_SPEED;
speciality.addNewBonus(bonus); speciality.addNewBonus(bonus);
break; break;
case 13://Dragon bonuses (Mutare) case 13://Dragon bonuses (Mutare)
bonus.type = Bonus::PRIMARY_SKILL; bonus->type = Bonus::PRIMARY_SKILL;
bonus.valType = Bonus::ADDITIVE_VALUE; bonus->valType = Bonus::ADDITIVE_VALUE;
switch (it->subtype) switch (it->subtype)
{ {
case 1: case 1:
bonus.subtype = PrimarySkill::ATTACK; bonus->subtype = PrimarySkill::ATTACK;
break; break;
case 2: case 2:
bonus.subtype = PrimarySkill::DEFENSE; bonus->subtype = PrimarySkill::DEFENSE;
break; break;
} }
bonus.limiter = new HasAnotherBonusLimiter(Bonus::DRAGON_NATURE); bonus->limiter.reset(new HasAnotherBonusLimiter(Bonus::DRAGON_NATURE));
speciality.addNewBonus(bonus); speciality.addNewBonus(bonus);
break; break;
default: default:
@ -1247,9 +1247,9 @@ void CGHeroInstance::updateSkill(int which, int val)
} }
else else
{ {
Bonus bonus(Bonus::PERMANENT, Bonus::SECONDARY_SKILL_PREMY, id, skillVal, ID, which, Bonus::BASE_NUMBER); Bonus *bonus = new Bonus(Bonus::PERMANENT, Bonus::SECONDARY_SKILL_PREMY, id, skillVal, ID, which, Bonus::BASE_NUMBER);
bonus.source = Bonus::SECONDARY_SKILL; bonus->source = Bonus::SECONDARY_SKILL;
addNewBonus (bonus); addNewBonus(bonus);
} }
} }
} }
@ -1506,7 +1506,7 @@ int CGHeroInstance::getSpellCost(const CSpell *sp) const
void CGHeroInstance::pushPrimSkill(int which, int val) 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 // 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 //add special bonuses from buildings
if(subID == 4 && vstd::contains(builtBuildings, 17)) 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) );
} }
} }

View File

@ -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); CStack * ret = new CStack(&base, attackerOwned ? side1 : side2, stackID, attackerOwned, slot);
ret->position = position;
//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;
return ret; return ret;
} }

View File

@ -236,7 +236,7 @@ struct DLL_EXPORT BattleInfo : public CBonusSystemNode
void calculateCasualties(std::map<ui32,si32> *casualties) const; //casualties are array of maps size 2 (attacker, defeneder), maps are (crid => amount) void calculateCasualties(std::map<ui32,si32> *casualties) const; //casualties are array of maps size 2 (attacker, defeneder), maps are (crid => amount)
std::set<CStack*> getAttackedCreatures(const CSpell * s, int skillLevel, ui8 attackerOwner, int destinationTile); //calculates stack affected by given spell std::set<CStack*> 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); 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 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 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 int lineToWallHex(int line) const; //returns hex with wall in given line
@ -278,19 +278,19 @@ public:
void stackEffectToFeature(BonusList & sf, const Bonus & sse); void stackEffectToFeature(BonusList & sf, const Bonus & sse);
std::vector<si32> activeSpells() const; //returns vector of active spell IDs sorted by time of cast std::vector<si32> 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)); Bonus *hb = makeFeature(type, Bonus::N_TURNS, subtype, value, Bonus::SPELL_EFFECT, turnsRemain, additionalInfo);
hb.effectRange = limit; hb->effectRange = limit;
hb.source = Bonus::CASTED_SPELL; //right? hb->source = Bonus::CASTED_SPELL; //right?
return hb; 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)); Bonus *ret(makeFeature(type, Bonus::N_TURNS, subtype, value, Bonus::SPELL_EFFECT, turnsRemain));
ret.valType = valType; ret->valType = valType;
ret.source = Bonus::CASTED_SPELL; //right? ret->source = Bonus::CASTED_SPELL; //right?
return ret; return ret;
} }

View File

@ -488,6 +488,12 @@ public:
const_cast<T&>(data).serialize(*this,version); const_cast<T&>(data).serialize(*this,version);
} }
template <typename T> template <typename T>
void saveSerializable(const boost::shared_ptr<T> &data)
{
T *internalPtr = data.get();
*this << internalPtr;
}
template <typename T>
void saveSerializable(const std::vector<T> &data) void saveSerializable(const std::vector<T> &data)
{ {
boost::uint32_t length = data.size(); boost::uint32_t length = data.size();
@ -735,6 +741,13 @@ public:
}; };
template <typename T>
void loadSerializable(boost::shared_ptr<T> &data)
{
T *internalPtr;
*this >> internalPtr;
data.reset(internalPtr);
}
template <typename T> template <typename T>
void loadSerializable(std::vector<T> &data) void loadSerializable(std::vector<T> &data)
{ {

View File

@ -8,6 +8,8 @@
#include <boost/assign/list_of.hpp> #include <boost/assign/list_of.hpp>
#include "CCreatureSet.h" #include "CCreatureSet.h"
#include <boost/algorithm/string/trim.hpp> #include <boost/algorithm/string/trim.hpp>
#include <boost/bind.hpp>
#include "../hch/CHeroHandler.h"
#define FOREACH_CONST_PARENT(pname) TCNodes parents; getParents(parents); BOOST_FOREACH(const CBonusSystemNode *pname, parents) #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) #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); 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) 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) void BonusList::limit(const CBonusSystemNode &node)
{ {
limit_start: remove_if(boost::bind(&CBonusSystemNode::isLimitedOnUs, node, _1));
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;
}
}
}
} }
int CBonusSystemNode::valOfBonuses(Bonus::BonusType type, const CSelector &selector) const int CBonusSystemNode::valOfBonuses(Bonus::BonusType type, const CSelector &selector) const
@ -358,27 +326,36 @@ void CBonusSystemNode::popBonuses(const CSelector &s)
child->popBonuses(s); child->popBonuses(s);
} }
void CBonusSystemNode::addNewBonus(const Bonus &b) // void CBonusSystemNode::addNewBonus(const Bonus &b)
{ // {
addNewBonus(new Bonus(b)); // addNewBonus(new Bonus(b));
} // }
void CBonusSystemNode::addNewBonus(Bonus *b) void CBonusSystemNode::addNewBonus(Bonus *b)
{ {
exportedBonuses.push_back(b); exportedBonuses.push_back(b);
whereToPropagate(b)->bonuses.push_back(b);
if(!b->propagator)
bonuses.push_back(b);
else
{
//prop
}
} }
void CBonusSystemNode::removeBonus(Bonus *b) void CBonusSystemNode::removeBonus(Bonus *b)
{ {
exportedBonuses -= 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*/) 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; turnsRemain = 0;
valType = ADDITIVE_VALUE; valType = ADDITIVE_VALUE;
effectRange = NO_LIMIT; effectRange = NO_LIMIT;
limiter = NULL;
propagator = NULL;
boost::algorithm::trim(description); 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; additionalInfo = -1;
turnsRemain = 0; turnsRemain = 0;
effectRange = NO_LIMIT; effectRange = NO_LIMIT;
limiter = NULL;
propagator = NULL;
} }
Bonus::Bonus() Bonus::Bonus()
@ -467,8 +440,16 @@ Bonus::Bonus()
turnsRemain = 0; turnsRemain = 0;
valType = ADDITIVE_VALUE; valType = ADDITIVE_VALUE;
effectRange = NO_LIMIT; 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) 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<const CCreature *>(node));
case CBonusSystemNode::STACK:
return (static_cast<const CStackInstance *>(node))->type;
default:
return NULL;
}
}
DLL_EXPORT std::ostream & operator<<(std::ostream &out, const BonusList &bonusList) DLL_EXPORT std::ostream & operator<<(std::ostream &out, const BonusList &bonusList)
{ {
int i = 0; int i = 0;
@ -621,4 +615,66 @@ bool HasAnotherBonusLimiter::limit( const Bonus *b, const CBonusSystemNode &node
IPropagator::~IPropagator() 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;
}
} }

View File

@ -4,6 +4,7 @@
#include <list> #include <list>
#include <set> #include <set>
#include <boost/function.hpp> #include <boost/function.hpp>
#include <boost/smart_ptr/shared_ptr.hpp>
/* /*
* HeroBonus.h, part of VCMI engine * HeroBonus.h, part of VCMI engine
@ -229,14 +230,15 @@ struct DLL_EXPORT Bonus
si32 additionalInfo; si32 additionalInfo;
ui8 effectRange; //if not NO_LIMIT, bonus will be ommitted by default ui8 effectRange; //if not NO_LIMIT, bonus will be ommitted by default
ILimiter *limiter; boost::shared_ptr<ILimiter> limiter;
IPropagator *propagator; boost::shared_ptr<IPropagator> propagator;
std::string description; 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, 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(ui8 Dur, ui8 Type, ui8 Src, si32 Val, ui32 ID, si32 Subtype=-1, ui8 ValType = ADDITIVE_VALUE);
Bonus(); Bonus();
~Bonus();
// //comparison // //comparison
// bool operator==(const HeroBonus &other) // bool operator==(const HeroBonus &other)
@ -294,6 +296,8 @@ struct DLL_EXPORT Bonus
const CSpell * sourceSpell() const; const CSpell * sourceSpell() const;
std::string Description() const; std::string Description() const;
Bonus *addLimiter(ILimiter *Limiter); //returns this for convenient chain-calls
}; };
struct DLL_EXPORT stackExperience : public Bonus struct DLL_EXPORT stackExperience : public Bonus
@ -337,6 +341,7 @@ class DLL_EXPORT IPropagator
{ {
public: public:
virtual ~IPropagator(); virtual ~IPropagator();
virtual CBonusSystemNode *getDestNode(CBonusSystemNode *source);
}; };
class DLL_EXPORT ILimiter class DLL_EXPORT ILimiter
@ -405,9 +410,12 @@ public:
void attachTo(const CBonusSystemNode *parent); void attachTo(const CBonusSystemNode *parent);
void detachFrom(const CBonusSystemNode *parent); void detachFrom(const CBonusSystemNode *parent);
void addNewBonus(Bonus *b); //b will be deleted with destruction of node 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); 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); void popBonuses(const CSelector &s);
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
@ -432,16 +440,16 @@ namespace NBonus
}; };
//generates HeroBonus from given data //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; Bonus* sf = new Bonus();
sf.type = type; sf->type = type;
sf.duration = duration; sf->duration = duration;
sf.source = source; sf->source = source;
sf.turnsRemain = turnsRemain; sf->turnsRemain = turnsRemain;
sf.subtype = subtype; sf->subtype = subtype;
sf.val = value; sf->val = value;
sf.additionalInfo = additionalInfo; sf->additionalInfo = additionalInfo;
return sf; return sf;
} }
@ -497,7 +505,7 @@ public:
} }
}; };
class CWillLastTurns class DLL_EXPORT CWillLastTurns
{ {
public: public:
int turnsRequested; 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: public:
const CCreature *creature; 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: public:
TBonusType type; TBonusType type;
TBonusSubtype subtype; TBonusSubtype subtype;
ui8 isSubtypeRelevant; //check for subtype only if this is true ui8 isSubtypeRelevant; //check for subtype only if this is true
HasAnotherBonusLimiter(TBonusType bonus); HasAnotherBonusLimiter(TBonusType bonus = Bonus::NONE);
HasAnotherBonusLimiter(TBonusType bonus, TBonusSubtype _subtype); HasAnotherBonusLimiter(TBonusType bonus, TBonusSubtype _subtype);
bool limit(const Bonus *b, const CBonusSystemNode &node) const OVERRIDE; 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 <typename Handler> 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 <typename Handler> 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 <typename Handler> void serialize(Handler &h, const int version)
{
h & alignment;
}
};
const CCreature *retrieveCreature(const CBonusSystemNode *node);
namespace Selector namespace Selector
{ {
extern DLL_EXPORT CSelectFieldEqual<TBonusType> type; extern DLL_EXPORT CSelectFieldEqual<TBonusType> type;

View File

@ -664,17 +664,17 @@ DLL_EXPORT void NewTurn::applyGs( CGameState *gs )
case DOUBLE_GROWTH: case DOUBLE_GROWTH:
b->val = 100; b->val = 100;
b->type = Bonus::CREATURE_GROWTH_PERCENT; 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; break;
case BONUS_GROWTH: case BONUS_GROWTH:
b->val = 5; b->val = 5;
b->type = Bonus::CREATURE_GROWTH; 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; break;
case DEITYOFFIRE: case DEITYOFFIRE:
b->val = 15; b->val = 15;
b->type = Bonus::CREATURE_GROWTH; 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; break;
case PLAGUE: case PLAGUE:
b->val = -100; //no basic creatures b->val = -100; //no basic creatures
@ -985,8 +985,8 @@ DLL_EXPORT void BattleSpellCast::applyGs( CGameState *gs )
creID = 112; //air elemental creID = 112; //air elemental
break; break;
} }
const int3 & tile = gs->curB->tile; // const int3 & tile = gs->curB->tile;
TerrainTile::EterrainType ter = gs->map->terrain[tile.x][tile.y][tile.z].tertype; // TerrainTile::EterrainType ter = gs->map->terrain[tile.x][tile.y][tile.z].tertype;
int pos; //position of stack on the battlefield - to be calculated 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->state.insert(SUMMONED);
//summonedStack->addNewBonus( makeFeature(HeroBonus::SUMMONED, HeroBonus::ONE_BATTLE, 0, 0, HeroBonus::BONUS_FROM_HERO) ); //summonedStack->addNewBonus( makeFeature(HeroBonus::SUMMONED, HeroBonus::ONE_BATTLE, 0, 0, HeroBonus::BONUS_FROM_HERO) );

View File

@ -75,6 +75,10 @@ void registerTypes1(Serializer &s)
//end of objects //end of objects
s.template registerType<ILimiter>(); s.template registerType<ILimiter>();
s.template registerType<CCreatureTypeLimiter>(); s.template registerType<CCreatureTypeLimiter>();
s.template registerType<HasAnotherBonusLimiter>();
s.template registerType<CreatureNativeTerrainLimiter>();
s.template registerType<CreatureFactionLimiter>();
s.template registerType<CreatureAlignmentLimiter>();
} }
template<typename Serializer> DLL_EXPORT template<typename Serializer> DLL_EXPORT

View File

@ -314,7 +314,9 @@ struct DLL_EXPORT Mapa : public CMapHeader
{ {
h & static_cast<CMapHeader&>(*this); h & static_cast<CMapHeader&>(*this);
h & rumors & allowedSpell & allowedAbilities & allowedArtifact & allowedHeroes & events & grailPos; 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 //TODO: viccondetails
if(h.saving) if(h.saving)

View File

@ -1478,7 +1478,7 @@ void CGameHandler::setupBattle(BattleInfo * curB, int3 tile, const CArmedInstanc
else else
pos = attackerLoose[army1->stacksCount()-1][k]; 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); stacks.push_back(stack);
} }
@ -1493,7 +1493,7 @@ void CGameHandler::setupBattle(BattleInfo * curB, int3 tile, const CArmedInstanc
else else
pos = defenderLoose[army2->stacksCount()-1][k]; 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); stacks.push_back(stack);
} }
@ -1514,17 +1514,17 @@ void CGameHandler::setupBattle(BattleInfo * curB, int3 tile, const CArmedInstanc
{ {
if(hero1->getArt(13)) //ballista 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); stacks.push_back(stack);
} }
if(hero1->getArt(14)) //ammo cart 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); stacks.push_back(stack);
} }
if(hero1->getArt(15)) //first aid tent 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); 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) //defending hero shouldn't receive ballista (bug #551)
if(hero2->getArt(13) && !town) //ballista 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); stacks.push_back(stack);
} }
if(hero2->getArt(14)) //ammo cart 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); stacks.push_back(stack);
} }
if(hero2->getArt(15)) //first aid tent 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); stacks.push_back(stack);
} }
} }
if(town && hero1 && town->hasFort()) //catapult 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); stacks.push_back(stack);
} }
//war machines added //war machines added
@ -1559,14 +1559,14 @@ void CGameHandler::setupBattle(BattleInfo * curB, int3 tile, const CArmedInstanc
case 3: //castle case 3: //castle
{//lower tower / upper tower {//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); 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); stacks.push_back(stack);
} }
case 2: //citadel case 2: //citadel
{//main tower {//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); 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; int bonusSubtype = -1;
switch(terType) switch(terType)
{ {
@ -1703,86 +1702,47 @@ void CGameHandler::setupBattle(BattleInfo * curB, int3 tile, const CArmedInstanc
} }
{ //common part for cases 9, 14, 15, 16, 17 { //common part for cases 9, 14, 15, 16, 17
const CGHeroInstance * cHero = NULL; curB->addNewBonus(new Bonus(Bonus::ONE_BATTLE, Bonus::MAGIC_SCHOOL_SKILL, Bonus::TERRAIN_OVERLAY, 3, -1, "", bonusSubtype));
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);
}
break; break;
} }
case 18: //holy ground case 18: //holy ground
{ {
for(int g=0; g<stacks.size(); ++g) //+1 morale bonus for good creatures, -1 morale bonus for evil creatures 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)));
if (stacks[g]->type->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));
}
break; break;
} }
case 19: //clover field case 19: //clover field
{ { //+2 luck bonus for neutral creatures
for(int g=0; g<stacks.size(); ++g) curB->addNewBonus(makeFeature(Bonus::LUCK, Bonus::ONE_BATTLE, 0, +2, Bonus::TERRAIN_OVERLAY)->addLimiter(new CreatureFactionLimiter(-1)));
{
if(stacks[g]->type->faction == -1) //+2 luck bonus for neutral creatures
{
stacks[g]->addNewBonus(makeFeature(Bonus::LUCK, Bonus::ONE_BATTLE, 0, 2, Bonus::TERRAIN_OVERLAY));
}
}
break; break;
} }
case 20: //evil fog case 20: //evil fog
{ {
for(int g=0; g<stacks.size(); ++g) //-1 morale bonus for good creatures, +1 morale bonus for evil creatures 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)));
if (stacks[g]->type->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));
}
break; break;
} }
case 22: //cursed ground case 22: //cursed ground
{ {
for(int g=0; g<stacks.size(); ++g) //no luck nor morale 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));
stacks[g]->addNewBonus(makeFeature(Bonus::NO_MORALE, Bonus::ONE_BATTLE, 0, 0, Bonus::TERRAIN_OVERLAY)); curB->addNewBonus(makeFeature(Bonus::BLOCK_SPELLS_ABOVE_LEVEL, Bonus::ONE_BATTLE, 0, 1, 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);
}
break; 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 //send info about battles
BattleStart bs; BattleStart bs;