Bläddra i källkod

* fixed bugs 470 and 523
* minor improvements

mateuszb 14 år sedan
förälder
incheckning
519a4186de

+ 2 - 2
CCallback.cpp

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

+ 1 - 1
client/CBattleInterface.cpp

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

+ 1 - 1
client/CCastleInterface.cpp

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

+ 1 - 1
global.h

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

+ 99 - 55
lib/BattleState.cpp

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

+ 5 - 2
lib/BattleState.h

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

+ 3 - 3
lib/CCreatureHandler.cpp

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

+ 7 - 7
lib/CObjectHandler.cpp

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

+ 8 - 8
lib/HeroBonus.cpp

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

+ 3 - 4
lib/HeroBonus.h

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

+ 5 - 5
lib/NetPacksLib.cpp

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

+ 8 - 2
server/CGameHandler.cpp

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