Просмотр исходного кода

SpellHandler: cleanup, formatting, simplification.

alexvins 11 лет назад
Родитель
Сommit
c959fdcce0
3 измененных файлов с 270 добавлено и 417 удалено
  1. 3 0
      AUTHORS
  2. 252 322
      lib/CSpellHandler.cpp
  3. 15 95
      lib/CSpellHandler.h

+ 3 - 0
AUTHORS

@@ -45,3 +45,6 @@ Ivan Savenko,				<[email protected]>
    
 Benjamin Gentner aka beegee,		<>
    * battle support, programming
+
+Alexander Shishkin aka alexvins,
+   * MinGW platform support, modding related programming

+ 252 - 322
lib/CSpellHandler.cpp

@@ -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;
@@ -132,26 +133,24 @@ namespace SRSLPraserHelpers
 using namespace SRSLPraserHelpers;
 
 CSpell::CSpell():
-    id(SpellID::NONE), level(0),
-    earth(false),water(false),fire(false),air(false),
-    power(0),
-    combatSpell(false),creatureAbility(false),
-    positiveness(ESpellPositiveness::NEUTRAL),
-    mainEffectAnim(-1),
-    defaultProbability(0),
-    isRising(false),isDamage(false),isOffensive(false),targetType(ETargetType::NO_TARGET)
-
+	id(SpellID::NONE), level(0),
+	earth(false), water(false), fire(false), air(false),
+	power(0),
+	combatSpell(false), creatureAbility(false),
+	positiveness(ESpellPositiveness::NEUTRAL),
+	mainEffectAnim(-1),
+	defaultProbability(0),
+	isRising(false), isDamage(false), isOffensive(false),
+	targetType(ETargetType::NO_TARGET)
 {
 
 }
 
 CSpell::~CSpell()
 {
-	for (auto & elem : effects)
-	{
-		for (size_t j=0; j<elem.size(); j++)
+	for(auto & elem : effects)
+		for(size_t j=0; j<elem.size(); j++)
 			delete elem[j];
-	}
 }
 
 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;
 		for(auto & elem : rng)
 		{
-			if( std::isdigit(elem) ) //reading numer
+			if(std::isdigit(elem) ) //reading numer
 			{
 				if(readingFirst)
 					number1 += elem;
@@ -259,25 +258,104 @@ CSpell::ETargetType CSpell::getTargetType() const
 	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
 {
-	if (level < 0 || level >= GameConstants::SPELL_SCHOOL_LEVELS)
+	if(level < 0 || level >= GameConstants::SPELL_SCHOOL_LEVELS)
 	{
         logGlobal->errorStream() << __FUNCTION__ << " invalid school level " << level;
 		return;
 	}
-	if (effects.empty())
+	if(effects.empty())
 	{
         logGlobal->errorStream() << __FUNCTION__ << " This spell ("  + name + ") has no bonus effects! " << name;
 		return;
 	}
-	if (effects.size() <= level)
+	if(effects.size() <= level)
 	{
 		logGlobal->errorStream() << __FUNCTION__ << " This spell ("  + name + ") is missing entry for level " << level;
 		return;
 	}
-	if (effects[level].empty())
+	if(effects[level].empty())
     {
 		logGlobal->errorStream() << __FUNCTION__ << " This spell ("  + name + ") has no effects for level " << level;
 		return;
@@ -285,7 +363,7 @@ void CSpell::getEffects(std::vector<Bonus>& lst, const int level) const
 
 	lst.reserve(lst.size() + effects[level].size());
 
-	for (Bonus *b : effects[level])
+	for(Bonus *b : effects[level])
 	{
 		lst.push_back(Bonus(*b));
 	}
@@ -310,7 +388,7 @@ bool CSpell::isImmuneBy(const IBonusBearer* obj) const
 	}
 
     //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;
 
     //4. Check negatable immunities
@@ -322,36 +400,36 @@ bool CSpell::isImmuneBy(const IBonusBearer* obj) const
 
 	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;
-		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 false;
 	};
 
     //4. Check elemental immunities
-	if (fire)
+	if(fire)
 	{
-		if (battleTestElementalImmunity(Bonus::FIRE_IMMUNITY))
+		if(battleTestElementalImmunity(Bonus::FIRE_IMMUNITY))
 			return true;
 	}
-	if (water)
+	if(water)
 	{
-		if (battleTestElementalImmunity(Bonus::WATER_IMMUNITY))
+		if(battleTestElementalImmunity(Bonus::WATER_IMMUNITY))
 			return true;
 	}
 
-	if (earth)
+	if(earth)
 	{
-		if (battleTestElementalImmunity(Bonus::EARTH_IMMUNITY))
+		if(battleTestElementalImmunity(Bonus::EARTH_IMMUNITY))
 			return true;
 	}
-	if (air)
+	if(air)
 	{
-		if (battleTestElementalImmunity(Bonus::AIR_IMMUNITY))
+		if(battleTestElementalImmunity(Bonus::AIR_IMMUNITY))
 			return true;
 	}
 
@@ -384,7 +462,7 @@ void CSpell::setIsOffensive(const bool val)
 {
    isOffensive = val;
 
-   if (val)
+   if(val)
    {
        positiveness = CSpell::NEGATIVE;
        isDamage = true;
@@ -395,7 +473,7 @@ void CSpell::setIsRising(const bool val)
 {
     isRising = val;
 
-    if (val)
+    if(val)
     {
         positiveness = CSpell::POSITIVE;
     }
@@ -419,7 +497,7 @@ CSpellHandler::CSpellHandler()
 
 std::vector<JsonNode> CSpellHandler::loadLegacyData(size_t dataSize)
 {
-    using namespace SpellConfigJson;
+    using namespace SpellConfig;
     std::vector<JsonNode> legacyData;
 
 	CLegacyConfigParser parser("DATA/SPTRAITS.TXT");
@@ -457,13 +535,10 @@ std::vector<JsonNode> CSpellHandler::loadLegacyData(size_t dataSize)
 
             auto& levels = lineNode["levels"].Struct();
 
-
-
             auto getLevel = [&](const size_t idx)->JsonMap&
             {
                 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);
@@ -472,14 +547,14 @@ std::vector<JsonNode> CSpellHandler::loadLegacyData(size_t dataSize)
 
             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();
             }
 
             auto AIVals = parser.readNumArray<si32>(GameConstants::SPELL_SCHOOL_LEVELS);
 
             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());
 
             std::string attributes = parser.readString();
@@ -496,21 +571,16 @@ std::vector<JsonNode> CSpellHandler::loadLegacyData(size_t dataSize)
 
             lineNode["targetType"].String() = targetType;
 
-
-
             //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);
                 level["description"].String() = descriptions[i];
                 level["cost"].Float() = costs[i];
                 level["power"].Float() = powers[i];
                 level["aiValue"].Float() = AIVals[i];
-
             }
 
-
-//            logGlobal->errorStream() << lineNode;
 		    legacyData.push_back(lineNode);
 
 
@@ -544,81 +614,47 @@ std::vector<JsonNode> CSpellHandler::loadLegacyData(size_t dataSize)
 
 const std::string CSpellHandler::getTypeName() const
 {
-    return "spell";
-}
-
-static void fatalConfigurationError()
-{
-   throw std::runtime_error("SpellHandler: Fatal configuration error, See log for details");
+	return "spell";
 }
 
 CSpell * CSpellHandler::loadFromJson(const JsonNode& json)
 {
-    using namespace SpellConfigJson;
-
-    CSpell * spell = new CSpell();
-
-    const auto type_str = json["type"].String();
+	using namespace SpellConfig;
 
-    if (type_str == "ability")
-    {
-        spell->creatureAbility = true;
-        spell->combatSpell = true;
-    }
-    else
-    {
-       spell->creatureAbility = false;
-       spell->combatSpell = type_str == "combat";
-    }
-
-    spell->name = json["name"].String();
-
-    logGlobal->traceStream() << __FUNCTION__ << ": loading spell " << spell->name;
+	CSpell * spell = new CSpell();
 
-    auto readFlag = [](const JsonNode& flagsNode, const std::string& name)
-    {
-        if (flagsNode.getType() != JsonNode::DATA_STRUCT)
-        {
-            logGlobal->errorStream() << "Flags node shall be object";
-            return false;
-        }
+	const auto type = json["type"].String();
 
-        const JsonNode& flag = flagsNode[name];
-
-        if (flag.isNull())
-        {
-            return false;
-        }
-        else if (flag.getType() == JsonNode::DATA_BOOL)
-        {
-            return flag.Bool();
-        }
-        else
-        {
-            logGlobal->errorStream() << "Flag shall be boolean: "<<name;
-            return false;
-        }
+	if(type == "ability")
+	{
+		spell->creatureAbility = true;
+		spell->combatSpell = true;
+	}
+	else
+	{
+		spell->creatureAbility = false;
+		spell->combatSpell = type == "combat";
+	}
 
-    };
+	spell->name = json["name"].String();
 
-    const auto school_names = json["school"];
+	logGlobal->traceStream() << __FUNCTION__ << ": loading spell " << spell->name;
 
-    spell->air = readFlag(school_names, "air");
-    spell->earth = readFlag(school_names, "earth");
-    spell->fire = readFlag(school_names, "fire");
-    spell->water = readFlag(school_names, "water");
+	const auto schoolNames = json["school"];
 
-    spell->level = json["level"].Float();
-    spell->power = json["power"].Float();
+	spell->air   = schoolNames["air"].Bool();
+	spell->earth = schoolNames["earth"].Bool();
+	spell->fire  = schoolNames["fire"].Bool();
+	spell->water = schoolNames["water"].Bool();
 
-    //TODO: default chance
-    spell->defaultProbability = json["defaultGainChance"].Float();
+	spell->level = json["level"].Float();
+	spell->power = json["power"].Float();
 
-    auto chances = json["gainChance"].Struct();
+	spell->defaultProbability = json["defaultGainChance"].Float();
 
-    for(auto &node : chances)
+	for(const auto & node : json["gainChance"].Struct())
 	{
-		int chance = node.second.Float();
+		const int chance = node.second.Float();
 
 		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")
+		spell->targetType = CSpell::NO_TARGET;
+	else if(targetType == "CREATURE")
+		spell->targetType = CSpell::CREATURE;
+	else if(targetType == "OBSTACLE")
+		spell->targetType = CSpell::OBSTACLE;
+	else if(targetType == "CREATURE_EXPERT_MASSIVE")
+		spell->targetType = CSpell::CREATURE_EXPERT_MASSIVE;
 
-    if (target_type_str == "NO_TARGET")
-        spell->targetType = CSpell::NO_TARGET;
-    else if (target_type_str == "CREATURE")
-        spell->targetType = CSpell::CREATURE;
-    else if (target_type_str == "OBSTACLE")
-        spell->targetType = CSpell::OBSTACLE;
-    else if (target_type_str == "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())
-    {
-        if (k_v.second.Bool())
-        {
-            JsonNode tmp(JsonNode::DATA_STRING);
-            tmp.meta = json.meta;
-            tmp.String() = k_v.first;
+	for(const auto & counteredSpell: json["counters"].Struct())
+		if (counteredSpell.second.Bool())
+		{
+			JsonNode tmp(JsonNode::DATA_STRING);
+			tmp.meta = json.meta;
+			tmp.String() = counteredSpell.first;
 
-            VLC->modh->identifiers.requestIdentifier(tmp,[=](si32 id){
-                spell->counteredSpells.push_back(SpellID(id));
-            });
+			VLC->modh->identifiers.requestIdentifier(tmp,[=](si32 id){
+				spell->counteredSpells.push_back(SpellID(id));
+			});
+		}
 
-        }
-    }
-    //TODO: more error checking - f.e. conflicting flags
-    const auto flags = json["flags"];
+	//TODO: more error checking - f.e. conflicting 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"))
-    {
-        logGlobal->warnStream() << spell->name << ": summoning flag in unimplemented";
-    }
+	if(flags["summoning"].Bool())
+	{
+		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"))
-    {
-        spell->setIsOffensive(true);
-    }
+	if(flags["offensive"].Bool())
+	{
+		spell->setIsOffensive(true);
+	}
 
-    if (readFlag(flags,"rising"))
-    {
-        spell->setIsRising(true);
-    }
+	if(flags["rising"].Bool())
+	{
+		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"))
-    {
-        spell->positiveness = CSpell::NEUTRAL;
-    }
-    else if (readFlag(flags,"negative"))
-    {
-        spell->positiveness = CSpell::NEGATIVE;
-    }
-    else if (readFlag(flags,"positive"))
-    {
-        spell->positiveness = CSpell::POSITIVE;
-    }
-    else if(!implicit_positiveness)
-    {
-        spell->positiveness = CSpell::NEUTRAL; //duplicates constructor but, just in case
-        logGlobal->errorStream() << "No positiveness specified, assumed NEUTRAL";
-    }
+	if(flags["indifferent"].Bool())
+	{
+		spell->positiveness = CSpell::NEUTRAL;
+	}
+	else if(flags["negative"].Bool())
+	{
+		spell->positiveness = CSpell::NEGATIVE;
+	}
+	else if(flags["positive"].Bool())
+	{
+		spell->positiveness = CSpell::POSITIVE;
+	}
+	else if(!implicitPositiveness)
+	{
+		spell->positiveness = CSpell::NEUTRAL; //duplicates constructor but, just in case
+		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);
-        if (it == bonusNameMap.end())
+        if(it == bonusNameMap.end())
         {
             logGlobal->errorStream() << spell->name << ": invalid bonus name" << name;
         }
@@ -716,187 +745,88 @@ 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];
-
-        if (!node.isNull())
-        {
-            for (auto key_value: node.Struct())
-            {
-                const std::string bonus_id = key_value.first;
-                const bool flag = key_value.second.Bool();
+		for(auto bonusData: json[name].Struct())
+		{
+			const std::string bonusId = bonusData.first;
+			const bool flag = bonusData.second.Bool();
 
-                if (flag)
-                {
-                   find_in_map(bonus_id, vec);
-                }
-            }
-        }
+			if(flag)
+				findBonus(bonusId, 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"];
-    if (!graphicsNode.isNull())
-    {
-        spell->iconImmune = graphicsNode["iconImmune"].String();
-    }
-
-    //load level attributes
-
-    const int level_count = GameConstants::SPELL_SCHOOL_LEVELS;
-
-    spell->AIVals.resize(level_count);
-    spell->costs.resize(level_count);
-    spell->descriptions.resize(level_count);
+ 
+	spell->iconImmune = graphicsNode["iconImmune"].String();
 
-    spell->powers.resize(level_count);
-    spell->range.resize(level_count);
-
-
-    const JsonNode & levels_node = json["levels"];
-
-    if (levels_node.isNull())
-    {
-        logGlobal->errorStream() << spell->name << ": no level specific data";
-        fatalConfigurationError();
-    }
-
-    if (levels_node.getType()!=JsonNode::DATA_STRUCT)
-    {
-        logGlobal->errorStream() << spell->name << ": level specific data shall be JSON object";
-        fatalConfigurationError();
-    }
-
-    const JsonMap & levels = json["levels"].Struct();
-
-
-    for(int level_idx = 0; level_idx < level_count; level_idx++)
-    {
-        const auto& level_node = levels.at(level_names[level_idx]);
 
+    //load level attributes
 
-        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();
-            }
-        };
+    const int levelsCount = GameConstants::SPELL_SCHOOL_LEVELS;
 
-        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();
-            }
-        };
+    spell->AIVals.resize(levelsCount);
+    spell->costs.resize(levelsCount);
+    spell->descriptions.resize(levelsCount);
 
-        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);
-        }
+    spell->powers.resize(levelsCount);
+    spell->range.resize(levelsCount);
 
+	for(int levelIndex = 0; levelIndex < levelsCount; levelIndex++)
+	{
+		const JsonNode & levelNode = json["levels"][LEVEL_NAMES[levelIndex]];
 
+		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& effects_node = level_node["effects"];
+		const JsonNode & effectsNode = levelNode["effects"];
 
-        if (!effects_node.isNull())
-        {
-            if (spell->effects.empty())
-                spell->effects.resize(level_count);
+		if(!effectsNode.isNull())
+		{
+			if(spell->effects.empty())
+				spell->effects.resize(levelsCount);
 
-            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();
+			for(const auto & elem : effectsNode.Struct())
+			{
+				const JsonNode & bonusNode = elem.second;
+				Bonus * b = JsonUtils::parseBonus(bonusNode);
+				const bool usePowerAsValue = bonusNode["val"].isNull();
 
 				//TODO: make this work. see CSpellHandler::afterLoadFinalization()
 				//b->sid = spell->id; //for all
+				
 				b->source = Bonus::SPELL_EFFECT;//for all
 
-				if (usePowerAsValue)
-                {
-                   b->val = spell->powers[level_idx];
-                }
-
-				spell->effects[level_idx].push_back(b);
+				if(usePowerAsValue)
+				{
+					b->val = spell->powers[levelIndex];
+				}
 
-            }
-        }
-    }
+				spell->effects[levelIndex].push_back(b);
+			}
+		}
+	}
 
     return spell;
 }
 
 void CSpellHandler::afterLoadFinalization()
 {
-    //FIXME: this a bad place for this code, should refactor loadFromJson to know object id during load
-
-    for (auto spell: objects)
-        for (auto & level: spell->effects)
-            for (auto * bonus: level)
-                bonus->sid = spell->id;
-
-
+    //FIXME: it is a bad place for this code, should refactor loadFromJson to know object id during loading
+	for(auto spell: objects)
+		for(auto & level: spell->effects)
+			for(auto * bonus: level)
+				bonus->sid = spell->id;
 }
 
 

+ 15 - 95
lib/CSpellHandler.h

@@ -65,43 +65,43 @@ public:
 	si16 mainEffectAnim; //main spell effect animation, in AC format (or -1 when none)
 	ETargetType getTargetType() const;
 
-	inline bool isCombatSpell() const;
-	inline bool isAdventureSpell() const;
-	inline bool isCreatureAbility() const;
+	bool isCombatSpell() const;
+	bool isAdventureSpell() const;
+	bool isCreatureAbility() const;
 
-	inline bool isPositive() const;
-	inline bool isNegative() const;
+	bool isPositive() const;
+	bool isNegative() const;
 
-	inline bool isRisingSpell() const;
-	inline bool isDamageSpell() const;
-	inline bool isOffensiveSpell() const;
+	bool isRisingSpell() const;
+	bool isDamageSpell() 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;
 
 	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
 	*/
-	inline si32 getPower(const int skillLevel) const;
+	si32 getPower(const int skillLevel) const;
 
 //    /**
 //	* 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
 	*/
-	inline const std::string& getIconImmune() const;
+	const std::string& getIconImmune() const;
 
 	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