1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

Allow multiple destinations in BattleSpellCastParameters

This commit is contained in:
AlexVinS 2015-09-29 21:47:04 +03:00
parent a06e34cf61
commit 57e5b768e8
6 changed files with 86 additions and 24 deletions

View File

@ -367,7 +367,7 @@ ESpellCastProblem::ESpellCastProblem HypnotizeMechanics::isImmuneByStack(const I
///ObstacleMechanics ///ObstacleMechanics
void ObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const void ObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
{ {
auto placeObstacle = [&, this](BattleHex pos) auto placeObstacle = [&, this](const BattleHex & pos)
{ {
static int obstacleIdToGive = parameters.cb->obstacles.size() static int obstacleIdToGive = parameters.cb->obstacles.size()
? (parameters.cb->obstacles.back()->uniqueID+1) ? (parameters.cb->obstacles.back()->uniqueID+1)
@ -413,6 +413,8 @@ void ObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env, con
env->sendAndApply(&bop); env->sendAndApply(&bop);
}; };
const BattleHex destination = parameters.getFirstDestinationHex();
switch(owner->id) switch(owner->id)
{ {
case SpellID::QUICKSAND: case SpellID::QUICKSAND:
@ -437,12 +439,22 @@ void ObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env, con
break; break;
case SpellID::FORCE_FIELD: case SpellID::FORCE_FIELD:
placeObstacle(parameters.destination); if(!destination.isValid())
{
env->complain("Invalid destination for FORCE_FIELD");
return;
}
placeObstacle(destination);
break; break;
case SpellID::FIRE_WALL: case SpellID::FIRE_WALL:
{ {
if(!destination.isValid())
{
env->complain("Invalid destination for FIRE_WALL");
return;
}
//fire wall is build from multiple obstacles - one fire piece for each affected hex //fire wall is build from multiple obstacles - one fire piece for each affected hex
auto affectedHexes = owner->rangeInHexes(parameters.destination, parameters.spellLvl, parameters.casterSide); auto affectedHexes = owner->rangeInHexes(destination, parameters.spellLvl, parameters.casterSide);
for(BattleHex hex : affectedHexes) for(BattleHex hex : affectedHexes)
placeObstacle(hex); placeObstacle(hex);
} }
@ -493,7 +505,7 @@ std::vector<BattleHex> WallMechanics::rangeInHexes(BattleHex centralHex, ui8 sch
///RemoveObstacleMechanics ///RemoveObstacleMechanics
void RemoveObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const void RemoveObstacleMechanics::applyBattleEffects(const SpellCastEnvironment * env, const BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
{ {
if(auto obstacleToRemove = parameters.cb->battleGetObstacleOnPos(parameters.destination, false)) if(auto obstacleToRemove = parameters.cb->battleGetObstacleOnPos(parameters.getFirstDestinationHex(), false))
{ {
ObstaclesRemoved obr; ObstaclesRemoved obr;
obr.obstacles.insert(obstacleToRemove->uniqueID); obr.obstacles.insert(obstacleToRemove->uniqueID);
@ -659,9 +671,9 @@ void TeleportMechanics::applyBattleEffects(const SpellCastEnvironment * env, con
BattleStackMoved bsm; BattleStackMoved bsm;
bsm.distance = -1; bsm.distance = -1;
bsm.stack = parameters.selectedStack->ID; bsm.stack = parameters.selectedStack->ID;//todo: use destinations
std::vector<BattleHex> tiles; std::vector<BattleHex> tiles;
tiles.push_back(parameters.destination); tiles.push_back(parameters.getFirstDestinationHex());
bsm.tilesToMove = tiles; bsm.tilesToMove = tiles;
bsm.teleporting = true; bsm.teleporting = true;
env->sendAndApply(&bsm); env->sendAndApply(&bsm);

View File

@ -265,7 +265,7 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS
//must be vector, as in Chain Lightning order matters //must be vector, as in Chain Lightning order matters
std::vector<const CStack*> attackedCres; //CStack vector is somewhat more suitable than ID vector std::vector<const CStack*> attackedCres; //CStack vector is somewhat more suitable than ID vector
auto creatures = owner->getAffectedStacks(parameters.cb, parameters.mode, parameters.casterColor, parameters.spellLvl, parameters.destination, parameters.caster); auto creatures = owner->getAffectedStacks(parameters.cb, parameters.mode, parameters.casterColor, parameters.spellLvl, parameters.getFirstDestinationHex(), parameters.caster);
std::copy(creatures.begin(), creatures.end(), std::back_inserter(attackedCres)); std::copy(creatures.begin(), creatures.end(), std::back_inserter(attackedCres));
logGlobal->debugStream() << "will affect: " << attackedCres.size() << " stacks"; logGlobal->debugStream() << "will affect: " << attackedCres.size() << " stacks";
@ -363,7 +363,7 @@ void DefaultSpellMechanics::battleCast(const SpellCastEnvironment * env, BattleS
BattleSpellCastParameters mirrorParameters(parameters.cb, attackedCre, owner); BattleSpellCastParameters mirrorParameters(parameters.cb, attackedCre, owner);
mirrorParameters.spellLvl = 0; mirrorParameters.spellLvl = 0;
mirrorParameters.destination = targetHex; mirrorParameters.aimToHex(targetHex);
mirrorParameters.mode = ECastingMode::MAGIC_MIRROR; mirrorParameters.mode = ECastingMode::MAGIC_MIRROR;
mirrorParameters.selectedStack = nullptr; mirrorParameters.selectedStack = nullptr;
mirrorParameters.spellLvl = parameters.spellLvl; mirrorParameters.spellLvl = parameters.spellLvl;
@ -766,7 +766,8 @@ void DefaultSpellMechanics::castMagicMirror(const SpellCastEnvironment* env, Bat
env->complain("MagicMirror: invalid mode"); env->complain("MagicMirror: invalid mode");
return; return;
} }
if(!parameters.destination.isValid()) BattleHex destination = parameters.getFirstDestinationHex();
if(!destination.isValid())
{ {
env->complain("MagicMirror: invalid destination"); env->complain("MagicMirror: invalid destination");
return; return;
@ -779,7 +780,7 @@ void DefaultSpellMechanics::castMagicMirror(const SpellCastEnvironment* env, Bat
//must be vector, as in Chain Lightning order matters //must be vector, as in Chain Lightning order matters
std::vector<const CStack*> attackedCres; //CStack vector is somewhat more suitable than ID vector std::vector<const CStack*> attackedCres; //CStack vector is somewhat more suitable than ID vector
auto creatures = owner->getAffectedStacks(parameters.cb, parameters.mode, parameters.casterColor, parameters.spellLvl, parameters.destination, parameters.caster); auto creatures = owner->getAffectedStacks(parameters.cb, parameters.mode, parameters.casterColor, parameters.spellLvl, destination, parameters.caster);
std::copy(creatures.begin(), creatures.end(), std::back_inserter(attackedCres)); std::copy(creatures.begin(), creatures.end(), std::back_inserter(attackedCres));
logGlobal->debugStream() << "will affect: " << attackedCres.size() << " stacks"; logGlobal->debugStream() << "will affect: " << attackedCres.size() << " stacks";
@ -839,7 +840,7 @@ void DefaultSpellMechanics::prepareBattleCast(const BattleSpellCastParameters& p
sc.side = parameters.casterSide; sc.side = parameters.casterSide;
sc.id = owner->id; sc.id = owner->id;
sc.skill = parameters.spellLvl; sc.skill = parameters.spellLvl;
sc.tile = parameters.destination; sc.tile = parameters.getFirstDestinationHex();
sc.dmgToDisplay = 0; sc.dmgToDisplay = 0;
sc.castByHero = parameters.mode == ECastingMode::HERO_CASTING; sc.castByHero = parameters.mode == ECastingMode::HERO_CASTING;
sc.casterStack = (parameters.casterStack ? parameters.casterStack->ID : -1); sc.casterStack = (parameters.casterStack ? parameters.casterStack->ID : -1);

View File

@ -115,9 +115,13 @@ bool CSpell::adventureCast(const SpellCastEnvironment * env, AdventureSpellCastP
} }
void CSpell::battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const void CSpell::battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const
{ {
assert(env); assert(env);
if(parameters.destinations.size()<1)
{
env->complain("Spell must have at least one destination");
return;
}
mechanics->battleCast(env, parameters); mechanics->battleCast(env, parameters);
} }

View File

@ -20,9 +20,23 @@
#include "BattleSpellMechanics.h" #include "BattleSpellMechanics.h"
#include "CreatureSpellMechanics.h" #include "CreatureSpellMechanics.h"
BattleSpellCastParameters::Destination::Destination(const CStack * destination):
stackValue(destination),
hexValue(destination->position)
{
}
BattleSpellCastParameters::Destination::Destination(const BattleHex & destination):
stackValue(nullptr),
hexValue(destination)
{
}
BattleSpellCastParameters::BattleSpellCastParameters(const BattleInfo * cb, const ISpellCaster * caster, const CSpell * spell) BattleSpellCastParameters::BattleSpellCastParameters(const BattleInfo * cb, const ISpellCaster * caster, const CSpell * spell)
: cb(cb), caster(caster), casterColor(caster->getOwner()), casterSide(cb->whatSide(casterColor)), : cb(cb), caster(caster), casterColor(caster->getOwner()), casterSide(cb->whatSide(casterColor)),
destination(BattleHex::INVALID),casterHero(nullptr), casterHero(nullptr),
mode(ECastingMode::HERO_CASTING), casterStack(nullptr), selectedStack(nullptr), mode(ECastingMode::HERO_CASTING), casterStack(nullptr), selectedStack(nullptr),
spellLvl(-1), effectLevel(-1), effectPower(0), enchantPower(0), effectValue(0) spellLvl(-1), effectLevel(-1), effectPower(0), enchantPower(0), effectValue(0)
{ {
@ -31,6 +45,22 @@ BattleSpellCastParameters::BattleSpellCastParameters(const BattleInfo * cb, cons
prepare(spell); prepare(spell);
} }
void BattleSpellCastParameters::aimToHex(const BattleHex& destination)
{
destinations.push_back(Destination(destination));
}
void BattleSpellCastParameters::aimToStack(const CStack * destination)
{
destinations.push_back(Destination(destination));
}
BattleHex BattleSpellCastParameters::getFirstDestinationHex() const
{
return destinations.at(0).hexValue;
}
void BattleSpellCastParameters::prepare(const CSpell * spell) void BattleSpellCastParameters::prepare(const CSpell * spell)
{ {
spellLvl = caster->getSpellSchoolLevel(spell); spellLvl = caster->getSpellSchoolLevel(spell);

View File

@ -30,21 +30,37 @@ public:
virtual bool moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, PlayerColor asker = PlayerColor::NEUTRAL) const =0; //TODO: remove virtual bool moveHero(ObjectInstanceID hid, int3 dst, ui8 teleporting, PlayerColor asker = PlayerColor::NEUTRAL) const =0; //TODO: remove
}; };
///helper struct ///all parameters of particular cast event
struct DLL_LINKAGE BattleSpellCastParameters struct DLL_LINKAGE BattleSpellCastParameters
{ {
public: public:
///Single spell destination.
/// (assumes that anything but battle stack can share same hex)
struct DLL_LINKAGE Destination
{
explicit Destination(const CStack * destination);
explicit Destination(const BattleHex & destination);
const CStack * stackValue;
const BattleHex hexValue;
};
BattleSpellCastParameters(const BattleInfo * cb, const ISpellCaster * caster, const CSpell * spell); BattleSpellCastParameters(const BattleInfo * cb, const ISpellCaster * caster, const CSpell * spell);
void aimToHex(const BattleHex & destination);
void aimToStack(const CStack * destination);
BattleHex getFirstDestinationHex() const;
const BattleInfo * cb; const BattleInfo * cb;
const ISpellCaster * caster; const ISpellCaster * caster;
const PlayerColor casterColor; const PlayerColor casterColor;
const ui8 casterSide; const ui8 casterSide;
BattleHex destination; std::vector<Destination> destinations;
const CGHeroInstance * casterHero; //deprecated const CGHeroInstance * casterHero; //deprecated
ECastingMode::ECastingMode mode; ECastingMode::ECastingMode mode;
const CStack * casterStack; //deprecated const CStack * casterStack; //deprecated
const CStack * selectedStack; const CStack * selectedStack;//deprecated
///spell school level ///spell school level
int spellLvl; int spellLvl;

View File

@ -3878,7 +3878,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
vstd::amin (parameters.spellLvl, 3); vstd::amin (parameters.spellLvl, 3);
parameters.effectLevel = parameters.spellLvl; parameters.effectLevel = parameters.spellLvl;
parameters.mode = ECastingMode::CREATURE_ACTIVE_CASTING; parameters.mode = ECastingMode::CREATURE_ACTIVE_CASTING;
parameters.destination = destination; parameters.aimToHex(destination);//todo: allow multiple destinations
parameters.selectedStack = nullptr; parameters.selectedStack = nullptr;
spell->battleCast(spellEnv, parameters); spell->battleCast(spellEnv, parameters);
} }
@ -4069,7 +4069,7 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
const CSpell * s = SpellID(ba.additionalInfo).toSpell(); const CSpell * s = SpellID(ba.additionalInfo).toSpell();
BattleSpellCastParameters parameters(gs->curB, h, s); BattleSpellCastParameters parameters(gs->curB, h, s);
parameters.destination = ba.destinationTile; parameters.aimToHex(ba.destinationTile);//todo: allow multiple destinations
parameters.mode = ECastingMode::HERO_CASTING; parameters.mode = ECastingMode::HERO_CASTING;
parameters.selectedStack = gs->curB->battleGetStackByID(ba.selectedStack, false); parameters.selectedStack = gs->curB->battleGetStackByID(ba.selectedStack, false);
@ -4222,7 +4222,7 @@ void CGameHandler::stackTurnTrigger(const CStack * st)
BattleSpellCastParameters parameters(gs->curB, st, spell); BattleSpellCastParameters parameters(gs->curB, st, spell);
parameters.spellLvl = bonus->val; parameters.spellLvl = bonus->val;
parameters.effectLevel = bonus->val;//todo: recheck parameters.effectLevel = bonus->val;//todo: recheck
parameters.destination = BattleHex::INVALID; parameters.aimToHex(BattleHex::INVALID);
parameters.mode = ECastingMode::ENCHANTER_CASTING; parameters.mode = ECastingMode::ENCHANTER_CASTING;
parameters.selectedStack = nullptr; parameters.selectedStack = nullptr;
@ -4913,7 +4913,6 @@ void CGameHandler::attackCasting(const BattleAttack & bat, Bonus::BonusType atta
} }
int chance = attacker->valOfBonuses((Selector::typeSubtype(attackMode, spellID))); int chance = attacker->valOfBonuses((Selector::typeSubtype(attackMode, spellID)));
vstd::amin (chance, 100); vstd::amin (chance, 100);
int destination = oneOfAttacked->position;
const CSpell * spell = SpellID(spellID).toSpell(); const CSpell * spell = SpellID(spellID).toSpell();
if(gs->curB->battleCanCastThisSpellHere(attacker, spell, ECastingMode::AFTER_ATTACK_CASTING, oneOfAttacked->position) != ESpellCastProblem::OK) if(gs->curB->battleCanCastThisSpellHere(attacker, spell, ECastingMode::AFTER_ATTACK_CASTING, oneOfAttacked->position) != ESpellCastProblem::OK)
@ -4929,7 +4928,7 @@ void CGameHandler::attackCasting(const BattleAttack & bat, Bonus::BonusType atta
BattleSpellCastParameters parameters(gs->curB, attacker, spell); BattleSpellCastParameters parameters(gs->curB, attacker, spell);
parameters.spellLvl = spellLevel; parameters.spellLvl = spellLevel;
parameters.effectLevel = spellLevel; parameters.effectLevel = spellLevel;
parameters.destination = destination; parameters.aimToStack(oneOfAttacked);
parameters.mode = ECastingMode::AFTER_ATTACK_CASTING; parameters.mode = ECastingMode::AFTER_ATTACK_CASTING;
parameters.selectedStack = nullptr; parameters.selectedStack = nullptr;
@ -4958,7 +4957,7 @@ void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
BattleSpellCastParameters parameters(gs->curB, attacker, spell); BattleSpellCastParameters parameters(gs->curB, attacker, spell);
parameters.spellLvl = 0; parameters.spellLvl = 0;
parameters.effectLevel = 0; parameters.effectLevel = 0;
parameters.destination = gs->curB->battleGetStackByID(bat.bsa.at(0).stackAttacked)->position; parameters.aimToStack(gs->curB->battleGetStackByID(bat.bsa.at(0).stackAttacked));
parameters.effectPower = power; parameters.effectPower = power;
parameters.mode = ECastingMode::AFTER_ATTACK_CASTING; parameters.mode = ECastingMode::AFTER_ATTACK_CASTING;
parameters.selectedStack = nullptr; parameters.selectedStack = nullptr;
@ -5266,7 +5265,7 @@ void CGameHandler::runBattle()
BattleSpellCastParameters parameters(gs->curB, h, spell); BattleSpellCastParameters parameters(gs->curB, h, spell);
parameters.spellLvl = 3; parameters.spellLvl = 3;
parameters.effectLevel = 3; parameters.effectLevel = 3;
parameters.destination = BattleHex::INVALID; parameters.aimToHex(BattleHex::INVALID);
parameters.mode = ECastingMode::PASSIVE_CASTING; parameters.mode = ECastingMode::PASSIVE_CASTING;
parameters.selectedStack = nullptr; parameters.selectedStack = nullptr;
parameters.enchantPower = b->val; parameters.enchantPower = b->val;