1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-03-17 20:58:07 +02:00

vcmi: remove obstacle caster logic

It is possible now to cast something via obstacle
Immune creatures should not trigger an obstacle trigger now
and should not reveal it.
This commit is contained in:
Konstantin 2023-03-19 03:44:10 +03:00
parent db428faeeb
commit cd1730b1fb
5 changed files with 167 additions and 112 deletions

View File

@ -133,6 +133,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE)
${MAIN_LIB_DIR}/spells/BonusCaster.cpp
${MAIN_LIB_DIR}/spells/CSpellHandler.cpp
${MAIN_LIB_DIR}/spells/ISpellMechanics.cpp
${MAIN_LIB_DIR}/spells/ObstacleCasterProxy.cpp
${MAIN_LIB_DIR}/spells/Problem.cpp
${MAIN_LIB_DIR}/spells/ProxyCaster.cpp
${MAIN_LIB_DIR}/spells/TargetCondition.cpp

View File

@ -0,0 +1,98 @@
/*
* ObstacleCasterProxy.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 "ObstacleCasterProxy.h"
VCMI_LIB_NAMESPACE_BEGIN
namespace spells
{
ObstacleCasterProxy::ObstacleCasterProxy(PlayerColor owner_, const Caster * hero_, const SpellCreatedObstacle * obs_):
ProxyCaster(hero_),
owner(std::move(owner_)),
obs(*obs_)
{
}
int32_t ObstacleCasterProxy::getCasterUnitId() const
{
if(actualCaster)
return actualCaster->getCasterUnitId();
else
return -1;
}
int32_t ObstacleCasterProxy::getSpellSchoolLevel(const Spell * spell, int32_t * outSelectedSchool) const
{
return obs.spellLevel;
}
int32_t ObstacleCasterProxy::getEffectLevel(const Spell * spell) const
{
return obs.spellLevel;
}
int64_t ObstacleCasterProxy::getSpellBonus(const Spell * spell, int64_t base, const battle::Unit * affectedStack) const
{
if(actualCaster)
return std::max<int64_t>(actualCaster->getSpellBonus(spell, base, affectedStack), obs.minimalDamage);
else
return std::max<int64_t>(base, obs.minimalDamage);
}
int64_t ObstacleCasterProxy::getSpecificSpellBonus(const Spell * spell, int64_t base) const
{
if(actualCaster)
return actualCaster->getSpecificSpellBonus(spell, base);
else
return base;
}
int32_t ObstacleCasterProxy::getEffectPower(const Spell * spell) const
{
return obs.casterSpellPower;
}
int32_t ObstacleCasterProxy::getEnchantPower(const Spell * spell) const
{
return obs.casterSpellPower;
}
int64_t ObstacleCasterProxy::getEffectValue(const Spell * spell) const
{
if(actualCaster)
return std::max(static_cast<int64_t>(obs.minimalDamage), actualCaster->getEffectValue(spell));
else
return obs.minimalDamage;
}
PlayerColor ObstacleCasterProxy::getCasterOwner() const
{
return owner;
}
void ObstacleCasterProxy::getCasterName(MetaString & text) const
{
logGlobal->error("Unexpected call to ObstacleCasterProxy::getCasterName");
}
void ObstacleCasterProxy::getCastDescription(const Spell * spell, const std::vector<const battle::Unit *> & attacked, MetaString & text) const
{
//do nothing
}
void ObstacleCasterProxy::spendMana(ServerCallback * server, const int spellCost) const
{
//do nothing
}
}
VCMI_LIB_NAMESPACE_END

View File

@ -0,0 +1,44 @@
/*
* ObstacleCasterProxy.h, 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 "ProxyCaster.h"
#include "../lib/NetPacksBase.h"
#include "../battle/BattleHex.h"
#include "../battle/CObstacleInstance.h"
VCMI_LIB_NAMESPACE_BEGIN
namespace spells
{
class DLL_LINKAGE ObstacleCasterProxy : public ProxyCaster
{
public:
ObstacleCasterProxy(PlayerColor owner_, const Caster * hero_, const SpellCreatedObstacle * obs_);
int32_t getCasterUnitId() const override;
int32_t getSpellSchoolLevel(const Spell * spell, int32_t * outSelectedSchool = nullptr) const override;
int32_t getEffectLevel(const Spell * spell) const override;
int64_t getSpellBonus(const Spell * spell, int64_t base, const battle::Unit * affectedStack) const override;
int64_t getSpecificSpellBonus(const Spell * spell, int64_t base) const override;
int32_t getEffectPower(const Spell * spell) const override;
int32_t getEnchantPower(const Spell * spell) const override;
int64_t getEffectValue(const Spell * spell) const override;
PlayerColor getCasterOwner() const override;
void getCasterName(MetaString & text) const override;
void getCastDescription(const Spell * spell, const std::vector<const battle::Unit *> & attacked, MetaString & text) const override;
void spendMana(ServerCallback * server, const int spellCost) const override;
private:
const PlayerColor owner;
const SpellCreatedObstacle & obs;
};
}//
VCMI_LIB_NAMESPACE_END

View File

@ -121,7 +121,7 @@ void Obstacle::adjustAffectedHexes(std::set<BattleHex> & hexes, const Mechanics
bool Obstacle::applicable(Problem & problem, const Mechanics * m) const
{
if(hidden && m->battle()->battleHasNativeStack(m->battle()->otherSide(m->casterSide)))
if(hidden && !hideNative && m->battle()->battleHasNativeStack(m->battle()->otherSide(m->casterSide)))
return m->adaptProblem(ESpellCastProblem::NO_APPROPRIATE_TARGET, problem);
return LocationEffect::applicable(problem, m);

View File

@ -22,6 +22,7 @@
#include "../lib/spells/BonusCaster.h"
#include "../lib/spells/CSpellHandler.h"
#include "../lib/spells/ISpellMechanics.h"
#include "../lib/spells/ObstacleCasterProxy.h"
#include "../lib/spells/Problem.h"
#include "../lib/CGeneralTextHandler.h"
#include "../lib/CTownHandler.h"
@ -93,102 +94,6 @@ private:
CGameHandler * gh;
};
VCMI_LIB_NAMESPACE_BEGIN
namespace spells
{
class ObstacleCasterProxy : public Caster
{
public:
ObstacleCasterProxy(const PlayerColor owner_, const CGHeroInstance * hero_, const SpellCreatedObstacle * obs_)
: owner(owner_),
hero(hero_),
obs(obs_)
{
};
~ObstacleCasterProxy() = default;
int32_t getCasterUnitId() const override
{
if(hero)
return hero->getCasterUnitId();
else
return -1;
}
int32_t getSpellSchoolLevel(const Spell * spell, int32_t * outSelectedSchool = nullptr) const override
{
return obs->spellLevel;
}
int32_t getEffectLevel(const Spell * spell) const override
{
return obs->spellLevel;
}
int64_t getSpellBonus(const Spell * spell, int64_t base, const battle::Unit * affectedStack) const override
{
if(hero)
return hero->getSpellBonus(spell, base, affectedStack);
else
return base;
}
int64_t getSpecificSpellBonus(const Spell * spell, int64_t base) const override
{
if(hero)
return hero->getSpecificSpellBonus(spell, base);
else
return base;
}
int32_t getEffectPower(const Spell * spell) const override
{
return obs->casterSpellPower;
}
int32_t getEnchantPower(const Spell * spell) const override
{
return obs->casterSpellPower;
}
int64_t getEffectValue(const Spell * spell) const override
{
if(hero)
return hero->getEffectValue(spell);
else
return 0;
}
PlayerColor getCasterOwner() const override
{
return owner;
}
void getCasterName(MetaString & text) const override
{
logGlobal->error("Unexpected call to ObstacleCasterProxy::getCasterName");
}
void getCastDescription(const Spell * spell, const std::vector<const battle::Unit *> & attacked, MetaString & text) const override
{
logGlobal->error("Unexpected call to ObstacleCasterProxy::getCastDescription");
}
void spendMana(ServerCallback * server, const int spellCost) const override
{
logGlobal->error("Unexpected call to ObstacleCasterProxy::spendMana");
}
private:
const CGHeroInstance * hero;
const PlayerColor owner;
const SpellCreatedObstacle * obs;
};
}//
VCMI_LIB_NAMESPACE_END
CondSh<bool> battleMadeAction(false);
CondSh<BattleResult *> battleResult(nullptr);
@ -5333,27 +5238,18 @@ bool CGameHandler::handleDamageFromObstacle(const CStack * curStack, bool stackI
if(spellObstacle->triggersEffects())
{
const bool oneTimeObstacle = spellObstacle->removeOnTrigger;
//hidden obstacle triggers effects until revealed
if(!(spellObstacle->hidden && gs->curB->battleIsObstacleVisibleForSide(*obstacle, (BattlePerspective::BattlePerspective)side)))
auto revealObstacles = [&](const SpellCreatedObstacle & spellObstacle) -> void
{
const CGHeroInstance * hero = gs->curB->battleGetFightingHero(spellObstacle->casterSide);
spells::ObstacleCasterProxy caster(gs->curB->sides.at(spellObstacle->casterSide).color, hero, spellObstacle);
const CSpell * sp = SpellID(spellObstacle->ID).toSpell();
if(!sp)
COMPLAIN_RET("Invalid obstacle instance");
// For the hidden spell created obstacles, e.g. QuickSand, it should be revealed after taking damage
ObstacleChanges changeInfo;
changeInfo.id = spellObstacle->uniqueID;
changeInfo.id = spellObstacle.uniqueID;
if (oneTimeObstacle)
changeInfo.operation = ObstacleChanges::EOperation::REMOVE;
else
changeInfo.operation = ObstacleChanges::EOperation::UPDATE;
SpellCreatedObstacle changedObstacle;
changedObstacle.uniqueID = spellObstacle->uniqueID;
changedObstacle.uniqueID = changeInfo.id;
changedObstacle.revealed = true;
changeInfo.data.clear();
@ -5363,10 +5259,26 @@ bool CGameHandler::handleDamageFromObstacle(const CStack * curStack, bool stackI
BattleObstaclesChanged bocp;
bocp.changes.emplace_back(changeInfo);
sendAndApply(&bocp);
spells::BattleCast battleCast(gs->curB, &caster, spells::Mode::HERO, sp);
battleCast.applyEffects(spellEnv, spells::Target(1, spells::Destination(curStack)), true);
};
auto shouldReveal = !spellObstacle->hidden || !gs->curB->battleIsObstacleVisibleForSide(*obstacle, (BattlePerspective::BattlePerspective)side);
const auto * hero = gs->curB->battleGetFightingHero(spellObstacle->casterSide);
auto caster = spells::ObstacleCasterProxy(gs->curB->sides.at(spellObstacle->casterSide).color, hero, spellObstacle);
const auto * sp = SpellID(spellObstacle->ID).toSpell();
if(sp)
{
auto cast = spells::BattleCast(gs->curB, &caster, spells::Mode::PASSIVE, sp);
spells::detail::ProblemImpl ignored;
auto target = spells::Target(1, spells::Destination(curStack));
if(sp->battleMechanics(&cast)->canBeCastAt(target, ignored)) // Obstacles should not be revealed by immune creatures
{
if(shouldReveal) { //hidden obstacle triggers effects after revealed
revealObstacles(*spellObstacle);
cast.cast(spellEnv, target);
}
}
}
else if(shouldReveal)
revealObstacles(*spellObstacle);
}
}
else if(obstacle->obstacleType == CObstacleInstance::MOAT)