1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-09-16 09:26:28 +02:00

Merge pull request #5952 from IvanSavenko/spell_ban_fix

Fix artifacts providing hero with banned spells
This commit is contained in:
Ivan Savenko
2025-07-28 18:53:50 +03:00
committed by GitHub
10 changed files with 48 additions and 28 deletions

View File

@@ -154,6 +154,11 @@
"restorationOfErathia" : {
"supported" : true,
"iconIndex" : 0,
"settings": {
"spells": {
"tomesGrantBannedSpells" : true
}
},
"buildingsCommon": {
"townHall" : 0,
"cityHall" : 1,
@@ -476,7 +481,12 @@
"iconIndex" : 3
},
"hornOfTheAbyss" : {
"supported" : false
"supported" : false,
"settings": {
"spells": {
"tomesGrantBannedSpells" : false
}
}
},
"inTheWakeOfGods" : {
"supported" : false
@@ -750,16 +760,12 @@
"spells":
{
// if enabled, dimension work doesn't work into tiles under Fog of War
"dimensionDoorOnlyToUncoveredTiles" : false,
// if enabled, dimension door will hint regarding tile being incompatible terrain type, unlike H3 (water/land)
"dimensionDoorExposesTerrainType" : false,
// if enabled, attempt to use dimension door on incompatible terrain (water/land) will result in spending of mana, movement and casts per day (H3 behavior)
"dimensionDoorFailureSpendsPoints" : true,
// if enabled, dimension door will initiate a fight upon landing on tile adjacent to neutral creature
"dimensionDoorTriggersGuards" : false,
// if enabled, dimension door can be used 1x per day, exception being 2x per day for XL+U or bigger maps (41472 tiles) + hero having expert air magic
"dimensionDoorTournamentRulesLimit" : false
// if enabled, SPELLS_OF_SCHOOL bonus (Tomes of Water/Air/Earth/Fire Magic)
// and SPELLS_OF_LEVEL bonus (Spellbinder Hat) will grant spells that are banned on map (SoD behavior)
// NOTE: this value only affects random maps and .vmap's. For h3m's value is loaded from map format configuration
"tomesGrantBannedSpells" : false
},
"bonuses" :

View File

@@ -167,11 +167,8 @@
"type" : "object",
"additionalProperties" : false,
"properties" : {
"dimensionDoorOnlyToUncoveredTiles" : { "type" : "boolean" },
"dimensionDoorExposesTerrainType" : { "type" : "boolean" },
"dimensionDoorFailureSpendsPoints" : { "type" : "boolean" },
"dimensionDoorTriggersGuards" : { "type" : "boolean" },
"dimensionDoorTournamentRulesLimit" : { "type" : "boolean" }
"tomesGrantBannedSpells" : { "type" : "boolean" }
}
},
"bonuses": {

View File

@@ -68,7 +68,6 @@ const std::vector<GameSettings::SettingOption> GameSettings::settingProperties =
{EGameSettings::CREATURES_JOINING_PERCENTAGE, "creatures", "joiningPercentage" },
{EGameSettings::CREATURES_WEEKLY_GROWTH_CAP, "creatures", "weeklyGrowthCap" },
{EGameSettings::CREATURES_WEEKLY_GROWTH_PERCENT, "creatures", "weeklyGrowthPercent" },
{EGameSettings::DIMENSION_DOOR_TRIGGERS_GUARDS, "spells", "dimensionDoorTriggersGuards" },
{EGameSettings::DWELLINGS_ACCUMULATE_WHEN_NEUTRAL, "dwellings", "accumulateWhenNeutral" },
{EGameSettings::DWELLINGS_ACCUMULATE_WHEN_OWNED, "dwellings", "accumulateWhenOwned" },
{EGameSettings::DWELLINGS_MERGE_ON_RECRUIT, "dwellings", "mergeOnRecruit" },
@@ -106,6 +105,8 @@ const std::vector<GameSettings::SettingOption> GameSettings::settingProperties =
{EGameSettings::PATHFINDER_USE_MONOLITH_TWO_WAY, "pathfinder", "useMonolithTwoWay" },
{EGameSettings::PATHFINDER_USE_WHIRLPOOL, "pathfinder", "useWhirlpool" },
{EGameSettings::RESOURCES_WEEKLY_BONUSES_AI, "resources", "weeklyBonusesAI" },
{EGameSettings::SPELLS_DIMENSION_DOOR_TRIGGERS_GUARDS, "spells", "dimensionDoorTriggersGuards" },
{EGameSettings::SPELLS_TOMES_GRANT_BANNED_SPELLS, "spells", "tomesGrantBannedSpells" },
{EGameSettings::TEXTS_ARTIFACT, "textData", "artifact" },
{EGameSettings::TEXTS_CREATURE, "textData", "creature" },
{EGameSettings::TEXTS_FACTION, "textData", "faction" },

View File

@@ -41,7 +41,6 @@ enum class EGameSettings
CREATURES_JOINING_PERCENTAGE,
CREATURES_WEEKLY_GROWTH_CAP,
CREATURES_WEEKLY_GROWTH_PERCENT,
DIMENSION_DOOR_TRIGGERS_GUARDS,
DWELLINGS_ACCUMULATE_WHEN_NEUTRAL,
DWELLINGS_ACCUMULATE_WHEN_OWNED,
DWELLINGS_MERGE_ON_RECRUIT,
@@ -80,6 +79,8 @@ enum class EGameSettings
PATHFINDER_USE_MONOLITH_TWO_WAY,
PATHFINDER_USE_WHIRLPOOL,
RESOURCES_WEEKLY_BONUSES_AI,
SPELLS_DIMENSION_DOOR_TRIGGERS_GUARDS,
SPELLS_TOMES_GRANT_BANNED_SPELLS,
TEXTS_ARTIFACT,
TEXTS_CREATURE,
TEXTS_FACTION,

View File

@@ -1250,15 +1250,20 @@ std::vector<BonusSourceID> CGHeroInstance::getSourcesForSpell(const SpellID & sp
for(const auto & bonus : *getBonusesOfType(BonusType::SPELL, spellId))
sources.emplace_back(bonus->sid);
const auto spell = spellId.toSpell();
spell->forEachSchool([this, &sources](const SpellSchool & cnf, bool & stop)
{
for(const auto & bonus : *getBonusesOfType(BonusType::SPELLS_OF_SCHOOL, cnf))
sources.emplace_back(bonus->sid);
});
bool tomesGrantBannedSpells = cb->getSettings().getBoolean(EGameSettings::SPELLS_TOMES_GRANT_BANNED_SPELLS);
for(const auto & bonus : *getBonusesOfType(BonusType::SPELLS_OF_LEVEL, BonusCustomSubtype::spellLevel(spell->getLevel())))
sources.emplace_back(bonus->sid);
if (tomesGrantBannedSpells || cb->isAllowed(spellId))
{
const auto spell = spellId.toSpell();
spell->forEachSchool([this, &sources](const SpellSchool & cnf, bool & stop)
{
for(const auto & bonus : *getBonusesOfType(BonusType::SPELLS_OF_SCHOOL, cnf))
sources.emplace_back(bonus->sid);
});
for(const auto & bonus : *getBonusesOfType(BonusType::SPELLS_OF_LEVEL, BonusCustomSubtype::spellLevel(spell->getLevel())))
sources.emplace_back(bonus->sid);
}
return sources;
}

View File

@@ -743,6 +743,9 @@ void CMapLoaderH3M::readMapOptions()
logGlobal->warn("Map '%s': option to ban hero recruitment for %s is not implemented!!", mapName, PlayerColor(i).toString());
}
}
const MapIdentifiersH3M & identifierMapper = LIBRARY->mapFormat->getMapping(mapHeader->version);
map->overrideGameSettings(identifierMapper.getFormatSettings());
}
void CMapLoaderH3M::readAllowedArtifacts()

View File

@@ -15,6 +15,7 @@
#include "../entities/faction/CFaction.h"
#include "../entities/faction/CTownHandler.h"
#include "../filesystem/Filesystem.h"
#include "../json/JsonUtils.h"
#include "../mapObjectConstructors/AObjectTypeHandler.h"
#include "../mapObjectConstructors/CObjectClassesHandler.h"
#include "../mapObjects/ObjectTemplate.h"
@@ -39,6 +40,10 @@ void MapIdentifiersH3M::loadMapping(const JsonNode & mapping)
if (!mapping["supported"].Bool())
throw std::runtime_error("Unsupported map format!");
formatSettings.Struct(); // change type
if (!mapping["settings"].isNull())
JsonUtils::inherit(formatSettings, mapping["settings"]);
for (auto entryFaction : mapping["buildings"].Struct())
{
FactionID factionID (*LIBRARY->identifiers()->getIdentifier(entryFaction.second.getModScope(), "faction", entryFaction.first));

View File

@@ -12,10 +12,10 @@
#include "../GameConstants.h"
#include "../filesystem/ResourcePath.h"
#include "../json/JsonNode.h"
VCMI_LIB_NAMESPACE_BEGIN
class JsonNode;
class ObjectTemplate;
struct ObjectTypeIdentifier
@@ -50,6 +50,8 @@ class DLL_LINKAGE MapIdentifiersH3M
std::map<AnimationPath, AnimationPath> mappingObjectTemplate;
std::map<ObjectTypeIdentifier, ObjectTypeIdentifier> mappingObjectIndex;
JsonNode formatSettings;
template<typename IdentifierID>
void loadMapping(std::map<IdentifierID, IdentifierID> & result, const JsonNode & mapping, const std::string & identifierName);
public:
@@ -70,6 +72,8 @@ public:
SecondarySkill remap(SecondarySkill input) const;
CampaignRegionID remap(CampaignRegionID input) const;
const JsonNode & getFormatSettings() const { return formatSettings; }
};
VCMI_LIB_NAMESPACE_END

View File

@@ -34,7 +34,7 @@ DimensionDoorEffect::DimensionDoorEffect(const CSpell * s, const JsonNode & conf
std::string DimensionDoorEffect::getCursorForTarget(const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const
{
if(!cb->getSettings().getBoolean(EGameSettings::DIMENSION_DOOR_TRIGGERS_GUARDS))
if(!cb->getSettings().getBoolean(EGameSettings::SPELLS_DIMENSION_DOOR_TRIGGERS_GUARDS))
return cursor;
if (!exposeFow && !cb->isVisibleFor(pos, caster->getCasterOwner()))

View File

@@ -1021,7 +1021,7 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, EMovementMode moveme
if (blockingVisit()) // e.g. hero on the other side of teleporter
return true;
EGuardLook guardsCheck = (gameInfo().getSettings().getBoolean(EGameSettings::DIMENSION_DOOR_TRIGGERS_GUARDS) && movementMode == EMovementMode::DIMENSION_DOOR)
EGuardLook guardsCheck = (gameInfo().getSettings().getBoolean(EGameSettings::SPELLS_DIMENSION_DOOR_TRIGGERS_GUARDS) && movementMode == EMovementMode::DIMENSION_DOOR)
? CHECK_FOR_GUARDS
: IGNORE_GUARDS;
@@ -1034,10 +1034,8 @@ bool CGameHandler::moveHero(ObjectInstanceID hid, int3 dst, EMovementMode moveme
if (const auto * town = dynamic_cast<const CGTownInstance *>(objectToVisit))
objectVisited(town, h);
}
return true;
}
//still here? it is standard movement!
{