1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

SpellHandler: cleanup, formatting, simplification.

This commit is contained in:
alexvins 2014-03-08 23:18:51 +00:00
parent 7d1e54baa7
commit c959fdcce0
3 changed files with 277 additions and 424 deletions

View File

@ -45,3 +45,6 @@ Ivan Savenko, <saven.ivan@gmail.com>
Benjamin Gentner aka beegee, <> Benjamin Gentner aka beegee, <>
* battle support, programming * battle support, programming
Alexander Shishkin aka alexvins,
* MinGW platform support, modding related programming

View File

@ -20,9 +20,10 @@
* *
*/ */
namespace SpellConfigJson namespace SpellConfig
{ {
static const std::string level_names[] = {"none","basic","advanced","expert"}; static const std::string LEVEL_NAMES[] = {"none", "basic", "advanced", "expert"};
} }
using namespace boost::assign; using namespace boost::assign;
@ -133,25 +134,23 @@ using namespace SRSLPraserHelpers;
CSpell::CSpell(): CSpell::CSpell():
id(SpellID::NONE), level(0), id(SpellID::NONE), level(0),
earth(false),water(false),fire(false),air(false), earth(false), water(false), fire(false), air(false),
power(0), power(0),
combatSpell(false),creatureAbility(false), combatSpell(false), creatureAbility(false),
positiveness(ESpellPositiveness::NEUTRAL), positiveness(ESpellPositiveness::NEUTRAL),
mainEffectAnim(-1), mainEffectAnim(-1),
defaultProbability(0), defaultProbability(0),
isRising(false),isDamage(false),isOffensive(false),targetType(ETargetType::NO_TARGET) isRising(false), isDamage(false), isOffensive(false),
targetType(ETargetType::NO_TARGET)
{ {
} }
CSpell::~CSpell() CSpell::~CSpell()
{ {
for (auto & elem : effects) for(auto & elem : effects)
{ for(size_t j=0; j<elem.size(); j++)
for (size_t j=0; j<elem.size(); j++)
delete elem[j]; delete elem[j];
}
} }
std::vector<BattleHex> CSpell::rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes) const std::vector<BattleHex> CSpell::rangeInHexes(BattleHex centralHex, ui8 schoolLvl, ui8 side, bool *outDroppedHexes) const
@ -202,7 +201,7 @@ std::vector<BattleHex> CSpell::rangeInHexes(BattleHex centralHex, ui8 schoolLvl,
bool readingFirst = true; bool readingFirst = true;
for(auto & elem : rng) for(auto & elem : rng)
{ {
if( std::isdigit(elem) ) //reading numer if(std::isdigit(elem) ) //reading numer
{ {
if(readingFirst) if(readingFirst)
number1 += elem; number1 += elem;
@ -259,25 +258,104 @@ CSpell::ETargetType CSpell::getTargetType() const
return targetType; return targetType;
} }
bool CSpell::isCombatSpell() const
{
return combatSpell;
}
bool CSpell::isAdventureSpell() const
{
return !combatSpell;
}
bool CSpell::isCreatureAbility() const
{
return creatureAbility;
}
bool CSpell::isPositive() const
{
return positiveness == POSITIVE;
}
bool CSpell::isNegative() const
{
return positiveness == NEGATIVE;
}
bool CSpell::isRisingSpell() const
{
return isRising;
}
bool CSpell::isDamageSpell() const
{
return isDamage;
}
bool CSpell::isOffensiveSpell() const
{
return isOffensive;
}
bool CSpell::isSpecialSpell() const
{
return isSpecial;
}
bool CSpell::hasEffects() const
{
return effects.size() && effects[0].size();
}
const std::string& CSpell::getIconImmune() const
{
return iconImmune;
}
si32 CSpell::getCost(const int skillLevel) const
{
return costs[skillLevel];
}
si32 CSpell::getPower(const int skillLevel) const
{
return powers[skillLevel];
}
//si32 CSpell::calculatePower(const int skillLevel) const
//{
// return power + getPower(skillLevel);
//}
si32 CSpell::getProbability(const TFaction factionId) const
{
if(!vstd::contains(probabilities,factionId))
{
return defaultProbability;
}
return probabilities.at(factionId);
}
void CSpell::getEffects(std::vector<Bonus>& lst, const int level) const void CSpell::getEffects(std::vector<Bonus>& lst, const int level) const
{ {
if (level < 0 || level >= GameConstants::SPELL_SCHOOL_LEVELS) if(level < 0 || level >= GameConstants::SPELL_SCHOOL_LEVELS)
{ {
logGlobal->errorStream() << __FUNCTION__ << " invalid school level " << level; logGlobal->errorStream() << __FUNCTION__ << " invalid school level " << level;
return; return;
} }
if (effects.empty()) if(effects.empty())
{ {
logGlobal->errorStream() << __FUNCTION__ << " This spell (" + name + ") has no bonus effects! " << name; logGlobal->errorStream() << __FUNCTION__ << " This spell (" + name + ") has no bonus effects! " << name;
return; return;
} }
if (effects.size() <= level) if(effects.size() <= level)
{ {
logGlobal->errorStream() << __FUNCTION__ << " This spell (" + name + ") is missing entry for level " << level; logGlobal->errorStream() << __FUNCTION__ << " This spell (" + name + ") is missing entry for level " << level;
return; return;
} }
if (effects[level].empty()) if(effects[level].empty())
{ {
logGlobal->errorStream() << __FUNCTION__ << " This spell (" + name + ") has no effects for level " << level; logGlobal->errorStream() << __FUNCTION__ << " This spell (" + name + ") has no effects for level " << level;
return; return;
@ -285,7 +363,7 @@ void CSpell::getEffects(std::vector<Bonus>& lst, const int level) const
lst.reserve(lst.size() + effects[level].size()); lst.reserve(lst.size() + effects[level].size());
for (Bonus *b : effects[level]) for(Bonus *b : effects[level])
{ {
lst.push_back(Bonus(*b)); lst.push_back(Bonus(*b));
} }
@ -310,7 +388,7 @@ bool CSpell::isImmuneBy(const IBonusBearer* obj) const
} }
//3. Check negation //3. Check negation
if (obj->hasBonusOfType(Bonus::NEGATE_ALL_NATURAL_IMMUNITIES)) //Orb of vulnerability if(obj->hasBonusOfType(Bonus::NEGATE_ALL_NATURAL_IMMUNITIES)) //Orb of vulnerability
return false; return false;
//4. Check negatable immunities //4. Check negatable immunities
@ -322,36 +400,36 @@ bool CSpell::isImmuneBy(const IBonusBearer* obj) const
auto battleTestElementalImmunity = [&,this](Bonus::BonusType element) -> bool auto battleTestElementalImmunity = [&,this](Bonus::BonusType element) -> bool
{ {
if (obj->hasBonusOfType(element, 0)) //always resist if immune to all spells altogether if(obj->hasBonusOfType(element, 0)) //always resist if immune to all spells altogether
return true; return true;
else if (!isPositive()) //negative or indifferent else if(!isPositive()) //negative or indifferent
{ {
if ((isDamageSpell() && obj->hasBonusOfType(element, 2)) || obj->hasBonusOfType(element, 1)) if((isDamageSpell() && obj->hasBonusOfType(element, 2)) || obj->hasBonusOfType(element, 1))
return true; return true;
} }
return false; return false;
}; };
//4. Check elemental immunities //4. Check elemental immunities
if (fire) if(fire)
{ {
if (battleTestElementalImmunity(Bonus::FIRE_IMMUNITY)) if(battleTestElementalImmunity(Bonus::FIRE_IMMUNITY))
return true; return true;
} }
if (water) if(water)
{ {
if (battleTestElementalImmunity(Bonus::WATER_IMMUNITY)) if(battleTestElementalImmunity(Bonus::WATER_IMMUNITY))
return true; return true;
} }
if (earth) if(earth)
{ {
if (battleTestElementalImmunity(Bonus::EARTH_IMMUNITY)) if(battleTestElementalImmunity(Bonus::EARTH_IMMUNITY))
return true; return true;
} }
if (air) if(air)
{ {
if (battleTestElementalImmunity(Bonus::AIR_IMMUNITY)) if(battleTestElementalImmunity(Bonus::AIR_IMMUNITY))
return true; return true;
} }
@ -384,7 +462,7 @@ void CSpell::setIsOffensive(const bool val)
{ {
isOffensive = val; isOffensive = val;
if (val) if(val)
{ {
positiveness = CSpell::NEGATIVE; positiveness = CSpell::NEGATIVE;
isDamage = true; isDamage = true;
@ -395,7 +473,7 @@ void CSpell::setIsRising(const bool val)
{ {
isRising = val; isRising = val;
if (val) if(val)
{ {
positiveness = CSpell::POSITIVE; positiveness = CSpell::POSITIVE;
} }
@ -419,7 +497,7 @@ CSpellHandler::CSpellHandler()
std::vector<JsonNode> CSpellHandler::loadLegacyData(size_t dataSize) std::vector<JsonNode> CSpellHandler::loadLegacyData(size_t dataSize)
{ {
using namespace SpellConfigJson; using namespace SpellConfig;
std::vector<JsonNode> legacyData; std::vector<JsonNode> legacyData;
CLegacyConfigParser parser("DATA/SPTRAITS.TXT"); CLegacyConfigParser parser("DATA/SPTRAITS.TXT");
@ -457,13 +535,10 @@ std::vector<JsonNode> CSpellHandler::loadLegacyData(size_t dataSize)
auto& levels = lineNode["levels"].Struct(); auto& levels = lineNode["levels"].Struct();
auto getLevel = [&](const size_t idx)->JsonMap& auto getLevel = [&](const size_t idx)->JsonMap&
{ {
assert(idx < GameConstants::SPELL_SCHOOL_LEVELS); assert(idx < GameConstants::SPELL_SCHOOL_LEVELS);
return levels[level_names[idx]].Struct(); return levels[LEVEL_NAMES[idx]].Struct();
}; };
auto costs = parser.readNumArray<si32>(GameConstants::SPELL_SCHOOL_LEVELS); auto costs = parser.readNumArray<si32>(GameConstants::SPELL_SCHOOL_LEVELS);
@ -472,14 +547,14 @@ std::vector<JsonNode> CSpellHandler::loadLegacyData(size_t dataSize)
auto& chances = lineNode["gainChance"].Struct(); auto& chances = lineNode["gainChance"].Struct();
for (size_t i = 0; i < GameConstants::F_NUMBER ; i++){ for(size_t i = 0; i < GameConstants::F_NUMBER ; i++){
chances[ETownType::names[i]].Float() = parser.readNumber(); chances[ETownType::names[i]].Float() = parser.readNumber();
} }
auto AIVals = parser.readNumArray<si32>(GameConstants::SPELL_SCHOOL_LEVELS); auto AIVals = parser.readNumArray<si32>(GameConstants::SPELL_SCHOOL_LEVELS);
std::vector<std::string> descriptions; std::vector<std::string> descriptions;
for (size_t i = 0; i < GameConstants::SPELL_SCHOOL_LEVELS ; i++) for(size_t i = 0; i < GameConstants::SPELL_SCHOOL_LEVELS ; i++)
descriptions.push_back(parser.readString()); descriptions.push_back(parser.readString());
std::string attributes = parser.readString(); std::string attributes = parser.readString();
@ -496,21 +571,16 @@ std::vector<JsonNode> CSpellHandler::loadLegacyData(size_t dataSize)
lineNode["targetType"].String() = targetType; lineNode["targetType"].String() = targetType;
//save parsed level specific data //save parsed level specific data
for (size_t i = 0; i < GameConstants::SPELL_SCHOOL_LEVELS; i++) for(size_t i = 0; i < GameConstants::SPELL_SCHOOL_LEVELS; i++)
{ {
auto& level = getLevel(i); auto& level = getLevel(i);
level["description"].String() = descriptions[i]; level["description"].String() = descriptions[i];
level["cost"].Float() = costs[i]; level["cost"].Float() = costs[i];
level["power"].Float() = powers[i]; level["power"].Float() = powers[i];
level["aiValue"].Float() = AIVals[i]; level["aiValue"].Float() = AIVals[i];
} }
// logGlobal->errorStream() << lineNode;
legacyData.push_back(lineNode); legacyData.push_back(lineNode);
@ -547,20 +617,15 @@ const std::string CSpellHandler::getTypeName() const
return "spell"; return "spell";
} }
static void fatalConfigurationError()
{
throw std::runtime_error("SpellHandler: Fatal configuration error, See log for details");
}
CSpell * CSpellHandler::loadFromJson(const JsonNode& json) CSpell * CSpellHandler::loadFromJson(const JsonNode& json)
{ {
using namespace SpellConfigJson; using namespace SpellConfig;
CSpell * spell = new CSpell(); CSpell * spell = new CSpell();
const auto type_str = json["type"].String(); const auto type = json["type"].String();
if (type_str == "ability") if(type == "ability")
{ {
spell->creatureAbility = true; spell->creatureAbility = true;
spell->combatSpell = true; spell->combatSpell = true;
@ -568,57 +633,28 @@ CSpell * CSpellHandler::loadFromJson(const JsonNode& json)
else else
{ {
spell->creatureAbility = false; spell->creatureAbility = false;
spell->combatSpell = type_str == "combat"; spell->combatSpell = type == "combat";
} }
spell->name = json["name"].String(); spell->name = json["name"].String();
logGlobal->traceStream() << __FUNCTION__ << ": loading spell " << spell->name; logGlobal->traceStream() << __FUNCTION__ << ": loading spell " << spell->name;
auto readFlag = [](const JsonNode& flagsNode, const std::string& name) const auto schoolNames = json["school"];
{
if (flagsNode.getType() != JsonNode::DATA_STRUCT)
{
logGlobal->errorStream() << "Flags node shall be object";
return false;
}
const JsonNode& flag = flagsNode[name]; spell->air = schoolNames["air"].Bool();
spell->earth = schoolNames["earth"].Bool();
if (flag.isNull()) spell->fire = schoolNames["fire"].Bool();
{ spell->water = schoolNames["water"].Bool();
return false;
}
else if (flag.getType() == JsonNode::DATA_BOOL)
{
return flag.Bool();
}
else
{
logGlobal->errorStream() << "Flag shall be boolean: "<<name;
return false;
}
};
const auto school_names = json["school"];
spell->air = readFlag(school_names, "air");
spell->earth = readFlag(school_names, "earth");
spell->fire = readFlag(school_names, "fire");
spell->water = readFlag(school_names, "water");
spell->level = json["level"].Float(); spell->level = json["level"].Float();
spell->power = json["power"].Float(); spell->power = json["power"].Float();
//TODO: default chance
spell->defaultProbability = json["defaultGainChance"].Float(); spell->defaultProbability = json["defaultGainChance"].Float();
auto chances = json["gainChance"].Struct(); for(const auto & node : json["gainChance"].Struct())
for(auto &node : chances)
{ {
int chance = node.second.Float(); const int chance = node.second.Float();
VLC->modh->identifiers.requestIdentifier(node.second.meta, "faction",node.first, [=](si32 factionID) VLC->modh->identifiers.requestIdentifier(node.second.meta, "faction",node.first, [=](si32 factionID)
{ {
@ -626,87 +662,80 @@ CSpell * CSpellHandler::loadFromJson(const JsonNode& json)
}); });
} }
auto targetType = json["targetType"].String();
auto target_type_str = json["targetType"].String(); if(targetType == "NO_TARGET")
if (target_type_str == "NO_TARGET")
spell->targetType = CSpell::NO_TARGET; spell->targetType = CSpell::NO_TARGET;
else if (target_type_str == "CREATURE") else if(targetType == "CREATURE")
spell->targetType = CSpell::CREATURE; spell->targetType = CSpell::CREATURE;
else if (target_type_str == "OBSTACLE") else if(targetType == "OBSTACLE")
spell->targetType = CSpell::OBSTACLE; spell->targetType = CSpell::OBSTACLE;
else if (target_type_str == "CREATURE_EXPERT_MASSIVE") else if(targetType == "CREATURE_EXPERT_MASSIVE")
spell->targetType = CSpell::CREATURE_EXPERT_MASSIVE; spell->targetType = CSpell::CREATURE_EXPERT_MASSIVE;
else
{
logGlobal->errorStream() << spell->name << ": invalid target type '" <<target_type_str<<"'";
fatalConfigurationError();
}
spell->mainEffectAnim = json["anim"].Float(); spell->mainEffectAnim = json["anim"].Float();
for(const auto& k_v: json["counters"].Struct()) for(const auto & counteredSpell: json["counters"].Struct())
{ if (counteredSpell.second.Bool())
if (k_v.second.Bool())
{ {
JsonNode tmp(JsonNode::DATA_STRING); JsonNode tmp(JsonNode::DATA_STRING);
tmp.meta = json.meta; tmp.meta = json.meta;
tmp.String() = k_v.first; tmp.String() = counteredSpell.first;
VLC->modh->identifiers.requestIdentifier(tmp,[=](si32 id){ VLC->modh->identifiers.requestIdentifier(tmp,[=](si32 id){
spell->counteredSpells.push_back(SpellID(id)); spell->counteredSpells.push_back(SpellID(id));
}); });
}
}
}
//TODO: more error checking - f.e. conflicting flags //TODO: more error checking - f.e. conflicting flags
const auto flags = json["flags"]; const auto flags = json["flags"];
//by default all flags are set to false in constructor //by default all flags are set to false in constructor
if (readFlag(flags,"summoning")) if(flags["summoning"].Bool())
{ {
logGlobal->warnStream() << spell->name << ": summoning flag in unimplemented"; logGlobal->warnStream() << spell->name << ": summoning flag in unimplemented";
} }
spell->isDamage = readFlag(flags,"damage"); //do this before "offensive" spell->isDamage = flags["damage"].Bool(); //do this before "offensive"
if (readFlag(flags,"offensive")) if(flags["offensive"].Bool())
{ {
spell->setIsOffensive(true); spell->setIsOffensive(true);
} }
if (readFlag(flags,"rising")) if(flags["rising"].Bool())
{ {
spell->setIsRising(true); spell->setIsRising(true);
} }
const bool implicit_positiveness = spell->isOffensive || spell->isRising; //(!) "damage" does not mean NEGATIVE --AVS const bool implicitPositiveness = spell->isOffensive || spell->isRising; //(!) "damage" does not mean NEGATIVE --AVS
if (readFlag(flags,"indifferent")) if(flags["indifferent"].Bool())
{ {
spell->positiveness = CSpell::NEUTRAL; spell->positiveness = CSpell::NEUTRAL;
} }
else if (readFlag(flags,"negative")) else if(flags["negative"].Bool())
{ {
spell->positiveness = CSpell::NEGATIVE; spell->positiveness = CSpell::NEGATIVE;
} }
else if (readFlag(flags,"positive")) else if(flags["positive"].Bool())
{ {
spell->positiveness = CSpell::POSITIVE; spell->positiveness = CSpell::POSITIVE;
} }
else if(!implicit_positiveness) else if(!implicitPositiveness)
{ {
spell->positiveness = CSpell::NEUTRAL; //duplicates constructor but, just in case spell->positiveness = CSpell::NEUTRAL; //duplicates constructor but, just in case
logGlobal->errorStream() << "No positiveness specified, assumed NEUTRAL"; logGlobal->errorStream() << "No positiveness specified, assumed NEUTRAL";
} }
spell->isSpecial = readFlag(flags,"special"); spell->isSpecial = flags["special"].Bool();
auto find_in_map = [&](std::string name, std::vector<Bonus::BonusType> &vec) auto findBonus = [&](std::string name, std::vector<Bonus::BonusType> &vec)
{ {
auto it = bonusNameMap.find(name); auto it = bonusNameMap.find(name);
if (it == bonusNameMap.end()) if(it == bonusNameMap.end())
{ {
logGlobal->errorStream() << spell->name << ": invalid bonus name" << name; logGlobal->errorStream() << spell->name << ": invalid bonus name" << name;
} }
@ -716,170 +745,74 @@ CSpell * CSpellHandler::loadFromJson(const JsonNode& json)
} }
}; };
auto read_node = [&](std::string name, std::vector<Bonus::BonusType> &vec) auto readBonusStruct = [&](std::string name, std::vector<Bonus::BonusType> &vec)
{ {
const JsonNode & node = json[name]; for(auto bonusData: json[name].Struct())
{
const std::string bonusId = bonusData.first;
const bool flag = bonusData.second.Bool();
if (!node.isNull()) if(flag)
{ findBonus(bonusId, vec);
for (auto key_value: node.Struct())
{
const std::string bonus_id = key_value.first;
const bool flag = key_value.second.Bool();
if (flag)
{
find_in_map(bonus_id, vec);
}
}
} }
}; };
read_node("immunity",spell->immunities); readBonusStruct("immunity", spell->immunities);
read_node("absoluteImmunity", spell->absoluteImmunities); readBonusStruct("absoluteImmunity", spell->absoluteImmunities);
read_node("limit",spell->limiters); readBonusStruct("limit", spell->limiters);
const JsonNode & graphicsNode = json["graphics"]; const JsonNode & graphicsNode = json["graphics"];
if (!graphicsNode.isNull())
{
spell->iconImmune = graphicsNode["iconImmune"].String(); spell->iconImmune = graphicsNode["iconImmune"].String();
}
//load level attributes //load level attributes
const int level_count = GameConstants::SPELL_SCHOOL_LEVELS; const int levelsCount = GameConstants::SPELL_SCHOOL_LEVELS;
spell->AIVals.resize(level_count); spell->AIVals.resize(levelsCount);
spell->costs.resize(level_count); spell->costs.resize(levelsCount);
spell->descriptions.resize(level_count); spell->descriptions.resize(levelsCount);
spell->powers.resize(level_count); spell->powers.resize(levelsCount);
spell->range.resize(level_count); spell->range.resize(levelsCount);
for(int levelIndex = 0; levelIndex < levelsCount; levelIndex++)
const JsonNode & levels_node = json["levels"];
if (levels_node.isNull())
{ {
logGlobal->errorStream() << spell->name << ": no level specific data"; const JsonNode & levelNode = json["levels"][LEVEL_NAMES[levelIndex]];
fatalConfigurationError();
}
if (levels_node.getType()!=JsonNode::DATA_STRUCT) spell->descriptions[levelIndex] = levelNode["description"].String();
spell->costs[levelIndex] = levelNode["cost"].Float();
spell->powers[levelIndex] = levelNode["power"].Float();
spell->AIVals[levelIndex] = levelNode["aiValue"].Float();
const JsonNode & effectsNode = levelNode["effects"];
if(!effectsNode.isNull())
{ {
logGlobal->errorStream() << spell->name << ": level specific data shall be JSON object"; if(spell->effects.empty())
fatalConfigurationError(); spell->effects.resize(levelsCount);
}
const JsonMap & levels = json["levels"].Struct(); for(const auto & elem : effectsNode.Struct())
for(int level_idx = 0; level_idx < level_count; level_idx++)
{ {
const auto& level_node = levels.at(level_names[level_idx]); const JsonNode & bonusNode = elem.second;
Bonus * b = JsonUtils::parseBonus(bonusNode);
const bool usePowerAsValue = bonusNode["val"].isNull();
if (level_node.getType()!=JsonNode::DATA_STRUCT)
{
logGlobal->errorStream() << spell->name << ": level specific data shall be JSON object";
fatalConfigurationError();
}
auto ensure_field = [&](const std::string json_name,JsonNode::JsonType type)->JsonNode
{
const auto& node = level_node[json_name];
if (node.isNull())
{
logGlobal->errorStream() << spell->name << ": mandatory field "<<json_name<<" missing";
fatalConfigurationError();
}
if (node.getType()!=type)
{
logGlobal->errorStream() << spell->name << ": field "<<json_name<<" - type mismatch";
fatalConfigurationError();
}
return node;
};
auto get_string_mandatory = [&](const std::string json_name, std::vector<std::string>& target)
{
const auto& node = ensure_field(json_name, JsonNode::DATA_STRING);
target[level_idx] = node.String();
};
auto get_string = [&](const std::string json_name, std::vector<std::string>& target)
{
const auto& node = level_node[json_name];
if (node.getType() == JsonNode::DATA_STRING)
{
target[level_idx] = node.String();
}
};
auto get_nomber = [&](const std::string json_name, std::vector<si32>& target)
{
const auto& node = level_node[json_name];
if (node.getType() == JsonNode::DATA_FLOAT)
{
target[level_idx] = node.Float();
}
};
auto get_nomber_mandatory = [&](const std::string json_name, std::vector<si32>& target)
{
const auto& node = ensure_field(json_name, JsonNode::DATA_FLOAT);
target[level_idx] = node.Float();
};
if (spell->isCreatureAbility())
{
get_string("description", spell->descriptions);
get_nomber("cost", spell->costs);
get_nomber("power", spell->powers);
get_nomber("aiValue", spell->AIVals);
}
else
{
get_string_mandatory("description", spell->descriptions);
get_nomber_mandatory("cost", spell->costs);
get_nomber_mandatory("power", spell->powers);
get_nomber_mandatory("aiValue", spell->AIVals);
}
const JsonNode& effects_node = level_node["effects"];
if (!effects_node.isNull())
{
if (spell->effects.empty())
spell->effects.resize(level_count);
for (const auto& elem : effects_node.Struct())
{
const JsonNode& bonus_node = elem.second;
Bonus * b = JsonUtils::parseBonus(bonus_node);
const bool usePowerAsValue = bonus_node["val"].isNull();
//TODO: make this work. see CSpellHandler::afterLoadFinalization() //TODO: make this work. see CSpellHandler::afterLoadFinalization()
//b->sid = spell->id; //for all //b->sid = spell->id; //for all
b->source = Bonus::SPELL_EFFECT;//for all b->source = Bonus::SPELL_EFFECT;//for all
if (usePowerAsValue) if(usePowerAsValue)
{ {
b->val = spell->powers[level_idx]; b->val = spell->powers[levelIndex];
} }
spell->effects[level_idx].push_back(b); spell->effects[levelIndex].push_back(b);
} }
} }
} }
@ -889,14 +822,11 @@ CSpell * CSpellHandler::loadFromJson(const JsonNode& json)
void CSpellHandler::afterLoadFinalization() void CSpellHandler::afterLoadFinalization()
{ {
//FIXME: this a bad place for this code, should refactor loadFromJson to know object id during load //FIXME: it is a bad place for this code, should refactor loadFromJson to know object id during loading
for(auto spell: objects)
for (auto spell: objects) for(auto & level: spell->effects)
for (auto & level: spell->effects) for(auto * bonus: level)
for (auto * bonus: level)
bonus->sid = spell->id; bonus->sid = spell->id;
} }

View File

@ -65,43 +65,43 @@ public:
si16 mainEffectAnim; //main spell effect animation, in AC format (or -1 when none) si16 mainEffectAnim; //main spell effect animation, in AC format (or -1 when none)
ETargetType getTargetType() const; ETargetType getTargetType() const;
inline bool isCombatSpell() const; bool isCombatSpell() const;
inline bool isAdventureSpell() const; bool isAdventureSpell() const;
inline bool isCreatureAbility() const; bool isCreatureAbility() const;
inline bool isPositive() const; bool isPositive() const;
inline bool isNegative() const; bool isNegative() const;
inline bool isRisingSpell() const; bool isRisingSpell() const;
inline bool isDamageSpell() const; bool isDamageSpell() const;
inline bool isOffensiveSpell() const; bool isOffensiveSpell() const;
inline bool isSpecialSpell() const; bool isSpecialSpell() const;
inline bool hasEffects() const; bool hasEffects() const;
void getEffects(std::vector<Bonus> &lst, const int level) const; void getEffects(std::vector<Bonus> &lst, const int level) const;
bool isImmuneBy(const IBonusBearer *obj) const; bool isImmuneBy(const IBonusBearer *obj) const;
inline si32 getCost(const int skillLevel) const; si32 getCost(const int skillLevel) const;
/** /**
* Returns spell level power, base power ignored * Returns spell level power, base power ignored
*/ */
inline si32 getPower(const int skillLevel) const; si32 getPower(const int skillLevel) const;
// /** // /**
// * Returns spell power, taking base power into account // * Returns spell power, taking base power into account
// */ // */
// inline si32 calculatePower(const int skillLevel) const; // si32 calculatePower(const int skillLevel) const;
inline si32 getProbability(const TFaction factionId) const; si32 getProbability(const TFaction factionId) const;
/** /**
* Returns resource name of icon for SPELL_IMMUNITY bonus * Returns resource name of icon for SPELL_IMMUNITY bonus
*/ */
inline const std::string& getIconImmune() const; const std::string& getIconImmune() const;
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
@ -152,86 +152,6 @@ private:
}; };
///CSpell inlines
bool CSpell::isCombatSpell() const
{
return combatSpell;
}
bool CSpell::isAdventureSpell() const
{
return !combatSpell;
}
bool CSpell::isCreatureAbility() const
{
return creatureAbility;
}
bool CSpell::isPositive() const
{
return positiveness == POSITIVE;
}
bool CSpell::isNegative() const
{
return positiveness == NEGATIVE;
}
bool CSpell::isRisingSpell() const
{
return isRising;
}
bool CSpell::isDamageSpell() const
{
return isDamage;
}
bool CSpell::isOffensiveSpell() const
{
return isOffensive;
}
bool CSpell::isSpecialSpell() const
{
return isSpecial;
}
bool CSpell::hasEffects() const
{
return effects.size() && effects[0].size();
}
const std::string& CSpell::getIconImmune() const
{
return iconImmune;
}
si32 CSpell::getCost(const int skillLevel) const
{
return costs[skillLevel];
}
si32 CSpell::getPower(const int skillLevel) const
{
return powers[skillLevel];
}
//si32 CSpell::calculatePower(const int skillLevel) const
//{
// return power + getPower(skillLevel);
//}
si32 CSpell::getProbability(const TFaction factionId) const
{
if (! vstd::contains(probabilities,factionId))
{
return defaultProbability;
}
return probabilities.at(factionId);
}
bool DLL_LINKAGE isInScreenRange(const int3 &center, const int3 &pos); //for spells like Dimension Door bool DLL_LINKAGE isInScreenRange(const int3 &center, const int3 &pos); //for spells like Dimension Door