mirror of
https://github.com/vcmi/vcmi.git
synced 2024-11-28 08:48:48 +02:00
Merge pull request #94 from vcmi/feature/spell.earthQuake
Okay, let's get this all together for 0.98.
This commit is contained in:
commit
6001a89632
@ -1188,19 +1188,32 @@ void CBattleInterface::hexLclicked(int whichOne)
|
||||
|
||||
void CBattleInterface::stackIsCatapulting(const CatapultAttack & ca)
|
||||
{
|
||||
for(auto it = ca.attackedParts.begin(); it != ca.attackedParts.end(); ++it)
|
||||
if(ca.attacker != -1)
|
||||
{
|
||||
const CStack * stack = curInt->cb->battleGetStackByID(ca.attacker);
|
||||
addNewAnim(new CShootingAnimation(this, stack, it->destinationTile, nullptr, true, it->damageDealt));
|
||||
for(auto attackInfo : ca.attackedParts)
|
||||
{
|
||||
addNewAnim(new CShootingAnimation(this, stack, attackInfo.destinationTile, nullptr, true, attackInfo.damageDealt));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//no attacker stack, assume spell-related (earthquake) - only hit animation
|
||||
for(auto attackInfo : ca.attackedParts)
|
||||
{
|
||||
Point destPos = CClickableHex::getXYUnitAnim(attackInfo.destinationTile, nullptr, this) + Point(99, 120);
|
||||
|
||||
addNewAnim(new CSpellEffectAnimation(this, "SGEXPL.DEF", destPos.x, destPos.y));
|
||||
}
|
||||
}
|
||||
|
||||
waitForAnims();
|
||||
|
||||
for(auto it = ca.attackedParts.begin(); it != ca.attackedParts.end(); ++it)
|
||||
for(auto attackInfo : ca.attackedParts)
|
||||
{
|
||||
SDL_FreeSurface(siegeH->walls[it->attackedPart + 2]);
|
||||
siegeH->walls[it->attackedPart + 2] = BitmapHandler::loadBitmap(
|
||||
siegeH->getSiegeName(it->attackedPart + 2, curInt->cb->battleGetWallState(it->attackedPart)) );
|
||||
SDL_FreeSurface(siegeH->walls[attackInfo.attackedPart + 2]);
|
||||
siegeH->walls[attackInfo.attackedPart + 2] = BitmapHandler::loadBitmap(
|
||||
siegeH->getSiegeName(attackInfo.attackedPart + 2, curInt->cb->battleGetWallState(attackInfo.attackedPart)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -86,6 +86,7 @@
|
||||
},
|
||||
"levels" : {
|
||||
"base":{
|
||||
"targetModifier":{"smart":true},
|
||||
"range" : "X"
|
||||
}
|
||||
},
|
||||
|
@ -1599,6 +1599,11 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell
|
||||
if(!spell->combatSpell)
|
||||
return ESpellCastProblem::ADVMAP_SPELL_INSTEAD_OF_BATTLE_SPELL;
|
||||
|
||||
const ESpellCastProblem::ESpellCastProblem specificProblem = spell->canBeCasted(this, player);
|
||||
|
||||
if(specificProblem != ESpellCastProblem::OK)
|
||||
return specificProblem;
|
||||
|
||||
if(spell->isNegative() || spell->hasEffects())
|
||||
{
|
||||
bool allStacksImmune = true;
|
||||
@ -1633,7 +1638,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell
|
||||
if(arpos < ARRAY_COUNT(spellIDs))
|
||||
{
|
||||
//check if there are summoned elementals of other type
|
||||
for( const CStack * st : battleAliveStacks())
|
||||
for(const CStack * st : battleAliveStacks(side))
|
||||
if(vstd::contains(st->state, EBattleStackState::SUMMONED) && st->getCreature()->idNumber != creIDs[arpos])
|
||||
return ESpellCastProblem::ANOTHER_ELEMENTAL_SUMMONED;
|
||||
}
|
||||
|
@ -1555,7 +1555,6 @@ struct ObstaclesRemoved : public CPackForClient //3014
|
||||
};
|
||||
|
||||
struct ELF_VISIBILITY CatapultAttack : public CPackForClient //3015
|
||||
|
||||
{
|
||||
struct AttackInfo
|
||||
{
|
||||
|
@ -152,6 +152,115 @@ void DispellMechanics::applyBattle(BattleInfo * battle, const BattleSpellCast *
|
||||
}
|
||||
}
|
||||
|
||||
///EarthquakeMechanics
|
||||
void EarthquakeMechanics::applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const
|
||||
{
|
||||
if(nullptr == parameters.cb->town)
|
||||
{
|
||||
env->complain("EarthquakeMechanics: not town siege");
|
||||
return;
|
||||
}
|
||||
|
||||
if(CGTownInstance::NONE == parameters.cb->town->fortLevel())
|
||||
{
|
||||
env->complain("EarthquakeMechanics: town has no fort");
|
||||
return;
|
||||
}
|
||||
|
||||
//start with all destructible parts
|
||||
std::set<EWallPart::EWallPart> possibleTargets =
|
||||
{
|
||||
EWallPart::KEEP,
|
||||
EWallPart::BOTTOM_TOWER,
|
||||
EWallPart::BOTTOM_WALL,
|
||||
EWallPart::BELOW_GATE,
|
||||
EWallPart::OVER_GATE,
|
||||
EWallPart::UPPER_WALL,
|
||||
EWallPart::UPPER_TOWER,
|
||||
EWallPart::GATE
|
||||
};
|
||||
|
||||
assert(possibleTargets.size() == EWallPart::PARTS_COUNT);
|
||||
|
||||
const int targetsToAttack = 2 + std::max<int>(parameters.spellLvl - 1, 0);
|
||||
|
||||
CatapultAttack ca;
|
||||
ca.attacker = -1;
|
||||
|
||||
for(int i = 0; i < targetsToAttack; i++)
|
||||
{
|
||||
//Any destructible part can be hit regardless of its HP. Multiple hit on same target is allowed.
|
||||
EWallPart::EWallPart target = *RandomGeneratorUtil::nextItem(possibleTargets, env->getRandomGenerator());
|
||||
|
||||
auto & currentHP = parameters.cb->si.wallState;
|
||||
|
||||
if(currentHP.at(target) == EWallState::DESTROYED || currentHP.at(target) == EWallState::NONE)
|
||||
continue;
|
||||
|
||||
CatapultAttack::AttackInfo attackInfo;
|
||||
|
||||
attackInfo.damageDealt = 1;
|
||||
attackInfo.attackedPart = target;
|
||||
attackInfo.destinationTile = parameters.cb->wallPartToBattleHex(target);
|
||||
|
||||
ca.attackedParts.push_back(attackInfo);
|
||||
|
||||
//removing creatures in turrets / keep if one is destroyed
|
||||
BattleHex posRemove;
|
||||
|
||||
switch(target)
|
||||
{
|
||||
case EWallPart::KEEP:
|
||||
posRemove = -2;
|
||||
break;
|
||||
case EWallPart::BOTTOM_TOWER:
|
||||
posRemove = -3;
|
||||
break;
|
||||
case EWallPart::UPPER_TOWER:
|
||||
posRemove = -4;
|
||||
break;
|
||||
}
|
||||
|
||||
if(posRemove != BattleHex::INVALID)
|
||||
{
|
||||
BattleStacksRemoved bsr;
|
||||
for(auto & elem : parameters.cb->stacks)
|
||||
{
|
||||
if(elem->position == posRemove)
|
||||
{
|
||||
bsr.stackIDs.insert(elem->ID);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(bsr.stackIDs.size() > 0)
|
||||
env->sendAndApply(&bsr);
|
||||
}
|
||||
};
|
||||
|
||||
env->sendAndApply(&ca);
|
||||
}
|
||||
|
||||
ESpellCastProblem::ESpellCastProblem EarthquakeMechanics::canBeCasted(const CBattleInfoCallback * cb, PlayerColor player) const
|
||||
{
|
||||
if(nullptr == cb->battleGetDefendedTown())
|
||||
{
|
||||
return ESpellCastProblem::NO_APPROPRIATE_TARGET;
|
||||
}
|
||||
|
||||
if(CGTownInstance::NONE == cb->battleGetDefendedTown()->fortLevel())
|
||||
{
|
||||
return ESpellCastProblem::NO_APPROPRIATE_TARGET;
|
||||
}
|
||||
|
||||
if(owner->getTargetInfo(0).smart) //TODO: use real spell level
|
||||
{
|
||||
//if spell targeting is smart, then only attacker can use it
|
||||
if(cb->playerToSide(player) != 0)
|
||||
return ESpellCastProblem::NO_APPROPRIATE_TARGET;
|
||||
}
|
||||
|
||||
return ESpellCastProblem::OK;
|
||||
}
|
||||
|
||||
///HypnotizeMechanics
|
||||
ESpellCastProblem::ESpellCastProblem HypnotizeMechanics::isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const
|
||||
|
@ -44,6 +44,15 @@ public:
|
||||
void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override final;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE EarthquakeMechanics : public DefaultSpellMechanics
|
||||
{
|
||||
public:
|
||||
EarthquakeMechanics(CSpell * s): DefaultSpellMechanics(s){};
|
||||
ESpellCastProblem::ESpellCastProblem canBeCasted(const CBattleInfoCallback * cb, PlayerColor player) const override;
|
||||
protected:
|
||||
void applyBattleEffects(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters, SpellCastContext & ctx) const override;
|
||||
};
|
||||
|
||||
class DLL_LINKAGE HypnotizeMechanics : public DefaultSpellMechanics
|
||||
{
|
||||
public:
|
||||
|
@ -712,6 +712,13 @@ std::set<const CStack *> DefaultSpellMechanics::getAffectedStacks(SpellTargeting
|
||||
return attackedCres;
|
||||
}
|
||||
|
||||
ESpellCastProblem::ESpellCastProblem DefaultSpellMechanics::canBeCasted(const CBattleInfoCallback * cb, PlayerColor player) const
|
||||
{
|
||||
//no problems by default, this method is for spell-specific problems
|
||||
return ESpellCastProblem::OK;
|
||||
}
|
||||
|
||||
|
||||
ESpellCastProblem::ESpellCastProblem DefaultSpellMechanics::isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const
|
||||
{
|
||||
//by default use general algorithm
|
||||
|
@ -33,6 +33,8 @@ public:
|
||||
std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool * outDroppedHexes = nullptr) const override;
|
||||
std::set<const CStack *> getAffectedStacks(SpellTargetingContext & ctx) const override;
|
||||
|
||||
ESpellCastProblem::ESpellCastProblem canBeCasted(const CBattleInfoCallback * cb, PlayerColor player) const override;
|
||||
|
||||
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const override;
|
||||
|
||||
virtual void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const override;
|
||||
|
@ -234,6 +234,11 @@ ui32 CSpell::calculateDamage(const CGHeroInstance * caster, const CStack * affec
|
||||
return ret;
|
||||
}
|
||||
|
||||
ESpellCastProblem::ESpellCastProblem CSpell::canBeCasted(const CBattleInfoCallback * cb, PlayerColor player) const
|
||||
{
|
||||
return mechanics->canBeCasted(cb, player);
|
||||
}
|
||||
|
||||
std::vector<BattleHex> CSpell::rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes) const
|
||||
{
|
||||
return mechanics->rangeInHexes(centralHex,schoolLvl,side,outDroppedHexes);
|
||||
|
@ -246,9 +246,6 @@ public:
|
||||
//internal, for use only by Mechanics classes
|
||||
ESpellCastProblem::ESpellCastProblem isImmuneBy(const IBonusBearer *obj) const;
|
||||
|
||||
//checks for creature immunity / anything that prevent casting *at given target* - doesn't take into account general problems such as not having spellbook or mana points etc.
|
||||
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const;
|
||||
|
||||
//internal, for use only by Mechanics classes. applying secondary skills
|
||||
ui32 calculateBonus(ui32 baseDamage, const CGHeroInstance * caster, const CStack * affectedCreature) const;
|
||||
|
||||
@ -301,6 +298,14 @@ public:
|
||||
}
|
||||
friend class CSpellHandler;
|
||||
friend class Graphics;
|
||||
public:
|
||||
///internal interface (for callbacks)
|
||||
|
||||
///Checks general but spell-specific problems for all casting modes. Use only during battle.
|
||||
ESpellCastProblem::ESpellCastProblem canBeCasted(const CBattleInfoCallback * cb, PlayerColor player) const;
|
||||
|
||||
///checks for creature immunity / anything that prevent casting *at given target* - doesn't take into account general problems such as not having spellbook or mana points etc.
|
||||
ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const;
|
||||
public:
|
||||
///Server logic. Has write access to GameState via packets.
|
||||
///May be executed on client side by (future) non-cheat-proof scripts.
|
||||
|
@ -42,6 +42,8 @@ ISpellMechanics * ISpellMechanics::createMechanics(CSpell * s)
|
||||
return new DispellMechanics(s);
|
||||
case SpellID::DISPEL_HELPFUL_SPELLS:
|
||||
return new DispellHelpfulMechanics(s);
|
||||
case SpellID::EARTHQUAKE:
|
||||
return new EarthquakeMechanics(s);
|
||||
case SpellID::FIRE_WALL:
|
||||
case SpellID::FORCE_FIELD:
|
||||
return new WallMechanics(s);
|
||||
|
@ -38,9 +38,11 @@ public:
|
||||
|
||||
virtual std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool * outDroppedHexes = nullptr) const = 0;
|
||||
virtual std::set<const CStack *> getAffectedStacks(SpellTargetingContext & ctx) const = 0;
|
||||
|
||||
|
||||
virtual ESpellCastProblem::ESpellCastProblem canBeCasted(const CBattleInfoCallback * cb, PlayerColor player) const = 0;
|
||||
|
||||
virtual ESpellCastProblem::ESpellCastProblem isImmuneByStack(const CGHeroInstance * caster, const CStack * obj) const = 0;
|
||||
|
||||
|
||||
virtual void applyBattle(BattleInfo * battle, const BattleSpellCast * packet) const = 0;
|
||||
virtual bool adventureCast(const SpellCastEnvironment * env, AdventureSpellCastParameters & parameters) const = 0;
|
||||
virtual void battleCast(const SpellCastEnvironment * env, BattleSpellCastParameters & parameters) const = 0;
|
||||
|
Loading…
Reference in New Issue
Block a user