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);
|
||||
|
@ -817,7 +817,7 @@ TDmgRange CBattleInfoCallback::calculateDmgRange(const BattleAttackInfo &info) c
|
||||
if(const Bonus *slayerEffect = info.attackerBonuses->getEffect(SpellID::SLAYER)) //slayer handling //TODO: apply only ONLY_MELEE_FIGHT / DISTANCE_FIGHT?
|
||||
{
|
||||
std::vector<int> affectedIds;
|
||||
int spLevel = slayerEffect->val;
|
||||
int spLevel = slayerEffect->val;
|
||||
|
||||
for(int g = 0; g < VLC->creh->creatures.size(); ++g)
|
||||
{
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -1476,7 +1476,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleIsImmune(const C
|
||||
{
|
||||
if (spell->isPositive() && subject->hasBonusOfType(Bonus::RECEPTIVE)) //accept all positive spells
|
||||
return ESpellCastProblem::OK;
|
||||
|
||||
|
||||
if (spell->isImmuneBy(subject)) //TODO: move all logic to spellhandler
|
||||
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
|
||||
|
||||
@ -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"))
|
||||
@ -925,7 +925,7 @@ void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigPars
|
||||
case 'K':
|
||||
case 'k':
|
||||
b.type = Bonus::SPELL_AFTER_ATTACK;
|
||||
b.subtype = stringToNumber(mod);
|
||||
b.subtype = stringToNumber(mod);
|
||||
break;
|
||||
case 'h':
|
||||
b.type= Bonus::HATE;
|
||||
@ -1018,7 +1018,7 @@ CreatureID CCreatureHandler::pickRandomMonster(const boost::function<int()> &ran
|
||||
int r = 0;
|
||||
if(tier == -1) //pick any allowed creature
|
||||
{
|
||||
do
|
||||
do
|
||||
{
|
||||
r = vstd::pickRandomElementOf(creatures, randGen)->idNumber;
|
||||
} while (vstd::contains(VLC->creh->notUsedMonsters,r));
|
||||
|
@ -299,7 +299,7 @@ void CCreatureSet::eraseStack(TSlot slot)
|
||||
|
||||
bool CCreatureSet::contains(const CStackInstance *stack) const
|
||||
{
|
||||
if(!stack)
|
||||
if(!stack)
|
||||
return false;
|
||||
|
||||
for(TSlots::const_iterator i = stacks.begin(); i != stacks.end(); ++i)
|
||||
@ -315,7 +315,7 @@ TSlot CCreatureSet::findStack(const CStackInstance *stack) const
|
||||
if (h && h->commander == stack)
|
||||
return -2;
|
||||
|
||||
if(!stack)
|
||||
if(!stack)
|
||||
return -1;
|
||||
|
||||
for(TSlots::const_iterator i = stacks.begin(); i != stacks.end(); ++i)
|
||||
@ -345,7 +345,7 @@ void CCreatureSet::joinStack(TSlot slot, CStackInstance * stack)
|
||||
assert(c == stack->type);
|
||||
assert(c);
|
||||
|
||||
//TODO move stuff
|
||||
//TODO move stuff
|
||||
changeStackCount(slot, stack->count);
|
||||
vstd::clear_pointer(stack);
|
||||
}
|
||||
@ -486,10 +486,10 @@ void CStackInstance::init()
|
||||
type = NULL;
|
||||
idRand = -1;
|
||||
_armyObj = NULL;
|
||||
setNodeType(STACK_INSTANCE);
|
||||
setNodeType(STACK_INSTANCE);
|
||||
}
|
||||
|
||||
int CStackInstance::getQuantityID() const
|
||||
int CStackInstance::getQuantityID() const
|
||||
{
|
||||
return CCreature::getQuantityID(count);
|
||||
}
|
||||
@ -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"
|
||||
@ -853,7 +835,7 @@ std::string CStackInstance::bonusToGraphics(Bonus *bonus) const
|
||||
fileName = "E_SPCOLD.bmp"; break; //direct damage
|
||||
}
|
||||
break;
|
||||
case Bonus::AIR_IMMUNITY:
|
||||
case Bonus::AIR_IMMUNITY:
|
||||
switch (bonus->subtype)
|
||||
{
|
||||
case 0:
|
||||
@ -864,7 +846,7 @@ std::string CStackInstance::bonusToGraphics(Bonus *bonus) const
|
||||
fileName = "E_LIGHT.bmp"; break;//direct damage
|
||||
}
|
||||
break;
|
||||
case Bonus::EARTH_IMMUNITY:
|
||||
case Bonus::EARTH_IMMUNITY:
|
||||
switch (bonus->subtype)
|
||||
{
|
||||
case 0:
|
||||
@ -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;
|
||||
}
|
||||
@ -981,7 +963,7 @@ CreatureID CStackInstance::getCreatureID() const
|
||||
{
|
||||
if(type)
|
||||
return type->idNumber;
|
||||
else
|
||||
else
|
||||
return CreatureID::NONE;
|
||||
}
|
||||
|
||||
|
@ -161,10 +161,10 @@ void MetaString::getLocalString(const std::pair<ui8,ui32> &txt, std::string &dst
|
||||
else if(type == MINE_EVNTS)
|
||||
{
|
||||
dst = VLC->generaltexth->mines[ser].second;
|
||||
}
|
||||
}
|
||||
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;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@ namespace GameConstants
|
||||
{
|
||||
const std::string VCMI_VERSION = "VCMI 0.91b";
|
||||
|
||||
/*
|
||||
/*
|
||||
* DATA_DIR contains the game data (Data/, MP3/, ...).
|
||||
* BIN_DIR is where the vcmiclient/vcmiserver binaries reside
|
||||
* LIB_DIR is where the AI libraries reside (linux only)
|
||||
@ -306,7 +306,7 @@ namespace EMarketMode
|
||||
{
|
||||
enum EMarketMode
|
||||
{
|
||||
RESOURCE_RESOURCE, RESOURCE_PLAYER, CREATURE_RESOURCE, RESOURCE_ARTIFACT,
|
||||
RESOURCE_RESOURCE, RESOURCE_PLAYER, CREATURE_RESOURCE, RESOURCE_ARTIFACT,
|
||||
ARTIFACT_RESOURCE, ARTIFACT_EXP, CREATURE_EXP, CREATURE_UNDEAD, RESOURCE_SKILL,
|
||||
MARTKET_AFTER_LAST_PLACEHOLDER
|
||||
};
|
||||
@ -419,7 +419,7 @@ public:
|
||||
RANDOM_MAJOR_ART = 68,
|
||||
RANDOM_RELIC_ART = 69,
|
||||
RANDOM_HERO = 70,
|
||||
RANDOM_MONSTER = 71,
|
||||
RANDOM_MONSTER = 71,
|
||||
RANDOM_MONSTER_L1 = 72,
|
||||
RANDOM_MONSTER_L2 = 73,
|
||||
RANDOM_MONSTER_L3 = 74,
|
||||
@ -461,7 +461,7 @@ public:
|
||||
WATERING_HOLE = 110,
|
||||
WHIRLPOOL = 111,
|
||||
WINDMILL = 112,
|
||||
WITCH_HUT = 113,
|
||||
WITCH_HUT = 113,
|
||||
HOLE = 124,
|
||||
RANDOM_MONSTER_L5 = 162,
|
||||
RANDOM_MONSTER_L6 = 163,
|
||||
@ -574,7 +574,7 @@ ID_LIKE_OPERATORS_DECLS(ETerrainType, ETerrainType::EETerrainType)
|
||||
class BFieldType
|
||||
{
|
||||
public:
|
||||
// 1. sand/shore 2. sand/mesas 3. dirt/birches 4. dirt/hills 5. dirt/pines 6. grass/hills 7. grass/pines
|
||||
// 1. sand/shore 2. sand/mesas 3. dirt/birches 4. dirt/hills 5. dirt/pines 6. grass/hills 7. grass/pines
|
||||
//8. lava 9. magic plains 10. snow/mountains 11. snow/trees 12. subterranean 13. swamp/trees 14. fiery fields
|
||||
//15. rock lands 16. magic clouds 17. lucid pools 18. holy ground 19. clover field 20. evil fog
|
||||
//21. "favourable winds" text on magic plains background 22. cursed ground 23. rough 24. ship to ship 25. ship
|
||||
@ -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)
|
||||
|
@ -40,7 +40,7 @@
|
||||
|
||||
#define BONUS_ITEM(x) ( #x, Bonus::x )
|
||||
|
||||
const std::map<std::string, int> bonusDurationMap = boost::assign::map_list_of
|
||||
const std::map<std::string, int> bonusDurationMap = boost::assign::map_list_of
|
||||
BONUS_ITEM(PERMANENT)
|
||||
BONUS_ITEM(ONE_BATTLE)
|
||||
BONUS_ITEM(ONE_DAY)
|
||||
@ -156,9 +156,9 @@ int BonusList::totalValue() const
|
||||
if(hasIndepMin && hasIndepMax)
|
||||
assert(indepMin < indepMax);
|
||||
|
||||
const int notIndepBonuses = boost::count_if(bonuses, [](const Bonus *b)
|
||||
{
|
||||
return b->valType != Bonus::INDEPENDENT_MAX && b->valType != Bonus::INDEPENDENT_MIN;
|
||||
const int notIndepBonuses = boost::count_if(bonuses, [](const Bonus *b)
|
||||
{
|
||||
return b->valType != Bonus::INDEPENDENT_MAX && b->valType != Bonus::INDEPENDENT_MIN;
|
||||
});
|
||||
|
||||
if (hasIndepMax)
|
||||
@ -260,7 +260,7 @@ void BonusList::eliminateDuplicates()
|
||||
void BonusList::push_back(Bonus* const &x)
|
||||
{
|
||||
bonuses.push_back(x);
|
||||
|
||||
|
||||
if (belongsToTree)
|
||||
CBonusSystemNode::incrementTreeChangedNum();
|
||||
}
|
||||
@ -317,7 +317,7 @@ int IBonusBearer::valOfBonuses(Bonus::BonusType type, int subtype /*= -1*/) cons
|
||||
{
|
||||
std::stringstream cachingStr;
|
||||
cachingStr << "type_" << type << "s_" << subtype;
|
||||
|
||||
|
||||
CSelector s = Selector::type(type);
|
||||
if(subtype != -1)
|
||||
s = s && Selector::subtype(subtype);
|
||||
@ -393,7 +393,7 @@ int IBonusBearer::MoraleVal() const
|
||||
if(hasBonusOfType(Bonus::NON_LIVING) || hasBonusOfType(Bonus::UNDEAD) ||
|
||||
hasBonusOfType(Bonus::NO_MORALE) || hasBonusOfType(Bonus::SIEGE_WEAPON))
|
||||
return 0;
|
||||
|
||||
|
||||
int ret = valOfBonuses(Bonus::MORALE);
|
||||
|
||||
if(hasBonusOfType(Bonus::SELF_MORALE)) //eg. minotaur
|
||||
@ -406,9 +406,9 @@ int IBonusBearer::LuckVal() const
|
||||
{
|
||||
if(hasBonusOfType(Bonus::NO_LUCK))
|
||||
return 0;
|
||||
|
||||
|
||||
int ret = valOfBonuses(Bonus::LUCK);
|
||||
|
||||
|
||||
if(hasBonusOfType(Bonus::SELF_LUCK)) //eg. halfling
|
||||
vstd::amax(ret, +1);
|
||||
|
||||
@ -461,8 +461,8 @@ ui32 IBonusBearer::getMaxDamage() const
|
||||
|
||||
si32 IBonusBearer::manaLimit() const
|
||||
{
|
||||
return si32(getPrimSkillLevel(PrimarySkill::KNOWLEDGE)
|
||||
* (100.0 + valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::INTELLIGENCE))
|
||||
return si32(getPrimSkillLevel(PrimarySkill::KNOWLEDGE)
|
||||
* (100.0 + valOfBonuses(Bonus::SECONDARY_SKILL_PREMY, SecondarySkill::INTELLIGENCE))
|
||||
/ 10.0);
|
||||
}
|
||||
|
||||
@ -580,7 +580,7 @@ void CBonusSystemNode::getParents(TNodes &out)
|
||||
{
|
||||
const CBonusSystemNode *parent = parents[i];
|
||||
out.insert(const_cast<CBonusSystemNode*>(parent));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CBonusSystemNode::getBonusesRec(BonusList &out, const CSelector &selector, const CSelector &limit) const
|
||||
@ -606,13 +606,13 @@ void CBonusSystemNode::getAllBonusesRec(BonusList &out) const
|
||||
const TBonusListPtr CBonusSystemNode::getAllBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root /*= NULL*/, const std::string &cachingStr /*= ""*/) const
|
||||
{
|
||||
bool limitOnUs = (!root || root == this); //caching won't work when we want to limit bonuses against an external node
|
||||
if (CBonusSystemNode::cachingEnabled && limitOnUs)
|
||||
if (CBonusSystemNode::cachingEnabled && limitOnUs)
|
||||
{
|
||||
// Exclusive access for one thread
|
||||
static boost::mutex m;
|
||||
boost::mutex::scoped_lock lock(m);
|
||||
|
||||
// If the bonus system tree changes(state of a single node or the relations to each other) then
|
||||
// If the bonus system tree changes(state of a single node or the relations to each other) then
|
||||
// cache all bonus objects. Selector objects doesn't matter.
|
||||
if (cachedLast != treeChanged)
|
||||
{
|
||||
@ -626,7 +626,7 @@ const TBonusListPtr CBonusSystemNode::getAllBonuses(const CSelector &selector, c
|
||||
|
||||
cachedLast = treeChanged;
|
||||
}
|
||||
|
||||
|
||||
// If a bonus system request comes with a caching string then look up in the map if there are any
|
||||
// pre-calculated bonus results. Limiters can't be cached so they have to be calculated.
|
||||
if (cachingStr != "")
|
||||
@ -642,7 +642,7 @@ const TBonusListPtr CBonusSystemNode::getAllBonuses(const CSelector &selector, c
|
||||
//We still don't have the bonuses (didn't returned them from cache)
|
||||
//Perform bonus selection
|
||||
auto ret = make_shared<BonusList>();
|
||||
cachedBonuses.getBonuses(*ret, selector, limit);
|
||||
cachedBonuses.getBonuses(*ret, selector, limit);
|
||||
|
||||
// Save the results in the cache
|
||||
if(cachingStr != "")
|
||||
@ -672,12 +672,12 @@ const TBonusListPtr CBonusSystemNode::getAllBonusesWithoutCaching(const CSelecto
|
||||
}
|
||||
else if(root)
|
||||
{
|
||||
//We want to limit our query against an external node. We get all its bonuses,
|
||||
//We want to limit our query against an external node. We get all its bonuses,
|
||||
// add the ones we're considering and see if they're cut out by limiters
|
||||
BonusList rootBonuses, limitedRootBonuses;
|
||||
getAllBonusesRec(rootBonuses);
|
||||
|
||||
BOOST_FOREACH(Bonus *b, beforeLimiting)
|
||||
BOOST_FOREACH(Bonus *b, beforeLimiting)
|
||||
rootBonuses.push_back(b);
|
||||
|
||||
rootBonuses.eliminateDuplicates();
|
||||
@ -709,7 +709,7 @@ CBonusSystemNode::~CBonusSystemNode()
|
||||
while(children.size())
|
||||
children.front()->detachFrom(this);
|
||||
}
|
||||
|
||||
|
||||
BOOST_FOREACH(Bonus *b, exportedBonuses)
|
||||
delete b;
|
||||
}
|
||||
@ -855,7 +855,7 @@ bool CBonusSystemNode::isIndependentNode() const
|
||||
|
||||
std::string CBonusSystemNode::nodeName() const
|
||||
{
|
||||
return description.size()
|
||||
return description.size()
|
||||
? description
|
||||
: std::string("Bonus system node of type ") + typeid(*this).name();
|
||||
}
|
||||
@ -1024,7 +1024,7 @@ void CBonusSystemNode::limitBonuses(const BonusList &allBonuses, BonusList &out)
|
||||
{
|
||||
assert(&allBonuses != &out); //todo should it work in-place?
|
||||
|
||||
BonusList undecided = allBonuses,
|
||||
BonusList undecided = allBonuses,
|
||||
&accepted = out;
|
||||
|
||||
while(true)
|
||||
@ -1038,13 +1038,13 @@ void CBonusSystemNode::limitBonuses(const BonusList &allBonuses, BonusList &out)
|
||||
if(decision == ILimiter::DISCARD)
|
||||
{
|
||||
undecided.erase(i);
|
||||
i--; continue;
|
||||
i--; continue;
|
||||
}
|
||||
else if(decision == ILimiter::ACCEPT)
|
||||
{
|
||||
accepted.push_back(b);
|
||||
undecided.erase(i);
|
||||
i--; continue;
|
||||
i--; continue;
|
||||
}
|
||||
else
|
||||
assert(decision == ILimiter::NOT_SURE);
|
||||
@ -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;
|
||||
@ -1124,11 +1124,11 @@ std::string Bonus::Description() const
|
||||
str << VLC->generaltexth->skillName[sid]/* << " secondary skill"*/;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
return str.str();
|
||||
}
|
||||
|
||||
Bonus::Bonus(ui16 Dur, ui8 Type, BonusSource Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype/*=-1*/)
|
||||
Bonus::Bonus(ui16 Dur, ui8 Type, BonusSource Src, si32 Val, ui32 ID, std::string Desc, si32 Subtype/*=-1*/)
|
||||
: duration(Dur), type(Type), subtype(Subtype), source(Src), val(Val), sid(ID), description(Desc)
|
||||
{
|
||||
additionalInfo = -1;
|
||||
@ -1138,7 +1138,7 @@ Bonus::Bonus(ui16 Dur, ui8 Type, BonusSource Src, si32 Val, ui32 ID, std::string
|
||||
boost::algorithm::trim(description);
|
||||
}
|
||||
|
||||
Bonus::Bonus(ui16 Dur, ui8 Type, BonusSource Src, si32 Val, ui32 ID, si32 Subtype/*=-1*/, ValueType ValType /*= ADDITIVE_VALUE*/)
|
||||
Bonus::Bonus(ui16 Dur, ui8 Type, BonusSource Src, si32 Val, ui32 ID, si32 Subtype/*=-1*/, ValueType ValType /*= ADDITIVE_VALUE*/)
|
||||
: duration(Dur), type(Type), subtype(Subtype), source(Src), val(Val), sid(ID), valType(ValType)
|
||||
{
|
||||
additionalInfo = -1;
|
||||
@ -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
|
||||
@ -1373,8 +1373,8 @@ HasAnotherBonusLimiter::HasAnotherBonusLimiter( TBonusType bonus, TBonusSubtype
|
||||
|
||||
int HasAnotherBonusLimiter::limit(const BonusLimitationContext &context) const
|
||||
{
|
||||
CSelector mySelector = isSubtypeRelevant
|
||||
? Selector::typeSubtype(type, subtype)
|
||||
CSelector mySelector = isSubtypeRelevant
|
||||
? Selector::typeSubtype(type, subtype)
|
||||
: Selector::type(type);
|
||||
|
||||
//if we have a bonus of required type accepted, limiter should accept also this bonus
|
||||
@ -1421,7 +1421,7 @@ bool CPropagatorNodeType::shouldBeAttached(CBonusSystemNode *dest)
|
||||
return nodeType == dest->getNodeType();
|
||||
}
|
||||
|
||||
CreatureNativeTerrainLimiter::CreatureNativeTerrainLimiter(int TerrainType)
|
||||
CreatureNativeTerrainLimiter::CreatureNativeTerrainLimiter(int TerrainType)
|
||||
: terrainType(TerrainType)
|
||||
{
|
||||
}
|
||||
@ -1465,7 +1465,7 @@ CreatureAlignmentLimiter::CreatureAlignmentLimiter(si8 Alignment)
|
||||
int CreatureAlignmentLimiter::limit(const BonusLimitationContext &context) const
|
||||
{
|
||||
const CCreature *c = retrieveCreature(&context.node);
|
||||
if(!c)
|
||||
if(!c)
|
||||
return true;
|
||||
switch(alignment)
|
||||
{
|
||||
@ -1503,7 +1503,7 @@ int RankRangeLimiter::limit(const BonusLimitationContext &context) const
|
||||
return true;
|
||||
}
|
||||
|
||||
int StackOwnerLimiter::limit(const BonusLimitationContext &context) const
|
||||
int StackOwnerLimiter::limit(const BonusLimitationContext &context) const
|
||||
{
|
||||
const CStack *s = retreiveStackBattle(&context.node);
|
||||
if(s)
|
||||
@ -1524,16 +1524,16 @@ StackOwnerLimiter::StackOwnerLimiter(ui8 Owner)
|
||||
: owner(Owner)
|
||||
{
|
||||
}
|
||||
// int Bonus::limit(const BonusLimitationContext &context) const
|
||||
// 1162 {
|
||||
// 1163 if (limiter)
|
||||
// 1164 return limiter->callNext(context);
|
||||
// 1165 else
|
||||
// 1166 return ILimiter::ACCEPT; //accept if there's no limiter
|
||||
// 1167 }
|
||||
//1168
|
||||
// int Bonus::limit(const BonusLimitationContext &context) const
|
||||
// 1162 {
|
||||
// 1163 if (limiter)
|
||||
// 1164 return limiter->callNext(context);
|
||||
// 1165 else
|
||||
// 1166 return ILimiter::ACCEPT; //accept if there's no limiter
|
||||
// 1167 }
|
||||
//1168
|
||||
|
||||
int LimiterList::limit( const BonusLimitationContext &context ) const
|
||||
int LimiterList::limit( const BonusLimitationContext &context ) const
|
||||
{
|
||||
bool wasntSure = false;
|
||||
|
||||
|
@ -37,7 +37,7 @@
|
||||
extern boost::rand48 ran;
|
||||
|
||||
CGameState * CPrivilagedInfoCallback::gameState ()
|
||||
{
|
||||
{
|
||||
return gs;
|
||||
}
|
||||
|
||||
@ -92,7 +92,7 @@ void CPrivilagedInfoCallback::getTilesInRange( boost::unordered_set<int3, ShashI
|
||||
double distance = pos.dist2d(int3(xd,yd,pos.z)) - 0.5;
|
||||
if(distance <= radious)
|
||||
{
|
||||
if(player < 0
|
||||
if(player < 0
|
||||
|| (mode == 1 && team->fogOfWarMap[xd][yd][pos.z]==0)
|
||||
|| (mode == -1 && team->fogOfWarMap[xd][yd][pos.z]==1)
|
||||
)
|
||||
@ -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);
|
||||
@ -394,7 +393,7 @@ std::vector<const CGObjectInstance*> CGameInfoCallback::getGuardingCreatures (in
|
||||
bool CGameInfoCallback::getHeroInfo( const CGObjectInstance *hero, InfoAboutHero &dest ) const
|
||||
{
|
||||
const CGHeroInstance *h = dynamic_cast<const CGHeroInstance *>(hero);
|
||||
|
||||
|
||||
ERROR_RET_VAL_IF(!h, "That's not a hero!", false);
|
||||
ERROR_RET_VAL_IF(!isVisible(h->getPosition(false)), "That hero is not visible!", false);
|
||||
|
||||
@ -448,7 +447,7 @@ bool CGameInfoCallback::isVisible(const CGObjectInstance *obj) const
|
||||
// const CArmedInstance *armi = dynamic_cast<const CArmedInstance*>(obj);
|
||||
// if(!armi)
|
||||
// return NULL;
|
||||
// else
|
||||
// else
|
||||
// return armi;
|
||||
// }
|
||||
|
||||
@ -509,7 +508,7 @@ std::vector<const CGHeroInstance *> CGameInfoCallback::getAvailableHeroes(const
|
||||
ret.resize(gs->players[*player].availableHeroes.size());
|
||||
std::copy(gs->players[*player].availableHeroes.begin(),gs->players[*player].availableHeroes.end(),ret.begin());
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
const TerrainTile * CGameInfoCallback::getTile( int3 tile, bool verbose) const
|
||||
{
|
||||
@ -573,7 +572,7 @@ EBuildingState::EBuildingState CGameInfoCallback::canBuildStructure( const CGTow
|
||||
else if(ID == BuildingID::SHIPYARD)
|
||||
{
|
||||
const TerrainTile *tile = getTile(t->bestLocation(), false);
|
||||
|
||||
|
||||
if(!tile || tile->terType != ETerrainType::WATER)
|
||||
return EBuildingState::NO_WATER; //lack of water
|
||||
}
|
||||
@ -653,7 +652,7 @@ int CGameInfoCallback::getHeroCount( TPlayerColor player, bool includeGarrisoned
|
||||
int ret = 0;
|
||||
const PlayerState *p = gs->getPlayer(player);
|
||||
ERROR_RET_VAL_IF(!p, "No such player!", -1);
|
||||
|
||||
|
||||
if(includeGarrisoned)
|
||||
return p->heroes.size();
|
||||
else
|
||||
|
@ -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