1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Moved battle effects to bonus system. May be buggy.

Moved creature damage to bonus system, simplified its handling. Some changes and tweaks.

Support for Adela's bless.
This commit is contained in:
DjWarmonger 2010-08-30 18:06:17 +00:00
parent 34b4e09927
commit bfe266a377
16 changed files with 259 additions and 248 deletions

View File

@ -3010,16 +3010,17 @@ void CBattleInterface::showAliveStack(int ID, const std::map<int, CStack> & stac
//blitting amoutn background box
SDL_Surface *amountBG = NULL;
if(curStack.effects.size() == 0)
if(!curStack.bonuses.size())
{
amountBG = amountNormal;
}
else
{
int pos=0; //determining total positiveness of effects
for(int c=0; c<curStack.effects.size(); ++c)
for(BonusList::const_iterator it = curStack.bonuses.begin(); it != curStack.bonuses.end(); it++)
{
pos += CGI->spellh->spells[ curStack.effects[c].id ].positiveness;
if (it->source == Bonus::CASTED_SPELL)
pos += CGI->spellh->spells[ it->id ].positiveness;
}
if(pos > 0)
{

View File

@ -2148,12 +2148,15 @@ CCreInfoWindow::CCreInfoWindow(const CStackInstance &st, int Type, boost::functi
{
//spell effects
int printed=0; //how many effect pics have been printed
BOOST_FOREACH(const CStack::StackEffect &effect, battleStack->effects)
BOOST_FOREACH(const Bonus effect, battleStack->bonuses)
{
blitAt(graphics->spellEffectsPics->ourImages[effect.id + 1].bitmap, 127 + 52 * printed, 186, *bitmap);
++printed;
if(printed >= 3) //we can fit only 3 effects
break;
if (effect.source == Bonus::CASTED_SPELL)
{
blitAt(graphics->spellEffectsPics->ourImages[effect.id + 1].bitmap, 127 + 52 * printed, 186, *bitmap);
++printed;
if(printed >= 3) //we can fit only 3 effects
break;
}
}
//print current health

View File

@ -574,7 +574,7 @@ void SetStackEffect::applyCl( CClient *cl )
BattleSpellCast sc;
sc.id = effect.id;
sc.side = 3; //doesn't matter
sc.skill = effect.level;
sc.skill = effect.val;
//informing about effects
if(cl->playerint.find(GS(cl)->curB->side1) != cl->playerint.end())

View File

@ -8,7 +8,7 @@
6 1 0 0 146
7 1 0 0 10
8 2 5 27 0
9 6 41 0 3
9 6 3 41 0
10 8 45 0 0
11 3 3 20 0
12 1 0 0 8
@ -28,7 +28,7 @@
26 2 5 24 0
27 2 5 27 0
28 2 5 11 0
29 7 51 0 0
29 7 0 51 0
30 3 3 16 0
31 1 0 0 20
32 1 0 0 30
@ -42,7 +42,7 @@
40 3 3 60 0
41 2 5 8 1
42 2 5 11 0
43 7 51 0 0
43 7 0 51 0
44 1 0 0 34
45 3 3 19 0
46 8 53 0 0

View File

@ -124,16 +124,6 @@ CCreature::CCreature()
doubleWide = false;
nodeType = CBonusSystemNode::CREATURE;
}
ui32 CCreature::getMinDamage() const
{
return damageMin + valOfBonuses(Bonus::CREATURE_DAMAGE, 0) + valOfBonuses(Bonus::CREATURE_DAMAGE, 1);
}
ui32 CCreature::getMaxDamage() const
{
return damageMax + valOfBonuses(Bonus::CREATURE_DAMAGE, 0) + valOfBonuses(Bonus::CREATURE_DAMAGE, 2);
}
void CCreature::addBonus(int val, int type, int subtype /*= -1*/)
{
Bonus added(Bonus::PERMANENT, type, Bonus::CREATURE_ABILITY, val, idNumber, subtype, Bonus::BASE_NUMBER);
@ -272,8 +262,10 @@ void CCreatureHandler::loadCreatures()
ncre.addBonus(ncre.attack, Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK);
ncre.defence = readNumber(befi, i, andame, buf);
ncre.addBonus(ncre.defence, Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE);
ncre.damageMin = readNumber(befi, i, andame, buf);
ncre.damageMin = readNumber(befi, i, andame, buf); //not used anymore?
ncre.addBonus(ncre.damageMin, Bonus::CREATURE_DAMAGE, 1);
ncre.damageMax = readNumber(befi, i, andame, buf);
ncre.addBonus(ncre.damageMax, Bonus::CREATURE_DAMAGE, 2);
ncre.shots = readNumber(befi, i, andame, buf);
ncre.spells = readNumber(befi, i, andame, buf);

View File

@ -60,8 +60,6 @@ public:
si32 maxAmount(const std::vector<si32> &res) const; //how many creatures can be bought
static int getQuantityID(const int & quantity); //0 - a few, 1 - several, 2 - pack, 3 - lots, 4 - horde, 5 - throng, 6 - swarm, 7 - zounds, 8 - legion
bool isMyUpgrade(const CCreature *anotherCre) const;
ui32 getMinDamage() const;
ui32 getMaxDamage() const;
void addBonus(int val, int type, int subtype = -1);
void getParents(TCNodes &out, const CBonusSystemNode *root /*= NULL*/) const;

View File

@ -1091,6 +1091,7 @@ void CGHeroInstance::initObj()
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
speciality.bonuses.push_back (bonus);
break;

View File

@ -278,15 +278,6 @@ void CStackInstance::getParents(TCNodes &out, const CBonusSystemNode *source /*=
out.insert(&IObjectInterface::cb->gameState()->globalEffects);
}
ui32 CStackInstance::getMinDamage() const
{
return type->damageMin + valOfBonuses(Bonus::CREATURE_DAMAGE, 0) + valOfBonuses(Bonus::CREATURE_DAMAGE, 1);
}
ui32 CStackInstance::getMaxDamage() const
{
return type->damageMax + valOfBonuses(Bonus::CREATURE_DAMAGE, 0) + valOfBonuses(Bonus::CREATURE_DAMAGE, 2);
}
std::string CStackInstance::getQuantityTXT(bool capitalized /*= true*/) const
{
return VLC->generaltexth->arraytxt[174 + getQuantityID()*3 + 2 - capitalized];

View File

@ -25,8 +25,6 @@ public:
const CArmedInstance *armyObj; //stack must be part of some army, army must be part of some object
const CCreature *type;
TQuantity count;
ui32 getMinDamage() const;
ui32 getMaxDamage() const;
ui32 experience; //TODO: handle
//TODO: stack artifacts

View File

@ -742,20 +742,161 @@ ui32 CStack::Speed( int turn /*= 0*/ ) const
return speed;
}
const CStack::StackEffect * CStack::getEffect( ui16 id, int turn /*= 0*/ ) const
const Bonus * CStack::getEffect( ui16 id, int turn /*= 0*/ ) const
{
for (unsigned int i=0; i< effects.size(); i++)
if(effects[i].id == id)
if(!turn || effects[i].turnsRemain > turn)
return &effects[i];
for (BonusList::const_iterator it = bonuses.begin(); it != bonuses.end(); it++)
{
if(it->id == id)
{
if(!turn || it->turnsRemain > turn)
return &(*it);
}
}
return NULL;
}
void CStack::stackEffectToFeature(BonusList & sf, const Bonus & sse)
{
si32 power = VLC->spellh->spells[sse.id].powers[sse.val];
switch(sse.id)
{
case 27: //shield
sf.push_back(featureGenerator(Bonus::GENERAL_DAMAGE_REDUCTION, 0, power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 28: //air shield
sf.push_back(featureGenerator(Bonus::GENERAL_DAMAGE_REDUCTION, 1, power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 29: //fire shield
sf.push_back(featureGenerator(Bonus::FIRE_SHIELD, 0, power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 30: //protection from air
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 0, power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 31: //protection from fire
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 1, power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 32: //protection from water
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 2, power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 33: //protection from earth
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 3, power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 34: //anti-magic
sf.push_back(featureGenerator(Bonus::LEVEL_SPELL_IMMUNITY, 0, power - 1, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 41: //bless
if (hasBonusOfType(Bonus::SPECIAL_BLESS_DAMAGE, 41)) //TODO: better handling of bonus percentages
{
int damagePercent = dynamic_cast<const CGHeroInstance*>(armyObj)->level * valOfBonuses(Bonus::SPECIAL_BLESS_DAMAGE, 41) / type->level;
sf.push_back(featureGenerator(Bonus::CREATURE_DAMAGE, 0, damagePercent, sse.turnsRemain));
sf.back().id = sse.id;
sf.back().valType = Bonus::PERCENT_TO_ALL;
}
sf.push_back(featureGenerator(Bonus::ALWAYS_MAXIMUM_DAMAGE, -1, power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 42: //curse
sf.push_back(featureGenerator(Bonus::ALWAYS_MINIMUM_DAMAGE, -1, -1 * power, sse.turnsRemain, sse.val >= 2 ? 20 : 0));
sf.back().id = sse.id;
break;
case 43: //bloodlust
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain, 0, Bonus::ONLY_MELEE_FIGHT));
sf.back().id = sse.id;
break;
case 44: //precision
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain, 0, Bonus::ONLY_DISTANCE_FIGHT));
sf.back().id = sse.id;
break;
case 45: //weakness
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, -1 * power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 46: //stone skin
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 47: //disrupting ray
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, -1 * power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 48: //prayer
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain));
sf.back().id = sse.id;
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power, sse.turnsRemain));
sf.back().id = sse.id;
sf.push_back(featureGenerator(Bonus::STACKS_SPEED, 0, power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 49: //mirth
sf.push_back(featureGenerator(Bonus::MORALE, 0, power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 50: //sorrow
sf.push_back(featureGenerator(Bonus::MORALE, 0, -1 * power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 51: //fortune
sf.push_back(featureGenerator(Bonus::LUCK, 0, power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 52: //misfortune
sf.push_back(featureGenerator(Bonus::LUCK, 0, -1 * power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 53: //haste
sf.push_back(featureGenerator(Bonus::STACKS_SPEED, 0, power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 54: //slow
sf.push_back(featureGeneratorVT(Bonus::STACKS_SPEED, 0, -1 * ( 100 - power ), sse.turnsRemain, Bonus::PERCENT_TO_ALL));
sf.back().id = sse.id;
break;
case 55: //slayer
sf.push_back(featureGenerator(Bonus::SLAYER, 0, sse.val, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 56: //frenzy
sf.push_back(featureGenerator(Bonus::IN_FRENZY, 0, VLC->spellh->spells[56].powers[sse.val]/100.0, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 58: //counterstrike
sf.push_back(featureGenerator(Bonus::ADDITIONAL_RETALIATION, 0, power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 59: //bersek
sf.push_back(featureGenerator(Bonus::ATTACKS_NEAREST_CREATURE, 0, sse.val, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 60: //hypnotize
sf.push_back(featureGenerator(Bonus::HYPNOTIZED, 0, sse.val, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 61: //forgetfulness
sf.push_back(featureGenerator(Bonus::FORGETFULL, 0, sse.val, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 62: //blind
sf.push_back(makeFeature(Bonus::NOT_ACTIVE, Bonus::UNITL_BEING_ATTACKED | Bonus::N_TURNS, 0, 0, Bonus::SPELL_EFFECT, sse.turnsRemain));
sf.back().id = sse.id;
sf.push_back(makeFeature(Bonus::GENERAL_ATTACK_REDUCTION, Bonus::UNTIL_ATTACK | Bonus::N_TURNS, 0, power, Bonus::SPELL_EFFECT, sse.turnsRemain));
sf.back().id = sse.id;
break;
}
}
ui8 CStack::howManyEffectsSet(ui16 id) const
{
ui8 ret = 0;
for (unsigned int i=0; i< effects.size(); i++)
if(effects[i].id == id) //effect found
for (BonusList::const_iterator it = bonuses.begin(); it != bonuses.end(); it++)
if(it->id == id) //effect found
{
++ret;
}
@ -2941,7 +3082,7 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con
if(attacker->getEffect(55)) //slayer handling
{
std::vector<int> affectedIds;
int spLevel = attacker->getEffect(55)->level;
int spLevel = attacker->getEffect(55)->val;
for(int g = 0; g < VLC->creh->creatures.size(); ++g)
{
@ -2961,7 +3102,7 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con
{
if(defender->type->idNumber == affectedIds[g])
{
attackDefenceDifference += VLC->spellh->spells[55].powers[attacker->getEffect(55)->level];
attackDefenceDifference += VLC->spellh->spells[55].powers[attacker->getEffect(55)->val];
break;
}
}
@ -3038,7 +3179,7 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con
}
if(attacker->getEffect(42)) //curse handling (partial, the rest is below)
{
multBonus *= 0.8f * float(VLC->spellh->spells[42].powers[attacker->getEffect(42)->level]); //the second factor is 1 or 0
multBonus *= 0.8f * float(VLC->spellh->spells[42].powers[attacker->getEffect(42)->val]); //the second factor is 1 or 0
}
class HLP
@ -3046,9 +3187,9 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con
public:
static bool hasAdvancedAirShield(const CStack * stack)
{
for(int g=0; g<stack->effects.size(); ++g)
for (BonusList::const_iterator it = stack->bonuses.begin(); it != stack->bonuses.end(); it++)
{
if (stack->effects[g].id == 28 && stack->effects[g].level >= 2)
if (it->id == 28 && it->val >= 2)
{
return true;
}
@ -3077,12 +3218,12 @@ std::pair<ui32, ui32> BattleInfo::calculateDmgRange( const CStack* attacker, con
if(attacker->getEffect(42)) //curse handling (rest)
{
minDmg -= VLC->spellh->spells[42].powers[attacker->getEffect(42)->level];
minDmg -= VLC->spellh->spells[42].powers[attacker->getEffect(42)->val];
returnedVal = std::make_pair(int(minDmg), int(minDmg));
}
else if(attacker->getEffect(41)) //bless handling
{
maxDmg += VLC->spellh->spells[41].powers[attacker->getEffect(41)->level];
maxDmg += VLC->spellh->spells[41].powers[attacker->getEffect(41)->val];
returnedVal = std::make_pair(int(maxDmg), int(maxDmg));
}
else

View File

@ -261,29 +261,34 @@ public:
si16 shots; //how many shots left
std::set<ECombatInfo> state;
struct StackEffect
{
ui16 id; //spell id
ui8 level; //skill level
si16 turnsRemain;
template <typename Handler> void serialize(Handler &h, const int version)
{
h & id & level & turnsRemain;
}
};
std::vector<StackEffect> effects;
//overrides
const CCreature* getCreature() const {return type;}
CStack(const CStackInstance *base, int O, int I, bool AO, int S); //c-tor
CStack() : ID(-1), baseAmount(-1), firstHPleft(-1), owner(255), slot(255), attackerOwned(true), position(-1), counterAttacks(1) {} //c-tor
const StackEffect * getEffect(ui16 id, int turn = 0) const; //effect id (SP)
const Bonus * getEffect(ui16 id, int turn = 0) const; //effect id (SP)
ui8 howManyEffectsSet(ui16 id) const; //returns amount of effects with given id set for this stack
bool willMove(int turn = 0) const; //if stack has remaining move this turn
bool moved(int turn = 0) const; //if stack was already moved this turn
bool canMove(int turn = 0) const; //if stack can move
ui32 Speed(int turn = 0) const; //get speed of creature with all modificators
void stackEffectToFeature(BonusList & sf, const Bonus & sse);
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::SPELL; //right?
return hb;
}
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::SPELL; //right?
return ret;
}
bool doubleWide() const;
int occupiedHex() const; //returns number of occupied hex (not the position) if stack is double wide; otherwise -1

View File

@ -98,6 +98,14 @@ void DLL_EXPORT BonusList::getBonuses(BonusList &out, const CSelector &selector,
if(selector(*i) && (!limit || limit(*i)))
out.push_back(*i);
}
void DLL_EXPORT BonusList::removeSpells(Bonus::BonusSource sourceType)
{
for(iterator i = begin(); i != end(); i++)
{
if (i->source == sourceType)
erase(i);
}
}
void BonusList::limit(const CBonusSystemNode &node)
{
@ -294,6 +302,15 @@ ui16 CBonusSystemNode::MaxHealth() const
return valOfBonuses(Bonus::STACK_HEALTH);
}
ui32 CBonusSystemNode::getMinDamage() const
{
return valOfBonuses(Selector::typeSybtype(Bonus::CREATURE_DAMAGE, 0) || Selector::typeSybtype(Bonus::CREATURE_DAMAGE, 1));
}
ui32 CBonusSystemNode::getMaxDamage() const
{
return valOfBonuses(Selector::typeSybtype(Bonus::CREATURE_DAMAGE, 0) || Selector::typeSybtype(Bonus::CREATURE_DAMAGE, 2));
}
CBonusSystemNode::CBonusSystemNode()
{
nodeType = UNKNOWN;
@ -395,6 +412,10 @@ CSelector DLL_EXPORT operator&&(const CSelector &first, const CSelector &second)
{
return CSelectorsConjunction(first, second);
}
CSelector DLL_EXPORT operator||(const CSelector &first, const CSelector &second)
{
return CSelectorsAlternative(first, second);
}
namespace Selector
{

View File

@ -302,6 +302,7 @@ public:
void DLL_EXPORT getBonuses(BonusList &out, const CSelector &selector, const CBonusSystemNode *source = NULL) const;
void DLL_EXPORT getBonuses(BonusList &out, const CSelector &selector, const CSelector &limit, const CBonusSystemNode *source = NULL) const;
void DLL_EXPORT getModifiersWDescr(TModDescr &out) const;
void DLL_EXPORT removeSpells(Bonus::BonusSource sourceType);
//special find functions
DLL_EXPORT Bonus * getFirst(const CSelector &select);
@ -359,8 +360,8 @@ public:
bool hasBonusFrom(ui8 source, ui32 sourceID) const;
void getModifiersWDescr( TModDescr &out, Bonus::BonusType type, int subtype = -1 ) const; //out: pairs<modifier value, modifier description>
int getBonusesCount(int from, int id) const;
virtual ui32 getMinDamage() const {return 0;}; //used for stacks and creatures only
virtual ui32 getMaxDamage() const {return 0;};
virtual ui32 getMinDamage() const; //used for stacks and creatures only
virtual ui32 getMaxDamage() const;
int MoraleVal() const; //range [-3, +3]
int LuckVal() const; //range [-3, +3]
@ -424,6 +425,20 @@ public:
};
CSelector DLL_EXPORT operator&&(const CSelector &first, const CSelector &second);
class DLL_EXPORT CSelectorsAlternative
{
const CSelector first, second;
public:
CSelectorsAlternative(const CSelector &First, const CSelector &Second)
:first(First), second(Second)
{
}
bool operator()(const Bonus &bonus) const
{
return first(bonus) || second(bonus);
}
};
CSelector DLL_EXPORT operator||(const CSelector &first, const CSelector &second);
template<typename T>
class CSelectFieldEqual

View File

@ -1123,7 +1123,7 @@ struct SetStackEffect : public CPackForClient //3010
void applyCl(CClient *cl);
std::vector<ui32> stacks; //affected stacks (IDs)
CStack::StackEffect effect; //type of effect
Bonus effect; //type of effect
template <typename Handler> void serialize(Handler &h, const int version)
{
h & stacks & effect;

View File

@ -760,13 +760,13 @@ DLL_EXPORT void BattleNextRound::applyGs( CGameState *gs )
s->firstHPleft = s->MaxHealth();
//remove effects and restore only those with remaining turns in duration
std::vector<CStack::StackEffect> tmpEffects = s->effects;
s->effects.clear();
for(int i=0; i < tmpEffects.size(); i++)
BonusList tmpEffects = s->bonuses;
s->bonuses.removeSpells(Bonus::CASTED_SPELL);
for (BonusList::iterator it = tmpEffects.begin(); it != tmpEffects.end(); it++)
{
tmpEffects[i].turnsRemain--;
if(tmpEffects[i].turnsRemain > 0)
s->effects.push_back(tmpEffects[i]);
it->turnsRemain--;
if(it->turnsRemain > 0)
s->bonuses.push_back(*it);
}
//the same as above for features
@ -929,17 +929,17 @@ DLL_EXPORT void BattleSpellCast::applyGs( CGameState *gs )
CStack *s = gs->curB->getStack(*it);
if(s && !vstd::contains(resisted, s->ID)) //if stack exists and it didn't resist
{
std::vector<CStack::StackEffect> remainingEff;
for(int g=0; g< s->effects.size(); ++g)
BonusList remainingEff;
for (BonusList::iterator it = remainingEff.begin(); it != remainingEff.end(); it++)
{
if (onlyHelpful && VLC->spellh->spells[ s->effects[g].id ].positiveness != 1)
if (onlyHelpful && VLC->spellh->spells[ it->id ].positiveness != 1)
{
remainingEff.push_back(s->effects[g]);
remainingEff.push_back(*it);
}
}
s->effects.clear(); //removing all effects
s->effects = remainingEff; //assigning effects that should remain
s->bonuses.removeSpells(Bonus::CASTED_SPELL); //removing all effects
s->bonuses = remainingEff; //assigning effects that should remain
//removing all features from spells
BonusList tmpFeatures = s->bonuses;
@ -1000,169 +1000,23 @@ DLL_EXPORT void BattleSpellCast::applyGs( CGameState *gs )
}
}
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;
return hb;
}
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;
return ret;
}
static BonusList stackEffectToFeature(const CStack::StackEffect & sse)
{
BonusList sf;
si32 power = VLC->spellh->spells[sse.id].powers[sse.level];
switch(sse.id)
{
case 27: //shield
sf.push_back(featureGenerator(Bonus::GENERAL_DAMAGE_REDUCTION, 0, power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 28: //air shield
sf.push_back(featureGenerator(Bonus::GENERAL_DAMAGE_REDUCTION, 1, power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 29: //fire shield
sf.push_back(featureGenerator(Bonus::FIRE_SHIELD, 0, power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 30: //protection from air
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 0, power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 31: //protection from fire
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 1, power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 32: //protection from water
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 2, power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 33: //protection from earth
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 3, power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 34: //anti-magic
sf.push_back(featureGenerator(Bonus::LEVEL_SPELL_IMMUNITY, 0, power - 1, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 41: //bless
sf.push_back(featureGenerator(Bonus::ALWAYS_MAXIMUM_DAMAGE, -1, power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 42: //curse
sf.push_back(featureGenerator(Bonus::ALWAYS_MINIMUM_DAMAGE, -1, -1 * power, sse.turnsRemain, sse.level >= 2 ? 20 : 0));
sf.back().id = sse.id;
break;
case 43: //bloodlust
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain, 0, Bonus::ONLY_MELEE_FIGHT));
sf.back().id = sse.id;
break;
case 44: //precision
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain, 0, Bonus::ONLY_DISTANCE_FIGHT));
sf.back().id = sse.id;
break;
case 45: //weakness
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, -1 * power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 46: //stone skin
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 47: //disrupting ray
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, -1 * power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 48: //prayer
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain));
sf.back().id = sse.id;
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power, sse.turnsRemain));
sf.back().id = sse.id;
sf.push_back(featureGenerator(Bonus::STACKS_SPEED, 0, power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 49: //mirth
sf.push_back(featureGenerator(Bonus::MORALE, 0, power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 50: //sorrow
sf.push_back(featureGenerator(Bonus::MORALE, 0, -1 * power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 51: //fortune
sf.push_back(featureGenerator(Bonus::LUCK, 0, power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 52: //misfortune
sf.push_back(featureGenerator(Bonus::LUCK, 0, -1 * power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 53: //haste
sf.push_back(featureGenerator(Bonus::STACKS_SPEED, 0, power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 54: //slow
sf.push_back(featureGeneratorVT(Bonus::STACKS_SPEED, 0, -1 * ( 100 - power ), sse.turnsRemain, Bonus::PERCENT_TO_ALL));
sf.back().id = sse.id;
break;
case 55: //slayer
sf.push_back(featureGenerator(Bonus::SLAYER, 0, sse.level, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 56: //frenzy
sf.push_back(featureGenerator(Bonus::IN_FRENZY, 0, VLC->spellh->spells[56].powers[sse.level]/100.0, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 58: //counterstrike
sf.push_back(featureGenerator(Bonus::ADDITIONAL_RETALIATION, 0, power, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 59: //bersek
sf.push_back(featureGenerator(Bonus::ATTACKS_NEAREST_CREATURE, 0, sse.level, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 60: //hypnotize
sf.push_back(featureGenerator(Bonus::HYPNOTIZED, 0, sse.level, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 61: //forgetfulness
sf.push_back(featureGenerator(Bonus::FORGETFULL, 0, sse.level, sse.turnsRemain));
sf.back().id = sse.id;
break;
case 62: //blind
sf.push_back(makeFeature(Bonus::NOT_ACTIVE, Bonus::UNITL_BEING_ATTACKED | Bonus::N_TURNS, 0, 0, Bonus::SPELL_EFFECT, sse.turnsRemain));
sf.back().id = sse.id;
sf.push_back(makeFeature(Bonus::GENERAL_ATTACK_REDUCTION, Bonus::UNTIL_ATTACK | Bonus::N_TURNS, 0, power, Bonus::SPELL_EFFECT, sse.turnsRemain));
sf.back().id = sse.id;
break;
}
return sf;
}
void actualizeEffect(CStack * s, CStack::StackEffect & ef)
void actualizeEffect(CStack * s, Bonus & ef)
{
//actualizing effects vector
for(int g=0; g<s->effects.size(); ++g)
for (BonusList::iterator it = s->bonuses.begin(); it != s->bonuses.end(); it++)
{
if(s->effects[g].id == ef.id)
if(it->id == ef.id)
{
s->effects[g].turnsRemain = std::max(s->effects[g].turnsRemain, ef.turnsRemain);
it->turnsRemain = std::max(it->turnsRemain, ef.turnsRemain);
}
}
//actualizing features vector
BonusList sf = stackEffectToFeature(ef);
BonusList sf;
s->stackEffectToFeature(sf, ef);
BOOST_FOREACH(const Bonus &fromEffect, sf)
{
BOOST_FOREACH(Bonus &stackBonus, s->bonuses)
BOOST_FOREACH(Bonus &stackBonus, s->bonuses) //TODO: optimize
{
if(stackBonus.source == Bonus::SPELL_EFFECT && stackBonus.type == fromEffect.type && stackBonus.subtype == fromEffect.subtype)
{
@ -1173,16 +1027,6 @@ void actualizeEffect(CStack * s, CStack::StackEffect & ef)
}
bool containsEff(const std::vector<CStack::StackEffect> & vec, int effectId)
{
for(int g=0; g<vec.size(); ++g)
{
if(vec[g].id == effectId)
return true;
}
return false;
}
DLL_EXPORT void SetStackEffect::applyGs( CGameState *gs )
{
BOOST_FOREACH(ui32 id, stacks)
@ -1190,10 +1034,11 @@ DLL_EXPORT void SetStackEffect::applyGs( CGameState *gs )
CStack *s = gs->curB->getStack(id);
if(s)
{
if(effect.id == 42 || !containsEff(s->effects, effect.id))//disrupting ray or not on the list - just add
if(effect.id == 42 || !s->hasBonus(Selector::source(Bonus::CASTED_SPELL, effect.id)))//disrupting ray or not on the list - just add
{
s->effects.push_back(effect);
BonusList sf = stackEffectToFeature(effect);
s->bonuses.push_back(effect);
BonusList sf;
s->stackEffectToFeature(sf, effect);
BOOST_FOREACH(const Bonus &fromEffect, sf)
{
s->bonuses.push_back(fromEffect);
@ -1258,11 +1103,11 @@ DLL_EXPORT void StacksHealedOrResurrected::applyGs( CGameState *gs )
//removal of negative effects
if(resurrected)
{
for(int h=0; h<changedStack->effects.size(); ++h)
for (BonusList::iterator it = changedStack->bonuses.begin(); it != changedStack->bonuses.end(); it++)
{
if(VLC->spellh->spells[changedStack->effects[h].id].positiveness < 0)
if(VLC->spellh->spells[it->id].positiveness < 0)
{
changedStack->effects.erase(changedStack->effects.begin() + h);
changedStack->bonuses.erase(it);
}
}

View File

@ -4305,7 +4305,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, int destinatio
sse.stacks.push_back((*it)->ID);
}
sse.effect.id = spellID;
sse.effect.level = spellLvl;
sse.effect.val = spellLvl;
sse.effect.turnsRemain = gs->curB->calculateSpellDuration(spell, caster, usedSpellPower);
if(!sse.stacks.empty())
sendAndApply(&sse);