mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
[refactor]
* spells are now more configurable (unused yet, WiP) * a few more cleanups
This commit is contained in:
parent
264ce77ec9
commit
68e91ada1c
File diff suppressed because it is too large
Load Diff
@ -186,7 +186,7 @@ ui32 BattleInfo::calculateHealedHP(const CSpell * spell, int usedSpellPower, int
|
||||
}
|
||||
bool BattleInfo::resurrects(TSpell spellid) const
|
||||
{
|
||||
return vstd::contains(VLC->spellh->risingSpells, spellid);
|
||||
return VLC->spellh->spells[spellid]->isRisingSpell();
|
||||
}
|
||||
|
||||
const CStack * BattleInfo::battleGetStack(BattleHex pos, bool onlyAlive)
|
||||
@ -931,170 +931,146 @@ si32 CStack::magicResistance() const
|
||||
|
||||
void CStack::stackEffectToFeature(std::vector<Bonus> & sf, const Bonus & sse)
|
||||
{
|
||||
si32 power = VLC->spellh->spells[sse.sid]->powers[sse.val];
|
||||
//TODO: get rid of this spaghetti code
|
||||
|
||||
const CSpell * sp = VLC->spellh->spells[sse.sid];
|
||||
si32 power = sp->powers[sse.val];
|
||||
|
||||
auto add = [&](Bonus::BonusType type, si16 subtype, si32 value,si32 additionalInfo = 0, si32 limit = Bonus::NO_LIMIT)
|
||||
{
|
||||
sf.push_back(featureGenerator(type, subtype, value, sse.turnsRemain,additionalInfo, limit));
|
||||
sf.back().sid = sse.sid;
|
||||
};
|
||||
|
||||
auto addVT = [&](Bonus::BonusType type, si16 subtype, si32 value, ui8 valType,si32 additionalInfo = 0, si32 limit = Bonus::NO_LIMIT)
|
||||
{
|
||||
add(type, subtype, value, additionalInfo, limit);
|
||||
sf.back().valType = valType;
|
||||
};
|
||||
|
||||
auto addDur = [&](Bonus::BonusType type, si16 subtype, si32 value, ui8 duration ,si32 additionalInfo = 0, si32 limit = Bonus::NO_LIMIT)
|
||||
{
|
||||
add(type, subtype, value, additionalInfo, limit);
|
||||
sf.back().duration = duration;
|
||||
};
|
||||
|
||||
switch(sse.sid)
|
||||
{
|
||||
case 27: //shield
|
||||
sf.push_back(featureGenerator(Bonus::GENERAL_DAMAGE_REDUCTION, 0, power, sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 28: //air shield
|
||||
sf.push_back(featureGenerator(Bonus::GENERAL_DAMAGE_REDUCTION, 1, power, sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 29: //fire shield
|
||||
sf.push_back(featureGenerator(Bonus::FIRE_SHIELD, 0, power, sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 30: //protection from air
|
||||
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 0, power, sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 31: //protection from fire
|
||||
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 1, power, sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 32: //protection from water
|
||||
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 2, power, sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 33: //protection from earth
|
||||
sf.push_back(featureGenerator(Bonus::SPELL_DAMAGE_REDUCTION, 3, power, sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 34: //anti-magic
|
||||
sf.push_back(featureGenerator(Bonus::LEVEL_SPELL_IMMUNITY, GameConstants::SPELL_LEVELS, power - 1, sse.turnsRemain));
|
||||
sf.back().valType = Bonus::INDEPENDENT_MAX;
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 36: //magic mirror
|
||||
sf.push_back(featureGenerator(Bonus::MAGIC_MIRROR, -1, power, sse.turnsRemain));
|
||||
sf.back().valType = Bonus::INDEPENDENT_MAX;
|
||||
sf.back().sid = sse.sid;
|
||||
case 41: //bless
|
||||
sf.push_back(featureGenerator(Bonus::ALWAYS_MAXIMUM_DAMAGE, -1, power, sse.turnsRemain));
|
||||
sf.back().valType = Bonus::INDEPENDENT_MAX;
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 42: //curse
|
||||
sf.push_back(featureGenerator(Bonus::ALWAYS_MINIMUM_DAMAGE, -1, power, sse.turnsRemain, sse.val >= 2 ? 20 : 0));
|
||||
sf.back().valType = Bonus::INDEPENDENT_MAX;
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 43: //bloodlust
|
||||
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain, 0, Bonus::ONLY_MELEE_FIGHT));
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 44: //precision
|
||||
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain, 0, Bonus::ONLY_DISTANCE_FIGHT));
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 45: //weakness
|
||||
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, -1 * power, sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 46: //stone skin
|
||||
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power, sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 47: //disrupting ray
|
||||
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, -1 * power, sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
sf.back().valType = Bonus::ADDITIVE_VALUE;
|
||||
break;
|
||||
case 48: //prayer
|
||||
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power, sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
sf.push_back(featureGenerator(Bonus::STACKS_SPEED, 0, power, sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 49: //mirth
|
||||
sf.push_back(featureGenerator(Bonus::MORALE, 0, power, sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 50: //sorrow
|
||||
sf.push_back(featureGenerator(Bonus::MORALE, 0, -1 * power, sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 51: //fortune
|
||||
sf.push_back(featureGenerator(Bonus::LUCK, 0, power, sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 52: //misfortune
|
||||
sf.push_back(featureGenerator(Bonus::LUCK, 0, -1 * power, sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 53: //haste
|
||||
sf.push_back(featureGenerator(Bonus::STACKS_SPEED, 0, power, sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 54: //slow
|
||||
sf.push_back(featureGeneratorVT(Bonus::STACKS_SPEED, 0, -1 * ( 100 - power ), sse.turnsRemain, Bonus::PERCENT_TO_ALL));
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 55: //slayer
|
||||
sf.push_back(featureGenerator(Bonus::SLAYER, 0, sse.val, sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 56: //frenzy
|
||||
sf.push_back(featureGenerator(Bonus::IN_FRENZY, 0, VLC->spellh->spells[56]->powers[sse.val]/100.0, sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 58: //counterstrike
|
||||
sf.push_back(featureGenerator(Bonus::ADDITIONAL_RETALIATION, 0, power, sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 59: //bersek
|
||||
sf.push_back(featureGenerator(Bonus::ATTACKS_NEAREST_CREATURE, 0, sse.val, sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 60: //hypnotize
|
||||
sf.push_back(featureGenerator(Bonus::HYPNOTIZED, 0, sse.val, sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 61: //forgetfulness
|
||||
sf.push_back(featureGenerator(Bonus::FORGETFULL, 0, sse.val, sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case Spells::BLIND: //blind
|
||||
sf.push_back(makeFeatureVal(Bonus::NOT_ACTIVE, Bonus::UNITL_BEING_ATTACKED | Bonus::N_TURNS, sse.sid, 0, Bonus::SPELL_EFFECT, sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
sf.push_back(makeFeatureVal(Bonus::GENERAL_ATTACK_REDUCTION, Bonus::UNTIL_ATTACK | Bonus::N_TURNS, 0, power, Bonus::SPELL_EFFECT, sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
sf.push_back(makeFeatureVal(Bonus::NO_RETALIATION, Bonus::UNITL_BEING_ATTACKED, 0, 0, Bonus::SPELL_EFFECT, 0)); // don't retaliate after basilisk / unicorn attack
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case Spells::STONE_GAZE: //Stone Gaze
|
||||
case Spells::PARALYZE: //Paralyze
|
||||
sf.push_back(makeFeatureVal(Bonus::NOT_ACTIVE, Bonus::UNITL_BEING_ATTACKED | Bonus::N_TURNS, sse.sid, 0, Bonus::SPELL_EFFECT, sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
sf.push_back(makeFeatureVal(Bonus::NO_RETALIATION, Bonus::UNITL_BEING_ATTACKED, 0, 0, Bonus::SPELL_EFFECT, 0)); // don't retaliate after basilisk / unicorn attack
|
||||
sf.back().sid = sse.sid;
|
||||
case Spells::SHIELD:
|
||||
add(Bonus::GENERAL_DAMAGE_REDUCTION, 0, power);
|
||||
break;
|
||||
case 71: //Poison
|
||||
sf.push_back(featureGeneratorVT(Bonus::POISON, 0, 30, sse.turnsRemain, Bonus::INDEPENDENT_MAX)); //max hp penalty from this source
|
||||
sf.back().sid = sse.sid;
|
||||
sf.push_back(featureGeneratorVT(Bonus::STACK_HEALTH, 0, -10, sse.turnsRemain, Bonus::PERCENT_TO_ALL));
|
||||
sf.back().sid = sse.sid;
|
||||
case Spells::AIR_SHIELD:
|
||||
add(Bonus::GENERAL_DAMAGE_REDUCTION, 1, power);
|
||||
break;
|
||||
case Spells::FIRE_SHIELD:
|
||||
add(Bonus::FIRE_SHIELD, 0, power);
|
||||
break;
|
||||
case Spells::PROTECTION_FROM_AIR:
|
||||
add(Bonus::SPELL_DAMAGE_REDUCTION, 0, power);
|
||||
break;
|
||||
case Spells::PROTECTION_FROM_FIRE:
|
||||
add(Bonus::SPELL_DAMAGE_REDUCTION, 1, power);
|
||||
break;
|
||||
case Spells::PROTECTION_FROM_WATER:
|
||||
add(Bonus::SPELL_DAMAGE_REDUCTION, 2, power);
|
||||
break;
|
||||
case Spells::PROTECTION_FROM_EARTH:
|
||||
add(Bonus::SPELL_DAMAGE_REDUCTION, 3, power);
|
||||
break;
|
||||
case Spells::ANTI_MAGIC:
|
||||
addVT(Bonus::LEVEL_SPELL_IMMUNITY, GameConstants::SPELL_LEVELS, power - 1, Bonus::INDEPENDENT_MAX);break;
|
||||
case Spells::MAGIC_MIRROR:
|
||||
addVT(Bonus::MAGIC_MIRROR, -1, power,Bonus::INDEPENDENT_MAX);
|
||||
break;
|
||||
case 72: //Bind
|
||||
case Spells::BLESS:
|
||||
addVT(Bonus::ALWAYS_MAXIMUM_DAMAGE, -1, power,Bonus::INDEPENDENT_MAX);
|
||||
break;
|
||||
case Spells::CURSE:
|
||||
addVT(Bonus::ALWAYS_MINIMUM_DAMAGE, -1, power, Bonus::INDEPENDENT_MAX, sse.val >= 2 ? 20 : 0);
|
||||
break;
|
||||
case Spells::BLOODLUST:
|
||||
add(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, 0, Bonus::ONLY_MELEE_FIGHT);
|
||||
break;
|
||||
case Spells::PRECISION:
|
||||
add(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power, 0, Bonus::ONLY_DISTANCE_FIGHT);
|
||||
break;
|
||||
case Spells::WEAKNESS:
|
||||
add(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, -1 * power);
|
||||
break;
|
||||
case Spells::STONE_SKIN:
|
||||
add(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power);
|
||||
break;
|
||||
case Spells::DISRUPTING_RAY:
|
||||
addVT(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, -1 * power,Bonus::ADDITIVE_VALUE);
|
||||
break;
|
||||
case Spells::PRAYER:
|
||||
add(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, power);
|
||||
add(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, power);
|
||||
add(Bonus::STACKS_SPEED, 0, power);
|
||||
break;
|
||||
case Spells::MIRTH:
|
||||
add(Bonus::MORALE, 0, power);
|
||||
break;
|
||||
case Spells::SORROW:
|
||||
add(Bonus::MORALE, 0, -1 * power);
|
||||
break;
|
||||
case Spells::FORTUNE:
|
||||
add(Bonus::LUCK, 0, power);
|
||||
break;
|
||||
case Spells::MISFORTUNE:
|
||||
add(Bonus::LUCK, 0, -1 * power);
|
||||
break;
|
||||
case Spells::HASTE: //haste
|
||||
add(Bonus::STACKS_SPEED, 0, power);
|
||||
break;
|
||||
case Spells::SLOW:
|
||||
addVT(Bonus::STACKS_SPEED, 0, -1 * ( 100 - power ),Bonus::PERCENT_TO_ALL);
|
||||
break;
|
||||
case Spells::SLAYER:
|
||||
add(Bonus::SLAYER, 0, sse.val);
|
||||
break;
|
||||
case Spells::FRENZY:
|
||||
add(Bonus::IN_FRENZY, 0, power/100.0);
|
||||
break;
|
||||
case Spells::COUNTERSTRIKE:
|
||||
add(Bonus::ADDITIONAL_RETALIATION, 0, power);
|
||||
break;
|
||||
case Spells::BERSERK:
|
||||
add(Bonus::ATTACKS_NEAREST_CREATURE, 0, sse.val);
|
||||
break;
|
||||
case Spells::HYPNOTIZE:
|
||||
add(Bonus::HYPNOTIZED, 0, sse.val);
|
||||
break;
|
||||
case Spells::FORGETFULNESS:
|
||||
add(Bonus::FORGETFULL, 0, sse.val);
|
||||
break;
|
||||
case Spells::BLIND:
|
||||
addDur(Bonus::NOT_ACTIVE, sse.sid, 0, Bonus::UNITL_BEING_ATTACKED | Bonus::N_TURNS);
|
||||
addDur(Bonus::GENERAL_ATTACK_REDUCTION, 0, power, Bonus::UNITL_BEING_ATTACKED | Bonus::N_TURNS);
|
||||
addDur(Bonus::NO_RETALIATION,0,0, Bonus::UNITL_BEING_ATTACKED);
|
||||
break;
|
||||
case Spells::STONE_GAZE:
|
||||
case Spells::PARALYZE:
|
||||
addDur(Bonus::NOT_ACTIVE, sse.sid, 0, Bonus::UNITL_BEING_ATTACKED | Bonus::N_TURNS);
|
||||
addDur(Bonus::NO_RETALIATION,0,0, Bonus::UNITL_BEING_ATTACKED);
|
||||
break;
|
||||
case Spells::POISON: //Poison
|
||||
addVT(Bonus::POISON, 0, 30,Bonus::INDEPENDENT_MAX); //max hp penalty from this source
|
||||
addVT(Bonus::STACK_HEALTH, 0, -10, Bonus::PERCENT_TO_ALL);
|
||||
break;
|
||||
case Spells::BIND:
|
||||
sf.push_back(featureGenerator(Bonus::BIND_EFFECT, 0, 0, 1)); //marker
|
||||
sf.back().duration = Bonus::PERMANENT;
|
||||
sf.back().sid = sse.sid;
|
||||
break;
|
||||
case 73: //Disease
|
||||
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, -2 , sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, -2 , sse.turnsRemain));
|
||||
sf.back().sid = sse.sid;
|
||||
case Spells::DISEASE:
|
||||
add(Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK, -2);
|
||||
add(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, -2);
|
||||
break;
|
||||
case 75: //Age
|
||||
sf.push_back(featureGeneratorVT(Bonus::STACK_HEALTH, 0, -50, sse.turnsRemain, Bonus::PERCENT_TO_ALL));
|
||||
sf.back().sid = sse.sid;
|
||||
case Spells::AGE:
|
||||
addVT(Bonus::STACK_HEALTH, 0, -50, Bonus::PERCENT_TO_ALL);
|
||||
break;
|
||||
case 80: //Acid Breath
|
||||
case Spells::ACID_BREATH_DEFENSE:
|
||||
sf.push_back(featureGenerator(Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE, -sse.turnsRemain, 1));
|
||||
sf.back().sid = sse.sid;
|
||||
sf.back().duration = Bonus::PERMANENT;
|
||||
|
@ -33,8 +33,8 @@ struct BattleStackAttacked;
|
||||
//only for use in BattleInfo
|
||||
struct DLL_LINKAGE SiegeInfo
|
||||
{
|
||||
ui8 wallState[EWallParts::PARTS_COUNT];
|
||||
|
||||
ui8 wallState[EWallParts::PARTS_COUNT];
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & wallState;
|
||||
@ -101,7 +101,7 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallb
|
||||
|
||||
ui32 calculateDmg(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting, ui8 charge, bool lucky, bool deathBlow, bool ballistaDoubleDmg); //charge - number of hexes travelled before attack (for champion's jousting)
|
||||
void calculateCasualties(std::map<ui32,si32> *casualties) const; //casualties are array of maps size 2 (attacker, defeneder), maps are (crid => amount)
|
||||
|
||||
|
||||
//void getPotentiallyAttackableHexes(AttackableTiles &at, const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos); //hexes around target that could be attacked in melee
|
||||
//std::set<CStack*> getAttackedCreatures(const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos = BattleHex::INVALID); //calculates range of multi-hex attacks
|
||||
//std::set<BattleHex> getAttackedHexes(const CStack* attacker, BattleHex destinationTile, BattleHex attackerPos = BattleHex::INVALID); //calculates range of multi-hex attacks
|
||||
@ -114,7 +114,7 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallb
|
||||
ui32 calculateHealedHP(int healedHealth, const CSpell * spell, const CStack * stack) const; //for Archangel
|
||||
ui32 calculateHealedHP(const CSpell * spell, int usedSpellPower, int spellSchoolLevel, const CStack * stack) const; //unused
|
||||
bool resurrects(TSpell spellid) const; //TODO: move it to spellHandler?
|
||||
|
||||
|
||||
const CGHeroInstance * getHero(int player) const; //returns fighting hero that belongs to given player
|
||||
|
||||
|
||||
@ -136,7 +136,7 @@ struct DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallb
|
||||
};
|
||||
|
||||
class DLL_LINKAGE CStack : public CBonusSystemNode, public CStackBasicDescriptor
|
||||
{
|
||||
{
|
||||
public:
|
||||
const CStackInstance *base; //garrison slot from which stack originates (NULL for war machines, summoned cres, etc)
|
||||
|
||||
@ -179,7 +179,6 @@ public:
|
||||
{
|
||||
Bonus hb = makeFeatureVal(type, Bonus::N_TURNS, subtype, value, Bonus::SPELL_EFFECT, turnsRemain, additionalInfo);
|
||||
hb.effectRange = limit;
|
||||
hb.source = Bonus::SPELL_EFFECT;
|
||||
return hb;
|
||||
}
|
||||
|
||||
@ -187,7 +186,6 @@ public:
|
||||
{
|
||||
Bonus ret = makeFeatureVal(type, Bonus::N_TURNS, subtype, value, Bonus::SPELL_EFFECT, turnsRemain);
|
||||
ret.valType = valType;
|
||||
ret.source = Bonus::SPELL_EFFECT;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -782,7 +782,7 @@ TDmgRange CBattleInfoCallback::calculateDmgRange(const BattleAttackInfo &info) c
|
||||
minDmg = info.attackerBonuses->getMinDamage() * info.attackerCount,
|
||||
maxDmg = info.attackerBonuses->getMaxDamage() * info.attackerCount;
|
||||
|
||||
const CCreature *attackerType = info.attacker->getCreature(),
|
||||
const CCreature *attackerType = info.attacker->getCreature(),
|
||||
*defenderType = info.defender->getCreature();
|
||||
|
||||
if(attackerType->idNumber == 149) //arrow turret
|
||||
@ -1591,7 +1591,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleIsImmune(const C
|
||||
if (battleTestElementalImmunity(Bonus::AIR_IMMUNITY))
|
||||
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
|
||||
}
|
||||
if (vstd::contains(VLC->spellh->mindSpells, spell->id))
|
||||
if (spell->isMindSpell())
|
||||
{
|
||||
if (subject->hasBonusOfType(Bonus::MIND_IMMUNITY))
|
||||
return ESpellCastProblem::STACK_IMMUNE_TO_SPELL;
|
||||
@ -1706,7 +1706,7 @@ ESpellCastProblem::ESpellCastProblem CBattleInfoCallback::battleCanCastThisSpell
|
||||
switch(spell->getTargetType())
|
||||
{
|
||||
case CSpell::CREATURE:
|
||||
case CSpell::CREATURE_EXPERT_MASSIVE:
|
||||
case CSpell::CREATURE_EXPERT_MASSIVE:
|
||||
if(mode == ECastingMode::HERO_CASTING)
|
||||
{
|
||||
const CGHeroInstance * caster = battleGetFightingHero(side);
|
||||
@ -1909,7 +1909,7 @@ ui32 CBattleInfoCallback::calculateSpellDmg( const CSpell * sp, const CGHeroInst
|
||||
ui32 ret = 0; //value to return
|
||||
|
||||
//check if spell really does damage - if not, return 0
|
||||
if(VLC->spellh->damageSpells.find(sp->id) == VLC->spellh->damageSpells.end())
|
||||
if(!sp->isDamageSpell())
|
||||
return 0;
|
||||
|
||||
ret = usedSpellPower * sp->power;
|
||||
@ -2373,7 +2373,7 @@ const CGHeroInstance * CPlayerBattleCallback::battleGetMyHero() const
|
||||
|
||||
InfoAboutHero CPlayerBattleCallback::battleGetEnemyHero() const
|
||||
{
|
||||
InfoAboutHero ret;
|
||||
InfoAboutHero ret;
|
||||
assert(0);
|
||||
///TODO implement and replace usages of battleGetFightingHero obtaining enemy hero
|
||||
return ret;
|
||||
|
@ -176,7 +176,7 @@ void MetaString::getLocalString(const std::pair<ui8,ui32> &txt, std::string &dst
|
||||
}
|
||||
else if (type == ART_EVNTS)
|
||||
{
|
||||
dst = VLC->arth->artifacts[ser]->EventText();
|
||||
dst = VLC->arth->artifacts[ser]->EventText();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -522,7 +522,7 @@ std::pair<int,int> CGameState::pickObject (CGObjectInstance *obj)
|
||||
{
|
||||
case Obj::RANDOM_ART:
|
||||
return std::pair<int,int>(Obj::ARTIFACT, VLC->arth->getRandomArt (CArtifact::ART_TREASURE | CArtifact::ART_MINOR | CArtifact::ART_MAJOR | CArtifact::ART_RELIC));
|
||||
case Obj::RANDOM_TREASURE_ART:
|
||||
case Obj::RANDOM_TREASURE_ART:
|
||||
return std::pair<int,int>(Obj::ARTIFACT, VLC->arth->getRandomArt (CArtifact::ART_TREASURE));
|
||||
case Obj::RANDOM_MINOR_ART:
|
||||
return std::pair<int,int>(Obj::ARTIFACT, VLC->arth->getRandomArt (CArtifact::ART_MINOR));
|
||||
@ -573,7 +573,7 @@ std::pair<int,int> CGameState::pickObject (CGObjectInstance *obj)
|
||||
return std::pair<int,int>(Obj::MONSTER, VLC->creh->pickRandomMonster(boost::ref(ran), 6));
|
||||
case Obj::RANDOM_MONSTER_L7:
|
||||
return std::pair<int,int>(Obj::MONSTER, VLC->creh->pickRandomMonster(boost::ref(ran), 7));
|
||||
case Obj::RANDOM_DWELLING:
|
||||
case Obj::RANDOM_DWELLING:
|
||||
case Obj::RANDOM_DWELLING_LVL:
|
||||
case Obj::RANDOM_DWELLING_FACTION:
|
||||
{
|
||||
@ -1963,7 +1963,7 @@ std::vector<CGObjectInstance*> CGameState::guardingCreatures (int3 pos) const
|
||||
{
|
||||
if(obj->blockVisit)
|
||||
{
|
||||
if (obj->ID == 54) // Monster
|
||||
if (obj->ID == Obj::MONSTER) // Monster
|
||||
guards.push_back(obj);
|
||||
}
|
||||
}
|
||||
@ -1976,11 +1976,11 @@ std::vector<CGObjectInstance*> CGameState::guardingCreatures (int3 pos) const
|
||||
if (map->isInTheMap(pos))
|
||||
{
|
||||
TerrainTile &tile = map->terrain[pos.x][pos.y][pos.z];
|
||||
if (tile.visitable && (tile.terType == ETerrainType::WATER) == (posTile.terType == ETerrainType::WATER))
|
||||
if (tile.visitable && (tile.isWater() == posTile.isWater()))
|
||||
{
|
||||
BOOST_FOREACH (CGObjectInstance* obj, tile.visitableObjects)
|
||||
{
|
||||
if (obj->ID == 54 && checkForVisitableDir(pos, &map->getTile(originalPos), originalPos)) // Monster being able to attack investigated tile
|
||||
if (obj->ID == Obj::MONSTER && checkForVisitableDir(pos, &map->getTile(originalPos), originalPos)) // Monster being able to attack investigated tile
|
||||
{
|
||||
guards.push_back(obj);
|
||||
}
|
||||
@ -2010,7 +2010,7 @@ int3 CGameState::guardingCreaturePosition (int3 pos) const
|
||||
{
|
||||
if(obj->blockVisit)
|
||||
{
|
||||
if (obj->ID == 54) // Monster
|
||||
if (obj->ID == Obj::MONSTER) // Monster
|
||||
return pos;
|
||||
else
|
||||
return int3(-1, -1, -1); //blockvis objects are not guarded by neighbouring creatures
|
||||
@ -2027,11 +2027,11 @@ int3 CGameState::guardingCreaturePosition (int3 pos) const
|
||||
if (map->isInTheMap(pos))
|
||||
{
|
||||
TerrainTile &tile = map->terrain[pos.x][pos.y][pos.z];
|
||||
if (tile.visitable && (tile.terType == ETerrainType::WATER) == (posTile.terType == ETerrainType::WATER))
|
||||
if (tile.visitable && (tile.isWater() == posTile.isWater()))
|
||||
{
|
||||
BOOST_FOREACH (CGObjectInstance* obj, tile.visitableObjects)
|
||||
{
|
||||
if (obj->ID == 54 && checkForVisitableDir(pos, &map->getTile(originalPos), originalPos)) // Monster being able to attack investigated tile
|
||||
if (obj->ID == Obj::MONSTER && checkForVisitableDir(pos, &map->getTile(originalPos), originalPos)) // Monster being able to attack investigated tile
|
||||
{
|
||||
return pos;
|
||||
}
|
||||
@ -2429,7 +2429,7 @@ void CGameState::obtainPlayersStats(SThievesGuildInfo & tgi, int level)
|
||||
}
|
||||
if(level >= 4) //obelisks found
|
||||
{
|
||||
//TODO
|
||||
//TODO: obtainPlayersStats - obelisks found
|
||||
}
|
||||
if(level >= 5) //artifacts
|
||||
{
|
||||
@ -2441,7 +2441,7 @@ void CGameState::obtainPlayersStats(SThievesGuildInfo & tgi, int level)
|
||||
}
|
||||
if(level >= 7) //income
|
||||
{
|
||||
//TODO
|
||||
//TODO:obtainPlayersStats - income
|
||||
}
|
||||
if(level >= 8) //best hero's stats
|
||||
{
|
||||
@ -2507,18 +2507,11 @@ int CGameState::lossCheck( ui8 player ) const
|
||||
switch(map->lossCondition.typeOfLossCon)
|
||||
{
|
||||
case ELossConditionType::LOSSCASTLE:
|
||||
{
|
||||
const CGTownInstance *t = dynamic_cast<const CGTownInstance *>(map->lossCondition.obj);
|
||||
assert(t);
|
||||
if(t->tempOwner != player)
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case ELossConditionType::LOSSHERO:
|
||||
{
|
||||
const CGHeroInstance *h = dynamic_cast<const CGHeroInstance *>(map->lossCondition.obj);
|
||||
assert(h);
|
||||
if(h->tempOwner != player)
|
||||
const CGObjectInstance *obj = map->lossCondition.obj;
|
||||
assert(obj);
|
||||
if(obj->tempOwner != player)
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
@ -3177,13 +3170,6 @@ bool CPathfinder::canMoveBetween(const int3 &a, const int3 &b) const
|
||||
return gs->checkForVisitableDir(a, b) && gs->checkForVisitableDir(b, a);
|
||||
}
|
||||
|
||||
bool CPathfinder::canStepOntoDst() const
|
||||
{
|
||||
//TODO remove
|
||||
assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
CGPathNode::EAccessibility CPathfinder::evaluateAccessibility(const TerrainTile *tinfo) const
|
||||
{
|
||||
CGPathNode::EAccessibility ret = (tinfo->blocked ? CGPathNode::BLOCKED : CGPathNode::ACCESSIBLE);
|
||||
@ -3194,7 +3180,7 @@ CGPathNode::EAccessibility CPathfinder::evaluateAccessibility(const TerrainTile
|
||||
|
||||
if(tinfo->visitable)
|
||||
{
|
||||
if(tinfo->visitableObjects.front()->ID == 80 && tinfo->visitableObjects.back()->ID == Obj::HERO && tinfo->visitableObjects.back()->tempOwner != hero->tempOwner) //non-owned hero stands on Sanctuary
|
||||
if(tinfo->visitableObjects.front()->ID == Obj::SANCTUARY && tinfo->visitableObjects.back()->ID == Obj::HERO && tinfo->visitableObjects.back()->tempOwner != hero->tempOwner) //non-owned hero stands on Sanctuary
|
||||
{
|
||||
return CGPathNode::BLOCKED;
|
||||
}
|
||||
|
@ -368,7 +368,6 @@ private:
|
||||
|
||||
CGPathNode::EAccessibility evaluateAccessibility(const TerrainTile *tinfo) const;
|
||||
bool canMoveBetween(const int3 &a, const int3 &b) const; //checks only for visitable objects that may make moving between tiles impossible, not other conditions (like tiles itself accessibility)
|
||||
bool canStepOntoDst() const;
|
||||
|
||||
public:
|
||||
CPathfinder(CPathsInfo &_out, CGameState *_gs, const CGHeroInstance *_hero);
|
||||
|
@ -292,6 +292,7 @@ void CModHandler::loadActiveMods()
|
||||
handleData(VLC->townh, config["factions"]);
|
||||
handleData(VLC->creh, config["creatures"]);
|
||||
handleData(VLC->arth, config["artifacts"]);
|
||||
//todo: spells
|
||||
|
||||
handleData(&VLC->heroh->classes, config["heroClasses"]);
|
||||
handleData(VLC->heroh, config["heroes"]);
|
||||
|
@ -1384,13 +1384,12 @@ void CGHeroInstance::showNecromancyDialog(const CStackBasicDescriptor &raisedSta
|
||||
{
|
||||
iw.text.addTxt(MetaString::GENERAL_TXT, 145);
|
||||
iw.text.addReplacement(raisedStack.count);
|
||||
iw.text.addReplacement(MetaString::CRE_PL_NAMES, raisedStack.type->idNumber);
|
||||
}
|
||||
else // Practicing the dark arts of necromancy, ... (singular)
|
||||
{
|
||||
iw.text.addTxt(MetaString::GENERAL_TXT, 146);
|
||||
iw.text.addReplacement(MetaString::CRE_SING_NAMES, raisedStack.type->idNumber);
|
||||
}
|
||||
iw.text.addReplacement(raisedStack);
|
||||
|
||||
cb->showInfoDialog(&iw);
|
||||
}
|
||||
@ -4772,7 +4771,7 @@ void CGWitchHut::onHeroVisit( const CGHeroInstance * h ) const
|
||||
const std::string & CGWitchHut::getHoverText() const
|
||||
{
|
||||
hoverName = VLC->generaltexth->names[ID];
|
||||
if(wasVisited(cb->getCurrentPlayer())) //TODO: use local player, not current
|
||||
if(wasVisited(cb->getLocalPlayer()))
|
||||
{
|
||||
hoverName += "\n" + VLC->generaltexth->allTexts[356]; // + (learn %s)
|
||||
boost::algorithm::replace_first(hoverName,"%s",VLC->generaltexth->skillName[ability]);
|
||||
@ -6113,14 +6112,12 @@ void CBank::endBattle (const CGHeroInstance *h, const BattleResult *result) cons
|
||||
//display loot
|
||||
if (!iw.components.empty())
|
||||
{
|
||||
iw.text.addTxt (MetaString::ADVOB_TXT, textID);
|
||||
if (textID == 34)
|
||||
{
|
||||
iw.text.addTxt(MetaString::ADVOB_TXT, 34);//Heaving defeated %s, you discover %s
|
||||
iw.text.addReplacement(MetaString::CRE_PL_NAMES, result->casualties[1].begin()->first);
|
||||
iw.text.addReplacement(loot.buildList());
|
||||
}
|
||||
else
|
||||
iw.text.addTxt (MetaString::ADVOB_TXT, textID);
|
||||
cb->showInfoDialog(&iw);
|
||||
}
|
||||
loot.clear();
|
||||
|
@ -167,7 +167,7 @@ public:
|
||||
mutable std::string hoverName;
|
||||
int3 pos; //h3m pos
|
||||
si32 ID, subID; //normal ID (this one from OH3 maps ;]) - eg. town=98; hero=34
|
||||
si32 id;//number of object in CObjectHandler's vector
|
||||
si32 id;//number of object in map's vector
|
||||
CGDefInfo * defInfo;
|
||||
ui8 animPhaseShift;
|
||||
|
||||
|
@ -96,7 +96,7 @@ namespace SRSLPraserHelpers
|
||||
mainPointForLayer[b] = hexToPair(center);
|
||||
|
||||
for(int it=1; it<=high; ++it) //it - distance to the center
|
||||
{
|
||||
{
|
||||
for(int b=0; b<6; ++b)
|
||||
mainPointForLayer[b] = gotoDir(mainPointForLayer[b], b);
|
||||
|
||||
@ -122,11 +122,19 @@ namespace SRSLPraserHelpers
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
using namespace SRSLPraserHelpers;
|
||||
CSpellHandler::CSpellHandler()
|
||||
{
|
||||
VLC->spellh = this;
|
||||
}
|
||||
|
||||
CSpell::CSpell()
|
||||
{
|
||||
_isDamage = false;
|
||||
_isMind = false;
|
||||
_isRising = false;
|
||||
}
|
||||
|
||||
std::vector<BattleHex> CSpell::rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes) const
|
||||
{
|
||||
std::vector<BattleHex> ret;
|
||||
@ -238,7 +246,7 @@ CSpell::ETargetType CSpell::getTargetType() const //TODO: parse these at game la
|
||||
|
||||
if(attributes.find("OBSTACLE_TARGET") != std::string::npos)
|
||||
return OBSTACLE;
|
||||
|
||||
|
||||
return NO_TARGET;
|
||||
}
|
||||
|
||||
@ -254,13 +262,30 @@ bool CSpell::isNegative() const
|
||||
|
||||
bool CSpell::isRisingSpell() const
|
||||
{
|
||||
return vstd::contains(VLC->spellh->risingSpells, id);
|
||||
return _isRising;
|
||||
}
|
||||
|
||||
bool CSpell::isDamageSpell() const
|
||||
{
|
||||
return vstd::contains(VLC->spellh->damageSpells, id);
|
||||
return _isDamage;
|
||||
}
|
||||
|
||||
bool CSpell::isMindSpell() const
|
||||
{
|
||||
return _isMind;
|
||||
}
|
||||
|
||||
void CSpell::getEffects(std::vector<Bonus>& lst) const
|
||||
{
|
||||
lst.reserve(lst.size() + _effects.size());
|
||||
|
||||
BOOST_FOREACH (Bonus b, _effects)
|
||||
{
|
||||
lst.push_back(b);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool DLL_LINKAGE isInScreenRange(const int3 ¢er, const int3 &pos)
|
||||
{
|
||||
int3 diff = pos - center;
|
||||
@ -343,7 +368,10 @@ void CSpellHandler::loadSpells()
|
||||
}
|
||||
while (parser.endLine() && !parser.isNextEntryEmpty());
|
||||
|
||||
boost::replace_first (spells[47]->attributes, "2", ""); // disrupting ray will now affect single creature
|
||||
boost::replace_first (spells[Spells::DISRUPTING_RAY]->attributes, "2", ""); // disrupting ray will now affect single creature
|
||||
|
||||
|
||||
spells.push_back(spells[Spells::ACID_BREATH_DEFENSE]); //clone Acid Breath attributes for Acid Breath damage effect
|
||||
|
||||
//loading of additional spell traits
|
||||
const JsonNode config(ResourceID("config/spell_info.json"));
|
||||
@ -367,16 +395,50 @@ void CSpellHandler::loadSpells()
|
||||
s->identifier = spell.first;
|
||||
VLC->modh->identifiers.registerObject("spell." + spell.first, spellID);
|
||||
|
||||
const JsonNode & flags_node = spell.second["flags"];
|
||||
if (!flags_node.isNull())
|
||||
{
|
||||
auto flags = flags_node.convertTo<std::vector<std::string> >();
|
||||
|
||||
BOOST_FOREACH (const auto & flag, flags)
|
||||
{
|
||||
if (flag == "damage")
|
||||
{
|
||||
s->_isDamage = true;
|
||||
}
|
||||
else if (flag == "rising")
|
||||
{
|
||||
s->_isRising = true;
|
||||
}
|
||||
else if (flag == "mind")
|
||||
{
|
||||
s->_isMind = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const JsonNode & effects_node = spell.second["effects"];
|
||||
|
||||
if (!effects_node.isNull())
|
||||
{
|
||||
BOOST_FOREACH (const JsonNode & bonus_node, effects_node.Vector())
|
||||
{
|
||||
Bonus * b = JsonUtils::parseBonus(bonus_node);
|
||||
b->sid = s->id;
|
||||
b->source = Bonus::SPELL_EFFECT;
|
||||
b->duration = Bonus::N_TURNS; //default
|
||||
//TODO: make duration configurable
|
||||
s->_effects.push_back(*b);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//spell fixes
|
||||
|
||||
spells.push_back(spells[80]); //clone Acid Breath attributes for Acid Breath damage effect
|
||||
//forgetfulness needs to get targets automatically on expert level
|
||||
boost::replace_first(spells[61]->attributes, "CREATURE_TARGET", "CREATURE_TARGET_2"); //TODO: use flags instead?
|
||||
|
||||
damageSpells += 11, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 57, 77;
|
||||
risingSpells += 38, 39, 40;
|
||||
mindSpells += 50, 59, 60, 61, 62;
|
||||
boost::replace_first(spells[Spells::FORGETFULNESS]->attributes, "CREATURE_TARGET", "CREATURE_TARGET_2"); //TODO: use flags instead?
|
||||
}
|
||||
|
||||
std::vector<ui8> CSpellHandler::getDefaultAllowedSpells() const
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "../lib/ConstTransitivePtr.h"
|
||||
#include "int3.h"
|
||||
#include "GameConstants.h"
|
||||
#include "HeroBonus.h"
|
||||
|
||||
/*
|
||||
* CSpellHandler.h, part of VCMI engine
|
||||
@ -44,20 +45,38 @@ public:
|
||||
std::vector<std::string> range; //description of spell's range in SRSL by magic school level
|
||||
std::vector<TSpell> counteredSpells; //spells that are removed when effect of this spell is placed on creature (for bless-curse, haste-slow, and similar pairs)
|
||||
|
||||
CSpell();
|
||||
|
||||
std::vector<BattleHex> rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes = NULL ) const; //convert range to specific hexes; last optional out parameter is set to true, if spell would cover unavailable hexes (that are not included in ret)
|
||||
si16 mainEffectAnim; //main spell effect animation, in AC format (or -1 when none)
|
||||
ETargetType getTargetType() const;
|
||||
|
||||
bool isPositive() const;
|
||||
bool isNegative() const;
|
||||
|
||||
bool isRisingSpell() const;
|
||||
bool isDamageSpell() const;
|
||||
bool isMindSpell() const;
|
||||
|
||||
|
||||
void getEffects(std::vector<Bonus> & lst) 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 & _effects;
|
||||
}
|
||||
friend class CSpellHandler;
|
||||
|
||||
private:
|
||||
bool _isRising;
|
||||
bool _isDamage;
|
||||
bool _isMind;
|
||||
|
||||
std::vector<Bonus> _effects;
|
||||
|
||||
};
|
||||
|
||||
namespace Spells
|
||||
@ -68,18 +87,18 @@ namespace Spells
|
||||
FLY=6, WATER_WALK=7, DIMENSION_DOOR=8, TOWN_PORTAL=9,
|
||||
|
||||
QUICKSAND=10, LAND_MINE=11, FORCE_FIELD=12, FIRE_WALL=13, EARTHQUAKE=14,
|
||||
MAGIC_ARROW=15, ICE_BOLT=16, LIGHTNING_BOLT=17, IMPLOSION=18,
|
||||
CHAIN_LIGHTNING=19, FROST_RING=20, FIREBALL=21, INFERNO=22,
|
||||
METEOR_SHOWER=23, DEATH_RIPPLE=24, DESTROY_UNDEAD=25, ARMAGEDDON=26,
|
||||
SHIELD=27, AIR_SHIELD=28, FIRE_SHIELD=29, PROTECTION_FROM_AIR=30,
|
||||
PROTECTION_FROM_FIRE=31, PROTECTION_FROM_WATER=32,
|
||||
PROTECTION_FROM_EARTH=33, ANTI_MAGIC=34, DISPEL=35, MAGIC_MIRROR=36,
|
||||
CURE=37, RESURRECTION=38, ANIMATE_DEAD=39, SACRIFICE=40, BLESS=41,
|
||||
CURSE=42, BLOODLUST=43, PRECISION=44, WEAKNESS=45, STONE_SKIN=46,
|
||||
DISRUPTING_RAY=47, PRAYER=48, MIRTH=49, SORROW=50, FORTUNE=51,
|
||||
MISFORTUNE=52, HASTE=53, SLOW=54, SLAYER=55, FRENZY=56,
|
||||
TITANS_LIGHTNING_BOLT=57, COUNTERSTRIKE=58, BERSERK=59, HYPNOTIZE=60,
|
||||
FORGETFULNESS=61, BLIND=62, TELEPORT=63, REMOVE_OBSTACLE=64, CLONE=65,
|
||||
MAGIC_ARROW=15, ICE_BOLT=16, LIGHTNING_BOLT=17, IMPLOSION=18,
|
||||
CHAIN_LIGHTNING=19, FROST_RING=20, FIREBALL=21, INFERNO=22,
|
||||
METEOR_SHOWER=23, DEATH_RIPPLE=24, DESTROY_UNDEAD=25, ARMAGEDDON=26,
|
||||
SHIELD=27, AIR_SHIELD=28, FIRE_SHIELD=29, PROTECTION_FROM_AIR=30,
|
||||
PROTECTION_FROM_FIRE=31, PROTECTION_FROM_WATER=32,
|
||||
PROTECTION_FROM_EARTH=33, ANTI_MAGIC=34, DISPEL=35, MAGIC_MIRROR=36,
|
||||
CURE=37, RESURRECTION=38, ANIMATE_DEAD=39, SACRIFICE=40, BLESS=41,
|
||||
CURSE=42, BLOODLUST=43, PRECISION=44, WEAKNESS=45, STONE_SKIN=46,
|
||||
DISRUPTING_RAY=47, PRAYER=48, MIRTH=49, SORROW=50, FORTUNE=51,
|
||||
MISFORTUNE=52, HASTE=53, SLOW=54, SLAYER=55, FRENZY=56,
|
||||
TITANS_LIGHTNING_BOLT=57, COUNTERSTRIKE=58, BERSERK=59, HYPNOTIZE=60,
|
||||
FORGETFULNESS=61, BLIND=62, TELEPORT=63, REMOVE_OBSTACLE=64, CLONE=65,
|
||||
SUMMON_FIRE_ELEMENTAL=66, SUMMON_EARTH_ELEMENTAL=67, SUMMON_WATER_ELEMENTAL=68, SUMMON_AIR_ELEMENTAL=69,
|
||||
|
||||
STONE_GAZE=70, POISON=71, BIND=72, DISEASE=73, PARALYZE=74, AGE=75, DEATH_CLOUD=76, THUNDERBOLT=77,
|
||||
@ -96,9 +115,7 @@ class DLL_LINKAGE CSpellHandler
|
||||
public:
|
||||
CSpellHandler();
|
||||
std::vector< ConstTransitivePtr<CSpell> > spells;
|
||||
std::set<TSpell> damageSpells; //they inflict damage and require particular threatment
|
||||
std::set<TSpell> risingSpells; //they affect dead stacks and need special target selection
|
||||
std::set<TSpell> mindSpells;
|
||||
|
||||
void loadSpells();
|
||||
|
||||
/**
|
||||
@ -110,6 +127,6 @@ public:
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & spells & damageSpells & risingSpells & mindSpells;
|
||||
h & spells ;
|
||||
}
|
||||
};
|
||||
|
@ -955,7 +955,7 @@ void CMapLoaderH3M::readDefInfo()
|
||||
defInfo->visitMap[zi] = reverse(bytes[6 + zi]);
|
||||
}
|
||||
pos += 16;
|
||||
if(defInfo->id != Obj::HERO && defInfo->id != 70)
|
||||
if(defInfo->id != Obj::HERO && defInfo->id != Obj::RANDOM_HERO)
|
||||
{
|
||||
CGDefInfo * h = VLC->dobjinfo->gobjs[defInfo->id][defInfo->subid];
|
||||
if(!h)
|
||||
@ -1160,11 +1160,22 @@ void CMapLoaderH3M::readObjects()
|
||||
case Obj::FLOTSAM:
|
||||
case Obj::SEA_CHEST:
|
||||
case Obj::SHIPWRECK_SURVIVOR:
|
||||
case Obj::TREASURE_CHEST:
|
||||
{
|
||||
nobj = new CGPickable();
|
||||
break;
|
||||
}
|
||||
case Obj::TREASURE_CHEST:
|
||||
if(defInfo->subid == 0)
|
||||
{
|
||||
nobj = new CGPickable();
|
||||
}
|
||||
else
|
||||
{
|
||||
//WoG pickable object
|
||||
//TODO: possible special handling
|
||||
nobj = new CGObjectInstance();
|
||||
}
|
||||
break;
|
||||
case Obj::MONSTER: //Monster
|
||||
case Obj::RANDOM_MONSTER:
|
||||
case Obj::RANDOM_MONSTER_L1:
|
||||
|
@ -4376,7 +4376,7 @@ void CGameHandler::handleSpellCasting( int spellID, int spellLvl, BattleHex dest
|
||||
{
|
||||
BattleStackAttacked bsa;
|
||||
bsa.flags |= BattleStackAttacked::EFFECT;
|
||||
bsa.effect = VLC->spellh->spells[80]->mainEffectAnim; //use acid breath
|
||||
bsa.effect = spell->mainEffectAnim;
|
||||
bsa.damageAmount = usedSpellPower; //damage times the number of attackers
|
||||
bsa.stackAttacked = (*it)->ID;
|
||||
bsa.attackerID = -1;
|
||||
|
Loading…
Reference in New Issue
Block a user