1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-11-23 22:37:55 +02:00
Files
vcmi/lib/spells/adventure/DimensionDoorEffect.cpp
Ivan Savenko 1f9a1dbf37 Fix artifacts providing hero with banned spells
Tomes of X Spells and Spellbinder's Hat (and any other sources for such
bonuses from mods) will no longer provide spells that are banned on map.

Option is only active for random maps and for HotA h3m's. RoE-SoD .h3m's
work as before.

If needed, behavior can be changed in config
2025-07-26 19:44:00 +03:00

142 lines
4.3 KiB
C++

/*
* DimensionDoorEffect.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "DimensionDoorEffect.h"
#include "../CSpellHandler.h"
#include "../../IGameSettings.h"
#include "../../callback/IGameInfoCallback.h"
#include "../../mapObjects/CGHeroInstance.h"
#include "../../mapping/TerrainTile.h"
#include "../../networkPacks/PacksForClient.h"
VCMI_LIB_NAMESPACE_BEGIN
DimensionDoorEffect::DimensionDoorEffect(const CSpell * s, const JsonNode & config)
: AdventureSpellRangedEffect(config)
, cursor(config["cursor"].String())
, cursorGuarded(config["cursorGuarded"].String())
, movementPointsRequired(config["movementPointsRequired"].Integer())
, movementPointsTaken(config["movementPointsTaken"].Integer())
, waterLandFailureTakesPoints(config["waterLandFailureTakesPoints"].Bool())
, exposeFow(config["exposeFow"].Bool())
{
}
std::string DimensionDoorEffect::getCursorForTarget(const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const
{
if(!cb->getSettings().getBoolean(EGameSettings::SPELLS_DIMENSION_DOOR_TRIGGERS_GUARDS))
return cursor;
if (!exposeFow && !cb->isVisibleFor(pos, caster->getCasterOwner()))
return cursor;
if (!cb->isTileGuardedUnchecked(pos))
return cursor;
return cursorGuarded;
}
bool DimensionDoorEffect::canBeCastImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster) const
{
if(!caster->getHeroCaster())
return false;
if(caster->getHeroCaster()->movementPointsRemaining() <= movementPointsRequired)
{
problem.add(MetaString::createFromTextID("core.genrltxt.125"));
return false;
}
return true;
}
bool DimensionDoorEffect::canBeCastAtImpl(spells::Problem & problem, const IGameInfoCallback * cb, const spells::Caster * caster, const int3 & pos) const
{
if (!isTargetInRange(cb, caster, pos))
return false;
int3 casterPosition = caster->getHeroCaster()->getSightCenter();
const TerrainTile * dest = cb->getTileUnchecked(pos);
const TerrainTile * curr = cb->getTileUnchecked(casterPosition);
if(!dest)
return false;
if(!curr)
return false;
if(exposeFow)
{
if(!dest->isClear(curr))
return false;
}
else
{
if(dest->blocked())
return false;
}
return true;
}
ESpellCastResult DimensionDoorEffect::applyAdventureEffects(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
{
int3 casterPosition = parameters.caster->getHeroCaster()->getSightCenter();
const TerrainTile * dest = env->getCb()->getTile(parameters.pos);
const TerrainTile * curr = env->getCb()->getTile(casterPosition);
if(!dest->isClear(curr))
{
InfoWindow iw;
iw.player = parameters.caster->getCasterOwner();
// tile is either blocked or not possible to move (e.g. water <-> land)
if(waterLandFailureTakesPoints)
{
// SOD: DD to such "wrong" terrain results in mana and move points spending, but fails to move hero
iw.text = MetaString::createFromTextID("core.genrltxt.70"); // Dimension Door failed!
env->apply(iw);
// no return - resources will be spent
}
else
{
// HotA: game will show error message without taking mana or move points, even when DD into terra incognita
iw.text = MetaString::createFromTextID("vcmi.dimensionDoor.seaToLandError");
env->apply(iw);
return ESpellCastResult::CANCEL;
}
}
SetMovePoints smp;
smp.hid = ObjectInstanceID(parameters.caster->getCasterUnitId());
if(movementPointsTaken < static_cast<int>(parameters.caster->getHeroCaster()->movementPointsRemaining()))
smp.val = parameters.caster->getHeroCaster()->movementPointsRemaining() - movementPointsTaken;
else
smp.val = 0;
env->apply(smp);
return ESpellCastResult::OK;
}
void DimensionDoorEffect::endCast(SpellCastEnvironment * env, const AdventureSpellCastParameters & parameters) const
{
int3 casterPosition = parameters.caster->getHeroCaster()->getSightCenter();
const TerrainTile * dest = env->getCb()->getTile(parameters.pos);
const TerrainTile * curr = env->getCb()->getTile(casterPosition);
if(dest->isClear(curr))
env->moveHero(ObjectInstanceID(parameters.caster->getCasterUnitId()), parameters.caster->getHeroCaster()->convertFromVisitablePos(parameters.pos), EMovementMode::DIMENSION_DOOR);
}
VCMI_LIB_NAMESPACE_END