mirror of
https://github.com/vcmi/vcmi.git
synced 2025-07-17 01:32:21 +02:00
* support for SPELL_AFTER_ATTACK, including most of spell 77 support
This commit is contained in:
@ -132,7 +132,7 @@ int CCallback::estimateSpellDamage(const CSpell * sp) const
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
const CGHeroInstance * ourHero = gs->curB->heroes[0]->tempOwner == player ? gs->curB->heroes[0] : gs->curB->heroes[1];
|
const CGHeroInstance * ourHero = gs->curB->heroes[0]->tempOwner == player ? gs->curB->heroes[0] : gs->curB->heroes[1];
|
||||||
return gs->curB->calculateSpellDmg(sp, ourHero, NULL);
|
return gs->curB->calculateSpellDmg(sp, ourHero, NULL, ourHero->getSpellSchoolLevel(sp));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CCallback::getThievesGuildInfo(SThievesGuildInfo & thi, const CGObjectInstance * obj)
|
void CCallback::getThievesGuildInfo(SThievesGuildInfo & thi, const CGObjectInstance * obj)
|
||||||
|
@ -2563,7 +2563,8 @@ void CBattleInterface::spellCast(SpellCast * sc)
|
|||||||
{
|
{
|
||||||
CSpell &spell = CGI->spellh->spells[sc->id];
|
CSpell &spell = CGI->spellh->spells[sc->id];
|
||||||
|
|
||||||
if(sc->side == !curInt->cb->battleGetStackByID(activeStack)->attackerOwned)
|
|
||||||
|
if(sc->castedByHero && sc->side == !curInt->cb->battleGetStackByID(activeStack)->attackerOwned)
|
||||||
bSpell->block(true);
|
bSpell->block(true);
|
||||||
|
|
||||||
std::vector< std::string > anims; //for magic arrow and ice bolt
|
std::vector< std::string > anims; //for magic arrow and ice bolt
|
||||||
@ -2621,6 +2622,7 @@ void CBattleInterface::spellCast(SpellCast * sc)
|
|||||||
break; //for 15 and 16 cases
|
break; //for 15 and 16 cases
|
||||||
}
|
}
|
||||||
case 17: //lightning bolt
|
case 17: //lightning bolt
|
||||||
|
case 77: //thunderbolt
|
||||||
displayEffect(1, sc->tile);
|
displayEffect(1, sc->tile);
|
||||||
displayEffect(spell.mainEffectAnim, sc->tile);
|
displayEffect(spell.mainEffectAnim, sc->tile);
|
||||||
break;
|
break;
|
||||||
|
@ -2272,6 +2272,34 @@ void CBonusSelection::show( SDL_Surface * to )
|
|||||||
CIntObject::show(to);
|
CIntObject::show(to);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CBonusSelection::updateBonusSelection()
|
||||||
|
{
|
||||||
|
//graphics:
|
||||||
|
//spell - SPELLBON.DEF
|
||||||
|
//monster - TWCRPORT.DEF
|
||||||
|
//building - ?
|
||||||
|
//artifact - ARTIFBON.DEF
|
||||||
|
//spell scroll - SPELLBON.DEF
|
||||||
|
//prim skill - PSKILBON.DEF
|
||||||
|
//sec skill - SSKILBON.DEF
|
||||||
|
//resource - BORES.DEF
|
||||||
|
//player - ?
|
||||||
|
//hero -?
|
||||||
|
|
||||||
|
bonuses = new CHighlightableButtonsGroup(0);
|
||||||
|
{
|
||||||
|
static const char *bonDefs[] = {"SPELLBON.DEF", "TWCRPORT.DEF", "GSPBUT5.DEF", "ARTIFBON.DEF", "SPELLBON.DEF",
|
||||||
|
"PSKILBON.DEF", "SSKILBON.DEF", "BORES.DEF", "GSPBUT5.DEF", "GSPBUT5.DEF"};
|
||||||
|
|
||||||
|
for(int i = 0; i < 5; i++)
|
||||||
|
{
|
||||||
|
bonuses->addButton(new CHighlightableButton("", "", 0, 110 + i*32, 450, bonDefs[i], i));
|
||||||
|
bonuses->buttons.back()->pos += Point(68, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
CBonusSelection::CRegion::CRegion( CBonusSelection * _owner, bool _accessible, bool _selectable, int _myNumber )
|
CBonusSelection::CRegion::CRegion( CBonusSelection * _owner, bool _accessible, bool _selectable, int _myNumber )
|
||||||
: owner(_owner), accessible(_accessible), selectable(_selectable), myNumber(_myNumber)
|
: owner(_owner), accessible(_accessible), selectable(_selectable), myNumber(_myNumber)
|
||||||
{
|
{
|
||||||
|
@ -301,6 +301,12 @@ class CBonusSelection : public CIntObject
|
|||||||
CMapHeader *ourHeader;
|
CMapHeader *ourHeader;
|
||||||
CDefHandler *sizes; //icons of map sizes
|
CDefHandler *sizes; //icons of map sizes
|
||||||
int whichMap;
|
int whichMap;
|
||||||
|
|
||||||
|
//bonus selection
|
||||||
|
void updateBonusSelection();
|
||||||
|
void selectBonus(int id);
|
||||||
|
CHighlightableButtonsGroup * bonuses;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
StartInfo sInfo;
|
StartInfo sInfo;
|
||||||
void selectMap(int whichOne);
|
void selectMap(int whichOne);
|
||||||
|
@ -95,8 +95,8 @@
|
|||||||
+ 72 RETURN_AFTER_STRIKE 0 0 0 //Harpies return after attack
|
+ 72 RETURN_AFTER_STRIKE 0 0 0 //Harpies return after attack
|
||||||
+ 73 BLOCKS_RETALIATION 0 0 0 //Harpy Hags
|
+ 73 BLOCKS_RETALIATION 0 0 0 //Harpy Hags
|
||||||
+ 73 RETURN_AFTER_STRIKE 0 0 0 //Harpy Hags return after attack
|
+ 73 RETURN_AFTER_STRIKE 0 0 0 //Harpy Hags return after attack
|
||||||
+ 76 SPELL_AFTER_ATTACK 0 70 220 //medusas
|
+ 76 SPELL_AFTER_ATTACK 0 70 2020 //medusas
|
||||||
+ 77 SPELL_AFTER_ATTACK 0 70 220 //medusa queens
|
+ 77 SPELL_AFTER_ATTACK 0 70 2020 //medusa queens
|
||||||
+ 78 SELF_MORALE 0 0 0 //minotaurs
|
+ 78 SELF_MORALE 0 0 0 //minotaurs
|
||||||
+ 79 SELF_MORALE 0 0 0 //minotaur kings
|
+ 79 SELF_MORALE 0 0 0 //minotaur kings
|
||||||
+ 81 SPELL_AFTER_ATTACK 0 74 20 //scorpicore
|
+ 81 SPELL_AFTER_ATTACK 0 74 20 //scorpicore
|
||||||
|
@ -70,4 +70,5 @@
|
|||||||
67 0 -1 X X X X
|
67 0 -1 X X X X
|
||||||
68 0 -1 X X X X
|
68 0 -1 X X X X
|
||||||
69 0 -1 X X X X
|
69 0 -1 X X X X
|
||||||
|
77 -1 38 0 0 0 0
|
||||||
-1
|
-1
|
@ -2668,9 +2668,9 @@ si8 CGameState::battleMaxSpellLevel()
|
|||||||
return levelLimit;
|
return levelLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::set<CStack*> BattleInfo::getAttackedCreatures(const CSpell * s, const CGHeroInstance * caster, int destinationTile)
|
std::set<CStack*> BattleInfo::getAttackedCreatures( const CSpell * s, int skillLevel, ui8 attackerOwner, int destinationTile )
|
||||||
{
|
{
|
||||||
std::set<ui16> attackedHexes = s->rangeInHexes(destinationTile, caster->getSpellSchoolLevel(s));
|
std::set<ui16> attackedHexes = s->rangeInHexes(destinationTile, skillLevel);
|
||||||
std::set<CStack*> attackedCres; /*std::set to exclude multiple occurrences of two hex creatures*/
|
std::set<CStack*> attackedCres; /*std::set to exclude multiple occurrences of two hex creatures*/
|
||||||
|
|
||||||
bool onlyAlive = s->id != 38 && s->id != 39; //when casting resurrection or animate dead we should be allow to select dead stack
|
bool onlyAlive = s->id != 38 && s->id != 39; //when casting resurrection or animate dead we should be allow to select dead stack
|
||||||
@ -2692,7 +2692,7 @@ std::set<CStack*> BattleInfo::getAttackedCreatures(const CSpell * s, const CGHer
|
|||||||
else if(VLC->spellh->spells[s->id].attributes.find("CREATURE_TARGET_1") != std::string::npos
|
else if(VLC->spellh->spells[s->id].attributes.find("CREATURE_TARGET_1") != std::string::npos
|
||||||
|| VLC->spellh->spells[s->id].attributes.find("CREATURE_TARGET_2") != std::string::npos) //spell to be cast on a specific creature but massive on expert
|
|| VLC->spellh->spells[s->id].attributes.find("CREATURE_TARGET_2") != std::string::npos) //spell to be cast on a specific creature but massive on expert
|
||||||
{
|
{
|
||||||
if(caster->getSpellSchoolLevel(s) < 3) /*not expert */
|
if(skillLevel < 3) /*not expert */
|
||||||
{
|
{
|
||||||
CStack * st = getStackT(destinationTile, onlyAlive);
|
CStack * st = getStackT(destinationTile, onlyAlive);
|
||||||
if(st)
|
if(st)
|
||||||
@ -2703,8 +2703,8 @@ std::set<CStack*> BattleInfo::getAttackedCreatures(const CSpell * s, const CGHer
|
|||||||
for(int it=0; it<stacks.size(); ++it)
|
for(int it=0; it<stacks.size(); ++it)
|
||||||
{
|
{
|
||||||
/*if it's non negative spell and our unit or non positive spell and hostile unit */
|
/*if it's non negative spell and our unit or non positive spell and hostile unit */
|
||||||
if((VLC->spellh->spells[s->id].positiveness >= 0 && stacks[it]->owner == caster->tempOwner)
|
if((VLC->spellh->spells[s->id].positiveness >= 0 && stacks[it]->owner == attackerOwner)
|
||||||
||(VLC->spellh->spells[s->id].positiveness <= 0 && stacks[it]->owner != caster->tempOwner )
|
||(VLC->spellh->spells[s->id].positiveness <= 0 && stacks[it]->owner != attackerOwner )
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
if(!onlyAlive || stacks[it]->alive())
|
if(!onlyAlive || stacks[it]->alive())
|
||||||
@ -2794,17 +2794,23 @@ ui32 BattleInfo::getSpellCost(const CSpell * sp, const CGHeroInstance * caster)
|
|||||||
{
|
{
|
||||||
ui32 ret = VLC->spellh->spells[sp->id].costs[caster->getSpellSchoolLevel(sp)];
|
ui32 ret = VLC->spellh->spells[sp->id].costs[caster->getSpellSchoolLevel(sp)];
|
||||||
|
|
||||||
//checking for friendly stacks reducing cost of the spell
|
//checking for friendly stacks reducing cost of the spell and
|
||||||
|
//enemy stacks increasing it
|
||||||
si32 manaReduction = 0;
|
si32 manaReduction = 0;
|
||||||
|
si32 manaIncrease = 0;
|
||||||
for(int g=0; g<stacks.size(); ++g)
|
for(int g=0; g<stacks.size(); ++g)
|
||||||
{
|
{
|
||||||
if( stacks[g]->owner == caster->tempOwner && stacks[g]->hasFeatureOfType(StackFeature::CHANGES_SPELL_COST_FOR_ALLY) )
|
if( stacks[g]->owner == caster->tempOwner && stacks[g]->hasFeatureOfType(StackFeature::CHANGES_SPELL_COST_FOR_ALLY) )
|
||||||
{
|
{
|
||||||
amin(manaReduction, stacks[g]->valOfFeatures(StackFeature::CHANGES_SPELL_COST_FOR_ALLY));
|
amin(manaReduction, stacks[g]->valOfFeatures(StackFeature::CHANGES_SPELL_COST_FOR_ALLY));
|
||||||
}
|
}
|
||||||
|
if( stacks[g]->owner != caster->tempOwner && stacks[g]->hasFeatureOfType(StackFeature::CHANGES_SPELL_COST_FOR_ENEMY) )
|
||||||
|
{
|
||||||
|
amax(manaIncrease, stacks[g]->valOfFeatures(StackFeature::CHANGES_SPELL_COST_FOR_ENEMY));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret + manaReduction;
|
return ret + manaReduction + manaIncrease;
|
||||||
}
|
}
|
||||||
|
|
||||||
int BattleInfo::hexToWallPart(int hex) const
|
int BattleInfo::hexToWallPart(int hex) const
|
||||||
@ -2875,47 +2881,54 @@ std::pair<const CStack *, int> BattleInfo::getNearestStack(const CStack * closes
|
|||||||
return std::make_pair<const CStack * , int>(NULL, -1);
|
return std::make_pair<const CStack * , int>(NULL, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ui32 BattleInfo::calculateSpellDmg(const CSpell * sp, const CGHeroInstance * caster, const CStack * affectedCreature) const
|
ui32 BattleInfo::calculateSpellDmg( const CSpell * sp, const CGHeroInstance * caster, const CStack * affectedCreature, int spellSchoolLevel ) const
|
||||||
{
|
{
|
||||||
ui32 ret = 0; //value to return
|
ui32 ret = 0; //value to return
|
||||||
|
|
||||||
//15 - magic arrows, 16 - ice bolt, 17 - lightning bolt, 18 - implosion, 20 - frost ring, 21 - fireball, 22 - inferno, 23 - meteor shower,
|
//15 - magic arrows, 16 - ice bolt, 17 - lightning bolt, 18 - implosion, 20 - frost ring, 21 - fireball, 22 - inferno, 23 - meteor shower,
|
||||||
//24 - death ripple, 25 - destroy undead, 26 - armageddon
|
//24 - death ripple, 25 - destroy undead, 26 - armageddon, 77 - thunderbolt
|
||||||
static std::map <int, int> dmgMultipliers = boost::assign::map_list_of(15, 10)(16, 20)(17, 25)(18, 75)(20, 10)(21, 10)(22, 10)(23, 10)(24, 5)(25, 10)(26, 50);
|
static std::map <int, int> dmgMultipliers = boost::assign::map_list_of(15, 10)(16, 20)(17, 25)(18, 75)(20, 10)(21, 10)(22, 10)(23, 10)(24, 5)(25, 10)(26, 50)(77, 10);
|
||||||
|
|
||||||
//check if spell really does damage - if not, return 0
|
//check if spell really does damage - if not, return 0
|
||||||
if(dmgMultipliers.find(sp->id) == dmgMultipliers.end())
|
if(dmgMultipliers.find(sp->id) == dmgMultipliers.end())
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
ret = caster->getPrimSkillLevel(2) * dmgMultipliers[sp->id] + sp->powers[caster->getSpellSchoolLevel(sp)];
|
if (caster)
|
||||||
|
{
|
||||||
|
ret = caster->getPrimSkillLevel(2) * dmgMultipliers[sp->id];
|
||||||
|
}
|
||||||
|
ret += sp->powers[spellSchoolLevel];
|
||||||
|
|
||||||
//applying sorcerery secondary skill
|
//applying sorcerery secondary skill
|
||||||
switch(caster->getSecSkillLevel(25))
|
if(caster)
|
||||||
{
|
{
|
||||||
case 1: //basic
|
switch(caster->getSecSkillLevel(25))
|
||||||
ret *= 1.05f;
|
{
|
||||||
break;
|
case 1: //basic
|
||||||
case 2: //advanced
|
ret *= 1.05f;
|
||||||
ret *= 1.1f;
|
break;
|
||||||
break;
|
case 2: //advanced
|
||||||
case 3: //expert
|
ret *= 1.1f;
|
||||||
ret *= 1.15f;
|
break;
|
||||||
break;
|
case 3: //expert
|
||||||
|
ret *= 1.15f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//applying hero bonuses
|
//applying hero bonuses
|
||||||
if(sp->air && caster->valOfBonuses(HeroBonus::AIR_SPELL_DMG_PREMY) != 0)
|
if(sp->air && caster && caster->valOfBonuses(HeroBonus::AIR_SPELL_DMG_PREMY) != 0)
|
||||||
{
|
{
|
||||||
ret *= (100.0f + caster->valOfBonuses(HeroBonus::AIR_SPELL_DMG_PREMY)) / 100.0f;
|
ret *= (100.0f + caster->valOfBonuses(HeroBonus::AIR_SPELL_DMG_PREMY)) / 100.0f;
|
||||||
}
|
}
|
||||||
else if(sp->fire && caster->valOfBonuses(HeroBonus::FIRE_SPELL_DMG_PREMY) != 0)
|
else if(sp->fire && caster && caster->valOfBonuses(HeroBonus::FIRE_SPELL_DMG_PREMY) != 0)
|
||||||
{
|
{
|
||||||
ret *= (100.0f + caster->valOfBonuses(HeroBonus::FIRE_SPELL_DMG_PREMY)) / 100.0f;
|
ret *= (100.0f + caster->valOfBonuses(HeroBonus::FIRE_SPELL_DMG_PREMY)) / 100.0f;
|
||||||
}
|
}
|
||||||
else if(sp->water && caster->valOfBonuses(HeroBonus::WATER_SPELL_DMG_PREMY) != 0)
|
else if(sp->water && caster && caster->valOfBonuses(HeroBonus::WATER_SPELL_DMG_PREMY) != 0)
|
||||||
{
|
{
|
||||||
ret *= (100.0f + caster->valOfBonuses(HeroBonus::WATER_SPELL_DMG_PREMY)) / 100.0f;
|
ret *= (100.0f + caster->valOfBonuses(HeroBonus::WATER_SPELL_DMG_PREMY)) / 100.0f;
|
||||||
}
|
}
|
||||||
else if(sp->earth && caster->valOfBonuses(HeroBonus::EARTH_SPELL_DMG_PREMY) != 0)
|
else if(sp->earth && caster && caster->valOfBonuses(HeroBonus::EARTH_SPELL_DMG_PREMY) != 0)
|
||||||
{
|
{
|
||||||
ret *= (100.0f + caster->valOfBonuses(HeroBonus::EARTH_SPELL_DMG_PREMY)) / 100.0f;
|
ret *= (100.0f + caster->valOfBonuses(HeroBonus::EARTH_SPELL_DMG_PREMY)) / 100.0f;
|
||||||
}
|
}
|
||||||
|
@ -223,13 +223,13 @@ struct DLL_EXPORT BattleInfo
|
|||||||
static ui32 calculateDmg(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge); //charge - number of hexes travelled before attack (for champion's jousting)
|
static ui32 calculateDmg(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge); //charge - number of hexes travelled before attack (for champion's jousting)
|
||||||
static std::pair<ui32, ui32> calculateDmgRange(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge); //charge - number of hexes travelled before attack (for champion's jousting); returns pair <min dmg, max dmg>
|
static std::pair<ui32, ui32> calculateDmgRange(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge); //charge - number of hexes travelled before attack (for champion's jousting); returns pair <min dmg, max dmg>
|
||||||
void calculateCasualties(std::map<ui32,si32> *casualties) const; //casualties are array of maps size 2 (attacker, defeneder), maps are (crid => amount)
|
void calculateCasualties(std::map<ui32,si32> *casualties) const; //casualties are array of maps size 2 (attacker, defeneder), maps are (crid => amount)
|
||||||
std::set<CStack*> getAttackedCreatures(const CSpell * s, const CGHeroInstance * caster, int destinationTile); //calculates stack affected by given spell
|
std::set<CStack*> getAttackedCreatures(const CSpell * s, int skillLevel, ui8 attackerOwner, int destinationTile); //calculates stack affected by given spell
|
||||||
static int calculateSpellDuration(const CSpell * spell, const CGHeroInstance * caster);
|
static int calculateSpellDuration(const CSpell * spell, const CGHeroInstance * caster);
|
||||||
CStack * generateNewStack(const CGHeroInstance * owner, int creatureID, int amount, int stackID, bool attackerOwned, int slot, int /*TerrainTile::EterrainType*/ terrain, int position) const; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield
|
CStack * generateNewStack(const CGHeroInstance * owner, int creatureID, int amount, int stackID, bool attackerOwned, int slot, int /*TerrainTile::EterrainType*/ terrain, int position) const; //helper for CGameHandler::setupBattle and spells addign new stacks to the battlefield
|
||||||
ui32 getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const; //returns cost of given spell
|
ui32 getSpellCost(const CSpell * sp, const CGHeroInstance * caster) const; //returns cost of given spell
|
||||||
int hexToWallPart(int hex) const; //returns part of destructible wall / gate / keep under given hex or -1 if not found
|
int hexToWallPart(int hex) const; //returns part of destructible wall / gate / keep under given hex or -1 if not found
|
||||||
std::pair<const CStack *, int> getNearestStack(const CStack * closest, boost::logic::tribool attackerOwned) const; //if attackerOwned is indetermnate, returened stack is of any owner; hex is the number of hex we should be looking from; returns (nerarest creature, predecessorHex)
|
std::pair<const CStack *, int> getNearestStack(const CStack * closest, boost::logic::tribool attackerOwned) const; //if attackerOwned is indetermnate, returened stack is of any owner; hex is the number of hex we should be looking from; returns (nerarest creature, predecessorHex)
|
||||||
ui32 calculateSpellDmg(const CSpell * sp, const CGHeroInstance * caster, const CStack * affectedCreature) const; //calculates damage inflicted by spell
|
ui32 calculateSpellDmg(const CSpell * sp, const CGHeroInstance * caster, const CStack * affectedCreature, int spellSchoolLevel) const; //calculates damage inflicted by spell
|
||||||
};
|
};
|
||||||
|
|
||||||
class DLL_EXPORT CStack
|
class DLL_EXPORT CStack
|
||||||
@ -496,3 +496,4 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
#endif // __CGAMESTATE_H__
|
#endif // __CGAMESTATE_H__
|
||||||
|
|
@ -998,9 +998,10 @@ struct SpellCast : public CPackForClient//3009
|
|||||||
ui16 tile; //destination tile (may not be set in some global/mass spells
|
ui16 tile; //destination tile (may not be set in some global/mass spells
|
||||||
std::vector<ui32> resisted; //ids of creatures that resisted this spell
|
std::vector<ui32> resisted; //ids of creatures that resisted this spell
|
||||||
std::set<ui32> affectedCres; //ids of creatures affected by this spell, generally used if spell does not set any effect (like dispel or cure)
|
std::set<ui32> affectedCres; //ids of creatures affected by this spell, generally used if spell does not set any effect (like dispel or cure)
|
||||||
|
ui8 castedByHero; //if true - spell has been casted by hero, otherwise by a creature
|
||||||
template <typename Handler> void serialize(Handler &h, const int version)
|
template <typename Handler> void serialize(Handler &h, const int version)
|
||||||
{
|
{
|
||||||
h & dmgToDisplay & side & id & skill & tile & resisted & affectedCres;
|
h & dmgToDisplay & side & id & skill & tile & resisted & affectedCres & castedByHero;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ struct StackFeature
|
|||||||
VCMI_CREATURE_ABILITY_NAME(MAGIC_RESISTANCE) /*in % (value)*/ \
|
VCMI_CREATURE_ABILITY_NAME(MAGIC_RESISTANCE) /*in % (value)*/ \
|
||||||
VCMI_CREATURE_ABILITY_NAME(CHANGES_SPELL_COST_FOR_ALLY) /*in mana points (value) , eg. mage*/ \
|
VCMI_CREATURE_ABILITY_NAME(CHANGES_SPELL_COST_FOR_ALLY) /*in mana points (value) , eg. mage*/ \
|
||||||
VCMI_CREATURE_ABILITY_NAME(CHANGES_SPELL_COST_FOR_ENEMY) /*in mana points (value) , eg. pegasus */ \
|
VCMI_CREATURE_ABILITY_NAME(CHANGES_SPELL_COST_FOR_ENEMY) /*in mana points (value) , eg. pegasus */ \
|
||||||
VCMI_CREATURE_ABILITY_NAME(SPELL_AFTER_ATTACK) /* subtype - spell id, value - spell level, (aditional info)%100 - chance in %; eg. dendroids, (additional info)/100 -> [0 - all attacks, 1 - shot only, 2 - melee only*/ \
|
VCMI_CREATURE_ABILITY_NAME(SPELL_AFTER_ATTACK) /* subtype - spell id, value - spell level, (additional info)%1000 - chance in %; eg. dendroids, (additional info)/1000 -> [0 - all attacks, 1 - shot only, 2 - melee only*/ \
|
||||||
VCMI_CREATURE_ABILITY_NAME(SPELL_RESISTANCE_AURA) /*eg. unicorns, value - resistance bonus in % for adjacent creatures*/ \
|
VCMI_CREATURE_ABILITY_NAME(SPELL_RESISTANCE_AURA) /*eg. unicorns, value - resistance bonus in % for adjacent creatures*/ \
|
||||||
VCMI_CREATURE_ABILITY_NAME(LEVEL_SPELL_IMMUNITY) /*creature is immune to all spell with level below or equal to value of this bonus*/ \
|
VCMI_CREATURE_ABILITY_NAME(LEVEL_SPELL_IMMUNITY) /*creature is immune to all spell with level below or equal to value of this bonus*/ \
|
||||||
VCMI_CREATURE_ABILITY_NAME(TWO_HEX_ATTACK_BREATH) /*eg. dragons*/ \
|
VCMI_CREATURE_ABILITY_NAME(TWO_HEX_ATTACK_BREATH) /*eg. dragons*/ \
|
||||||
|
@ -2926,6 +2926,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
BattleAttack bat;
|
BattleAttack bat;
|
||||||
prepareAttack(bat, curStack, stackAtEnd, distance);
|
prepareAttack(bat, curStack, stackAtEnd, distance);
|
||||||
sendAndApply(&bat);
|
sendAndApply(&bat);
|
||||||
|
handleAfterAttackCasting(bat);
|
||||||
|
|
||||||
//counterattack
|
//counterattack
|
||||||
if(!curStack->hasFeatureOfType(StackFeature::BLOCKS_RETALIATION)
|
if(!curStack->hasFeatureOfType(StackFeature::BLOCKS_RETALIATION)
|
||||||
@ -2937,6 +2938,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
prepareAttack(bat, stackAtEnd, curStack, 0);
|
prepareAttack(bat, stackAtEnd, curStack, 0);
|
||||||
bat.flags |= 2;
|
bat.flags |= 2;
|
||||||
sendAndApply(&bat);
|
sendAndApply(&bat);
|
||||||
|
handleAfterAttackCasting(bat);
|
||||||
}
|
}
|
||||||
|
|
||||||
//second attack
|
//second attack
|
||||||
@ -2948,6 +2950,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
bat.flags = 0;
|
bat.flags = 0;
|
||||||
prepareAttack(bat, curStack, stackAtEnd, 0);
|
prepareAttack(bat, curStack, stackAtEnd, 0);
|
||||||
sendAndApply(&bat);
|
sendAndApply(&bat);
|
||||||
|
handleAfterAttackCasting(bat);
|
||||||
}
|
}
|
||||||
|
|
||||||
//return
|
//return
|
||||||
@ -2981,6 +2984,7 @@ bool CGameHandler::makeBattleAction( BattleAction &ba )
|
|||||||
{
|
{
|
||||||
prepareAttack(bat, curStack, destStack, 0);
|
prepareAttack(bat, curStack, destStack, 0);
|
||||||
sendAndApply(&bat);
|
sendAndApply(&bat);
|
||||||
|
handleAfterAttackCasting(bat);
|
||||||
}
|
}
|
||||||
|
|
||||||
sendAndApply(&EndAction());
|
sendAndApply(&EndAction());
|
||||||
@ -3246,7 +3250,8 @@ static std::vector<ui32> calculateResistedStacks(const CSpell * sp, const CGHero
|
|||||||
for(std::set<CStack*>::const_iterator it = affectedCreatures.begin(); it != affectedCreatures.end(); ++it)
|
for(std::set<CStack*>::const_iterator it = affectedCreatures.begin(); it != affectedCreatures.end(); ++it)
|
||||||
{
|
{
|
||||||
if ((*it)->hasFeatureOfType(StackFeature::SPELL_IMMUNITY, sp->id) //100% sure spell immunity
|
if ((*it)->hasFeatureOfType(StackFeature::SPELL_IMMUNITY, sp->id) //100% sure spell immunity
|
||||||
|| ((*it)->valOfFeatures(StackFeature::LEVEL_SPELL_IMMUNITY) >= sp->level))
|
|| ( (*it)->hasFeatureOfType(StackFeature::LEVEL_SPELL_IMMUNITY) &&
|
||||||
|
(*it)->valOfFeatures(StackFeature::LEVEL_SPELL_IMMUNITY) >= sp->level) ) //some creature abilities have level 0
|
||||||
{
|
{
|
||||||
ret.push_back((*it)->ID);
|
ret.push_back((*it)->ID);
|
||||||
continue;
|
continue;
|
||||||
@ -3257,7 +3262,7 @@ static std::vector<ui32> calculateResistedStacks(const CSpell * sp, const CGHero
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
const CGHeroInstance * bonusHero; //hero we should take bonuses from
|
const CGHeroInstance * bonusHero; //hero we should take bonuses from
|
||||||
if((*it)->owner == caster->tempOwner)
|
if(caster && (*it)->owner == caster->tempOwner)
|
||||||
bonusHero = caster;
|
bonusHero = caster;
|
||||||
else
|
else
|
||||||
bonusHero = hero2;
|
bonusHero = hero2;
|
||||||
@ -3307,6 +3312,159 @@ static std::vector<ui32> calculateResistedStacks(const CSpell * sp, const CGHero
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CGameHandler::handleSpellCasting( int spellID, int spellLvl, int destination, ui8 casterSide, ui8 casterColor,
|
||||||
|
const CGHeroInstance * caster, const CGHeroInstance * secHero )
|
||||||
|
{
|
||||||
|
CSpell *spell = &VLC->spellh->spells[spellID];
|
||||||
|
|
||||||
|
SpellCast sc;
|
||||||
|
sc.side = casterSide;
|
||||||
|
sc.id = spellID;
|
||||||
|
sc.skill = spellLvl;
|
||||||
|
sc.tile = destination;
|
||||||
|
sc.dmgToDisplay = 0;
|
||||||
|
sc.castedByHero = (bool)caster;
|
||||||
|
|
||||||
|
//calculating affected creatures for all spells
|
||||||
|
std::set<CStack*> attackedCres = gs->curB->getAttackedCreatures(spell, spellLvl, casterColor, destination);
|
||||||
|
for(std::set<CStack*>::const_iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
|
||||||
|
{
|
||||||
|
sc.affectedCres.insert((*it)->ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
//checking if creatures resist
|
||||||
|
sc.resisted = calculateResistedStacks(spell, caster, secHero, attackedCres);
|
||||||
|
|
||||||
|
//calculating dmg to display
|
||||||
|
for(std::set<CStack*>::iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
|
||||||
|
{
|
||||||
|
if(vstd::contains(sc.resisted, (*it)->ID)) //this creature resisted the spell
|
||||||
|
continue;
|
||||||
|
sc.dmgToDisplay += gs->curB->calculateSpellDmg(spell, caster, *it, spellLvl);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendAndApply(&sc);
|
||||||
|
|
||||||
|
//applying effects
|
||||||
|
switch(spellID)
|
||||||
|
{
|
||||||
|
case 15: //magic arrow
|
||||||
|
case 16: //ice bolt
|
||||||
|
case 17: //lightning bolt
|
||||||
|
case 18: //implosion
|
||||||
|
case 20: //frost ring
|
||||||
|
case 21: //fireball
|
||||||
|
case 22: //inferno
|
||||||
|
case 23: //meteor shower
|
||||||
|
case 24: //death ripple
|
||||||
|
case 25: //destroy undead
|
||||||
|
case 26: //armageddon
|
||||||
|
case 77: //Thunderbolt (thunderbirds)
|
||||||
|
{
|
||||||
|
StacksInjured si;
|
||||||
|
for(std::set<CStack*>::iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
|
||||||
|
{
|
||||||
|
if(vstd::contains(sc.resisted, (*it)->ID)) //this creature resisted the spell
|
||||||
|
continue;
|
||||||
|
|
||||||
|
BattleStackAttacked bsa;
|
||||||
|
bsa.flags |= 2;
|
||||||
|
bsa.effect = spell->mainEffectAnim;
|
||||||
|
bsa.damageAmount = gs->curB->calculateSpellDmg(spell, caster, *it, spellLvl);
|
||||||
|
bsa.stackAttacked = (*it)->ID;
|
||||||
|
bsa.attackerID = -1;
|
||||||
|
prepareAttacked(bsa,*it);
|
||||||
|
si.stacks.push_back(bsa);
|
||||||
|
}
|
||||||
|
if(!si.stacks.empty())
|
||||||
|
sendAndApply(&si);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 27: //shield
|
||||||
|
case 28: //air shield
|
||||||
|
case 30: //protection from air
|
||||||
|
case 31: //protection from fire
|
||||||
|
case 32: //protection from water
|
||||||
|
case 33: //protection from earth
|
||||||
|
case 34: //anti-magic
|
||||||
|
case 41: //bless
|
||||||
|
case 42: //curse
|
||||||
|
case 43: //bloodlust
|
||||||
|
case 44: //precision
|
||||||
|
case 45: //weakness
|
||||||
|
case 46: //stone skin
|
||||||
|
case 47: //disrupting ray
|
||||||
|
case 48: //prayer
|
||||||
|
case 49: //mirth
|
||||||
|
case 50: //sorrow
|
||||||
|
case 51: //fortune
|
||||||
|
case 52: //misfortune
|
||||||
|
case 53: //haste
|
||||||
|
case 54: //slow
|
||||||
|
case 55: //slayer
|
||||||
|
case 56: //frenzy
|
||||||
|
case 58: //counterstrike
|
||||||
|
case 59: //berserk
|
||||||
|
case 60: //hypnotize
|
||||||
|
case 61: //forgetfulness
|
||||||
|
case 62: //blind
|
||||||
|
{
|
||||||
|
SetStackEffect sse;
|
||||||
|
for(std::set<CStack*>::iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
|
||||||
|
{
|
||||||
|
if(vstd::contains(sc.resisted, (*it)->ID)) //this creature resisted the spell
|
||||||
|
continue;
|
||||||
|
sse.stacks.push_back((*it)->ID);
|
||||||
|
}
|
||||||
|
sse.effect.id = spellID;
|
||||||
|
sse.effect.level = spellLvl;
|
||||||
|
sse.effect.turnsRemain = BattleInfo::calculateSpellDuration(spell, caster);
|
||||||
|
if(!sse.stacks.empty())
|
||||||
|
sendAndApply(&sse);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 37: //cure
|
||||||
|
case 38: //resurrection
|
||||||
|
case 39: //animate dead
|
||||||
|
{
|
||||||
|
StacksHealedOrResurrected shr;
|
||||||
|
for(std::set<CStack*>::iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
|
||||||
|
{
|
||||||
|
if(vstd::contains(sc.resisted, (*it)->ID) //this creature resisted the spell
|
||||||
|
|| (spellID == 39 && !(*it)->hasFeatureOfType(StackFeature::UNDEAD)) //we try to cast animate dead on living stack
|
||||||
|
)
|
||||||
|
continue;
|
||||||
|
StacksHealedOrResurrected::HealInfo hi;
|
||||||
|
hi.stackID = (*it)->ID;
|
||||||
|
hi.healedHP = calculateHealedHP(caster, spell, *it);
|
||||||
|
hi.lowLevelResurrection = spellLvl <= 1;
|
||||||
|
shr.healedStacks.push_back(hi);
|
||||||
|
}
|
||||||
|
if(!shr.healedStacks.empty())
|
||||||
|
sendAndApply(&shr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 64: //remove obstacle
|
||||||
|
{
|
||||||
|
ObstaclesRemoved obr;
|
||||||
|
for(int g=0; g<gs->curB->obstacles.size(); ++g)
|
||||||
|
{
|
||||||
|
std::vector<int> blockedHexes = VLC->heroh->obstacles[gs->curB->obstacles[g].ID].getBlocked(gs->curB->obstacles[g].pos);
|
||||||
|
|
||||||
|
if(vstd::contains(blockedHexes, destination)) //this obstacle covers given hex
|
||||||
|
{
|
||||||
|
obr.obstacles.insert(gs->curB->obstacles[g].uniqueID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!obr.obstacles.empty())
|
||||||
|
sendAndApply(&obr);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
bool CGameHandler::makeCustomAction( BattleAction &ba )
|
bool CGameHandler::makeCustomAction( BattleAction &ba )
|
||||||
{
|
{
|
||||||
switch(ba.actionType)
|
switch(ba.actionType)
|
||||||
@ -3343,149 +3501,8 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
|
|||||||
|
|
||||||
sendAndApply(&StartAction(ba)); //start spell casting
|
sendAndApply(&StartAction(ba)); //start spell casting
|
||||||
|
|
||||||
SpellCast sc;
|
handleSpellCasting(ba.additionalInfo, skill, ba.destinationTile, ba.side, h->tempOwner, h, secondHero);
|
||||||
sc.side = ba.side;
|
|
||||||
sc.id = ba.additionalInfo;
|
|
||||||
sc.skill = skill;
|
|
||||||
sc.tile = ba.destinationTile;
|
|
||||||
sc.dmgToDisplay = 0;
|
|
||||||
|
|
||||||
//calculating affected creatures for all spells
|
|
||||||
std::set<CStack*> attackedCres = gs->curB->getAttackedCreatures(s, h, ba.destinationTile);
|
|
||||||
for(std::set<CStack*>::const_iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
|
|
||||||
{
|
|
||||||
sc.affectedCres.insert((*it)->ID);
|
|
||||||
}
|
|
||||||
|
|
||||||
//checking if creatures resist
|
|
||||||
sc.resisted = calculateResistedStacks(s, h, secondHero, attackedCres);
|
|
||||||
|
|
||||||
//calculating dmg to display
|
|
||||||
for(std::set<CStack*>::iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
|
|
||||||
{
|
|
||||||
if(vstd::contains(sc.resisted, (*it)->ID)) //this creature resisted the spell
|
|
||||||
continue;
|
|
||||||
sc.dmgToDisplay += gs->curB->calculateSpellDmg(s, h, *it);
|
|
||||||
}
|
|
||||||
|
|
||||||
sendAndApply(&sc);
|
|
||||||
|
|
||||||
//applying effects
|
|
||||||
switch(ba.additionalInfo) //spell id
|
|
||||||
{
|
|
||||||
case 15: //magic arrow
|
|
||||||
case 16: //ice bolt
|
|
||||||
case 17: //lightning bolt
|
|
||||||
case 18: //implosion
|
|
||||||
case 20: //frost ring
|
|
||||||
case 21: //fireball
|
|
||||||
case 22: //inferno
|
|
||||||
case 23: //meteor shower
|
|
||||||
case 24: //death ripple
|
|
||||||
case 25: //destroy undead
|
|
||||||
case 26: //armageddon
|
|
||||||
{
|
|
||||||
StacksInjured si;
|
|
||||||
for(std::set<CStack*>::iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
|
|
||||||
{
|
|
||||||
if(vstd::contains(sc.resisted, (*it)->ID)) //this creature resisted the spell
|
|
||||||
continue;
|
|
||||||
|
|
||||||
BattleStackAttacked bsa;
|
|
||||||
bsa.flags |= 2;
|
|
||||||
bsa.effect = VLC->spellh->spells[ba.additionalInfo].mainEffectAnim;
|
|
||||||
bsa.damageAmount = gs->curB->calculateSpellDmg(s, h, *it);
|
|
||||||
bsa.stackAttacked = (*it)->ID;
|
|
||||||
bsa.attackerID = -1;
|
|
||||||
prepareAttacked(bsa,*it);
|
|
||||||
si.stacks.push_back(bsa);
|
|
||||||
}
|
|
||||||
if(!si.stacks.empty())
|
|
||||||
sendAndApply(&si);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 27: //shield
|
|
||||||
case 28: //air shield
|
|
||||||
case 30: //protection from air
|
|
||||||
case 31: //protection from fire
|
|
||||||
case 32: //protection from water
|
|
||||||
case 33: //protection from earth
|
|
||||||
case 34: //anti-magic
|
|
||||||
case 41: //bless
|
|
||||||
case 42: //curse
|
|
||||||
case 43: //bloodlust
|
|
||||||
case 44: //precision
|
|
||||||
case 45: //weakness
|
|
||||||
case 46: //stone skin
|
|
||||||
case 47: //disrupting ray
|
|
||||||
case 48: //prayer
|
|
||||||
case 49: //mirth
|
|
||||||
case 50: //sorrow
|
|
||||||
case 51: //fortune
|
|
||||||
case 52: //misfortune
|
|
||||||
case 53: //haste
|
|
||||||
case 54: //slow
|
|
||||||
case 55: //slayer
|
|
||||||
case 56: //frenzy
|
|
||||||
case 58: //counterstrike
|
|
||||||
case 59: //berserk
|
|
||||||
case 60: //hypnotize
|
|
||||||
case 61: //forgetfulness
|
|
||||||
case 62: //blind
|
|
||||||
{
|
|
||||||
SetStackEffect sse;
|
|
||||||
for(std::set<CStack*>::iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
|
|
||||||
{
|
|
||||||
if(vstd::contains(sc.resisted, (*it)->ID)) //this creature resisted the spell
|
|
||||||
continue;
|
|
||||||
sse.stacks.push_back((*it)->ID);
|
|
||||||
}
|
|
||||||
sse.effect.id = ba.additionalInfo;
|
|
||||||
sse.effect.level = h->getSpellSchoolLevel(s);
|
|
||||||
sse.effect.turnsRemain = BattleInfo::calculateSpellDuration(s, h);
|
|
||||||
if(!sse.stacks.empty())
|
|
||||||
sendAndApply(&sse);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 37: //cure
|
|
||||||
case 38: //resurrection
|
|
||||||
case 39: //animate dead
|
|
||||||
{
|
|
||||||
StacksHealedOrResurrected shr;
|
|
||||||
for(std::set<CStack*>::iterator it = attackedCres.begin(); it != attackedCres.end(); ++it)
|
|
||||||
{
|
|
||||||
if(vstd::contains(sc.resisted, (*it)->ID) //this creature resisted the spell
|
|
||||||
|| (s->id == 39 && !(*it)->hasFeatureOfType(StackFeature::UNDEAD)) //we try to cast animate dead on living stack
|
|
||||||
)
|
|
||||||
continue;
|
|
||||||
StacksHealedOrResurrected::HealInfo hi;
|
|
||||||
hi.stackID = (*it)->ID;
|
|
||||||
hi.healedHP = calculateHealedHP(h, s, *it);
|
|
||||||
hi.lowLevelResurrection = h->getSpellSchoolLevel(s) <= 1;
|
|
||||||
shr.healedStacks.push_back(hi);
|
|
||||||
}
|
|
||||||
if(!shr.healedStacks.empty())
|
|
||||||
sendAndApply(&shr);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 64: //remove obstacle
|
|
||||||
{
|
|
||||||
ObstaclesRemoved obr;
|
|
||||||
for(int g=0; g<gs->curB->obstacles.size(); ++g)
|
|
||||||
{
|
|
||||||
std::vector<int> blockedHexes = VLC->heroh->obstacles[gs->curB->obstacles[g].ID].getBlocked(gs->curB->obstacles[g].pos);
|
|
||||||
|
|
||||||
if(vstd::contains(blockedHexes, ba.destinationTile)) //this obstacle covers given hex
|
|
||||||
{
|
|
||||||
obr.obstacles.insert(gs->curB->obstacles[g].uniqueID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(!obr.obstacles.empty())
|
|
||||||
sendAndApply(&obr);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sendAndApply(&EndAction());
|
sendAndApply(&EndAction());
|
||||||
if( !gs->curB->getStack(gs->curB->activeStack, false)->alive() )
|
if( !gs->curB->getStack(gs->curB->activeStack, false)->alive() )
|
||||||
{
|
{
|
||||||
@ -3496,6 +3513,7 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
|
|||||||
{
|
{
|
||||||
endBattle(gs->curB->tile, gs->curB->heroes[0], gs->curB->heroes[1]);
|
endBattle(gs->curB->tile, gs->curB->heroes[0], gs->curB->heroes[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3904,4 +3922,42 @@ bool CGameHandler::dig( const CGHeroInstance *h )
|
|||||||
no.subID = 0;
|
no.subID = 0;
|
||||||
sendAndApply(&no);
|
sendAndApply(&no);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CGameHandler::handleAfterAttackCasting( const BattleAttack & bat )
|
||||||
|
{
|
||||||
|
const CStack * attacker = gs->curB->getStack(bat.stackAttacking);
|
||||||
|
if( attacker->hasFeatureOfType(StackFeature::SPELL_AFTER_ATTACK) )
|
||||||
|
{
|
||||||
|
for (int it=0; it<attacker->features.size(); ++it)
|
||||||
|
{
|
||||||
|
const StackFeature & sf = attacker->features[it];
|
||||||
|
if (sf.type == StackFeature::SPELL_AFTER_ATTACK)
|
||||||
|
{
|
||||||
|
const CStack * oneOfAttacked = NULL;
|
||||||
|
for(int g=0; g<bat.bsa.size(); ++g)
|
||||||
|
{
|
||||||
|
if (bat.bsa[g].newAmount > 0)
|
||||||
|
{
|
||||||
|
oneOfAttacked = gs->curB->getStack(bat.bsa[g].stackAttacked);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(oneOfAttacked == NULL) //all attacked creatures have been killed
|
||||||
|
return;
|
||||||
|
|
||||||
|
int spellID = sf.subtype;
|
||||||
|
int spellLevel = sf.value;
|
||||||
|
int chance = sf.additionalInfo % 1000;
|
||||||
|
int meleeRanged = sf.additionalInfo / 1000;
|
||||||
|
int destination = oneOfAttacked->position;
|
||||||
|
//check if spell should be casted (probability handling)
|
||||||
|
if( rand()%100 >= chance )
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//casting
|
||||||
|
handleSpellCasting(spellID, spellLevel, destination, !attacker->attackerOwned, attacker->owner, NULL, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -157,6 +157,7 @@ public:
|
|||||||
|
|
||||||
void playerMessage( ui8 player, const std::string &message);
|
void playerMessage( ui8 player, const std::string &message);
|
||||||
bool makeBattleAction(BattleAction &ba);
|
bool makeBattleAction(BattleAction &ba);
|
||||||
|
void handleSpellCasting(int spellID, int spellLvl, int destination, ui8 casterSide, ui8 casterColor, const CGHeroInstance * caster, const CGHeroInstance * secHero);
|
||||||
bool makeCustomAction(BattleAction &ba);
|
bool makeCustomAction(BattleAction &ba);
|
||||||
bool queryReply( ui32 qid, ui32 answer );
|
bool queryReply( ui32 qid, ui32 answer );
|
||||||
bool hireHero( ui32 tid, ui8 hid );
|
bool hireHero( ui32 tid, ui8 hid );
|
||||||
@ -200,6 +201,7 @@ public:
|
|||||||
|
|
||||||
void run(bool resume);
|
void run(bool resume);
|
||||||
void newTurn();
|
void newTurn();
|
||||||
|
void handleAfterAttackCasting( const BattleAttack & bat );
|
||||||
friend class CVCMIServer;
|
friend class CVCMIServer;
|
||||||
friend class CScriptCallback;
|
friend class CScriptCallback;
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user