Browse Source

Partial fix for 1791

AlexVinS 10 years ago
parent
commit
253b850ac3

+ 8 - 1
config/artifacts.json

@@ -1324,10 +1324,17 @@
 		"bonuses" : [
 			{
 				"type" : "NEGATE_ALL_NATURAL_IMMUNITIES",
+				"subtype" : 0,
 				"val" : 0,
 				"valueType" : "BASE_NUMBER",
 				"propagator": "BATTLE_WIDE"
-			}
+			},
+			{
+				"type" : "NEGATE_ALL_NATURAL_IMMUNITIES",
+				"subtype" : 1,
+				"val" : 0,
+				"valueType" : "BASE_NUMBER"
+			}			
 		],
 		"index" : 93,
 		"type" : ["HERO"]

+ 7 - 1
lib/spells/BattleSpellMechanics.cpp

@@ -13,6 +13,7 @@
 
 #include "../NetPacks.h"
 #include "../BattleState.h"
+#include "../mapObjects/CGHeroInstance.h"
 
 ///HealingSpellMechanics
 void HealingSpellMechanics::applyBattleEffects(const SpellCastEnvironment* env, BattleSpellCastParameters& parameters, SpellCastContext& ctx) const
@@ -505,13 +506,18 @@ ESpellCastProblem::ESpellCastProblem SacrificeMechanics::canBeCasted(const CBatt
 
 	bool targetExists = false;
 	bool targetToSacrificeExists = false;
+	
+	const CGHeroInstance * caster = nullptr; //todo: use ISpellCaster
+	
+	if(cb->battleHasHero(cb->playerToSide(player)))
+		caster = cb->battleGetFightingHero(cb->playerToSide(player));
 
 	for(const CStack * stack : cb->battleGetAllStacks())
 	{
 		//using isImmuneBy directly as this mechanics does not have overridden immunity check
 		//therefore we do not need to check caster and casting mode
 		//TODO: check that we really should check immunity for both stacks
-		ESpellCastProblem::ESpellCastProblem res = owner->isImmuneBy(stack);
+		ESpellCastProblem::ESpellCastProblem res = owner->internalIsImmune(caster, stack);
 		const bool immune =  ESpellCastProblem::OK != res && ESpellCastProblem::NOT_DECIDED != res;
 		const bool casterStack = stack->owner == player;
 

+ 1 - 1
lib/spells/CDefaultSpellMechanics.cpp

@@ -746,7 +746,7 @@ ESpellCastProblem::ESpellCastProblem DefaultSpellMechanics::canBeCasted(const CB
 ESpellCastProblem::ESpellCastProblem DefaultSpellMechanics::isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const
 {
 	//by default use general algorithm
-	return owner->isImmuneBy(obj);
+	return owner->internalIsImmune(caster, obj);
 }
 
 void DefaultSpellMechanics::doDispell(BattleInfo * battle, const BattleSpellCast * packet, const CSelector & selector) const

+ 15 - 3
lib/spells/CSpellHandler.cpp

@@ -402,7 +402,7 @@ int CSpell::calculateRawEffectValue(int effectLevel, int effectPower) const
 	return effectPower * power + getPower(effectLevel);	
 }
 
-ESpellCastProblem::ESpellCastProblem CSpell::isImmuneBy(const IBonusBearer* obj) const
+ESpellCastProblem::ESpellCastProblem CSpell::internalIsImmune(const ISpellCaster * caster, const CStack *obj) const
 {
 	//todo: use new bonus API
 	//1. Check absolute limiters
@@ -435,9 +435,21 @@ ESpellCastProblem::ESpellCastProblem CSpell::isImmuneBy(const IBonusBearer* obj)
 		return ESpellCastProblem::OK;
 		
 	//3. Check negation
-	//FIXME: Orb of vulnerability mechanics is not such trivial
-	if(obj->hasBonusOfType(Bonus::NEGATE_ALL_NATURAL_IMMUNITIES)) //Orb of vulnerability
+	//Orb of vulnerability
+	//FIXME: Orb of vulnerability mechanics is not such trivial (issue 1791)
+	const bool battleWideNegation = obj->hasBonusOfType(Bonus::NEGATE_ALL_NATURAL_IMMUNITIES, 0);
+	const bool heroNegation = obj->hasBonusOfType(Bonus::NEGATE_ALL_NATURAL_IMMUNITIES, 1);
+	//anyone can cast on artifact holder`s stacks
+	if(heroNegation) 
 		return ESpellCastProblem::NOT_DECIDED;
+	//this stack is from other player
+	//todo: check that caster is always present (not trivial is this case)
+	//todo: NEGATE_ALL_NATURAL_IMMUNITIES special cases: dispell, chain lightning
+	else if(battleWideNegation && caster)
+	{
+		if(obj->owner != caster->getOwner())
+			return ESpellCastProblem::NOT_DECIDED;
+	}
 
 	//4. Check negatable limit
 	for(auto b : limiters)

+ 1 - 1
lib/spells/CSpellHandler.h

@@ -298,7 +298,7 @@ public://internal, for use only by Mechanics classes
 	///returns raw damage or healed HP
 	int calculateRawEffectValue(int effectLevel, int effectPower) const;		
 	///generic immunity calculation
-	ESpellCastProblem::ESpellCastProblem isImmuneBy(const IBonusBearer *obj) const;
+	ESpellCastProblem::ESpellCastProblem internalIsImmune(const ISpellCaster * caster, const CStack *obj) const;
 
 private:
 	void setIsOffensive(const bool val);