Przeglądaj źródła

Merge pull request #3116 from IvanSavenko/bonus_fixes

Bonuses fixes
Ivan Savenko 2 lat temu
rodzic
commit
207968ced3

+ 14 - 1
docs/modders/Bonus/Bonus_Types.md

@@ -60,8 +60,14 @@ Allows flying movement for affected heroes
 
 
 Eliminates terrain penalty on certain terrain types for affected heroes (Nomads ability).
 Eliminates terrain penalty on certain terrain types for affected heroes (Nomads ability).
 
 
+Note: to eliminate all terrain penalties see ROUGH_TERRAIN_DISCOUNT bonus
+
 - subtype: type of terrain
 - subtype: type of terrain
 
 
+### TERRAIN_NATIVE
+
+Affected units will view any terrain as native
+
 ### PRIMARY_SKILL
 ### PRIMARY_SKILL
 
 
 Changes selected primary skill for affected heroes and units
 Changes selected primary skill for affected heroes and units
@@ -252,6 +258,7 @@ Allows creature upgrade for affected armies
 Changes duration of timed spells casted by affected hero
 Changes duration of timed spells casted by affected hero
 
 
 - val: additional duration, turns
 - val: additional duration, turns
+- subtype: optional, identifier of affected spells, or all if not set
 
 
 ### SPELL
 ### SPELL
 
 
@@ -791,7 +798,7 @@ Affected unit is permanently enchanted with a spell, that is cast again every tu
 
 
 Affected unit is immune to all spell with level below or equal to value of this bonus
 Affected unit is immune to all spell with level below or equal to value of this bonus
 
 
-- val: level to which this unit is immune to
+- val: level up to which this unit is immune to
 
 
 TODO: additional info?
 TODO: additional info?
 
 
@@ -893,6 +900,12 @@ Affected unit will never retaliate to an attack (Blind, Paralyze)
 
 
 # Others
 # Others
 
 
+### NEGATIVE_EFFECTS_IMMUNITY
+
+Affected unit is immune to all negative spells of specified spell school
+
+- subtype: affected spell school
+
 ### BLOCK_MAGIC_ABOVE
 ### BLOCK_MAGIC_ABOVE
 
 
 Blocks casting spells of the level above specified one in battles affected by this bonus
 Blocks casting spells of the level above specified one in battles affected by this bonus

+ 3 - 4
lib/BasicTypes.cpp

@@ -33,14 +33,13 @@ bool INativeTerrainProvider::isNativeTerrain(TerrainId terrain) const
 
 
 TerrainId AFactionMember::getNativeTerrain() const
 TerrainId AFactionMember::getNativeTerrain() const
 {
 {
-	constexpr auto any = TerrainId(ETerrainId::ANY_TERRAIN);
-	const std::string cachingStringNoTerrainPenalty = "type_NO_TERRAIN_PENALTY_sANY";
-	static const auto selectorNoTerrainPenalty = Selector::typeSubtype(BonusType::NO_TERRAIN_PENALTY, BonusSubtypeID(any));
+	const std::string cachingStringNoTerrainPenalty = "type_TERRAIN_NATIVE_NONE";
+	static const auto selectorNoTerrainPenalty = Selector::typeSubtype(BonusType::TERRAIN_NATIVE, BonusSubtypeID());
 
 
 	//this code is used in the CreatureTerrainLimiter::limit to setup battle bonuses
 	//this code is used in the CreatureTerrainLimiter::limit to setup battle bonuses
 	//and in the CGHeroInstance::getNativeTerrain() to setup movement bonuses or/and penalties.
 	//and in the CGHeroInstance::getNativeTerrain() to setup movement bonuses or/and penalties.
 	return getBonusBearer()->hasBonus(selectorNoTerrainPenalty, cachingStringNoTerrainPenalty)
 	return getBonusBearer()->hasBonus(selectorNoTerrainPenalty, cachingStringNoTerrainPenalty)
-		? any : VLC->factions()->getById(getFaction())->getNativeTerrain();
+		? TerrainId::ANY_TERRAIN : VLC->factions()->getById(getFaction())->getNativeTerrain();
 }
 }
 
 
 int32_t AFactionMember::magicResistance() const
 int32_t AFactionMember::magicResistance() const

+ 2 - 0
lib/JsonNode.cpp

@@ -446,6 +446,7 @@ static void loadBonusSubtype(BonusSubtypeID & subtype, BonusType type, const Jso
 		case BonusType::SPELLS_OF_SCHOOL:
 		case BonusType::SPELLS_OF_SCHOOL:
 		case BonusType::SPELL_DAMAGE_REDUCTION:
 		case BonusType::SPELL_DAMAGE_REDUCTION:
 		case BonusType::SPELL_SCHOOL_IMMUNITY:
 		case BonusType::SPELL_SCHOOL_IMMUNITY:
+		case BonusType::NEGATIVE_EFFECTS_IMMUNITY:
 		{
 		{
 			VLC->identifiers()->requestIdentifier( "spellSchool", node, [&subtype](int32_t identifier)
 			VLC->identifiers()->requestIdentifier( "spellSchool", node, [&subtype](int32_t identifier)
 			{
 			{
@@ -485,6 +486,7 @@ static void loadBonusSubtype(BonusSubtypeID & subtype, BonusType type, const Jso
 			break;
 			break;
 		}
 		}
 		case BonusType::SPELL_IMMUNITY:
 		case BonusType::SPELL_IMMUNITY:
+		case BonusType::SPELL_DURATION:
 		case BonusType::SPECIAL_ADD_VALUE_ENCHANT:
 		case BonusType::SPECIAL_ADD_VALUE_ENCHANT:
 		case BonusType::SPECIAL_FIXED_VALUE_ENCHANT:
 		case BonusType::SPECIAL_FIXED_VALUE_ENCHANT:
 		case BonusType::SPECIAL_PECULIAR_ENCHANT:
 		case BonusType::SPECIAL_PECULIAR_ENCHANT:

+ 1 - 0
lib/bonuses/BonusEnum.h

@@ -169,6 +169,7 @@ class JsonNode;
 	BONUS_NAME(MAX_LEARNABLE_SPELL_LEVEL) /*This can work as wisdom before. val = max learnable spell level*/\
 	BONUS_NAME(MAX_LEARNABLE_SPELL_LEVEL) /*This can work as wisdom before. val = max learnable spell level*/\
 	BONUS_NAME(SPELL_SCHOOL_IMMUNITY) /*This bonus will work as spell school immunity for all spells, subtype - spell school: 0 - air, 1 - fire, 2 - water, 3 - earth. Any is not handled for reducing overlap from LEVEL_SPELL_IMMUNITY*/\
 	BONUS_NAME(SPELL_SCHOOL_IMMUNITY) /*This bonus will work as spell school immunity for all spells, subtype - spell school: 0 - air, 1 - fire, 2 - water, 3 - earth. Any is not handled for reducing overlap from LEVEL_SPELL_IMMUNITY*/\
 	BONUS_NAME(NEGATIVE_EFFECTS_IMMUNITY) /*This bonus will work as spell school immunity for negative effects from spells of school, subtype - spell school: -1 - any, 0 - air, 1 - fire, 2 - water, 3 - earth*/\
 	BONUS_NAME(NEGATIVE_EFFECTS_IMMUNITY) /*This bonus will work as spell school immunity for negative effects from spells of school, subtype - spell school: -1 - any, 0 - air, 1 - fire, 2 - water, 3 - earth*/\
+	BONUS_NAME(TERRAIN_NATIVE)
 	/* end of list */
 	/* end of list */
 
 
 
 

+ 5 - 1
lib/mapObjects/CGHeroInstance.cpp

@@ -700,7 +700,11 @@ int32_t CGHeroInstance::getEffectPower(const spells::Spell * spell) const
 
 
 int32_t CGHeroInstance::getEnchantPower(const spells::Spell * spell) const
 int32_t CGHeroInstance::getEnchantPower(const spells::Spell * spell) const
 {
 {
-	return getPrimSkillLevel(PrimarySkill::SPELL_POWER) + valOfBonuses(BonusType::SPELL_DURATION);
+	int32_t spellpower = getPrimSkillLevel(PrimarySkill::SPELL_POWER);
+	int32_t durationCommon = valOfBonuses(BonusType::SPELL_DURATION, BonusSubtypeID());
+	int32_t durationSpecific = valOfBonuses(BonusType::SPELL_DURATION, BonusSubtypeID(spell->getId()));
+
+	return spellpower + durationCommon + durationSpecific;
 }
 }
 
 
 int64_t CGHeroInstance::getEffectValue(const spells::Spell * spell) const
 int64_t CGHeroInstance::getEffectValue(const spells::Spell * spell) const

+ 2 - 2
lib/pathfinder/TurnInfo.cpp

@@ -22,8 +22,8 @@ TurnInfo::BonusCache::BonusCache(const TConstBonusListPtr & bl)
 {
 {
 	for(const auto & terrain : VLC->terrainTypeHandler->objects)
 	for(const auto & terrain : VLC->terrainTypeHandler->objects)
 	{
 	{
-		noTerrainPenalty.push_back(static_cast<bool>(
-				bl->getFirst(Selector::type()(BonusType::NO_TERRAIN_PENALTY).And(Selector::subtype()(BonusSubtypeID(terrain->getId()))))));
+		auto selector = Selector::typeSubtype(BonusType::NO_TERRAIN_PENALTY, BonusSubtypeID(terrain->getId()));
+		noTerrainPenalty.push_back(static_cast<bool>(bl->getFirst(selector)));
 	}
 	}
 
 
 	freeShipBoarding = static_cast<bool>(bl->getFirst(Selector::type()(BonusType::FREE_SHIP_BOARDING)));
 	freeShipBoarding = static_cast<bool>(bl->getFirst(Selector::type()(BonusType::FREE_SHIP_BOARDING)));