1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +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
return false;
return gs->curB->battleCanCastSpell(player) == SpellCasting::OK;
return gs->curB->battleCanCastSpell(player, BattleInfo::HERO_CASTING) == SpellCasting::OK;
}
bool CBattleCallback::battleCanFlee()
@ -1097,7 +1097,7 @@ SpellCasting::ESpellCastProblem CBattleCallback::battleCanCastThisSpell( const C
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()

View File

@ -2859,7 +2859,7 @@ void CBattleInterface::spellCast( const BattleSpellCast * sc )
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
{
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;
};
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

View File

@ -313,7 +313,7 @@ namespace SpellCasting
{
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,
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)
{
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;
}
@ -1617,32 +1617,48 @@ bool BattleInfo::isInTacticRange( THex dest ) const
|| (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;
if(castSpells[side] > 0)
return SpellCasting::ALREADY_CASTED_THIS_TURN;
if(!heroes[side])
return SpellCasting::NO_HERO_TO_CAST_SPELL;
if(!heroes[side]->getArt(17))
return SpellCasting::NO_SPELLBOOK;
switch (mode)
{
case HERO_CASTING:
{
if(castSpells[side] > 0)
return SpellCasting::ALREADY_CASTED_THIS_TURN;
if(!heroes[side])
return SpellCasting::NO_HERO_TO_CAST_SPELL;
if(!heroes[side]->getArt(17))
return SpellCasting::NO_SPELLBOOK;
}
break;
}
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)
return genProblem;
int cside = sides[0] == player ? 0 : 1; //caster's side
const CGHeroInstance * caster = heroes[cside];
if(!caster->canCastThisSpell(spell))
return SpellCasting::HERO_DOESNT_KNOW_SPELL;
if(caster->mana < getSpellCost(spell, caster)) //not enough mana
return SpellCasting::NOT_ENOUGH_MANA;
int cside = sides[0] == player ? 0 : 1; //caster's side
switch(mode)
{
HERO_CASTING:
{
const CGHeroInstance * caster = heroes[cside];
if(!caster->canCastThisSpell(spell))
return SpellCasting::HERO_DOESNT_KNOW_SPELL;
if(caster->mana < getSpellCost(spell, caster)) //not enough mana
return SpellCasting::NOT_ENOUGH_MANA;
}
break;
}
if(spell->id < 10) //it's adventure spell (not combat))
return SpellCasting::ADVMAP_SPELL_INSTEAD_OF_BATTLE_SPELL;
@ -1673,6 +1689,34 @@ SpellCasting::ESpellCastProblem BattleInfo::battleCanCastThisSpell( int player,
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)
: base(Base), ID(I), owner(O), slot(S), attackerOwned(AO),
counterAttacks(1)
@ -1756,7 +1800,7 @@ const Bonus * CStack::getEffect( ui16 id, int turn /*= 0*/ ) const
{
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)
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)
{
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?!?
// Bonus * bonus = getBonus(Selector::typeSybtype(Bonus::SPECIAL_PECULIAR_ENCHANT, sse.id));
// 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
sf.push_back(featureGenerator(Bonus::GENERAL_DAMAGE_REDUCTION, 0, power, sse.turnsRemain));
sf.back().id = sse.id;
sf.back().sid = sse.sid;
break;
case 28: //air shield
sf.push_back(featureGenerator(Bonus::GENERAL_DAMAGE_REDUCTION, 1, power, sse.turnsRemain));
sf.back().id = sse.id;
sf.back().sid = sse.sid;
break;
case 29: //fire shield
sf.push_back(featureGenerator(Bonus::FIRE_SHIELD, 0, power, sse.turnsRemain));
sf.back().id = sse.id;
sf.back().sid = sse.sid;
break;
case 30: //protection from air
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 0, power, sse.turnsRemain));
sf.back().id = sse.id;
sf.back().sid = sse.sid;
break;
case 31: //protection from fire
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 1, power, sse.turnsRemain));
sf.back().id = sse.id;
sf.back().sid = sse.sid;
break;
case 32: //protection from water
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 2, power, sse.turnsRemain));
sf.back().id = sse.id;
sf.back().sid = sse.sid;
break;
case 33: //protection from earth
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 3, power, sse.turnsRemain));
sf.back().id = sse.id;
sf.back().sid = sse.sid;
break;
case 34: //anti-magic
sf.push_back(featureGenerator(Bonus::LEVEL_SPELL_IMMUNITY, 0, power - 1, sse.turnsRemain));
sf.back().id = sse.id;
sf.back().sid = sse.sid;
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().sid = sse.sid;
// sf.back().valType = Bonus::PERCENT_TO_ALL;
// }
sf.push_back(featureGenerator(Bonus::ALWAYS_MAXIMUM_DAMAGE, -1, power, sse.turnsRemain));
sf.back().id = sse.id;
sf.back().sid = sse.sid;
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;
sf.back().sid = sse.sid;
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;
sf.back().sid = sse.sid;
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;
sf.back().sid = sse.sid;
break;
case 45: //weakness
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, -1 * power, sse.turnsRemain));
sf.back().id = sse.id;
sf.back().sid = sse.sid;
break;
case 46: //stone skin
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power, sse.turnsRemain));
sf.back().id = sse.id;
sf.back().sid = sse.sid;
break;
case 47: //disrupting ray
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;
break;
case 48: //prayer
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.back().id = sse.id;
sf.back().sid = sse.sid;
sf.push_back(featureGenerator(Bonus::STACKS_SPEED, 0, power, sse.turnsRemain));
sf.back().id = sse.id;
sf.back().sid = sse.sid;
break;
case 49: //mirth
sf.push_back(featureGenerator(Bonus::MORALE, 0, power, sse.turnsRemain));
sf.back().id = sse.id;
sf.back().sid = sse.sid;
break;
case 50: //sorrow
sf.push_back(featureGenerator(Bonus::MORALE, 0, -1 * power, sse.turnsRemain));
sf.back().id = sse.id;
sf.back().sid = sse.sid;
break;
case 51: //fortune
sf.push_back(featureGenerator(Bonus::LUCK, 0, power, sse.turnsRemain));
sf.back().id = sse.id;
sf.back().sid = sse.sid;
break;
case 52: //misfortune
sf.push_back(featureGenerator(Bonus::LUCK, 0, -1 * power, sse.turnsRemain));
sf.back().id = sse.id;
sf.back().sid = sse.sid;
break;
case 53: //haste
sf.push_back(featureGenerator(Bonus::STACKS_SPEED, 0, power, sse.turnsRemain));
sf.back().id = sse.id;
sf.back().sid = sse.sid;
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;
sf.back().sid = sse.sid;
break;
case 55: //slayer
// if (bonus) //Coronius
// {
// 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.back().id = sse.id;
sf.back().sid = sse.sid;
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;
sf.back().sid = sse.sid;
break;
case 58: //counterstrike
sf.push_back(featureGenerator(Bonus::ADDITIONAL_RETALIATION, 0, power, sse.turnsRemain));
sf.back().id = sse.id;
sf.back().sid = sse.sid;
break;
case 59: //bersek
sf.push_back(featureGenerator(Bonus::ATTACKS_NEAREST_CREATURE, 0, sse.val, sse.turnsRemain));
sf.back().id = sse.id;
sf.back().sid = sse.sid;
break;
case 60: //hypnotize
sf.push_back(featureGenerator(Bonus::HYPNOTIZED, 0, sse.val, sse.turnsRemain));
sf.back().id = sse.id;
sf.back().sid = sse.sid;
break;
case 61: //forgetfulness
sf.push_back(featureGenerator(Bonus::FORGETFULL, 0, sse.val, sse.turnsRemain));
sf.back().id = sse.id;
sf.back().sid = sse.sid;
break;
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.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.back().id = sse.id;
sf.back().sid = sse.sid;
break;
}
}
@ -1938,7 +1982,7 @@ ui8 CStack::howManyEffectsSet(ui16 id) const
{
ui8 ret = 0;
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;
}
@ -1997,8 +2041,8 @@ std::vector<si32> CStack::activeSpells() const
BonusList spellEffects = getSpellBonuses();
BOOST_FOREACH(const Bonus *it, spellEffects)
{
if (!vstd::contains(ret, it->id)) //do not duplicate spells with multiple effects
ret.push_back(it->id);
if (!vstd::contains(ret, it->sid)) //do not duplicate spells with multiple effects
ret.push_back(it->sid);
}
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
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
SpellCasting::ESpellCastProblem battleCanCastThisSpell(int player, const CSpell * spell) const; //chcecks if given player can cast given spell
enum ECastingMode {HERO_CASTING, AFTER_ATTACK_CASTING};
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
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->additionalInfo = buf;
nsf->source = Bonus::CREATURE_ABILITY;
nsf->id = cre->idNumber;
nsf->sid = cre->idNumber;
nsf->duration = Bonus::ONE_BATTLE;
nsf->turnsRemain = 0;
@ -673,7 +673,7 @@ void CCreatureHandler::loadCreatures()
do //parse everything that's left
{
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
loadToIt (dump2, buf, it, 3); //crop comment
} 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)
{
CCreature * cre = creatures[b.id]; //odd workaround
CCreature * cre = creatures[b.sid]; //odd workaround
b.type = Bonus::SPELL_IMMUNITY;
b.val = Bonus::BASE_NUMBER;

View File

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

View File

@ -499,7 +499,7 @@ int NBonus::getCount(const CBonusSystemNode *obj, int from, int id)
const CSpell * Bonus::sourceSpell() const
{
if(source == SPELL_EFFECT)
return VLC->spellh->spells[id];
return VLC->spellh->spells[sid];
return NULL;
}
@ -519,18 +519,18 @@ std::string Bonus::Description() const
switch(source)
{
case CREATURE_ABILITY:
str << VLC->creh->creatures[id]->namePl;
str << VLC->creh->creatures[sid]->namePl;
break;
case SECONDARY_SKILL:
str << VLC->generaltexth->skillName[id] << " secondary skill";
str << VLC->generaltexth->skillName[sid] << " secondary skill";
break;
}
return str.str();
}
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;
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*/)
: 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;
turnsRemain = 0;
@ -596,7 +596,7 @@ namespace Selector
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)
@ -668,7 +668,7 @@ DLL_EXPORT std::ostream & operator<<(std::ostream &out, const Bonus &bonus)
printField(subtype);
printField(duration);
printField(source);
printField(id);
printField(sid);
printField(additionalInfo);
printField(turnsRemain);
printField(valType);

View File

@ -58,7 +58,6 @@ namespace PrimarySkill
BONUS_NAME(BLOCK_SPELLS_ABOVE_LEVEL) \
BONUS_NAME(WATER_WALKING) /*subtype 1 - without penalty, 2 - with penalty*/ \
BONUS_NAME(NO_SHOTING_PENALTY) \
BONUS_NAME(DISPEL_IMMUNITY) \
BONUS_NAME(NEGATE_ALL_NATURAL_IMMUNITIES) \
BONUS_NAME(STACK_HEALTH) \
BONUS_NAME(BLOCK_MORALE) \
@ -226,7 +225,7 @@ struct DLL_EXPORT Bonus
ui8 source;//source type" uses BonusSource values - what gave that bonus
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
si32 additionalInfo;
@ -256,7 +255,7 @@ struct DLL_EXPORT Bonus
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)
@ -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
{
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
{

View File

@ -186,7 +186,7 @@ DLL_EXPORT void GiveBonus::applyGs( CGameState *gs )
if(!bdescr.message.size()
&& bonus.source == Bonus::OBJECT
&& (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"
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++)
{
if((*i)->source == source && (*i)->id == id)
if((*i)->source == source && (*i)->sid == id)
{
bonus = **i; //backup bonus (to show to interfaces later)
bonuses.erase(i);
@ -1052,7 +1052,7 @@ DLL_EXPORT void BattleSpellCast::applyGs( CGameState *gs )
//WTF?
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);
}
@ -1147,7 +1147,7 @@ DLL_EXPORT void SetStackEffect::applyGs( CGameState *gs )
CStack *s = gs->curB->getStack(id);
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
{
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++)
{
if(VLC->spellh->spells[(*it)->id]->positiveness < 0)
if(VLC->spellh->spells[(*it)->sid]->positiveness < 0)
{
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);
}
Bonus pseudoBonus;
pseudoBonus.id = spellID;
pseudoBonus.sid = spellID;
pseudoBonus.val = spellLvl;
pseudoBonus.turnsRemain = gs->curB->calculateSpellDuration(spell, caster, usedSpellPower);
CStack::stackEffectToFeature(sse.effect, pseudoBonus);
@ -3824,7 +3824,7 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
const CSpell *s = VLC->spellh->spells[ba.additionalInfo];
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)
{
tlog2 << "Spell cannot be cast!\n";
@ -4408,6 +4408,12 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
int chance = sf->additionalInfo % 1000;
//int meleeRanged = sf->additionalInfo / 1000;
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)
if( rand()%100 >= chance )
continue;