1
0
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:
alexvins 2013-01-15 14:20:48 +00:00
parent 264ce77ec9
commit 68e91ada1c
13 changed files with 1202 additions and 329 deletions

File diff suppressed because it is too large Load Diff

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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"]);

View File

@ -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();

View File

@ -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;

View File

@ -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 &center, 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

View File

@ -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 ;
}
};

View File

@ -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:

View File

@ -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;