mirror of
https://github.com/vcmi/vcmi.git
synced 2024-11-28 08:48:48 +02:00
[refactor] spell handling
* more config options for spells + mind immunity handled by config + direct damage immunity handled by config + immunity icon configurable - removed mind_spell flag * more use of new spell identifacation
This commit is contained in:
parent
6d06710684
commit
ceea466f54
@ -9,10 +9,9 @@
|
||||
// counters: array of ids of countering spells
|
||||
|
||||
// flags: string array of
|
||||
// damage
|
||||
// damage - ATM used only in CBattleInfoCallback::calculateSpellDmg
|
||||
// offensive
|
||||
// rising
|
||||
// mind
|
||||
// summoning //todo:
|
||||
|
||||
//effects: array of structure for bonuses for permanent effects
|
||||
@ -26,6 +25,9 @@
|
||||
// immunity: array any of these bonus grants immunity
|
||||
// limit: array required bonus to be affected, all required
|
||||
|
||||
//graphics - OPTIONAL; object;
|
||||
// iconImmune - OPTIONAL; string; resourse path of icon for SPELL_IMMUNITY bonus (relative to DATA or SPRITES)
|
||||
|
||||
"spells":
|
||||
{
|
||||
"summonBoat" :
|
||||
@ -111,7 +113,9 @@
|
||||
"effect": 0,
|
||||
"anim": -1,
|
||||
"ranges": [ "X", "X", "X", "X" ],
|
||||
"flags" : ["damage"]
|
||||
"flags" : ["damage"],
|
||||
"immunities" : ["DIRECT_DAMAGE_IMMUNITY"]
|
||||
|
||||
},
|
||||
"forceField" :
|
||||
{
|
||||
@ -126,7 +130,8 @@
|
||||
"effect": 0,
|
||||
"anim": -1,
|
||||
"ranges": [ "0", "0", "0", "0" ],
|
||||
"flags" : ["damage"]
|
||||
"flags" : ["damage"],
|
||||
"immunities" : ["DIRECT_DAMAGE_IMMUNITY"]
|
||||
},
|
||||
"earthquake" :
|
||||
{
|
||||
@ -141,7 +146,8 @@
|
||||
"effect": -1,
|
||||
"anim": 64,
|
||||
"ranges": [ "0", "0", "0", "0" ],
|
||||
"flags" : ["damage", "offensive"]
|
||||
"flags" : ["damage", "offensive"],
|
||||
"immunities" : ["DIRECT_DAMAGE_IMMUNITY"]
|
||||
},
|
||||
"iceBolt" :
|
||||
{
|
||||
@ -149,7 +155,8 @@
|
||||
"effect": -1,
|
||||
"anim": 46,
|
||||
"ranges": [ "0", "0", "0", "0" ],
|
||||
"flags" : ["damage", "offensive"]
|
||||
"flags" : ["damage", "offensive"],
|
||||
"immunities" : ["DIRECT_DAMAGE_IMMUNITY"]
|
||||
},
|
||||
"lightningBolt" :
|
||||
{
|
||||
@ -157,7 +164,8 @@
|
||||
"effect": -1,
|
||||
"anim": 38,
|
||||
"ranges": [ "0", "0", "0", "0" ],
|
||||
"flags" : ["damage", "offensive"]
|
||||
"flags" : ["damage", "offensive"],
|
||||
"immunities" : ["DIRECT_DAMAGE_IMMUNITY"]
|
||||
},
|
||||
"implosion" :
|
||||
{
|
||||
@ -165,7 +173,11 @@
|
||||
"effect": -1,
|
||||
"anim": 10,
|
||||
"ranges": [ "0", "0", "0", "0" ],
|
||||
"flags" : ["damage", "offensive"]
|
||||
"graphics":{
|
||||
"iconImmune":"ZVS/LIB1.RES/E_SPIMP"
|
||||
},
|
||||
"flags" : ["damage", "offensive"],
|
||||
"immunities" : ["DIRECT_DAMAGE_IMMUNITY"]
|
||||
},
|
||||
"chainLightning" :
|
||||
{
|
||||
@ -181,7 +193,8 @@
|
||||
"effect": -1,
|
||||
"anim": 45,
|
||||
"ranges": [ "1", "1", "1", "1" ],
|
||||
"flags" : ["damage", "offensive"]
|
||||
"flags" : ["damage", "offensive"],
|
||||
"immunities" : ["DIRECT_DAMAGE_IMMUNITY"]
|
||||
},
|
||||
"fireball" :
|
||||
{
|
||||
@ -189,7 +202,8 @@
|
||||
"effect": -1,
|
||||
"anim": 53,
|
||||
"ranges": [ "0,1", "0,1", "0,1", "0,1" ],
|
||||
"flags" : ["damage", "offensive"]
|
||||
"flags" : ["damage", "offensive"],
|
||||
"immunities" : ["DIRECT_DAMAGE_IMMUNITY"]
|
||||
},
|
||||
"inferno" :
|
||||
{
|
||||
@ -197,7 +211,8 @@
|
||||
"effect": -1,
|
||||
"anim": 9,
|
||||
"ranges": [ "0-2", "0-2", "0-2", "0-2" ],
|
||||
"flags" : ["damage", "offensive"]
|
||||
"flags" : ["damage", "offensive"],
|
||||
"immunities" : ["DIRECT_DAMAGE_IMMUNITY"]
|
||||
},
|
||||
"meteorShower" :
|
||||
{
|
||||
@ -205,7 +220,11 @@
|
||||
"effect": -1,
|
||||
"anim": 16,
|
||||
"ranges": [ "0,1", "0,1", "0,1", "0,1" ],
|
||||
"flags" : ["damage", "offensive"]
|
||||
"graphics":{
|
||||
"iconImmune":"ZVS/LIB1.RES/E_SPMET"
|
||||
},
|
||||
"flags" : ["damage", "offensive"],
|
||||
"immunities" : ["DIRECT_DAMAGE_IMMUNITY"]
|
||||
},
|
||||
"deathRipple" :
|
||||
{
|
||||
@ -214,7 +233,8 @@
|
||||
"anim": 8,
|
||||
"ranges": [ "X", "X", "X", "X" ],
|
||||
"flags" : ["damage", "offensive"],
|
||||
"immunity": ["SIEGE_WEAPON","UNDEAD"]
|
||||
"immunity": ["SIEGE_WEAPON","UNDEAD"],
|
||||
"immunities" : ["DIRECT_DAMAGE_IMMUNITY"]
|
||||
},
|
||||
"destroyUndead" :
|
||||
{
|
||||
@ -223,7 +243,8 @@
|
||||
"anim": 29,
|
||||
"ranges": [ "X", "X", "X", "X" ],
|
||||
"flags" : ["damage", "offensive"],
|
||||
"limit":["UNDEAD"]
|
||||
"limit":["UNDEAD"],
|
||||
"immunities" : ["DIRECT_DAMAGE_IMMUNITY"]
|
||||
|
||||
},
|
||||
"armageddon" :
|
||||
@ -232,7 +253,11 @@
|
||||
"effect": -1,
|
||||
"anim": 12,
|
||||
"ranges": [ "X", "X", "X", "X" ],
|
||||
"flags" : ["damage", "offensive"]
|
||||
"graphics":{
|
||||
"iconImmune":"ZVS/LIB1.RES/E_SPARM"
|
||||
},
|
||||
"flags" : ["damage", "offensive"],
|
||||
"immunities" : ["DIRECT_DAMAGE_IMMUNITY"]
|
||||
},
|
||||
"shield" :
|
||||
{
|
||||
@ -364,7 +389,10 @@
|
||||
"id": 35,
|
||||
"effect": 0,
|
||||
"anim": 41,
|
||||
"ranges": [ "0", "0", "0", "X" ]
|
||||
"ranges": [ "0", "0", "0", "X" ],
|
||||
"graphics":{
|
||||
"iconImmune":"ZVS/LIB1.RES/E_SPDISP"
|
||||
}
|
||||
},
|
||||
"magicMirror" :
|
||||
{
|
||||
@ -573,7 +601,6 @@
|
||||
"effect": -1,
|
||||
"anim": 30,
|
||||
"ranges": [ "0", "0", "0", "X" ], "counters" : [49],
|
||||
"flags" : ["mind"],
|
||||
"effects":
|
||||
[
|
||||
{
|
||||
@ -581,7 +608,8 @@
|
||||
"duration": "N_TURNS",
|
||||
"values":[-1,-1,-2,-2]
|
||||
}
|
||||
]
|
||||
],
|
||||
"immunity":["MIND_IMMUNITY"]
|
||||
},
|
||||
"fortune" :
|
||||
{
|
||||
@ -636,6 +664,9 @@
|
||||
"effect": -1,
|
||||
"anim": 19,
|
||||
"ranges": [ "0", "0", "0", "X" ],
|
||||
"graphics":{
|
||||
"iconImmune":"ZVS/LIB1.RES/E_SPSLOW"
|
||||
},
|
||||
"counters" : [53],
|
||||
"effects":
|
||||
[
|
||||
@ -705,7 +736,9 @@
|
||||
"effect": -1,
|
||||
"anim": 35,
|
||||
"ranges": [ "0", "0", "0-1", "0-2" ],
|
||||
"flags" : ["mind"],
|
||||
"graphics":{
|
||||
"iconImmune":"ZVS/LIB1.RES/E_SPBERS"
|
||||
},
|
||||
"effects":
|
||||
[
|
||||
{
|
||||
@ -713,7 +746,8 @@
|
||||
"duration": "N_TURNS",
|
||||
"values":[0,1,2,3]
|
||||
}
|
||||
]
|
||||
],
|
||||
"immunity":["MIND_IMMUNITY"]
|
||||
},
|
||||
"hypnotize" :
|
||||
{
|
||||
@ -721,7 +755,9 @@
|
||||
"effect": -1,
|
||||
"anim": 21,
|
||||
"ranges": [ "0", "0", "0", "0" ],
|
||||
"flags" : ["mind"],
|
||||
"graphics":{
|
||||
"iconImmune":"ZVS/LIB1.RES/E_SPHYPN"
|
||||
},
|
||||
"effects":
|
||||
[
|
||||
{
|
||||
@ -729,7 +765,8 @@
|
||||
"duration": "N_TURNS",
|
||||
"values":[0,1,2,3]
|
||||
}
|
||||
]
|
||||
],
|
||||
"immunity":["MIND_IMMUNITY"]
|
||||
},
|
||||
"forgetfulness" :
|
||||
{
|
||||
@ -737,7 +774,6 @@
|
||||
"effect": -1,
|
||||
"anim": 42,
|
||||
"ranges": [ "0", "0", "0", "X" ],
|
||||
"flags" : ["mind"],
|
||||
"effects":
|
||||
[
|
||||
{
|
||||
@ -746,7 +782,8 @@
|
||||
"values":[0,1,2,3]
|
||||
}
|
||||
],
|
||||
"limit":["SHOOTER"]
|
||||
"limit":["SHOOTER"],
|
||||
"immunity":["MIND_IMMUNITY"]
|
||||
},
|
||||
"blind" :
|
||||
{
|
||||
@ -754,7 +791,9 @@
|
||||
"effect": -1,
|
||||
"anim": 6,
|
||||
"ranges": [ "0", "0", "0", "0" ],
|
||||
"flags" : ["mind"],
|
||||
"graphics":{
|
||||
"iconImmune":"ZVS/LIB1.RES/E_SPBLIND"
|
||||
},
|
||||
"effects":
|
||||
[
|
||||
{
|
||||
@ -772,7 +811,8 @@
|
||||
"duration": "UNITL_BEING_ATTACKED",
|
||||
"values":[0,0,0,0]
|
||||
}
|
||||
]
|
||||
],
|
||||
"immunity":["MIND_IMMUNITY"]
|
||||
},
|
||||
"teleport" :
|
||||
{
|
||||
@ -964,7 +1004,10 @@
|
||||
"id": 78,
|
||||
"effect": -1,
|
||||
"anim": 41,
|
||||
"ranges": [ "0", "0", "0", "0" ]
|
||||
"ranges": [ "0", "0", "0", "0" ],
|
||||
"graphics":{
|
||||
"iconImmune":"ZVS/LIB1.RES/E_SPDISB"
|
||||
}
|
||||
},
|
||||
"deathStare" :
|
||||
{
|
||||
@ -996,7 +1039,8 @@
|
||||
"effect": 0,
|
||||
"anim": 81,
|
||||
"ranges": [ "0", "0", "0", "0" ],
|
||||
"flags" : ["damage"]
|
||||
"flags" : ["damage"],
|
||||
"immunities" : ["DIRECT_DAMAGE_IMMUNITY"]
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -188,7 +188,7 @@ ui32 BattleInfo::calculateHealedHP(const CSpell * spell, int usedSpellPower, int
|
||||
}
|
||||
bool BattleInfo::resurrects(SpellID spellid) const
|
||||
{
|
||||
return VLC->spellh->spells[spellid]->isRisingSpell();
|
||||
return spellid.toSpell()->isRisingSpell();
|
||||
}
|
||||
|
||||
const CStack * BattleInfo::battleGetStack(BattleHex pos, bool onlyAlive)
|
||||
@ -942,7 +942,7 @@ si32 CStack::magicResistance() const
|
||||
|
||||
void CStack::stackEffectToFeature(std::vector<Bonus> & sf, const Bonus & sse)
|
||||
{
|
||||
const CSpell * sp = VLC->spellh->spells[sse.sid];
|
||||
const CSpell * sp = SpellID(sse.sid).toSpell();
|
||||
|
||||
std::vector<Bonus> tmp;
|
||||
sp->getEffects(tmp, sse.val);
|
||||
|
@ -837,7 +837,7 @@ TDmgRange CBattleInfoCallback::calculateDmgRange(const BattleAttackInfo &info) c
|
||||
{
|
||||
if(defenderType->idNumber == affectedIds[g])
|
||||
{
|
||||
attackDefenceDifference += VLC->spellh->spells[SpellID::SLAYER]->powers[spLevel];
|
||||
attackDefenceDifference += SpellID(SpellID::SLAYER).toSpell()->powers[spLevel];
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1499,7 +1499,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleIsImmune(const C
|
||||
bool hasPositiveSpell = false;
|
||||
BOOST_FOREACH(const Bonus * b, *spellBon)
|
||||
{
|
||||
if(VLC->spellh->spells[b->sid]->isPositive())
|
||||
if(SpellID(b->sid).toSpell()->isPositive())
|
||||
{
|
||||
hasPositiveSpell = true;
|
||||
break;
|
||||
|
@ -295,7 +295,7 @@ void CCreatureHandler::loadCreatures()
|
||||
ncre.addBonus(0, Bonus::ATTACKS_ALL_ADJACENT);
|
||||
|
||||
if(boost::algorithm::find_first(ncre.abilityRefs, "IMMUNE_TO_MIND_SPELLS"))
|
||||
ncre.addBonus(0, Bonus::MIND_IMMUNITY); //giants are immune to mind spells
|
||||
ncre.addBonus(0, Bonus::MIND_IMMUNITY);
|
||||
if(boost::algorithm::find_first(ncre.abilityRefs, "IMMUNE_TO_FIRE_SPELLS"))
|
||||
ncre.addBonus(0, Bonus::FIRE_IMMUNITY);
|
||||
if(boost::algorithm::find_first(ncre.abilityRefs, "HAS_EXTENDED_ATTACK"))
|
||||
|
@ -703,6 +703,7 @@ std::string CStackInstance::bonusToString(Bonus *bonus, bool description) const
|
||||
std::string CStackInstance::bonusToGraphics(Bonus *bonus) const
|
||||
{
|
||||
std::string fileName;
|
||||
bool fullPath = false;
|
||||
switch (bonus->type)
|
||||
{
|
||||
//"E_ALIVE.bmp"
|
||||
@ -800,28 +801,9 @@ std::string CStackInstance::bonusToGraphics(Bonus *bonus) const
|
||||
//"E_SHOOTN.bmp"
|
||||
case Bonus::SPELL_IMMUNITY:
|
||||
{
|
||||
switch (bonus->subtype)
|
||||
{
|
||||
case 62: //Blind
|
||||
fileName = "E_SPBLIND.bmp"; break;
|
||||
case 35: // Dispell
|
||||
fileName = "E_SPDISP.bmp"; break;
|
||||
case 78: // Dispell beneficial spells
|
||||
fileName = "E_SPDISB.bmp"; break;
|
||||
case 60: //Hypnotize
|
||||
fileName = "E_SPHYPN.bmp"; break;
|
||||
case 18: //Implosion
|
||||
fileName = "E_SPIMP.bmp"; break;
|
||||
case 59: //Berserk
|
||||
fileName = "E_SPBERS.bmp"; break;
|
||||
case 23: //Meteor Shower
|
||||
fileName = "E_SPMET.bmp"; break;
|
||||
case 26: //Armageddon
|
||||
fileName = "E_SPARM.bmp"; break;
|
||||
case 54: //Slow
|
||||
fileName = "E_SPSLOW.bmp"; break;
|
||||
//TODO: some generic spell handling?
|
||||
}
|
||||
fullPath = true;
|
||||
const CSpell * sp = SpellID(bonus->subtype).toSpell();
|
||||
fileName = sp->getIconImmune();
|
||||
break;
|
||||
}
|
||||
//"E_SPAWILL.bmp"
|
||||
@ -909,7 +891,7 @@ std::string CStackInstance::bonusToGraphics(Bonus *bonus) const
|
||||
case Bonus::LIFE_DRAIN:
|
||||
fileName = "DrainLife.bmp"; break;
|
||||
}
|
||||
if(!fileName.empty())
|
||||
if(!fileName.empty() && !fullPath)
|
||||
fileName = "zvs/Lib1.res/" + fileName;
|
||||
return fileName;
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ void MetaString::getLocalString(const std::pair<ui8,ui32> &txt, std::string &dst
|
||||
}
|
||||
else if(type == SPELL_NAME)
|
||||
{
|
||||
dst = VLC->spellh->spells[ser]->name;
|
||||
dst = SpellID(ser).toSpell()->name;
|
||||
}
|
||||
else if(type == CRE_SING_NAMES)
|
||||
{
|
||||
@ -819,7 +819,7 @@ void CGameState::init(StartInfo * si)
|
||||
break;
|
||||
case CScenarioTravel::STravelBonus::SPELL_SCROLL:
|
||||
{
|
||||
CArtifactInstance * scroll = CArtifactInstance::createScroll(VLC->spellh->spells[curBonus->info2]);
|
||||
CArtifactInstance * scroll = CArtifactInstance::createScroll(SpellID(curBonus->info2).toSpell());
|
||||
scroll->putAt(ArtifactLocation(hero, scroll->firstAvailableSlot(hero)));
|
||||
}
|
||||
break;
|
||||
@ -1531,10 +1531,10 @@ void CGameState::init(StartInfo * si)
|
||||
}
|
||||
//init spells
|
||||
vti->spells.resize(GameConstants::SPELL_LEVELS);
|
||||
CSpell *s;
|
||||
|
||||
for(ui32 z=0; z<vti->obligatorySpells.size();z++)
|
||||
{
|
||||
s = VLC->spellh->spells[vti->obligatorySpells[z]];
|
||||
CSpell *s = vti->obligatorySpells[z].toSpell();
|
||||
vti->spells[s->level-1].push_back(s->id);
|
||||
vti->possibleSpells -= s->id;
|
||||
}
|
||||
@ -1544,7 +1544,7 @@ void CGameState::init(StartInfo * si)
|
||||
int sel = -1;
|
||||
|
||||
for(ui32 ps=0;ps<vti->possibleSpells.size();ps++)
|
||||
total += VLC->spellh->spells[vti->possibleSpells[ps]]->probabilities[vti->subID];
|
||||
total += vti->possibleSpells[ps].toSpell()->probabilities[vti->subID];
|
||||
|
||||
if (total == 0) // remaining spells have 0 probability
|
||||
break;
|
||||
@ -1552,7 +1552,7 @@ void CGameState::init(StartInfo * si)
|
||||
int r = ran()%total;
|
||||
for(ui32 ps=0; ps<vti->possibleSpells.size();ps++)
|
||||
{
|
||||
r -= VLC->spellh->spells[vti->possibleSpells[ps]]->probabilities[vti->subID];
|
||||
r -= vti->possibleSpells[ps].toSpell()->probabilities[vti->subID];
|
||||
if(r<0)
|
||||
{
|
||||
sel = ps;
|
||||
@ -1562,7 +1562,7 @@ void CGameState::init(StartInfo * si)
|
||||
if(sel<0)
|
||||
sel=0;
|
||||
|
||||
CSpell *s = VLC->spellh->spells[vti->possibleSpells[sel]];
|
||||
CSpell *s = vti->possibleSpells[sel].toSpell();
|
||||
vti->spells[s->level-1].push_back(s->id);
|
||||
vti->possibleSpells -= s->id;
|
||||
}
|
||||
|
@ -5445,7 +5445,7 @@ void CGObservatory::onHeroVisit( const CGHeroInstance * h ) const
|
||||
|
||||
void CGShrine::onHeroVisit( const CGHeroInstance * h ) const
|
||||
{
|
||||
if(spell == 255)
|
||||
if(spell == SpellID::NONE)
|
||||
{
|
||||
tlog1 << "Not initialized shrine visited!\n";
|
||||
return;
|
||||
@ -5476,7 +5476,7 @@ void CGShrine::onHeroVisit( const CGHeroInstance * h ) const
|
||||
else //give spell
|
||||
{
|
||||
std::set<SpellID> spells;
|
||||
spells.insert(SpellID(spell));
|
||||
spells.insert(spell);
|
||||
cb->changeSpells(h, true, spells);
|
||||
|
||||
iw.components.push_back(Component(Component::SPELL,spell,0,0));
|
||||
@ -5487,7 +5487,7 @@ void CGShrine::onHeroVisit( const CGHeroInstance * h ) const
|
||||
|
||||
void CGShrine::initObj()
|
||||
{
|
||||
if(spell == 255) //spell not set
|
||||
if(spell == SpellID::NONE) //spell not set
|
||||
{
|
||||
int level = ID-87;
|
||||
std::vector<SpellID> possibilities;
|
||||
@ -5509,7 +5509,7 @@ const std::string & CGShrine::getHoverText() const
|
||||
if(wasVisited(cb->getCurrentPlayer())) //TODO: use local player, not current
|
||||
{
|
||||
hoverName += "\n" + VLC->generaltexth->allTexts[355]; // + (learn %s)
|
||||
boost::algorithm::replace_first(hoverName,"%s",VLC->spellh->spells[spell]->name);
|
||||
boost::algorithm::replace_first(hoverName,"%s", spell.toSpell()->name);
|
||||
const CGHeroInstance *h = cb->getSelectedHero(cb->getCurrentPlayer());
|
||||
if(h && vstd::contains(h->spells,spell)) //hero knows that ability
|
||||
hoverName += "\n\n" + VLC->generaltexth->allTexts[354]; // (Already learned)
|
||||
@ -5557,7 +5557,7 @@ void CGScholar::onHeroVisit( const CGHeroInstance * h ) const
|
||||
if((type == SECONDARY_SKILL
|
||||
&& ((ssl == 3) || (!ssl && !h->canLearnSkill()))) ////hero already has expert level in the skill or (don't know skill and doesn't have free slot)
|
||||
|| (type == SPELL && (!h->getArt(ArtifactPosition::SPELLBOOK) || vstd::contains(h->spells, (ui32) bid)
|
||||
|| (VLC->spellh->spells[bid]->level > h->getSecSkillLevel(SecondarySkill::WISDOM) + 2)
|
||||
|| ( SpellID(bid).toSpell()->level > h->getSecSkillLevel(SecondarySkill::WISDOM) + 2)
|
||||
))) //hero doesn't have a spellbook or already knows the spell or doesn't have Wisdom
|
||||
{
|
||||
type = PRIM_SKILL;
|
||||
|
@ -957,7 +957,7 @@ public:
|
||||
class DLL_LINKAGE CGShrine : public CPlayersVisited
|
||||
{
|
||||
public:
|
||||
ui8 spell; //number of spell or 255 if random
|
||||
SpellID spell; //id of spell or NONE if random
|
||||
void onHeroVisit(const CGHeroInstance * h) const override;
|
||||
void initObj() override;
|
||||
const std::string & getHoverText() const override;
|
||||
|
@ -129,7 +129,7 @@ std::vector<BattleHex> SpellCreatedObstacle::getAffectedTiles() const
|
||||
case FIRE_WALL:
|
||||
return std::vector<BattleHex>(1, pos);
|
||||
case FORCE_FIELD:
|
||||
return VLC->spellh->spells[SpellID::FORCE_FIELD]->rangeInHexes(pos, spellLevel, casterSide);
|
||||
return SpellID(SpellID::FORCE_FIELD).toSpell()->rangeInHexes(pos, spellLevel, casterSide);
|
||||
//TODO Fire Wall
|
||||
default:
|
||||
assert(0);
|
||||
|
@ -81,7 +81,7 @@ namespace SRSLPraserHelpers
|
||||
return xy.first >=0 && xy.first < 17 && xy.second >= 0 && xy.second < 11;
|
||||
}
|
||||
|
||||
//helper fonction for std::set<ui16> CSpell::rangeInHexes(unsigned int centralHex, ui8 schoolLvl ) const
|
||||
//helper function for std::set<ui16> CSpell::rangeInHexes(unsigned int centralHex, ui8 schoolLvl ) const
|
||||
static std::set<ui16> getInRange(unsigned int center, int low, int high)
|
||||
{
|
||||
std::set<ui16> ret;
|
||||
@ -123,14 +123,10 @@ namespace SRSLPraserHelpers
|
||||
}
|
||||
|
||||
using namespace SRSLPraserHelpers;
|
||||
CSpellHandler::CSpellHandler()
|
||||
{
|
||||
}
|
||||
|
||||
CSpell::CSpell()
|
||||
{
|
||||
isDamage = false;
|
||||
isMind = false;
|
||||
isRising = false;
|
||||
isOffensive = false;
|
||||
}
|
||||
@ -235,23 +231,12 @@ std::vector<BattleHex> CSpell::rangeInHexes(BattleHex centralHex, ui8 schoolLvl,
|
||||
return ret;
|
||||
}
|
||||
|
||||
CSpell::ETargetType CSpell::getTargetType() const //TODO: parse these at game launch
|
||||
CSpell::ETargetType CSpell::getTargetType() const
|
||||
{
|
||||
if(attributes.find("CREATURE_TARGET_1") != std::string::npos
|
||||
|| attributes.find("CREATURE_TARGET_2") != std::string::npos)
|
||||
return CREATURE_EXPERT_MASSIVE;
|
||||
|
||||
if(attributes.find("CREATURE_TARGET") != std::string::npos)
|
||||
return CREATURE;
|
||||
|
||||
if(attributes.find("OBSTACLE_TARGET") != std::string::npos)
|
||||
return OBSTACLE;
|
||||
|
||||
return NO_TARGET;
|
||||
return targetType;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CSpell::getEffects(std::vector<Bonus>& lst, const int level) const
|
||||
{
|
||||
if (level < 0 || level>3)
|
||||
@ -270,6 +255,7 @@ void CSpell::getEffects(std::vector<Bonus>& lst, const int level) const
|
||||
|
||||
bool CSpell::isImmuneBy(const IBonusBearer* obj) const
|
||||
{
|
||||
//todo: use new bonus API
|
||||
BOOST_FOREACH(auto b, limiters)
|
||||
{
|
||||
if (!obj->hasBonusOfType(b))
|
||||
@ -282,24 +268,18 @@ bool CSpell::isImmuneBy(const IBonusBearer* obj) const
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isMindSpell() && obj->hasBonusOfType(Bonus::MIND_IMMUNITY))
|
||||
return true;
|
||||
|
||||
if (isDamageSpell() && obj->hasBonusOfType(Bonus::DIRECT_DAMAGE_IMMUNITY))
|
||||
return true;
|
||||
|
||||
auto battleTestElementalImmunity = [&,this](Bonus::BonusType element) -> bool
|
||||
{
|
||||
if (!isPositive()) //negative or indifferent
|
||||
{
|
||||
if ((isDamageSpell() && obj->hasBonusOfType(element, 2)) || obj->hasBonusOfType(element, 1))
|
||||
return true;
|
||||
}
|
||||
else if (isPositive()) //positive
|
||||
if (isPositive())
|
||||
{
|
||||
if (obj->hasBonusOfType(element, 0)) //must be immune to all spells
|
||||
return true;
|
||||
}
|
||||
else //negative or indifferent
|
||||
{
|
||||
if ((isDamageSpell() && obj->hasBonusOfType(element, 2)) || obj->hasBonusOfType(element, 1))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
@ -325,14 +305,14 @@ bool CSpell::isImmuneBy(const IBonusBearer* obj) const
|
||||
return true;
|
||||
}
|
||||
|
||||
TBonusListPtr immunities = obj->getBonuses(Selector::type(Bonus::LEVEL_SPELL_IMMUNITY));
|
||||
TBonusListPtr levelImmunities = obj->getBonuses(Selector::type(Bonus::LEVEL_SPELL_IMMUNITY));
|
||||
if(obj->hasBonusOfType(Bonus::NEGATE_ALL_NATURAL_IMMUNITIES))
|
||||
{
|
||||
immunities->remove_if([](const Bonus* b){ return b->source == Bonus::CREATURE_ABILITY; });
|
||||
levelImmunities->remove_if([](const Bonus* b){ return b->source == Bonus::CREATURE_ABILITY; });
|
||||
}
|
||||
|
||||
if(obj->hasBonusOfType(Bonus::SPELL_IMMUNITY, id)
|
||||
|| ( immunities->size() > 0 && immunities->totalValue() >= level && level))
|
||||
|| ( levelImmunities->size() > 0 && levelImmunities->totalValue() >= level && level))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -340,6 +320,20 @@ bool CSpell::isImmuneBy(const IBonusBearer* obj) const
|
||||
return false;
|
||||
}
|
||||
|
||||
void CSpell::setAttributes(const std::string& newValue)
|
||||
{
|
||||
attributes = newValue;
|
||||
if(attributes.find("CREATURE_TARGET_1") != std::string::npos
|
||||
|| attributes.find("CREATURE_TARGET_2") != std::string::npos)
|
||||
targetType = CREATURE_EXPERT_MASSIVE;
|
||||
else if(attributes.find("CREATURE_TARGET") != std::string::npos)
|
||||
targetType = CREATURE;
|
||||
else if(attributes.find("OBSTACLE_TARGET") != std::string::npos)
|
||||
targetType = OBSTACLE;
|
||||
else
|
||||
targetType = NO_TARGET;
|
||||
}
|
||||
|
||||
|
||||
bool DLL_LINKAGE isInScreenRange(const int3 ¢er, const int3 &pos)
|
||||
{
|
||||
@ -350,10 +344,16 @@ bool DLL_LINKAGE isInScreenRange(const int3 ¢er, const int3 &pos)
|
||||
return false;
|
||||
}
|
||||
|
||||
CSpell * CSpellHandler::loadSpell(CLegacyConfigParser & parser)
|
||||
CSpellHandler::CSpellHandler()
|
||||
{
|
||||
}
|
||||
|
||||
CSpell * CSpellHandler::loadSpell(CLegacyConfigParser & parser, const SpellID id)
|
||||
{
|
||||
CSpell * spell = new CSpell; //new currently being read spell
|
||||
|
||||
spell->id = id;
|
||||
|
||||
spell->name = parser.readString();
|
||||
spell->abbName = parser.readString();
|
||||
spell->level = parser.readNumber();
|
||||
@ -375,7 +375,24 @@ CSpell * CSpellHandler::loadSpell(CLegacyConfigParser & parser)
|
||||
for (int i = 0; i < 4 ; i++)
|
||||
spell->descriptions.push_back(parser.readString());
|
||||
|
||||
spell->attributes = parser.readString();
|
||||
std::string attributes = parser.readString();
|
||||
|
||||
|
||||
//spell fixes
|
||||
if (id == SpellID::FORGETFULNESS)
|
||||
{
|
||||
//forgetfulness needs to get targets automatically on expert level
|
||||
boost::replace_first(attributes, "CREATURE_TARGET", "CREATURE_TARGET_2");
|
||||
}
|
||||
|
||||
if (id == SpellID::DISRUPTING_RAY)
|
||||
{
|
||||
// disrupting ray will now affect single creature
|
||||
boost::replace_first(attributes,"2", "");
|
||||
}
|
||||
|
||||
|
||||
spell->setAttributes(attributes);
|
||||
spell->mainEffectAnim = -1;
|
||||
return spell;
|
||||
}
|
||||
@ -388,8 +405,8 @@ void CSpellHandler::loadSpells()
|
||||
{
|
||||
do
|
||||
{
|
||||
CSpell * spell = loadSpell(parser);
|
||||
spell->id = SpellID(spells.size());
|
||||
const SpellID id = SpellID(spells.size());
|
||||
CSpell * spell = loadSpell(parser,id);
|
||||
spell->combatSpell = combat;
|
||||
spell->creatureAbility = alility;
|
||||
spells.push_back(spell);
|
||||
@ -410,9 +427,6 @@ void CSpellHandler::loadSpells()
|
||||
skip(3);
|
||||
read(true,true);//read creature abilities
|
||||
|
||||
boost::replace_first (spells[SpellID::DISRUPTING_RAY]->attributes, "2", ""); // disrupting ray will now affect single creature
|
||||
|
||||
|
||||
spells.push_back(spells[SpellID::ACID_BREATH_DEFENSE]); //clone Acid Breath attributes for Acid Breath damage effect
|
||||
|
||||
//loading of additional spell traits
|
||||
@ -452,10 +466,6 @@ void CSpellHandler::loadSpells()
|
||||
{
|
||||
s->isRising = true;
|
||||
}
|
||||
else if (flag == "mind")
|
||||
{
|
||||
s->isMind = true;
|
||||
}
|
||||
else if (flag == "offensive")
|
||||
{
|
||||
s->isOffensive = true;
|
||||
@ -519,12 +529,14 @@ void CSpellHandler::loadSpells()
|
||||
read_node("immunity",s->immunities);
|
||||
read_node("limit",s->limiters);
|
||||
|
||||
const JsonNode & graphicsNode = spell.second["graphics"];
|
||||
if (!graphicsNode.isNull())
|
||||
{
|
||||
const JsonNode& iconImmune = graphicsNode["iconImmune"];
|
||||
if (!iconImmune.isNull())
|
||||
s->iconImmune = iconImmune.String();
|
||||
}
|
||||
}
|
||||
|
||||
//spell fixes
|
||||
|
||||
//forgetfulness needs to get targets automatically on expert level
|
||||
boost::replace_first(spells[SpellID::FORGETFULNESS]->attributes, "CREATURE_TARGET", "CREATURE_TARGET_2"); //TODO: use flags instead?
|
||||
}
|
||||
|
||||
std::vector<bool> CSpellHandler::getDefaultAllowedSpells() const
|
||||
|
@ -38,7 +38,7 @@ public:
|
||||
std::vector<si32> powers; //[er skill level: 0 - none, 1 - basic, etc
|
||||
std::map<TFaction, si32> probabilities; //% chance to gain for castles
|
||||
std::vector<si32> AIVals; //AI values: per skill level: 0 - none, 1 - basic, etc
|
||||
std::string attributes; //reference only attributes
|
||||
|
||||
bool combatSpell; //is this spell combat (true) or adventure (false)
|
||||
bool creatureAbility; //if true, only creatures can use this spell
|
||||
si8 positiveness; //1 if spell is positive for influenced stacks, 0 if it is indifferent, -1 if it's negative
|
||||
@ -60,7 +60,6 @@ public:
|
||||
|
||||
inline bool isRisingSpell() const;
|
||||
inline bool isDamageSpell() const;
|
||||
inline bool isMindSpell() const; //TODO: deprecated - remove, refactor
|
||||
inline bool isOffensiveSpell() const;
|
||||
|
||||
inline bool hasEffects() const;
|
||||
@ -68,26 +67,42 @@ public:
|
||||
|
||||
bool isImmuneBy(const IBonusBearer *obj) const;
|
||||
|
||||
/**
|
||||
* Returns resource name of icon for SPELL_IMMUNITY bonus
|
||||
*/
|
||||
inline const std::string& getIconImmune() const;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & identifier & id & name & abbName & descriptions & level & earth & water & fire & air & power & costs
|
||||
& powers & probabilities & AIVals & attributes & combatSpell & creatureAbility & positiveness & range & counteredSpells & mainEffectAnim;
|
||||
h & isRising & isDamage & isMind;
|
||||
h & isRising & isDamage & isOffensive;
|
||||
h & targetType;
|
||||
h & effects & immunities & limiters;
|
||||
h & iconImmune;
|
||||
}
|
||||
friend class CSpellHandler;
|
||||
|
||||
private:
|
||||
|
||||
|
||||
bool isRising;
|
||||
bool isDamage;
|
||||
bool isMind;
|
||||
bool isOffensive;
|
||||
|
||||
std::string attributes; //reference only attributes
|
||||
|
||||
void setAttributes(const std::string& newValue);
|
||||
|
||||
ETargetType targetType;
|
||||
|
||||
std::vector<Bonus> effects [4];
|
||||
std::vector<Bonus::BonusType> immunities; //any of these hrants immunity
|
||||
std::vector<Bonus::BonusType> limiters; //all of them are required
|
||||
std::vector<Bonus::BonusType> immunities; //any of these grants immunity
|
||||
std::vector<Bonus::BonusType> limiters; //all of them are required to be affected
|
||||
|
||||
///graphics related stuff
|
||||
|
||||
std::string iconImmune;
|
||||
};
|
||||
|
||||
///CSpell inlines
|
||||
@ -127,11 +142,6 @@ bool CSpell::isDamageSpell() const
|
||||
return isDamage;
|
||||
}
|
||||
|
||||
bool CSpell::isMindSpell() const
|
||||
{
|
||||
return isMind;
|
||||
}
|
||||
|
||||
bool CSpell::isOffensiveSpell() const
|
||||
{
|
||||
return isOffensive;
|
||||
@ -142,11 +152,17 @@ bool CSpell::hasEffects() const
|
||||
return !effects[0].empty();
|
||||
}
|
||||
|
||||
const std::string& CSpell::getIconImmune() const
|
||||
{
|
||||
return iconImmune;
|
||||
}
|
||||
|
||||
|
||||
bool DLL_LINKAGE isInScreenRange(const int3 ¢er, const int3 &pos); //for spells like Dimension Door
|
||||
|
||||
class DLL_LINKAGE CSpellHandler
|
||||
{
|
||||
CSpell * loadSpell(CLegacyConfigParser & parser);
|
||||
CSpell * loadSpell(CLegacyConfigParser & parser, const SpellID id);
|
||||
|
||||
public:
|
||||
CSpellHandler();
|
||||
|
@ -468,7 +468,7 @@ void CTownHandler::loadTown(CTown &town, const JsonNode & source)
|
||||
|
||||
VLC->modh->identifiers.requestIdentifier("spell." + node.first, [=, &town](si32 spellID)
|
||||
{
|
||||
VLC->spellh->spells[spellID]->probabilities[town.typeID] = chance;
|
||||
SpellID(spellID).toSpell()->probabilities[town.typeID] = chance;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -744,6 +744,7 @@ public:
|
||||
SpellID(ESpellID _num = NONE) : num(_num)
|
||||
{}
|
||||
|
||||
//TODO: should this be const?
|
||||
DLL_LINKAGE CSpell * toSpell() const;
|
||||
|
||||
ID_LIKE_CLASS_COMMON(SpellID, ESpellID)
|
||||
|
@ -1097,7 +1097,7 @@ int NBonus::getCount(const CBonusSystemNode *obj, Bonus::BonusSource from, int i
|
||||
const CSpell * Bonus::sourceSpell() const
|
||||
{
|
||||
if(source == SPELL_EFFECT)
|
||||
return VLC->spellh->spells[sid];
|
||||
return SpellID(sid).toSpell();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1115,7 +1115,7 @@ std::string Bonus::Description() const
|
||||
str << VLC->arth->artifacts[sid]->Name();
|
||||
break;;
|
||||
case SPELL_EFFECT:
|
||||
str << VLC->spellh->spells[sid]->name;
|
||||
str << SpellID(sid).toSpell()->name;
|
||||
break;
|
||||
case CREATURE_ABILITY:
|
||||
str << VLC->creh->creatures[sid]->namePl;
|
||||
@ -1228,7 +1228,7 @@ namespace Selector
|
||||
{
|
||||
if(b->source == Bonus::SPELL_EFFECT)
|
||||
{
|
||||
CSpell *sp = VLC->spellh->spells[b->sid];
|
||||
CSpell *sp = SpellID(b->sid).toSpell();
|
||||
return sp->isPositive();
|
||||
}
|
||||
return false; //not a spell effect
|
||||
|
@ -199,11 +199,10 @@ ArtifactID CPrivilagedInfoCallback::getArtSync (ui32 rand, int flags, bool erase
|
||||
|
||||
void CPrivilagedInfoCallback::getAllowedSpells(std::vector<SpellID> &out, ui16 level)
|
||||
{
|
||||
|
||||
CSpell *spell;
|
||||
for (ui32 i = 0; i < gs->map->allowedSpell.size(); i++) //spellh size appears to be greater (?)
|
||||
{
|
||||
spell = VLC->spellh->spells[i];
|
||||
|
||||
const CSpell *spell = SpellID(i).toSpell();
|
||||
if (isAllowed (0, spell->id) && spell->level == level)
|
||||
{
|
||||
out.push_back(spell->id);
|
||||
|
@ -672,7 +672,7 @@ CArtifactInstance * CMapLoaderH3M::createArtifact(int aid, int spellID /*= -1*/)
|
||||
}
|
||||
else
|
||||
{
|
||||
a = CArtifactInstance::createScroll(VLC->spellh->spells[spellID]);
|
||||
a = CArtifactInstance::createScroll(SpellID(spellID).toSpell());
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1166,7 +1166,17 @@ void CMapLoaderH3M::readObjects()
|
||||
{
|
||||
CGShrine * shr = new CGShrine();
|
||||
nobj = shr;
|
||||
shr->spell = reader.readUInt8();
|
||||
ui8 raw_id = reader.readUInt8();
|
||||
|
||||
if (255 == raw_id)
|
||||
{
|
||||
shr->spell = SpellID(SpellID::NONE);
|
||||
}
|
||||
else
|
||||
{
|
||||
shr->spell = SpellID(raw_id);
|
||||
}
|
||||
|
||||
reader.skip(3);
|
||||
break;
|
||||
}
|
||||
|
@ -1199,7 +1199,7 @@ DLL_LINKAGE void StartAction::applyGs( CGameState *gs )
|
||||
}
|
||||
else
|
||||
{
|
||||
gs->curB->usedSpellsHistory[ba.side].push_back(VLC->spellh->spells[ba.additionalInfo]);
|
||||
gs->curB->usedSpellsHistory[ba.side].push_back(SpellID(ba.additionalInfo).toSpell());
|
||||
}
|
||||
|
||||
switch(ba.actionType)
|
||||
@ -1240,7 +1240,7 @@ DLL_LINKAGE void BattleSpellCast::applyGs( CGameState *gs )
|
||||
}
|
||||
|
||||
//Handle spells removing effects from stacks
|
||||
const CSpell *spell = VLC->spellh->spells[id];
|
||||
const CSpell *spell = SpellID(id).toSpell();
|
||||
const bool removeAllSpells = id == SpellID::DISPEL;
|
||||
const bool removeHelpful = id == SpellID::DISPEL_HELPFUL_SPELLS;
|
||||
|
||||
|
@ -827,7 +827,7 @@ void CGameHandler::prepareAttack(BattleAttack &bat, const CStack *att, const CSt
|
||||
bat.bsa.front().flags |= BattleStackAttacked::EFFECT;
|
||||
bat.bsa.front().effect = VLC->spellh->spells[bonus->subtype]->mainEffectAnim; //hopefully it does not interfere with any other effect?
|
||||
|
||||
std::set<const CStack*> attackedCreatures = gs->curB->getAffectedCreatures(VLC->spellh->spells[bonus->subtype], bonus->val, att->owner, targetHex);
|
||||
std::set<const CStack*> attackedCreatures = gs->curB->getAffectedCreatures(SpellID(bonus->subtype).toSpell(), bonus->val, att->owner, targetHex);
|
||||
//TODO: get exact attacked hex for defender
|
||||
|
||||
BOOST_FOREACH(const CStack * stack, attackedCreatures)
|
||||
@ -3913,7 +3913,7 @@ void CGameHandler::playerMessage( TPlayerColor player, const std::string &messag
|
||||
void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex destination, ui8 casterSide, TPlayerColor casterColor, const CGHeroInstance * caster, const CGHeroInstance * secHero,
|
||||
int usedSpellPower, ECastingMode::ECastingMode mode, const CStack * stack, si32 selectedStack)
|
||||
{
|
||||
const CSpell *spell = VLC->spellh->spells[spellID];
|
||||
const CSpell *spell = SpellID(spellID).toSpell();
|
||||
|
||||
|
||||
//Helper local function that creates obstacle on given position. Obstacle type is inferred from spell type.
|
||||
@ -3977,7 +3977,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
|
||||
|
||||
if (caster) //calculate spell cost
|
||||
{
|
||||
sc.spellCost = gs->curB->battleGetSpellCost(VLC->spellh->spells[spellID], caster);
|
||||
sc.spellCost = gs->curB->battleGetSpellCost(SpellID(spellID).toSpell(), caster);
|
||||
|
||||
if (secHero && mode == ECastingMode::HERO_CASTING) //handle mana channel
|
||||
{
|
||||
@ -4290,8 +4290,9 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
|
||||
//TODO stack casting -> probably power will be zero; set the proper number of creatures manually
|
||||
int percentBonus = caster ? caster->valOfBonuses(Bonus::SPECIFIC_SPELL_DAMAGE, spellID) : 0;
|
||||
|
||||
bsa.amount = usedSpellPower * VLC->spellh->spells[spellID]->powers[spellLvl] *
|
||||
(100 + percentBonus) / 100.0; //new feature - percentage bonus
|
||||
bsa.amount = usedSpellPower
|
||||
* SpellID(spellID).toSpell()->powers[spellLvl]
|
||||
* (100 + percentBonus) / 100.0; //new feature - percentage bonus
|
||||
if(bsa.amount)
|
||||
sendAndApply(&bsa);
|
||||
else
|
||||
@ -4440,7 +4441,7 @@ bool CGameHandler::makeCustomAction( BattleAction &ba )
|
||||
return false;
|
||||
}
|
||||
|
||||
const CSpell *s = VLC->spellh->spells[ba.additionalInfo];
|
||||
const CSpell *s = SpellID(ba.additionalInfo).toSpell();
|
||||
if (s->mainEffectAnim > -1 || (s->id >= 66 || s->id <= 69) || s->id == SpellID::CLONE) //allow summon elementals
|
||||
//TODO: special effects, like Clone
|
||||
{
|
||||
@ -4590,7 +4591,7 @@ void CGameHandler::stackTurnTrigger(const CStack * st)
|
||||
{
|
||||
int index = rand() % bl.size();
|
||||
int spellID = bl[index]->subtype; //spell ID
|
||||
if (gs->curB->battleCanCastThisSpell(st->owner, VLC->spellh->spells[spellID], ECastingMode::ENCHANTER_CASTING)) //TODO: select another?
|
||||
if (gs->curB->battleCanCastThisSpell(st->owner, SpellID(spellID).toSpell(), ECastingMode::ENCHANTER_CASTING)) //TODO: select another?
|
||||
{
|
||||
int spellLeveL = bl[index]->val; //spell level
|
||||
const CGHeroInstance * enemyHero = gs->curB->getHero(gs->curB->theOtherPlayer(st->owner));
|
||||
@ -4654,14 +4655,14 @@ void CGameHandler::handleDamageFromObstacle(const CObstacleInstance &obstacle, c
|
||||
|
||||
oneTimeObstacle = true;
|
||||
effect = 82; //makes
|
||||
damage = gs->curB->calculateSpellDmg(VLC->spellh->spells[SpellID::LAND_MINE], hero, curStack,
|
||||
damage = gs->curB->calculateSpellDmg(SpellID(SpellID::LAND_MINE).toSpell(), hero, curStack,
|
||||
spellObstacle->spellLevel, spellObstacle->casterSpellPower);
|
||||
//TODO even if obstacle wasn't created by hero (Tower "moat") it should deal dmg as if casted by hero,
|
||||
//if it is bigger than default dmg. Or is it just irrelevant H3 implementation quirk
|
||||
}
|
||||
else if(obstacle.obstacleType == CObstacleInstance::FIRE_WALL)
|
||||
{
|
||||
damage = gs->curB->calculateSpellDmg(VLC->spellh->spells[SpellID::FIRE_WALL], hero, curStack,
|
||||
damage = gs->curB->calculateSpellDmg(SpellID(SpellID::FIRE_WALL).toSpell(), hero, curStack,
|
||||
spellObstacle->spellLevel, spellObstacle->casterSpellPower);
|
||||
}
|
||||
else
|
||||
@ -5302,7 +5303,7 @@ void CGameHandler::attackCasting(const BattleAttack & bat, Bonus::BonusType atta
|
||||
vstd::amin (chance, 100);
|
||||
int destination = oneOfAttacked->position;
|
||||
|
||||
const CSpell * spell = VLC->spellh->spells[spellID];
|
||||
const CSpell * spell = SpellID(spellID).toSpell();
|
||||
if(gs->curB->battleCanCastThisSpellHere(attacker->owner, spell, ECastingMode::AFTER_ATTACK_CASTING, oneOfAttacked->position) != ESpellCastProblem::OK)
|
||||
continue;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user