1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-12 02:28:11 +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 )
{
Bonus added(Bonus::PERMANENT,type,Bonus::ARTIFACT,val,aid,subtype);
added.valType = valType;
added.limiter = limiter;
Bonus *added = new Bonus(Bonus::PERMANENT,type,Bonus::ARTIFACT,val,aid,subtype);
added->valType = valType;
added->limiter.reset(limiter);
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);
}

View File

@ -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;

View File

@ -979,17 +979,17 @@ void CGHeroInstance::initObj()
{
blockVisit = true;
speciality.growthsWithLevel = false;
Bonus bonus;
if(!type)
return; //TODO support prison
for (std::vector<SSpecialtyInfo>::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<CCreature*>* 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<ui32>::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) );
}
}

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);
//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;
}

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)
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);
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<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));
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;
}

View File

@ -488,6 +488,12 @@ public:
const_cast<T&>(data).serialize(*this,version);
}
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)
{
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>
void loadSerializable(std::vector<T> &data)
{

View File

@ -8,6 +8,8 @@
#include <boost/assign/list_of.hpp>
#include "CCreatureSet.h"
#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_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<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)
{
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;
}
}

View File

@ -4,6 +4,7 @@
#include <list>
#include <set>
#include <boost/function.hpp>
#include <boost/smart_ptr/shared_ptr.hpp>
/*
* 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<ILimiter> limiter;
boost::shared_ptr<IPropagator> 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 <typename Handler> 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 <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
{
extern DLL_EXPORT CSelectFieldEqual<TBonusType> type;

View File

@ -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) );

View File

@ -75,6 +75,10 @@ void registerTypes1(Serializer &s)
//end of objects
s.template registerType<ILimiter>();
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

View File

@ -314,7 +314,9 @@ struct DLL_EXPORT Mapa : public CMapHeader
{
h & static_cast<CMapHeader&>(*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)

View File

@ -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; g<stacks.size(); ++g) //+1 morale bonus for good creatures, -1 morale bonus for evil creatures
{
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));
}
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; g<stacks.size(); ++g)
{
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));
}
}
{ //+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; g<stacks.size(); ++g) //-1 morale bonus for good creatures, +1 morale bonus for evil creatures
{
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));
}
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; g<stacks.size(); ++g) //no luck nor morale
{
stacks[g]->addNewBonus(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;