mirror of
https://github.com/vcmi/vcmi.git
synced 2025-11-27 22:49:25 +02:00
Merge pull request #5851 from Laserlicht/max_range_spell
max range for spell cast
This commit is contained in:
@@ -888,7 +888,7 @@ Affected unit will not use spellcast as default attack option
|
|||||||
|
|
||||||
### SPELLCASTER
|
### SPELLCASTER
|
||||||
|
|
||||||
Affected units can cast a spell as targeted action (Archangel, Faerie Dragon). Use CASTS bonus to specify how many times per combat creature can use spellcasting. Use SPECIFIC_SPELL_POWER, CREATURE_SPELL_POWER or CREATURE_ENCHANT_POWER bonuses to set spell power.
|
Affected units can cast a spell as targeted action (Archangel, Faerie Dragon). Use CASTS bonus to specify how many times per combat creature can use spellcasting. Use SPECIFIC_SPELL_POWER, CREATURE_SPELL_POWER or CREATURE_ENCHANT_POWER bonuses to set spell power. SPECIFIC_SPELL_RANGE bonus can be used to limit range of spell.
|
||||||
|
|
||||||
- subtype: spell identifier
|
- subtype: spell identifier
|
||||||
- val: spell mastery level
|
- val: spell mastery level
|
||||||
@@ -939,6 +939,11 @@ Determines how many times per combat affected creature can cast its targeted spe
|
|||||||
- value: Used for Thunderbolt and Resurrection cast by units (multiplied by stack size). Also used for Healing secondary skill (for core:spell.firstAid used by First Aid tent)
|
- value: Used for Thunderbolt and Resurrection cast by units (multiplied by stack size). Also used for Healing secondary skill (for core:spell.firstAid used by First Aid tent)
|
||||||
- subtype - spell id
|
- subtype - spell id
|
||||||
|
|
||||||
|
### SPECIFIC_SPELL_RANGE
|
||||||
|
|
||||||
|
- value: Can be used to limit range of spells casted by creatures.
|
||||||
|
- subtype - spell id
|
||||||
|
|
||||||
### CREATURE_SPELL_POWER
|
### CREATURE_SPELL_POWER
|
||||||
|
|
||||||
- value: Spell Power of offensive spell cast unit, multiplied by 100. ie. Faerie Dragons have value fo 500, which gives them 5 Spell Power for each unit in the stack.
|
- value: Spell Power of offensive spell cast unit, multiplied by 100. ie. Faerie Dragons have value fo 500, which gives them 5 Spell Power for each unit in the stack.
|
||||||
|
|||||||
@@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "../../../lib/battle/BattleHex.h"
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
class PlayerColor;
|
class PlayerColor;
|
||||||
@@ -60,6 +62,9 @@ public:
|
|||||||
///damage/heal override(ignores spell configuration, effect level and effect power)
|
///damage/heal override(ignores spell configuration, effect level and effect power)
|
||||||
virtual int64_t getEffectValue(const Spell * spell) const = 0;
|
virtual int64_t getEffectValue(const Spell * spell) const = 0;
|
||||||
|
|
||||||
|
///maximal range of effect
|
||||||
|
virtual int64_t getEffectRange(const Spell * spell) const = 0;
|
||||||
|
|
||||||
virtual PlayerColor getCasterOwner() const = 0;
|
virtual PlayerColor getCasterOwner() const = 0;
|
||||||
|
|
||||||
///only name substitution
|
///only name substitution
|
||||||
|
|||||||
@@ -453,6 +453,11 @@ int64_t CUnitState::getEffectValue(const spells::Spell * spell) const
|
|||||||
return static_cast<int64_t>(getCount()) * valOfBonuses(BonusType::SPECIFIC_SPELL_POWER, BonusSubtypeID(spell->getId()));
|
return static_cast<int64_t>(getCount()) * valOfBonuses(BonusType::SPECIFIC_SPELL_POWER, BonusSubtypeID(spell->getId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t CUnitState::getEffectRange(const spells::Spell * spell) const
|
||||||
|
{
|
||||||
|
return valOfBonuses(BonusType::SPECIFIC_SPELL_RANGE, BonusSubtypeID(spell->getId()));
|
||||||
|
}
|
||||||
|
|
||||||
PlayerColor CUnitState::getCasterOwner() const
|
PlayerColor CUnitState::getCasterOwner() const
|
||||||
{
|
{
|
||||||
return env->unitEffectiveOwner(this);
|
return env->unitEffectiveOwner(this);
|
||||||
|
|||||||
@@ -180,6 +180,7 @@ public:
|
|||||||
int32_t getEffectPower(const spells::Spell * spell) const override;
|
int32_t getEffectPower(const spells::Spell * spell) const override;
|
||||||
int32_t getEnchantPower(const spells::Spell * spell) const override;
|
int32_t getEnchantPower(const spells::Spell * spell) const override;
|
||||||
int64_t getEffectValue(const spells::Spell * spell) const override;
|
int64_t getEffectValue(const spells::Spell * spell) const override;
|
||||||
|
int64_t getEffectRange(const spells::Spell * spell) const override;
|
||||||
|
|
||||||
PlayerColor getCasterOwner() const override;
|
PlayerColor getCasterOwner() const override;
|
||||||
const CGHeroInstance * getHeroCaster() const override;
|
const CGHeroInstance * getHeroCaster() const override;
|
||||||
|
|||||||
@@ -193,6 +193,7 @@ class JsonNode;
|
|||||||
BONUS_NAME(FULL_MAP_DARKNESS) /*opposite to Skyship*/\
|
BONUS_NAME(FULL_MAP_DARKNESS) /*opposite to Skyship*/\
|
||||||
BONUS_NAME(TRANSMUTATION_IMMUNITY) /*blocks TRANSMUTATION bonus*/\
|
BONUS_NAME(TRANSMUTATION_IMMUNITY) /*blocks TRANSMUTATION bonus*/\
|
||||||
BONUS_NAME(COMBAT_MANA_BONUS) /* Additional mana per combat */ \
|
BONUS_NAME(COMBAT_MANA_BONUS) /* Additional mana per combat */ \
|
||||||
|
BONUS_NAME(SPECIFIC_SPELL_RANGE) /* value used for allowed spell range, subtype - spell id */\
|
||||||
/* end of list */
|
/* end of list */
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -130,6 +130,7 @@ static void loadBonusSubtype(BonusSubtypeID & subtype, BonusType type, const Jso
|
|||||||
case BonusType::SPECIAL_PECULIAR_ENCHANT:
|
case BonusType::SPECIAL_PECULIAR_ENCHANT:
|
||||||
case BonusType::SPECIAL_SPELL_LEV:
|
case BonusType::SPECIAL_SPELL_LEV:
|
||||||
case BonusType::SPECIFIC_SPELL_DAMAGE:
|
case BonusType::SPECIFIC_SPELL_DAMAGE:
|
||||||
|
case BonusType::SPECIFIC_SPELL_RANGE:
|
||||||
case BonusType::SPELL:
|
case BonusType::SPELL:
|
||||||
case BonusType::OPENING_BATTLE_SPELL:
|
case BonusType::OPENING_BATTLE_SPELL:
|
||||||
case BonusType::SPELL_LIKE_ATTACK:
|
case BonusType::SPELL_LIKE_ATTACK:
|
||||||
|
|||||||
@@ -859,6 +859,11 @@ int64_t CGHeroInstance::getEffectValue(const spells::Spell * spell) const
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t CGHeroInstance::getEffectRange(const spells::Spell * spell) const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
PlayerColor CGHeroInstance::getCasterOwner() const
|
PlayerColor CGHeroInstance::getCasterOwner() const
|
||||||
{
|
{
|
||||||
return tempOwner;
|
return tempOwner;
|
||||||
|
|||||||
@@ -289,6 +289,7 @@ public:
|
|||||||
int32_t getEffectPower(const spells::Spell * spell) const override;
|
int32_t getEffectPower(const spells::Spell * spell) const override;
|
||||||
int32_t getEnchantPower(const spells::Spell * spell) const override;
|
int32_t getEnchantPower(const spells::Spell * spell) const override;
|
||||||
int64_t getEffectValue(const spells::Spell * spell) const override;
|
int64_t getEffectValue(const spells::Spell * spell) const override;
|
||||||
|
int64_t getEffectRange(const spells::Spell * spell) const override;
|
||||||
|
|
||||||
PlayerColor getCasterOwner() const override;
|
PlayerColor getCasterOwner() const override;
|
||||||
const CGHeroInstance * getHeroCaster() const override;
|
const CGHeroInstance * getHeroCaster() const override;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include "../battle/IBattleState.h"
|
#include "../battle/IBattleState.h"
|
||||||
#include "../battle/CBattleInfoCallback.h"
|
#include "../battle/CBattleInfoCallback.h"
|
||||||
|
#include "../battle/Unit.h"
|
||||||
#include "../networkPacks/PacksForClientBattle.h"
|
#include "../networkPacks/PacksForClientBattle.h"
|
||||||
#include "../networkPacks/SetStackEffect.h"
|
#include "../networkPacks/SetStackEffect.h"
|
||||||
#include "../CStack.h"
|
#include "../CStack.h"
|
||||||
@@ -208,6 +209,46 @@ bool BattleSpellMechanics::canBeCast(Problem & problem) const
|
|||||||
return effects->applicable(problem, this);
|
return effects->applicable(problem, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BattleSpellMechanics::canCastAtTarget(const battle::Unit * target) const
|
||||||
|
{
|
||||||
|
if(mode == Mode::HERO)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if(!target)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
auto spell = getSpell();
|
||||||
|
int range = caster->getEffectRange(spell);
|
||||||
|
|
||||||
|
if(range <= 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
auto casterStack = battle()->battleGetStackByID(caster->getCasterUnitId(), false);
|
||||||
|
std::vector<BattleHex> casterPos = { casterStack->getPosition() };
|
||||||
|
BattleHex casterWidePos = casterStack->occupiedHex();
|
||||||
|
if(casterWidePos != BattleHex::INVALID)
|
||||||
|
casterPos.push_back(casterWidePos);
|
||||||
|
|
||||||
|
std::vector<BattleHex> destPos = { target->getPosition() };
|
||||||
|
BattleHex destWidePos = target->occupiedHex();
|
||||||
|
if(destWidePos != BattleHex::INVALID)
|
||||||
|
destPos.push_back(destWidePos);
|
||||||
|
|
||||||
|
int minDistance = std::numeric_limits<int>::max();
|
||||||
|
for(auto & caster : casterPos)
|
||||||
|
for(auto & dest : destPos)
|
||||||
|
{
|
||||||
|
int distance = BattleHex::getDistance(caster, dest);
|
||||||
|
if(distance < minDistance)
|
||||||
|
minDistance = distance;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(minDistance > range)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool BattleSpellMechanics::canBeCastAt(const Target & target, Problem & problem) const
|
bool BattleSpellMechanics::canBeCastAt(const Target & target, Problem & problem) const
|
||||||
{
|
{
|
||||||
if(!canBeCast(problem))
|
if(!canBeCast(problem))
|
||||||
@@ -226,6 +267,9 @@ bool BattleSpellMechanics::canBeCastAt(const Target & target, Problem & problem)
|
|||||||
mainTarget = battle()->battleGetUnitByPos(target.front().hexValue, true);
|
mainTarget = battle()->battleGetUnitByPos(target.front().hexValue, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(!canCastAtTarget(mainTarget))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!getSpell()->canCastOnSelf() && !getSpell()->canCastOnlyOnSelf())
|
if (!getSpell()->canCastOnSelf() && !getSpell()->canCastOnlyOnSelf())
|
||||||
{
|
{
|
||||||
if(mainTarget && mainTarget == caster)
|
if(mainTarget && mainTarget == caster)
|
||||||
|
|||||||
@@ -83,6 +83,8 @@ private:
|
|||||||
BattleHexArray spellRangeInHexes(const BattleHex & centralHex) const;
|
BattleHexArray spellRangeInHexes(const BattleHex & centralHex) const;
|
||||||
|
|
||||||
Target transformSpellTarget(const Target & aimPoint) const;
|
Target transformSpellTarget(const Target & aimPoint) const;
|
||||||
|
|
||||||
|
bool canCastAtTarget(const battle::Unit * target) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,6 +58,14 @@ int64_t ObstacleCasterProxy::getEffectValue(const Spell * spell) const
|
|||||||
return obs.minimalDamage;
|
return obs.minimalDamage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t ObstacleCasterProxy::getEffectRange(const Spell * spell) const
|
||||||
|
{
|
||||||
|
if(actualCaster)
|
||||||
|
actualCaster->getEffectRange(spell);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int32_t SilentCaster::manaLimit() const
|
int32_t SilentCaster::manaLimit() const
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ public:
|
|||||||
int32_t getEffectPower(const Spell * spell) const override;
|
int32_t getEffectPower(const Spell * spell) const override;
|
||||||
int32_t getEnchantPower(const Spell * spell) const override;
|
int32_t getEnchantPower(const Spell * spell) const override;
|
||||||
int64_t getEffectValue(const Spell * spell) const override;
|
int64_t getEffectValue(const Spell * spell) const override;
|
||||||
|
int64_t getEffectRange(const Spell * spell) const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const SpellCreatedObstacle & obs;
|
const SpellCreatedObstacle & obs;
|
||||||
|
|||||||
@@ -92,6 +92,14 @@ int64_t ProxyCaster::getEffectValue(const Spell * spell) const
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t ProxyCaster::getEffectRange(const Spell * spell) const
|
||||||
|
{
|
||||||
|
if(actualCaster)
|
||||||
|
return actualCaster->getEffectRange(spell);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
PlayerColor ProxyCaster::getCasterOwner() const
|
PlayerColor ProxyCaster::getCasterOwner() const
|
||||||
{
|
{
|
||||||
if(actualCaster)
|
if(actualCaster)
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ public:
|
|||||||
int32_t getEffectPower(const Spell * spell) const override;
|
int32_t getEffectPower(const Spell * spell) const override;
|
||||||
int32_t getEnchantPower(const Spell * spell) const override;
|
int32_t getEnchantPower(const Spell * spell) const override;
|
||||||
int64_t getEffectValue(const Spell * spell) const override;
|
int64_t getEffectValue(const Spell * spell) const override;
|
||||||
|
int64_t getEffectRange(const Spell * spell) const override;
|
||||||
PlayerColor getCasterOwner() const override;
|
PlayerColor getCasterOwner() const override;
|
||||||
void getCasterName(MetaString & text) const override;
|
void getCasterName(MetaString & text) const override;
|
||||||
void getCastDescription(const Spell * spell, const battle::Units & attacked, MetaString & text) const override;
|
void getCastDescription(const Spell * spell, const battle::Units & attacked, MetaString & text) const override;
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ public:
|
|||||||
MOCK_CONST_METHOD1(getEffectPower, int32_t(const spells::Spell *));
|
MOCK_CONST_METHOD1(getEffectPower, int32_t(const spells::Spell *));
|
||||||
MOCK_CONST_METHOD1(getEnchantPower, int32_t(const spells::Spell *));
|
MOCK_CONST_METHOD1(getEnchantPower, int32_t(const spells::Spell *));
|
||||||
MOCK_CONST_METHOD1(getEffectValue, int64_t(const spells::Spell *));
|
MOCK_CONST_METHOD1(getEffectValue, int64_t(const spells::Spell *));
|
||||||
|
MOCK_CONST_METHOD1(getEffectRange, int64_t(const spells::Spell *));
|
||||||
MOCK_CONST_METHOD0(getCasterOwner, PlayerColor());
|
MOCK_CONST_METHOD0(getCasterOwner, PlayerColor());
|
||||||
MOCK_CONST_METHOD1(getCasterName, void(MetaString &));
|
MOCK_CONST_METHOD1(getCasterName, void(MetaString &));
|
||||||
MOCK_CONST_METHOD3(getCastDescription, void(const spells::Spell *, const battle::Units &, MetaString &));
|
MOCK_CONST_METHOD3(getCastDescription, void(const spells::Spell *, const battle::Units &, MetaString &));
|
||||||
|
|||||||
Reference in New Issue
Block a user