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

* fixed bugs 470 and 523

* minor improvements
This commit is contained in:
mateuszb 2011-02-20 18:32:39 +00:00
parent 450ae1772c
commit 519a4186de
12 changed files with 144 additions and 92 deletions

View File

@ -596,7 +596,7 @@ bool CBattleCallback::battleCanCastSpell()
if(!gs->curB) //there is no battle if(!gs->curB) //there is no battle
return false; return false;
return gs->curB->battleCanCastSpell(player) == SpellCasting::OK; return gs->curB->battleCanCastSpell(player, BattleInfo::HERO_CASTING) == SpellCasting::OK;
} }
bool CBattleCallback::battleCanFlee() bool CBattleCallback::battleCanFlee()
@ -1097,7 +1097,7 @@ SpellCasting::ESpellCastProblem CBattleCallback::battleCanCastThisSpell( const C
return SpellCasting::NO_HERO_TO_CAST_SPELL; return SpellCasting::NO_HERO_TO_CAST_SPELL;
} }
return gs->curB->battleCanCastThisSpell(player, spell); return gs->curB->battleCanCastThisSpell(player, spell, BattleInfo::HERO_CASTING);
} }
si8 CBattleCallback::battleGetTacticDist() si8 CBattleCallback::battleGetTacticDist()

View File

@ -2859,7 +2859,7 @@ void CBattleInterface::spellCast( const BattleSpellCast * sc )
void CBattleInterface::battleStacksEffectsSet(const SetStackEffect & sse) void CBattleInterface::battleStacksEffectsSet(const SetStackEffect & sse)
{ {
int effID = sse.effect.back().id; int effID = sse.effect.back().sid;
if(effID != -1) //can be -1 for defensive stance effect if(effID != -1) //can be -1 for defensive stance effect
{ {
for(std::vector<ui32>::const_iterator ci = sse.stacks.begin(); ci!=sse.stacks.end(); ++ci) for(std::vector<ui32>::const_iterator ci = sse.stacks.begin(); ci!=sse.stacks.end(); ++ci)

View File

@ -1138,7 +1138,7 @@ void CCastleInterface::CCreaInfo::clickRight(tribool down, bool previousState)
ch = ci->town->visitingHero; ch = ci->town->visitingHero;
}; };
if (bl.size()) if (bl.size())
summ+=AddToString (CGI->arth->artifacts[bl.front()->id]->Name()+" %+d", descr, bl.totalValue()); summ+=AddToString (CGI->arth->artifacts[bl.front()->sid]->Name()+" %+d", descr, bl.totalValue());
//TODO: player bonuses //TODO: player bonuses

View File

@ -313,7 +313,7 @@ namespace SpellCasting
{ {
OK, NO_HERO_TO_CAST_SPELL, ALREADY_CASTED_THIS_TURN, NO_SPELLBOOK, ANOTHER_ELEMENTAL_SUMMONED, OK, NO_HERO_TO_CAST_SPELL, ALREADY_CASTED_THIS_TURN, NO_SPELLBOOK, ANOTHER_ELEMENTAL_SUMMONED,
HERO_DOESNT_KNOW_SPELL, NOT_ENOUGH_MANA, ADVMAP_SPELL_INSTEAD_OF_BATTLE_SPELL, HERO_DOESNT_KNOW_SPELL, NOT_ENOUGH_MANA, ADVMAP_SPELL_INSTEAD_OF_BATTLE_SPELL,
SECOND_HEROS_SPELL_IMMUNITY, SPELL_LEVEL_LIMIT_EXCEEDED SECOND_HEROS_SPELL_IMMUNITY, SPELL_LEVEL_LIMIT_EXCEEDED, NO_SPELLS_TO_DISPEL
}; };
} }

View File

@ -550,7 +550,7 @@ TDmgRange BattleInfo::calculateDmgRange( const CStack* attacker, const CStack* d
BOOST_FOREACH(const Bonus *it, stack->bonuses) BOOST_FOREACH(const Bonus *it, stack->bonuses)
{ {
if (it->source == Bonus::SPELL_EFFECT && it->id == 28 && it->val >= 2) if (it->source == Bonus::SPELL_EFFECT && it->sid == 28 && it->val >= 2)
{ {
return true; return true;
} }
@ -1617,32 +1617,48 @@ bool BattleInfo::isInTacticRange( THex dest ) const
|| (tacticsSide && dest.getX() < BFIELD_WIDTH - 1 && dest.getX() >= BFIELD_WIDTH - tacticDistance - 1)); || (tacticsSide && dest.getX() < BFIELD_WIDTH - 1 && dest.getX() >= BFIELD_WIDTH - tacticDistance - 1));
} }
SpellCasting::ESpellCastProblem BattleInfo::battleCanCastSpell(int player) const SpellCasting::ESpellCastProblem BattleInfo::battleCanCastSpell(int player, ECastingMode mode) const
{ {
int side = sides[0] == player ? 0 : 1; int side = sides[0] == player ? 0 : 1;
switch (mode)
{
case HERO_CASTING:
{
if(castSpells[side] > 0) if(castSpells[side] > 0)
return SpellCasting::ALREADY_CASTED_THIS_TURN; return SpellCasting::ALREADY_CASTED_THIS_TURN;
if(!heroes[side]) if(!heroes[side])
return SpellCasting::NO_HERO_TO_CAST_SPELL; return SpellCasting::NO_HERO_TO_CAST_SPELL;
if(!heroes[side]->getArt(17)) if(!heroes[side]->getArt(17))
return SpellCasting::NO_SPELLBOOK; return SpellCasting::NO_SPELLBOOK;
}
break;
}
return SpellCasting::OK; return SpellCasting::OK;
} }
SpellCasting::ESpellCastProblem BattleInfo::battleCanCastThisSpell( int player, const CSpell * spell ) const SpellCasting::ESpellCastProblem BattleInfo::battleCanCastThisSpell( int player, const CSpell * spell, ECastingMode mode ) const
{ {
SpellCasting::ESpellCastProblem genProblem = battleCanCastSpell(player); SpellCasting::ESpellCastProblem genProblem = battleCanCastSpell(player, mode);
if(genProblem != SpellCasting::OK) if(genProblem != SpellCasting::OK)
return genProblem; return genProblem;
int cside = sides[0] == player ? 0 : 1; //caster's side int cside = sides[0] == player ? 0 : 1; //caster's side
switch(mode)
{
HERO_CASTING:
{
const CGHeroInstance * caster = heroes[cside]; const CGHeroInstance * caster = heroes[cside];
if(!caster->canCastThisSpell(spell)) if(!caster->canCastThisSpell(spell))
return SpellCasting::HERO_DOESNT_KNOW_SPELL; return SpellCasting::HERO_DOESNT_KNOW_SPELL;
if(caster->mana < getSpellCost(spell, caster)) //not enough mana if(caster->mana < getSpellCost(spell, caster)) //not enough mana
return SpellCasting::NOT_ENOUGH_MANA; return SpellCasting::NOT_ENOUGH_MANA;
}
break;
}
if(spell->id < 10) //it's adventure spell (not combat)) if(spell->id < 10) //it's adventure spell (not combat))
return SpellCasting::ADVMAP_SPELL_INSTEAD_OF_BATTLE_SPELL; return SpellCasting::ADVMAP_SPELL_INSTEAD_OF_BATTLE_SPELL;
@ -1673,6 +1689,34 @@ SpellCasting::ESpellCastProblem BattleInfo::battleCanCastThisSpell( int player,
return SpellCasting::OK; return SpellCasting::OK;
} }
SpellCasting::ESpellCastProblem BattleInfo::battleCanCastThisSpellHere( int player, const CSpell * spell, ECastingMode mode, THex dest )
{
SpellCasting::ESpellCastProblem moreGeneralProblem = battleCanCastThisSpell(player, spell, mode);
if(moreGeneralProblem != SpellCasting::OK)
return moreGeneralProblem;
const CStack * subject = getStackT(dest, false);
//dispel helpful spells
if(spell->id == 78)
{
BonusList spellBon = subject->getSpellBonuses();
bool hasPositiveSpell = false;
BOOST_FOREACH(const Bonus * b, spellBon)
{
if(VLC->spellh->spells[b->sid]->positiveness > 0)
{
hasPositiveSpell = true;
break;
}
}
if(!hasPositiveSpell)
{
return SpellCasting::NO_SPELLS_TO_DISPEL;
}
}
return SpellCasting::OK;
}
CStack::CStack(const CStackInstance *Base, int O, int I, bool AO, int S) CStack::CStack(const CStackInstance *Base, int O, int I, bool AO, int S)
: base(Base), ID(I), owner(O), slot(S), attackerOwned(AO), : base(Base), ID(I), owner(O), slot(S), attackerOwned(AO),
counterAttacks(1) counterAttacks(1)
@ -1756,7 +1800,7 @@ const Bonus * CStack::getEffect( ui16 id, int turn /*= 0*/ ) const
{ {
BOOST_FOREACH(Bonus *it, bonuses) BOOST_FOREACH(Bonus *it, bonuses)
{ {
if(it->source == Bonus::SPELL_EFFECT && it->id == id) if(it->source == Bonus::SPELL_EFFECT && it->sid == id)
{ {
if(!turn || it->turnsRemain > turn) if(!turn || it->turnsRemain > turn)
return &(*it); return &(*it);
@ -1767,7 +1811,7 @@ const Bonus * CStack::getEffect( ui16 id, int turn /*= 0*/ ) const
void CStack::stackEffectToFeature(std::vector<Bonus> & sf, const Bonus & sse) void CStack::stackEffectToFeature(std::vector<Bonus> & sf, const Bonus & sse)
{ {
si32 power = VLC->spellh->spells[sse.id]->powers[sse.val]; si32 power = VLC->spellh->spells[sse.sid]->powers[sse.val];
//why, why, WHY this code is here?!? //why, why, WHY this code is here?!?
// Bonus * bonus = getBonus(Selector::typeSybtype(Bonus::SPECIAL_PECULIAR_ENCHANT, sse.id)); // Bonus * bonus = getBonus(Selector::typeSybtype(Bonus::SPECIAL_PECULIAR_ENCHANT, sse.id));
// if (bonus) // if (bonus)
@ -1794,142 +1838,142 @@ void CStack::stackEffectToFeature(std::vector<Bonus> & sf, const Bonus & sse)
// } // }
// } // }
switch(sse.id) switch(sse.sid)
{ {
case 27: //shield case 27: //shield
sf.push_back(featureGenerator(Bonus::GENERAL_DAMAGE_REDUCTION, 0, power, sse.turnsRemain)); sf.push_back(featureGenerator(Bonus::GENERAL_DAMAGE_REDUCTION, 0, power, sse.turnsRemain));
sf.back().id = sse.id; sf.back().sid = sse.sid;
break; break;
case 28: //air shield case 28: //air shield
sf.push_back(featureGenerator(Bonus::GENERAL_DAMAGE_REDUCTION, 1, power, sse.turnsRemain)); sf.push_back(featureGenerator(Bonus::GENERAL_DAMAGE_REDUCTION, 1, power, sse.turnsRemain));
sf.back().id = sse.id; sf.back().sid = sse.sid;
break; break;
case 29: //fire shield case 29: //fire shield
sf.push_back(featureGenerator(Bonus::FIRE_SHIELD, 0, power, sse.turnsRemain)); sf.push_back(featureGenerator(Bonus::FIRE_SHIELD, 0, power, sse.turnsRemain));
sf.back().id = sse.id; sf.back().sid = sse.sid;
break; break;
case 30: //protection from air case 30: //protection from air
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 0, power, sse.turnsRemain)); sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 0, power, sse.turnsRemain));
sf.back().id = sse.id; sf.back().sid = sse.sid;
break; break;
case 31: //protection from fire case 31: //protection from fire
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 1, power, sse.turnsRemain)); sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 1, power, sse.turnsRemain));
sf.back().id = sse.id; sf.back().sid = sse.sid;
break; break;
case 32: //protection from water case 32: //protection from water
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 2, power, sse.turnsRemain)); sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 2, power, sse.turnsRemain));
sf.back().id = sse.id; sf.back().sid = sse.sid;
break; break;
case 33: //protection from earth case 33: //protection from earth
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 3, power, sse.turnsRemain)); sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 3, power, sse.turnsRemain));
sf.back().id = sse.id; sf.back().sid = sse.sid;
break; break;
case 34: //anti-magic case 34: //anti-magic
sf.push_back(featureGenerator(Bonus::LEVEL_SPELL_IMMUNITY, 0, power - 1, sse.turnsRemain)); sf.push_back(featureGenerator(Bonus::LEVEL_SPELL_IMMUNITY, 0, power - 1, sse.turnsRemain));
sf.back().id = sse.id; sf.back().sid = sse.sid;
break; break;
case 41: //bless case 41: //bless
// if (hasBonusOfType(Bonus::SPECIAL_BLESS_DAMAGE, 41)) //TODO: better handling of bonus percentages // 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; // 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.push_back(featureGenerator(Bonus::CREATURE_DAMAGE, 0, damagePercent, sse.turnsRemain));
// sf.back().id = sse.id; // sf.back().sid = sse.sid;
// sf.back().valType = Bonus::PERCENT_TO_ALL; // sf.back().valType = Bonus::PERCENT_TO_ALL;
// } // }
sf.push_back(featureGenerator(Bonus::ALWAYS_MAXIMUM_DAMAGE, -1, power, sse.turnsRemain)); sf.push_back(featureGenerator(Bonus::ALWAYS_MAXIMUM_DAMAGE, -1, power, sse.turnsRemain));
sf.back().id = sse.id; sf.back().sid = sse.sid;
break; break;
case 42: //curse case 42: //curse
sf.push_back(featureGenerator(Bonus::ALWAYS_MINIMUM_DAMAGE, -1, -1 * power, sse.turnsRemain, sse.val >= 2 ? 20 : 0)); sf.push_back(featureGenerator(Bonus::ALWAYS_MINIMUM_DAMAGE, -1, -1 * power, sse.turnsRemain, sse.val >= 2 ? 20 : 0));
sf.back().id = sse.id; sf.back().sid = sse.sid;
break; break;
case 43: //bloodlust case 43: //bloodlust
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain, 0, Bonus::ONLY_MELEE_FIGHT)); sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain, 0, Bonus::ONLY_MELEE_FIGHT));
sf.back().id = sse.id; sf.back().sid = sse.sid;
break; break;
case 44: //precision case 44: //precision
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain, 0, Bonus::ONLY_DISTANCE_FIGHT)); sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain, 0, Bonus::ONLY_DISTANCE_FIGHT));
sf.back().id = sse.id; sf.back().sid = sse.sid;
break; break;
case 45: //weakness case 45: //weakness
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, -1 * power, sse.turnsRemain)); sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, -1 * power, sse.turnsRemain));
sf.back().id = sse.id; sf.back().sid = sse.sid;
break; break;
case 46: //stone skin case 46: //stone skin
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power, sse.turnsRemain)); sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power, sse.turnsRemain));
sf.back().id = sse.id; sf.back().sid = sse.sid;
break; break;
case 47: //disrupting ray case 47: //disrupting ray
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, -1 * power, sse.turnsRemain)); sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, -1 * power, sse.turnsRemain));
sf.back().id = sse.id; sf.back().sid = sse.sid;
sf.back().valType = Bonus::ADDITIVE_VALUE; sf.back().valType = Bonus::ADDITIVE_VALUE;
break; break;
case 48: //prayer case 48: //prayer
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain)); sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain));
sf.back().id = sse.id; sf.back().sid = sse.sid;
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power, sse.turnsRemain)); sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power, sse.turnsRemain));
sf.back().id = sse.id; sf.back().sid = sse.sid;
sf.push_back(featureGenerator(Bonus::STACKS_SPEED, 0, power, sse.turnsRemain)); sf.push_back(featureGenerator(Bonus::STACKS_SPEED, 0, power, sse.turnsRemain));
sf.back().id = sse.id; sf.back().sid = sse.sid;
break; break;
case 49: //mirth case 49: //mirth
sf.push_back(featureGenerator(Bonus::MORALE, 0, power, sse.turnsRemain)); sf.push_back(featureGenerator(Bonus::MORALE, 0, power, sse.turnsRemain));
sf.back().id = sse.id; sf.back().sid = sse.sid;
break; break;
case 50: //sorrow case 50: //sorrow
sf.push_back(featureGenerator(Bonus::MORALE, 0, -1 * power, sse.turnsRemain)); sf.push_back(featureGenerator(Bonus::MORALE, 0, -1 * power, sse.turnsRemain));
sf.back().id = sse.id; sf.back().sid = sse.sid;
break; break;
case 51: //fortune case 51: //fortune
sf.push_back(featureGenerator(Bonus::LUCK, 0, power, sse.turnsRemain)); sf.push_back(featureGenerator(Bonus::LUCK, 0, power, sse.turnsRemain));
sf.back().id = sse.id; sf.back().sid = sse.sid;
break; break;
case 52: //misfortune case 52: //misfortune
sf.push_back(featureGenerator(Bonus::LUCK, 0, -1 * power, sse.turnsRemain)); sf.push_back(featureGenerator(Bonus::LUCK, 0, -1 * power, sse.turnsRemain));
sf.back().id = sse.id; sf.back().sid = sse.sid;
break; break;
case 53: //haste case 53: //haste
sf.push_back(featureGenerator(Bonus::STACKS_SPEED, 0, power, sse.turnsRemain)); sf.push_back(featureGenerator(Bonus::STACKS_SPEED, 0, power, sse.turnsRemain));
sf.back().id = sse.id; sf.back().sid = sse.sid;
break; break;
case 54: //slow case 54: //slow
sf.push_back(featureGeneratorVT(Bonus::STACKS_SPEED, 0, -1 * ( 100 - power ), sse.turnsRemain, Bonus::PERCENT_TO_ALL)); sf.push_back(featureGeneratorVT(Bonus::STACKS_SPEED, 0, -1 * ( 100 - power ), sse.turnsRemain, Bonus::PERCENT_TO_ALL));
sf.back().id = sse.id; sf.back().sid = sse.sid;
break; break;
case 55: //slayer case 55: //slayer
// if (bonus) //Coronius // if (bonus) //Coronius
// { // {
// sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain)); // sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain));
// sf.back().id = sse.id; // sf.back().sid = sse.sid;
// } // }
sf.push_back(featureGenerator(Bonus::SLAYER, 0, sse.val, sse.turnsRemain)); sf.push_back(featureGenerator(Bonus::SLAYER, 0, sse.val, sse.turnsRemain));
sf.back().id = sse.id; sf.back().sid = sse.sid;
break; break;
case 56: //frenzy case 56: //frenzy
sf.push_back(featureGenerator(Bonus::IN_FRENZY, 0, VLC->spellh->spells[56]->powers[sse.val]/100.0, sse.turnsRemain)); sf.push_back(featureGenerator(Bonus::IN_FRENZY, 0, VLC->spellh->spells[56]->powers[sse.val]/100.0, sse.turnsRemain));
sf.back().id = sse.id; sf.back().sid = sse.sid;
break; break;
case 58: //counterstrike case 58: //counterstrike
sf.push_back(featureGenerator(Bonus::ADDITIONAL_RETALIATION, 0, power, sse.turnsRemain)); sf.push_back(featureGenerator(Bonus::ADDITIONAL_RETALIATION, 0, power, sse.turnsRemain));
sf.back().id = sse.id; sf.back().sid = sse.sid;
break; break;
case 59: //bersek case 59: //bersek
sf.push_back(featureGenerator(Bonus::ATTACKS_NEAREST_CREATURE, 0, sse.val, sse.turnsRemain)); sf.push_back(featureGenerator(Bonus::ATTACKS_NEAREST_CREATURE, 0, sse.val, sse.turnsRemain));
sf.back().id = sse.id; sf.back().sid = sse.sid;
break; break;
case 60: //hypnotize case 60: //hypnotize
sf.push_back(featureGenerator(Bonus::HYPNOTIZED, 0, sse.val, sse.turnsRemain)); sf.push_back(featureGenerator(Bonus::HYPNOTIZED, 0, sse.val, sse.turnsRemain));
sf.back().id = sse.id; sf.back().sid = sse.sid;
break; break;
case 61: //forgetfulness case 61: //forgetfulness
sf.push_back(featureGenerator(Bonus::FORGETFULL, 0, sse.val, sse.turnsRemain)); sf.push_back(featureGenerator(Bonus::FORGETFULL, 0, sse.val, sse.turnsRemain));
sf.back().id = sse.id; sf.back().sid = sse.sid;
break; break;
case 62: //blind case 62: //blind
sf.push_back(makeFeatureVal(Bonus::NOT_ACTIVE, Bonus::UNITL_BEING_ATTACKED | Bonus::N_TURNS, 0, 0, Bonus::SPELL_EFFECT, sse.turnsRemain)); sf.push_back(makeFeatureVal(Bonus::NOT_ACTIVE, Bonus::UNITL_BEING_ATTACKED | Bonus::N_TURNS, 0, 0, Bonus::SPELL_EFFECT, sse.turnsRemain));
sf.back().id = sse.id; sf.back().sid = sse.sid;
sf.push_back(makeFeatureVal(Bonus::GENERAL_ATTACK_REDUCTION, Bonus::UNTIL_ATTACK | Bonus::N_TURNS, 0, power, Bonus::SPELL_EFFECT, sse.turnsRemain)); sf.push_back(makeFeatureVal(Bonus::GENERAL_ATTACK_REDUCTION, Bonus::UNTIL_ATTACK | Bonus::N_TURNS, 0, power, Bonus::SPELL_EFFECT, sse.turnsRemain));
sf.back().id = sse.id; sf.back().sid = sse.sid;
break; break;
} }
} }
@ -1938,7 +1982,7 @@ ui8 CStack::howManyEffectsSet(ui16 id) const
{ {
ui8 ret = 0; ui8 ret = 0;
BOOST_FOREACH(const Bonus *it, bonuses) BOOST_FOREACH(const Bonus *it, bonuses)
if(it->source == Bonus::SPELL_EFFECT && it->id == id) //effect found if(it->source == Bonus::SPELL_EFFECT && it->sid == id) //effect found
{ {
++ret; ++ret;
} }
@ -1997,8 +2041,8 @@ std::vector<si32> CStack::activeSpells() const
BonusList spellEffects = getSpellBonuses(); BonusList spellEffects = getSpellBonuses();
BOOST_FOREACH(const Bonus *it, spellEffects) BOOST_FOREACH(const Bonus *it, spellEffects)
{ {
if (!vstd::contains(ret, it->id)) //do not duplicate spells with multiple effects if (!vstd::contains(ret, it->sid)) //do not duplicate spells with multiple effects
ret.push_back(it->id); ret.push_back(it->sid);
} }
return ret; return ret;

View File

@ -115,8 +115,11 @@ struct DLL_EXPORT BattleInfo : public CBonusSystemNode
si8 canTeleportTo(const CStack * stack, THex destHex, int telportLevel) const; //determines if given stack can teleport to given place si8 canTeleportTo(const CStack * stack, THex destHex, int telportLevel) const; //determines if given stack can teleport to given place
bool battleCanShoot(const CStack * stack, THex dest) const; //determines if stack with given ID shoot at the selected destination bool battleCanShoot(const CStack * stack, THex dest) const; //determines if stack with given ID shoot at the selected destination
SpellCasting::ESpellCastProblem battleCanCastSpell(int player) const; //returns true if there are no general issues preventing from castng a spell enum ECastingMode {HERO_CASTING, AFTER_ATTACK_CASTING};
SpellCasting::ESpellCastProblem battleCanCastThisSpell(int player, const CSpell * spell) const; //chcecks if given player can cast given spell
SpellCasting::ESpellCastProblem battleCanCastSpell(int player, ECastingMode mode) const; //returns true if there are no general issues preventing from casting a spell
SpellCasting::ESpellCastProblem battleCanCastThisSpell(int player, const CSpell * spell, ECastingMode mode) const; //checks if given player can cast given spell
SpellCasting::ESpellCastProblem battleCanCastThisSpellHere(int player, const CSpell * spell, ECastingMode mode, THex dest); //checks if given player can cast given spell at given tile in given mode
bool battleCanFlee(int player) const; //returns true if player can flee from the battle bool battleCanFlee(int player) const; //returns true if player can flee from the battle
const CStack * battleGetStack(THex pos, bool onlyAlive); //returns stack at given tile const CStack * battleGetStack(THex pos, bool onlyAlive); //returns stack at given tile

View File

@ -415,7 +415,7 @@ void CCreatureHandler::loadCreatures()
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->sid = cre->idNumber;
nsf->duration = Bonus::ONE_BATTLE; nsf->duration = Bonus::ONE_BATTLE;
nsf->turnsRemain = 0; nsf->turnsRemain = 0;
@ -673,7 +673,7 @@ void CCreatureHandler::loadCreatures()
do //parse everything that's left do //parse everything that's left
{ {
loadToIt(creid, buf, it, 4); //get index loadToIt(creid, buf, it, 4); //get index
b.id = creid; //id = this particular creature ID b.sid = creid; //id = this particular creature ID
loadStackExp(b, creatures[creid]->bonuses, buf, it); //add directly to CCreature Node loadStackExp(b, creatures[creid]->bonuses, buf, it); //add directly to CCreature Node
loadToIt (dump2, buf, it, 3); //crop comment loadToIt (dump2, buf, it, 3); //crop comment
} while (it < buf.size()); } while (it < buf.size());
@ -1015,7 +1015,7 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, std::string & src
void CCreatureHandler::loadMindImmunity(Bonus & b, BonusList & bl, std::string & src, int & it) void CCreatureHandler::loadMindImmunity(Bonus & b, BonusList & bl, std::string & src, int & it)
{ {
CCreature * cre = creatures[b.id]; //odd workaround CCreature * cre = creatures[b.sid]; //odd workaround
b.type = Bonus::SPELL_IMMUNITY; b.type = Bonus::SPELL_IMMUNITY;
b.val = Bonus::BASE_NUMBER; b.val = Bonus::BASE_NUMBER;

View File

@ -461,7 +461,7 @@ void CGObjectInstance::giveDummyBonus(int heroID, ui8 duration) const
gbonus.id = heroID; gbonus.id = heroID;
gbonus.bonus.duration = duration; gbonus.bonus.duration = duration;
gbonus.bonus.source = Bonus::OBJECT; gbonus.bonus.source = Bonus::OBJECT;
gbonus.bonus.id = ID; gbonus.bonus.sid = ID;
cb->giveHeroBonus(&gbonus); cb->giveHeroBonus(&gbonus);
} }
@ -946,7 +946,7 @@ void CGHeroInstance::initObj()
{ {
Bonus *bonus = new Bonus(); Bonus *bonus = new Bonus();
bonus->val = it->val; bonus->val = it->val;
bonus->id = id; //from the hero, speciality has no unique id bonus->sid = id; //from the hero, speciality has no unique id
bonus->duration = Bonus::PERMANENT; bonus->duration = Bonus::PERMANENT;
bonus->source = Bonus::HERO_SPECIAL; bonus->source = Bonus::HERO_SPECIAL;
switch (it->type) switch (it->type)
@ -4548,7 +4548,7 @@ void CGBonusingObject::onHeroVisit( const CGHeroInstance * h ) const
gbonus.id = h->id; gbonus.id = h->id;
gbonus.bonus.duration = Bonus::ONE_BATTLE; gbonus.bonus.duration = Bonus::ONE_BATTLE;
gbonus.bonus.source = Bonus::OBJECT; gbonus.bonus.source = Bonus::OBJECT;
gbonus.bonus.id = ID; gbonus.bonus.sid = ID;
bool second = false; bool second = false;
Bonus secondBonus; Bonus secondBonus;
@ -5766,7 +5766,7 @@ void CBank::onHeroVisit (const CGHeroInstance * h) const
gbonus.id = h->id; gbonus.id = h->id;
gbonus.bonus.duration = Bonus::ONE_BATTLE; gbonus.bonus.duration = Bonus::ONE_BATTLE;
gbonus.bonus.source = Bonus::OBJECT; gbonus.bonus.source = Bonus::OBJECT;
gbonus.bonus.id = ID; gbonus.bonus.sid = ID;
gbonus.bdescr << "\n" << VLC->generaltexth->arraytxt[98]; gbonus.bdescr << "\n" << VLC->generaltexth->arraytxt[98];
gbonus.bonus.type = Bonus::MORALE; gbonus.bonus.type = Bonus::MORALE;
gbonus.bonus.val = -1; gbonus.bonus.val = -1;
@ -5812,7 +5812,7 @@ void CBank::endBattle (const CGHeroInstance *h, const BattleResult *result) cons
gbonus.id = h->id; gbonus.id = h->id;
gbonus.bonus.duration = Bonus::ONE_BATTLE; gbonus.bonus.duration = Bonus::ONE_BATTLE;
gbonus.bonus.source = Bonus::OBJECT; gbonus.bonus.source = Bonus::OBJECT;
gbonus.bonus.id = ID; gbonus.bonus.sid = ID;
gbonus.bdescr << "\n" << VLC->generaltexth->arraytxt[101]; gbonus.bdescr << "\n" << VLC->generaltexth->arraytxt[101];
gbonus.bonus.type = Bonus::MORALE; gbonus.bonus.type = Bonus::MORALE;
gbonus.bonus.val = -1; gbonus.bonus.val = -1;
@ -5831,7 +5831,7 @@ void CBank::endBattle (const CGHeroInstance *h, const BattleResult *result) cons
gbonus.id = h->id; gbonus.id = h->id;
gbonus.bonus.duration = Bonus::ONE_BATTLE; gbonus.bonus.duration = Bonus::ONE_BATTLE;
gbonus.bonus.source = Bonus::OBJECT; gbonus.bonus.source = Bonus::OBJECT;
gbonus.bonus.id = ID; gbonus.bonus.sid = ID;
gbonus.bdescr << "\n" << VLC->generaltexth->arraytxt[ID]; gbonus.bdescr << "\n" << VLC->generaltexth->arraytxt[ID];
gbonus.bonus.type = Bonus::MORALE; gbonus.bonus.type = Bonus::MORALE;
gbonus.bonus.val = -1; gbonus.bonus.val = -1;
@ -6526,7 +6526,7 @@ void CGLighthouse::giveBonusTo( ui8 player ) const
gb.id = player; gb.id = player;
gb.bonus.duration = Bonus::PERMANENT; gb.bonus.duration = Bonus::PERMANENT;
gb.bonus.source = Bonus::OBJECT; gb.bonus.source = Bonus::OBJECT;
gb.bonus.id = id; gb.bonus.sid = id;
cb->sendAndApply(&gb); cb->sendAndApply(&gb);
} }

View File

@ -499,7 +499,7 @@ int NBonus::getCount(const CBonusSystemNode *obj, int from, int id)
const CSpell * Bonus::sourceSpell() const const CSpell * Bonus::sourceSpell() const
{ {
if(source == SPELL_EFFECT) if(source == SPELL_EFFECT)
return VLC->spellh->spells[id]; return VLC->spellh->spells[sid];
return NULL; return NULL;
} }
@ -519,10 +519,10 @@ std::string Bonus::Description() const
switch(source) switch(source)
{ {
case CREATURE_ABILITY: case CREATURE_ABILITY:
str << VLC->creh->creatures[id]->namePl; str << VLC->creh->creatures[sid]->namePl;
break; break;
case SECONDARY_SKILL: case SECONDARY_SKILL:
str << VLC->generaltexth->skillName[id] << " secondary skill"; str << VLC->generaltexth->skillName[sid] << " secondary skill";
break; break;
} }
@ -530,7 +530,7 @@ std::string Bonus::Description() const
} }
Bonus::Bonus(ui8 Dur, ui8 Type, ui8 Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype/*=-1*/) Bonus::Bonus(ui8 Dur, ui8 Type, ui8 Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype/*=-1*/)
: duration(Dur), type(Type), subtype(Subtype), source(Src), val(Val), id(ID), description(Desc) : duration(Dur), type(Type), subtype(Subtype), source(Src), val(Val), sid(ID), description(Desc)
{ {
additionalInfo = -1; additionalInfo = -1;
turnsRemain = 0; turnsRemain = 0;
@ -540,7 +540,7 @@ Bonus::Bonus(ui8 Dur, ui8 Type, ui8 Src, si32 Val, ui32 ID, std::string Desc, si
} }
Bonus::Bonus(ui8 Dur, ui8 Type, ui8 Src, si32 Val, ui32 ID, si32 Subtype/*=-1*/, ui8 ValType /*= ADDITIVE_VALUE*/) Bonus::Bonus(ui8 Dur, ui8 Type, ui8 Src, si32 Val, ui32 ID, si32 Subtype/*=-1*/, ui8 ValType /*= ADDITIVE_VALUE*/)
: duration(Dur), type(Type), subtype(Subtype), source(Src), val(Val), id(ID), valType(ValType) : duration(Dur), type(Type), subtype(Subtype), source(Src), val(Val), sid(ID), valType(ValType)
{ {
additionalInfo = -1; additionalInfo = -1;
turnsRemain = 0; turnsRemain = 0;
@ -596,7 +596,7 @@ namespace Selector
CSelector DLL_EXPORT source(ui8 source, ui32 sourceID) CSelector DLL_EXPORT source(ui8 source, ui32 sourceID)
{ {
return CSelectFieldEqual<ui8>(&Bonus::source, source) && CSelectFieldEqual<ui32>(&Bonus::id, sourceID); return CSelectFieldEqual<ui8>(&Bonus::source, source) && CSelectFieldEqual<ui32>(&Bonus::sid, sourceID);
} }
CSelector DLL_EXPORT sourceTypeSel(ui8 source) CSelector DLL_EXPORT sourceTypeSel(ui8 source)
@ -668,7 +668,7 @@ DLL_EXPORT std::ostream & operator<<(std::ostream &out, const Bonus &bonus)
printField(subtype); printField(subtype);
printField(duration); printField(duration);
printField(source); printField(source);
printField(id); printField(sid);
printField(additionalInfo); printField(additionalInfo);
printField(turnsRemain); printField(turnsRemain);
printField(valType); printField(valType);

View File

@ -58,7 +58,6 @@ namespace PrimarySkill
BONUS_NAME(BLOCK_SPELLS_ABOVE_LEVEL) \ BONUS_NAME(BLOCK_SPELLS_ABOVE_LEVEL) \
BONUS_NAME(WATER_WALKING) /*subtype 1 - without penalty, 2 - with penalty*/ \ BONUS_NAME(WATER_WALKING) /*subtype 1 - without penalty, 2 - with penalty*/ \
BONUS_NAME(NO_SHOTING_PENALTY) \ BONUS_NAME(NO_SHOTING_PENALTY) \
BONUS_NAME(DISPEL_IMMUNITY) \
BONUS_NAME(NEGATE_ALL_NATURAL_IMMUNITIES) \ BONUS_NAME(NEGATE_ALL_NATURAL_IMMUNITIES) \
BONUS_NAME(STACK_HEALTH) \ BONUS_NAME(STACK_HEALTH) \
BONUS_NAME(BLOCK_MORALE) \ BONUS_NAME(BLOCK_MORALE) \
@ -226,7 +225,7 @@ struct DLL_EXPORT Bonus
ui8 source;//source type" uses BonusSource values - what gave that bonus ui8 source;//source type" uses BonusSource values - what gave that bonus
si32 val; si32 val;
ui32 id; //source id: id of object/artifact/spell ui32 sid; //source id: id of object/artifact/spell
ui8 valType; //by ValueType enum ui8 valType; //by ValueType enum
si32 additionalInfo; si32 additionalInfo;
@ -256,7 +255,7 @@ struct DLL_EXPORT Bonus
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
h & duration & type & subtype & source & val & id & description & additionalInfo & turnsRemain & valType & effectRange & limiter; h & duration & type & subtype & source & val & sid & description & additionalInfo & turnsRemain & valType & effectRange & limiter;
} }
static bool OneDay(const Bonus *hb) static bool OneDay(const Bonus *hb)
@ -285,7 +284,7 @@ struct DLL_EXPORT Bonus
} }
static bool IsFrom(const Bonus &hb, ui8 source, ui32 id) //if id==0xffffff then id doesn't matter static bool IsFrom(const Bonus &hb, ui8 source, ui32 id) //if id==0xffffff then id doesn't matter
{ {
return hb.source==source && (id==0xffffff || hb.id==id); return hb.source==source && (id==0xffffff || hb.sid==id);
} }
inline bool operator == (const BonusType & cf) const inline bool operator == (const BonusType & cf) const
{ {

View File

@ -186,7 +186,7 @@ DLL_EXPORT void GiveBonus::applyGs( CGameState *gs )
if(!bdescr.message.size() if(!bdescr.message.size()
&& bonus.source == Bonus::OBJECT && bonus.source == Bonus::OBJECT
&& (bonus.type == Bonus::LUCK || bonus.type == Bonus::MORALE) && (bonus.type == Bonus::LUCK || bonus.type == Bonus::MORALE)
&& gs->map->objects[bonus.id]->ID == EVENTI_TYPE) //it's morale/luck bonus from an event without description && gs->map->objects[bonus.sid]->ID == EVENTI_TYPE) //it's morale/luck bonus from an event without description
{ {
descr = VLC->generaltexth->arraytxt[bonus.val > 0 ? 110 : 109]; //+/-%d Temporary until next battle" descr = VLC->generaltexth->arraytxt[bonus.val > 0 ? 110 : 109]; //+/-%d Temporary until next battle"
boost::replace_first(descr,"%d",boost::lexical_cast<std::string>(std::abs(bonus.val))); boost::replace_first(descr,"%d",boost::lexical_cast<std::string>(std::abs(bonus.val)));
@ -222,7 +222,7 @@ DLL_EXPORT void RemoveBonus::applyGs( CGameState *gs )
for(BonusList::iterator i = bonuses.begin(); i != bonuses.end(); i++) for(BonusList::iterator i = bonuses.begin(); i != bonuses.end(); i++)
{ {
if((*i)->source == source && (*i)->id == id) if((*i)->source == source && (*i)->sid == id)
{ {
bonus = **i; //backup bonus (to show to interfaces later) bonus = **i; //backup bonus (to show to interfaces later)
bonuses.erase(i); bonuses.erase(i);
@ -1052,7 +1052,7 @@ DLL_EXPORT void BattleSpellCast::applyGs( CGameState *gs )
//WTF? //WTF?
for (BonusList::iterator it = remainingEff.begin(); it != remainingEff.end(); it++) for (BonusList::iterator it = remainingEff.begin(); it != remainingEff.end(); it++)
{ {
if (onlyHelpful && VLC->spellh->spells[ (*it)->id ]->positiveness != 1) if (onlyHelpful && VLC->spellh->spells[ (*it)->sid ]->positiveness != 1)
{ {
remainingEff.push_back(*it); remainingEff.push_back(*it);
} }
@ -1147,7 +1147,7 @@ DLL_EXPORT void SetStackEffect::applyGs( CGameState *gs )
CStack *s = gs->curB->getStack(id); CStack *s = gs->curB->getStack(id);
if(s) if(s)
{ {
int id = effect.begin()->id; //effects' source ID int id = effect.begin()->sid; //effects' source ID
if(id == 47 || !s->hasBonus(Selector::source(Bonus::SPELL_EFFECT, id)))//disrupting ray or not on the list - just add if(id == 47 || !s->hasBonus(Selector::source(Bonus::SPELL_EFFECT, id)))//disrupting ray or not on the list - just add
{ {
BOOST_FOREACH(Bonus &fromEffect, effect) BOOST_FOREACH(Bonus &fromEffect, effect)
@ -1217,7 +1217,7 @@ DLL_EXPORT void StacksHealedOrResurrected::applyGs( CGameState *gs )
for (BonusList::iterator it = changedStack->bonuses.begin(); it != changedStack->bonuses.end(); it++) for (BonusList::iterator it = changedStack->bonuses.begin(); it != changedStack->bonuses.end(); it++)
{ {
if(VLC->spellh->spells[(*it)->id]->positiveness < 0) if(VLC->spellh->spells[(*it)->sid]->positiveness < 0)
{ {
changedStack->bonuses.erase(it); changedStack->bonuses.erase(it);
} }

View File

@ -3739,7 +3739,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, int destinatio
sse.stacks.push_back((*it)->ID); sse.stacks.push_back((*it)->ID);
} }
Bonus pseudoBonus; Bonus pseudoBonus;
pseudoBonus.id = spellID; pseudoBonus.sid = spellID;
pseudoBonus.val = spellLvl; pseudoBonus.val = spellLvl;
pseudoBonus.turnsRemain = gs->curB->calculateSpellDuration(spell, caster, usedSpellPower); pseudoBonus.turnsRemain = gs->curB->calculateSpellDuration(spell, caster, usedSpellPower);
CStack::stackEffectToFeature(sse.effect, pseudoBonus); CStack::stackEffectToFeature(sse.effect, pseudoBonus);
@ -3824,7 +3824,7 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
const CSpell *s = VLC->spellh->spells[ba.additionalInfo]; const CSpell *s = VLC->spellh->spells[ba.additionalInfo];
ui8 skill = h->getSpellSchoolLevel(s); //skill level ui8 skill = h->getSpellSchoolLevel(s); //skill level
SpellCasting::ESpellCastProblem escp = gs->curB->battleCanCastThisSpell(h->tempOwner, s); SpellCasting::ESpellCastProblem escp = gs->curB->battleCanCastThisSpell(h->tempOwner, s, BattleInfo::HERO_CASTING);
if(escp != SpellCasting::OK) if(escp != SpellCasting::OK)
{ {
tlog2 << "Spell cannot be cast!\n"; tlog2 << "Spell cannot be cast!\n";
@ -4408,6 +4408,12 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
int chance = sf->additionalInfo % 1000; int chance = sf->additionalInfo % 1000;
//int meleeRanged = sf->additionalInfo / 1000; //int meleeRanged = sf->additionalInfo / 1000;
int destination = oneOfAttacked->position; int destination = oneOfAttacked->position;
const CSpell * spell = VLC->spellh->spells[spellID];
if(gs->curB->battleCanCastThisSpellHere(attacker->owner, spell, BattleInfo::AFTER_ATTACK_CASTING, oneOfAttacked->position)
!= SpellCasting::OK)
continue;
//check if spell should be casted (probability handling) //check if spell should be casted (probability handling)
if( rand()%100 >= chance ) if( rand()%100 >= chance )
continue; continue;