mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
Enabled new secondary skills to be created (#438)
* Universities, Scholars and Witch Huts may offer new skills * Moved encode/decodeSkill to CSkillHandler * Refactored CSkill interface and CSkill::LevelInfo image storage * Legacy game constants renamed to ORIGINAL_XXX_QUANTITY
This commit is contained in:
parent
b09a54fa9c
commit
6ddcb079a4
@ -25,7 +25,7 @@ SPELLS:
|
||||
|
||||
MODS:
|
||||
* Improve support for WoG commander artifacts and skill descriptions
|
||||
* Added basic support for secondary skill modding
|
||||
* Added support for modding of original secondary skills and creation of new ones.
|
||||
* Map object sounds can now be configured via json
|
||||
* Added bonus updaters for hero specialties
|
||||
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "../lib/CGeneralTextHandler.h"
|
||||
#include "../lib/CCreatureHandler.h"
|
||||
#include "CBitmapHandler.h"
|
||||
#include "../lib/CSkillHandler.h"
|
||||
#include "../lib/spells/CSpellHandler.h"
|
||||
#include "../lib/CGameState.h"
|
||||
#include "../lib/JsonNode.h"
|
||||
@ -443,4 +444,16 @@ void Graphics::initializeImageLists()
|
||||
addImageListEntry(spell->id, "SPELLBON", spell->iconScenarioBonus);
|
||||
addImageListEntry(spell->id, "SPELLSCR", spell->iconScroll);
|
||||
}
|
||||
|
||||
for(const CSkill * skill : CGI->skillh->objects)
|
||||
{
|
||||
for(int level = 1; level <= 3; level++)
|
||||
{
|
||||
int frame = 2 + level + 3 * skill->id;
|
||||
const CSkill::LevelInfo & skillAtLevel = skill->at(level);
|
||||
addImageListEntry(frame, "SECSK32", skillAtLevel.iconSmall);
|
||||
addImageListEntry(frame, "SECSKILL", skillAtLevel.iconMedium);
|
||||
addImageListEntry(frame, "SECSK82", skillAtLevel.iconLarge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,27 @@
|
||||
"description" : "Set of bonuses provided by skill at given level",
|
||||
"required" : ["description", "effects"],
|
||||
"properties" : {
|
||||
"images" : {
|
||||
"type" : "object",
|
||||
"description" : "skill icons of varying size",
|
||||
"properties" : {
|
||||
"small" : {
|
||||
"type" : "string",
|
||||
"description" : "32x32 skill icon",
|
||||
"format" : "imageFile"
|
||||
},
|
||||
"medium" : {
|
||||
"type" : "string",
|
||||
"description" : "44x44 skill icon",
|
||||
"format" : "imageFile"
|
||||
},
|
||||
"large" : {
|
||||
"type" : "string",
|
||||
"description" : "82x93 skill icon",
|
||||
"format" : "imageFile"
|
||||
}
|
||||
}
|
||||
},
|
||||
"description" : {
|
||||
"type" : "string",
|
||||
"description" : "localizable description"
|
||||
@ -39,6 +60,28 @@
|
||||
"type": "string",
|
||||
"description": "localizable skill name"
|
||||
},
|
||||
"gainChance" : {
|
||||
"description" : "Chance for the skill to be offered on level-up (heroClass may override)",
|
||||
"anyOf" : [
|
||||
{
|
||||
"type" : "number"
|
||||
},
|
||||
{
|
||||
"type" : "object",
|
||||
"required" : ["might", "magic"],
|
||||
"properties" : {
|
||||
"might" : {
|
||||
"type" : "number",
|
||||
"description" : "Chance for hero classes with might affinity"
|
||||
},
|
||||
"magic" : {
|
||||
"type" : "number",
|
||||
"description" : "Chance for hero classes with magic affinity"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"base" : {
|
||||
"type" : "object",
|
||||
"description" : "will be merged with all levels",
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "CModHandler.h"
|
||||
#include "CTownHandler.h"
|
||||
#include "mapObjects/CObjectHandler.h" //for hero specialty
|
||||
#include "CSkillHandler.h"
|
||||
#include <math.h>
|
||||
|
||||
#include "mapObjects/CObjectClassesHandler.h"
|
||||
@ -117,9 +118,15 @@ CHeroClass * CHeroClassHandler::loadFromJson(const JsonNode & node, const std::s
|
||||
heroClass->primarySkillHighLevel.push_back(node["highLevelChance"][pSkill].Float());
|
||||
}
|
||||
|
||||
for(const std::string & secSkill : NSecondarySkill::names)
|
||||
for(auto skillPair : node["secondarySkills"].Struct())
|
||||
{
|
||||
heroClass->secSkillProbability.push_back(node["secondarySkills"][secSkill].Float());
|
||||
int probability = skillPair.second.Integer();
|
||||
VLC->modh->identifiers.requestIdentifier(skillPair.second.meta, "skill", skillPair.first, [heroClass, probability](si32 skillID)
|
||||
{
|
||||
if(heroClass->secSkillProbability.size() <= skillID)
|
||||
heroClass->secSkillProbability.resize(skillID + 1, -1); // -1 = override with default later
|
||||
heroClass->secSkillProbability[skillID] = probability;
|
||||
});
|
||||
}
|
||||
|
||||
VLC->modh->identifiers.requestIdentifier ("creature", node["commander"],
|
||||
@ -241,6 +248,17 @@ void CHeroClassHandler::afterLoadFinalization()
|
||||
float chance = heroClass->defaultTavernChance * faction->town->defaultTavernChance;
|
||||
heroClass->selectionProbability[faction->index] = static_cast<int>(sqrt(chance) + 0.5); //FIXME: replace with std::round once MVS supports it
|
||||
}
|
||||
// set default probabilities for gaining secondary skills where not loaded previously
|
||||
heroClass->secSkillProbability.resize(VLC->skillh->size(), -1);
|
||||
for(int skillID = 0; skillID < VLC->skillh->size(); skillID++)
|
||||
{
|
||||
if(heroClass->secSkillProbability[skillID] < 0)
|
||||
{
|
||||
const CSkill * skill = (*VLC->skillh)[SecondarySkill(skillID)];
|
||||
logMod->trace("%s: no probability for %s, using default", heroClass->identifier, skill->identifier);
|
||||
heroClass->secSkillProbability[skillID] = skill->gainChance[heroClass->affinity];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (CHeroClass * hc : heroClasses)
|
||||
@ -277,11 +295,6 @@ CHeroHandler::CHeroHandler()
|
||||
{
|
||||
VLC->heroh = this;
|
||||
|
||||
for (int i = 0; i < GameConstants::SKILL_QUANTITY; ++i)
|
||||
{
|
||||
VLC->modh->identifiers.registerObject("core", "skill", NSecondarySkill::names[i], i);
|
||||
VLC->modh->identifiers.registerObject("core", "secondarySkill", NSecondarySkill::names[i], i);
|
||||
}
|
||||
loadObstacles();
|
||||
loadTerrains();
|
||||
for (int i = 0; i < GameConstants::TERRAIN_TYPES; ++i)
|
||||
@ -943,13 +956,6 @@ std::vector<bool> CHeroHandler::getDefaultAllowed() const
|
||||
return allowedHeroes;
|
||||
}
|
||||
|
||||
std::vector<bool> CHeroHandler::getDefaultAllowedAbilities() const
|
||||
{
|
||||
std::vector<bool> allowedAbilities;
|
||||
allowedAbilities.resize(GameConstants::SKILL_QUANTITY, true);
|
||||
return allowedAbilities;
|
||||
}
|
||||
|
||||
si32 CHeroHandler::decodeHero(const std::string & identifier)
|
||||
{
|
||||
auto rawId = VLC->modh->identifiers.getIdentifier("core", "hero", identifier);
|
||||
@ -963,17 +969,3 @@ std::string CHeroHandler::encodeHero(const si32 index)
|
||||
{
|
||||
return VLC->heroh->heroes.at(index)->identifier;
|
||||
}
|
||||
|
||||
si32 CHeroHandler::decodeSkill(const std::string & identifier)
|
||||
{
|
||||
auto rawId = VLC->modh->identifiers.getIdentifier("core", "skill", identifier);
|
||||
if(rawId)
|
||||
return rawId.get();
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string CHeroHandler::encodeSkill(const si32 index)
|
||||
{
|
||||
return NSecondarySkill::names[index];
|
||||
}
|
||||
|
@ -311,25 +311,12 @@ public:
|
||||
|
||||
std::vector<bool> getDefaultAllowed() const override;
|
||||
|
||||
/**
|
||||
* Gets a list of default allowed abilities. OH3 abilities/skills are all allowed by default.
|
||||
*
|
||||
* @return a list of allowed abilities, the index is the ability id
|
||||
*/
|
||||
std::vector<bool> getDefaultAllowedAbilities() const;
|
||||
|
||||
///json serialization helper
|
||||
static si32 decodeHero(const std::string & identifier);
|
||||
|
||||
///json serialization helper
|
||||
static std::string encodeHero(const si32 index);
|
||||
|
||||
///json serialization helper
|
||||
static si32 decodeSkill(const std::string & identifier);
|
||||
|
||||
///json serialization helper
|
||||
static std::string encodeSkill(const si32 index);
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & classes;
|
||||
|
@ -240,7 +240,7 @@ std::vector<CIdentifierStorage::ObjectData> CIdentifierStorage::getPossibleIdent
|
||||
{
|
||||
// allow only available to all core mod or dependencies
|
||||
auto myDeps = VLC->modh->getModData(request.localScope).dependencies;
|
||||
if (request.remoteScope == "core" || myDeps.count(request.remoteScope))
|
||||
if(request.remoteScope == "core" || request.remoteScope == request.localScope || myDeps.count(request.remoteScope))
|
||||
allowedScopes.insert(request.remoteScope);
|
||||
}
|
||||
}
|
||||
|
@ -31,16 +31,10 @@ CSkill::LevelInfo::~LevelInfo()
|
||||
{
|
||||
}
|
||||
|
||||
CSkill::CSkill(SecondarySkill id) : id(id)
|
||||
CSkill::CSkill(SecondarySkill id, std::string identifier)
|
||||
: id(id), identifier(identifier)
|
||||
{
|
||||
if(id == SecondarySkill::DEFAULT)
|
||||
identifier = "default";
|
||||
else
|
||||
identifier = NSecondarySkill::names[id];
|
||||
// init levels
|
||||
LevelInfo emptyLevel;
|
||||
for(int level = 1; level < NSecondarySkill::levels.size(); level++)
|
||||
levels.push_back(emptyLevel);
|
||||
levels.resize(NSecondarySkill::levels.size() - 1);
|
||||
}
|
||||
|
||||
CSkill::~CSkill()
|
||||
@ -56,19 +50,16 @@ void CSkill::addNewBonus(const std::shared_ptr<Bonus> & b, int level)
|
||||
levels[level-1].effects.push_back(b);
|
||||
}
|
||||
|
||||
void CSkill::setDescription(const std::string & desc, int level)
|
||||
const CSkill::LevelInfo & CSkill::at(int level) const
|
||||
{
|
||||
levels[level-1].description = desc;
|
||||
assert(1 <= level && level < NSecondarySkill::levels.size());
|
||||
return levels[level - 1];
|
||||
}
|
||||
|
||||
const std::vector<std::shared_ptr<Bonus>> & CSkill::getBonus(int level) const
|
||||
CSkill::LevelInfo & CSkill::at(int level)
|
||||
{
|
||||
return levels[level-1].effects;
|
||||
}
|
||||
|
||||
const std::string & CSkill::getDescription(int level) const
|
||||
{
|
||||
return levels[level-1].description;
|
||||
assert(1 <= level && level < NSecondarySkill::levels.size());
|
||||
return levels[level - 1];
|
||||
}
|
||||
|
||||
DLL_LINKAGE std::ostream & operator<<(std::ostream & out, const CSkill::LevelInfo & info)
|
||||
@ -139,14 +130,15 @@ std::vector<JsonNode> CSkillHandler::loadLegacyData(size_t dataSize)
|
||||
return legacyData;
|
||||
}
|
||||
|
||||
const std::string CSkillHandler::getTypeName() const
|
||||
const std::vector<std::string> & CSkillHandler::getTypeNames() const
|
||||
{
|
||||
return "skill";
|
||||
static const std::vector<std::string> typeNames = { "skill", "secondarySkill" };
|
||||
return typeNames;
|
||||
}
|
||||
|
||||
const std::string & CSkillHandler::skillInfo(int skill, int level) const
|
||||
{
|
||||
return objects[skill]->getDescription(level);
|
||||
return objects[skill]->at(level).description;
|
||||
}
|
||||
|
||||
const std::string & CSkillHandler::skillName(int skill) const
|
||||
@ -156,24 +148,22 @@ const std::string & CSkillHandler::skillName(int skill) const
|
||||
|
||||
CSkill * CSkillHandler::loadFromJson(const JsonNode & json, const std::string & identifier, size_t index)
|
||||
{
|
||||
CSkill * skill = nullptr;
|
||||
|
||||
for(int id = 0; id < GameConstants::SKILL_QUANTITY; id++)
|
||||
{
|
||||
if(NSecondarySkill::names[id].compare(identifier) == 0)
|
||||
{
|
||||
skill = new CSkill(SecondarySkill(id));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!skill)
|
||||
{
|
||||
logMod->error("unknown secondary skill %s", identifier);
|
||||
throw std::runtime_error("invalid skill");
|
||||
}
|
||||
CSkill * skill = new CSkill(SecondarySkill(index), identifier);
|
||||
|
||||
skill->name = json["name"].String();
|
||||
switch(json["gainChance"].getType())
|
||||
{
|
||||
case JsonNode::JsonType::DATA_INTEGER:
|
||||
skill->gainChance[0] = json["gainChance"].Integer();
|
||||
skill->gainChance[1] = json["gainChance"].Integer();
|
||||
break;
|
||||
case JsonNode::JsonType::DATA_STRUCT:
|
||||
skill->gainChance[0] = json["gainChance"]["might"].Integer();
|
||||
skill->gainChance[1] = json["gainChance"]["magic"].Integer();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
for(int level = 1; level < NSecondarySkill::levels.size(); level++)
|
||||
{
|
||||
const std::string & levelName = NSecondarySkill::levels[level]; // basic, advanced, expert
|
||||
@ -182,10 +172,13 @@ CSkill * CSkillHandler::loadFromJson(const JsonNode & json, const std::string &
|
||||
for(auto b : levelNode["effects"].Struct())
|
||||
{
|
||||
auto bonus = JsonUtils::parseBonus(b.second);
|
||||
bonus->sid = skill->id;
|
||||
skill->addNewBonus(bonus, level);
|
||||
}
|
||||
skill->setDescription(levelNode["description"].String(), level);
|
||||
CSkill::LevelInfo & skillAtLevel = skill->at(level);
|
||||
skillAtLevel.description = levelNode["description"].String();
|
||||
skillAtLevel.iconSmall = levelNode["images"]["small"].String();
|
||||
skillAtLevel.iconMedium = levelNode["images"]["medium"].String();
|
||||
skillAtLevel.iconLarge = levelNode["images"]["large"].String();
|
||||
}
|
||||
logMod->debug("loaded secondary skill %s(%d)", identifier, (int)skill->id);
|
||||
logMod->trace("%s", skill->toString());
|
||||
@ -220,3 +213,22 @@ std::vector<bool> CSkillHandler::getDefaultAllowed() const
|
||||
std::vector<bool> allowedSkills(objects.size(), true);
|
||||
return allowedSkills;
|
||||
}
|
||||
|
||||
si32 CSkillHandler::decodeSkill(const std::string & identifier)
|
||||
{
|
||||
auto rawId = VLC->modh->identifiers.getIdentifier("core", "skill", identifier);
|
||||
if(rawId)
|
||||
return rawId.get();
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::string CSkillHandler::encodeSkill(const si32 index)
|
||||
{
|
||||
return (*VLC->skillh)[SecondarySkill(index)]->identifier;
|
||||
}
|
||||
|
||||
std::string CSkillHandler::encodeSkillWithType(const si32 index)
|
||||
{
|
||||
return CModHandler::makeFullIdentifier("", "skill", encodeSkill(index));
|
||||
}
|
||||
|
@ -15,10 +15,13 @@
|
||||
|
||||
class DLL_LINKAGE CSkill // secondary skill
|
||||
{
|
||||
protected:
|
||||
public:
|
||||
struct LevelInfo
|
||||
{
|
||||
std::string description; //descriptions of spell for skill level
|
||||
std::string iconSmall;
|
||||
std::string iconMedium;
|
||||
std::string iconLarge;
|
||||
std::vector<std::shared_ptr<Bonus>> effects;
|
||||
|
||||
LevelInfo();
|
||||
@ -27,31 +30,43 @@ protected:
|
||||
template <typename Handler> void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & description;
|
||||
if(version >= 785)
|
||||
{
|
||||
h & iconSmall;
|
||||
h & iconMedium;
|
||||
h & iconLarge;
|
||||
}
|
||||
h & effects;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
std::vector<LevelInfo> levels; // bonuses provided by basic, advanced and expert level
|
||||
void addNewBonus(const std::shared_ptr<Bonus> & b, int level);
|
||||
|
||||
public:
|
||||
CSkill(SecondarySkill id = SecondarySkill::DEFAULT);
|
||||
CSkill(SecondarySkill id = SecondarySkill::DEFAULT, std::string identifier = "default");
|
||||
~CSkill();
|
||||
|
||||
void addNewBonus(const std::shared_ptr<Bonus> & b, int level);
|
||||
void setDescription(const std::string & desc, int level);
|
||||
const std::vector<std::shared_ptr<Bonus>> & getBonus(int level) const;
|
||||
const std::string & getDescription(int level) const;
|
||||
const LevelInfo & at(int level) const;
|
||||
LevelInfo & at(int level);
|
||||
|
||||
std::string toString() const;
|
||||
|
||||
SecondarySkill id;
|
||||
std::string identifier;
|
||||
std::string name; //as displayed in GUI
|
||||
std::array<si32, 2> gainChance; // gainChance[0/1] = default gain chance on level-up for might/magic heroes
|
||||
|
||||
template <typename Handler> void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & id;
|
||||
h & identifier;
|
||||
h & name;
|
||||
if(version >= 785)
|
||||
{
|
||||
h & gainChance;
|
||||
}
|
||||
h & levels;
|
||||
}
|
||||
|
||||
@ -72,11 +87,16 @@ public:
|
||||
void beforeValidate(JsonNode & object) override;
|
||||
|
||||
std::vector<bool> getDefaultAllowed() const override;
|
||||
const std::string getTypeName() const override;
|
||||
const std::vector<std::string> & getTypeNames() const override;
|
||||
|
||||
const std::string & skillInfo(int skill, int level) const;
|
||||
const std::string & skillName(int skill) const;
|
||||
|
||||
///json serialization helpers
|
||||
static si32 decodeSkill(const std::string & identifier);
|
||||
static std::string encodeSkill(const si32 index);
|
||||
static std::string encodeSkillWithType(const si32 index);
|
||||
|
||||
template <typename Handler> void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & objects;
|
||||
|
@ -1274,7 +1274,7 @@ JsonNode subtypeToJson(Bonus::BonusType type, int subtype)
|
||||
case Bonus::PRIMARY_SKILL:
|
||||
return JsonUtils::stringNode("primSkill." + PrimarySkill::names[subtype]);
|
||||
case Bonus::SECONDARY_SKILL_PREMY:
|
||||
return JsonUtils::stringNode("skill." + NSecondarySkill::names[subtype]);
|
||||
return JsonUtils::stringNode(CSkillHandler::encodeSkillWithType(subtype));
|
||||
case Bonus::SPECIAL_SPELL_LEV:
|
||||
case Bonus::SPECIFIC_SPELL_DAMAGE:
|
||||
case Bonus::SPECIAL_BLESS_DAMAGE:
|
||||
@ -1362,7 +1362,7 @@ std::string Bonus::nameForBonus() const
|
||||
case Bonus::PRIMARY_SKILL:
|
||||
return PrimarySkill::names[subtype];
|
||||
case Bonus::SECONDARY_SKILL_PREMY:
|
||||
return NSecondarySkill::names[subtype];
|
||||
return CSkillHandler::encodeSkill(subtype);
|
||||
case Bonus::SPECIAL_SPELL_LEV:
|
||||
case Bonus::SPECIFIC_SPELL_DAMAGE:
|
||||
case Bonus::SPECIAL_BLESS_DAMAGE:
|
||||
|
@ -67,21 +67,21 @@ public:
|
||||
}
|
||||
void loadObject(std::string scope, std::string name, const JsonNode & data) override
|
||||
{
|
||||
auto type_name = getTypeName();
|
||||
auto object = loadFromJson(data, normalizeIdentifier(scope, "core", name), objects.size());
|
||||
|
||||
objects.push_back(object);
|
||||
|
||||
for(auto type_name : getTypeNames())
|
||||
registerObject(scope, type_name, name, object->id);
|
||||
}
|
||||
void loadObject(std::string scope, std::string name, const JsonNode & data, size_t index) override
|
||||
{
|
||||
auto type_name = getTypeName();
|
||||
auto object = loadFromJson(data, normalizeIdentifier(scope, "core", name), index);
|
||||
|
||||
assert(objects[index] == nullptr); // ensure that this id was not loaded before
|
||||
objects[index] = object;
|
||||
|
||||
for(auto type_name : getTypeNames())
|
||||
registerObject(scope, type_name, name, object->id);
|
||||
}
|
||||
|
||||
@ -91,15 +91,19 @@ public:
|
||||
|
||||
if (raw_id < 0 || raw_id >= objects.size())
|
||||
{
|
||||
logMod->error("%s id %d is invalid", getTypeName(), static_cast<si64>(raw_id));
|
||||
logMod->error("%s id %d is invalid", getTypeNames()[0], static_cast<si64>(raw_id));
|
||||
throw std::runtime_error("internal error");
|
||||
}
|
||||
|
||||
return objects[raw_id];
|
||||
}
|
||||
size_t size() const
|
||||
{
|
||||
return objects.size();
|
||||
}
|
||||
protected:
|
||||
virtual _Object * loadFromJson(const JsonNode & json, const std::string & identifier, size_t index) = 0;
|
||||
virtual const std::string getTypeName() const = 0;
|
||||
virtual const std::vector<std::string> & getTypeNames() const = 0;
|
||||
public: //todo: make private
|
||||
std::vector<ConstTransitivePtr<_Object>> objects;
|
||||
};
|
||||
|
@ -560,7 +560,7 @@ void CGHeroInstance::recreateSpecialtyBonuses(std::vector<HeroSpecial *> & speci
|
||||
void CGHeroInstance::updateSkillBonus(SecondarySkill which, int val)
|
||||
{
|
||||
removeBonuses(Selector::source(Bonus::SECONDARY_SKILL, which));
|
||||
auto skillBonus = (*VLC->skillh)[which]->getBonus(val);
|
||||
auto skillBonus = (*VLC->skillh)[which]->at(val).effects;
|
||||
for (auto b : skillBonus)
|
||||
addNewBonus(std::make_shared<Bonus>(*b));
|
||||
}
|
||||
@ -1107,7 +1107,7 @@ std::vector<SecondarySkill> CGHeroInstance::getLevelUpProposedSecondarySkills()
|
||||
std::vector<SecondarySkill> skills;
|
||||
//picking sec. skills for choice
|
||||
std::set<SecondarySkill> basicAndAdv, expert, none;
|
||||
for(int i=0;i<GameConstants::SKILL_QUANTITY;i++)
|
||||
for(int i = 0; i < VLC->skillh->size(); i++)
|
||||
if (cb->isAllowed(2,i))
|
||||
none.insert(SecondarySkill(i));
|
||||
|
||||
@ -1450,10 +1450,10 @@ void CGHeroInstance::serializeCommonOptions(JsonSerializeFormat & handler)
|
||||
{
|
||||
const si32 rawId = p.first.num;
|
||||
|
||||
if(rawId < 0 || rawId >= GameConstants::SKILL_QUANTITY)
|
||||
if(rawId < 0 || rawId >= VLC->skillh->size())
|
||||
logGlobal->error("Invalid secondary skill %d", rawId);
|
||||
|
||||
handler.serializeEnum(NSecondarySkill::names[rawId], p.second, 0, NSecondarySkill::levels);
|
||||
handler.serializeEnum((*VLC->skillh)[SecondarySkill(rawId)]->identifier, p.second, 0, NSecondarySkill::levels);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1474,7 +1474,7 @@ void CGHeroInstance::serializeCommonOptions(JsonSerializeFormat & handler)
|
||||
const std::string skillId = p.first;
|
||||
const std::string levelId = p.second.String();
|
||||
|
||||
const int rawId = vstd::find_pos(NSecondarySkill::names, skillId);
|
||||
const int rawId = CSkillHandler::decodeSkill(skillId);
|
||||
if(rawId < 0)
|
||||
{
|
||||
logGlobal->error("Invalid secondary skill %s", skillId);
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "../CGameState.h"
|
||||
#include "CGTownInstance.h"
|
||||
#include "../CModHandler.h"
|
||||
#include "../CSkillHandler.h"
|
||||
|
||||
///helpers
|
||||
static void openWindow(const OpenWindow::EWindow type, const int id1, const int id2 = -1)
|
||||
@ -299,7 +300,7 @@ void CGBlackMarket::newTurn(CRandomGenerator & rand) const
|
||||
void CGUniversity::initObj(CRandomGenerator & rand)
|
||||
{
|
||||
std::vector<int> toChoose;
|
||||
for(int i = 0; i < GameConstants::SKILL_QUANTITY; ++i)
|
||||
for(int i = 0; i < VLC->skillh->size(); ++i)
|
||||
{
|
||||
if(cb->isAllowed(2, i))
|
||||
{
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "../CSoundBase.h"
|
||||
|
||||
#include "../spells/CSpellHandler.h"
|
||||
#include "../CSkillHandler.h"
|
||||
#include "../StartInfo.h"
|
||||
#include "../IGameCallback.h"
|
||||
#include "../StringConstants.h"
|
||||
@ -419,7 +420,7 @@ void CGPandoraBox::serializeJsonOptions(JsonSerializeFormat & handler)
|
||||
|
||||
for(size_t idx = 0; idx < abilities.size(); idx++)
|
||||
{
|
||||
handler.serializeEnum(NSecondarySkill::names[abilities[idx]], abilityLevels[idx], NSecondarySkill::levels);
|
||||
handler.serializeEnum(CSkillHandler::encodeSkill(abilities[idx]), abilityLevels[idx], NSecondarySkill::levels);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -437,7 +438,7 @@ void CGPandoraBox::serializeJsonOptions(JsonSerializeFormat & handler)
|
||||
const std::string skillName = p.first;
|
||||
const std::string levelId = p.second.String();
|
||||
|
||||
const int rawId = vstd::find_pos(NSecondarySkill::names, skillName);
|
||||
const int rawId = CSkillHandler::decodeSkill(skillName);
|
||||
if(rawId < 0)
|
||||
{
|
||||
logGlobal->error("Invalid secondary skill %s", skillName);
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "../GameConstants.h"
|
||||
#include "../StringConstants.h"
|
||||
#include "../spells/CSpellHandler.h"
|
||||
#include "../CSkillHandler.h"
|
||||
#include "../mapping/CMap.h"
|
||||
|
||||
|
||||
@ -920,7 +921,7 @@ void CGSeerHut::serializeJsonOptions(JsonSerializeFormat & handler)
|
||||
identifier = PrimarySkill::names[rID];
|
||||
break;
|
||||
case SECONDARY_SKILL:
|
||||
identifier = NSecondarySkill::names[rID];
|
||||
identifier = CSkillHandler::encodeSkill(rID);
|
||||
break;
|
||||
case ARTIFACT:
|
||||
identifier = ArtifactID(rID).toArtifact()->identifier;
|
||||
|
@ -1439,7 +1439,7 @@ void CGWitchHut::initObj(CRandomGenerator & rand)
|
||||
{
|
||||
if (allowedAbilities.empty()) //this can happen for RMG. regular maps load abilities from map file
|
||||
{
|
||||
for (int i = 0; i < GameConstants::SKILL_QUANTITY; i++)
|
||||
for(int i = 0; i < VLC->skillh->size(); i++)
|
||||
allowedAbilities.push_back(i);
|
||||
}
|
||||
ability = *RandomGeneratorUtil::nextItem(allowedAbilities, rand);
|
||||
@ -1496,23 +1496,24 @@ void CGWitchHut::serializeJsonOptions(JsonSerializeFormat & handler)
|
||||
//TODO: unify allowed abilities with others - make them std::vector<bool>
|
||||
|
||||
std::vector<bool> temp;
|
||||
temp.resize(GameConstants::SKILL_QUANTITY, false);
|
||||
size_t skillCount = VLC->skillh->size();
|
||||
temp.resize(skillCount, false);
|
||||
|
||||
auto standard = VLC->heroh->getDefaultAllowedAbilities(); //todo: for WitchHut default is all except Leadership and Necromancy
|
||||
auto standard = VLC->skillh->getDefaultAllowed(); //todo: for WitchHut default is all except Leadership and Necromancy
|
||||
|
||||
if(handler.saving)
|
||||
{
|
||||
for(si32 i = 0; i < GameConstants::SKILL_QUANTITY; ++i)
|
||||
for(si32 i = 0; i < skillCount; ++i)
|
||||
if(vstd::contains(allowedAbilities, i))
|
||||
temp[i] = true;
|
||||
}
|
||||
|
||||
handler.serializeLIC("allowedSkills", &CHeroHandler::decodeSkill, &CHeroHandler::encodeSkill, standard, temp);
|
||||
handler.serializeLIC("allowedSkills", &CSkillHandler::decodeSkill, &CSkillHandler::encodeSkill, standard, temp);
|
||||
|
||||
if(!handler.saving)
|
||||
{
|
||||
allowedAbilities.clear();
|
||||
for (si32 i=0; i<temp.size(); i++)
|
||||
for(si32 i = 0; i < skillCount; ++i)
|
||||
if(temp[i])
|
||||
allowedAbilities.push_back(i);
|
||||
}
|
||||
@ -1746,7 +1747,7 @@ void CGScholar::initObj(CRandomGenerator & rand)
|
||||
bonusID = rand.nextInt(GameConstants::PRIMARY_SKILLS -1);
|
||||
break;
|
||||
case SECONDARY_SKILL:
|
||||
bonusID = rand.nextInt(GameConstants::SKILL_QUANTITY -1);
|
||||
bonusID = rand.nextInt(VLC->skillh->size() - 1);
|
||||
break;
|
||||
case SPELL:
|
||||
std::vector<SpellID> possibilities;
|
||||
@ -1770,7 +1771,7 @@ void CGScholar::serializeJsonOptions(JsonSerializeFormat & handler)
|
||||
handler.serializeString("rewardPrimSkill", value);
|
||||
break;
|
||||
case SECONDARY_SKILL:
|
||||
value = NSecondarySkill::names[bonusID];
|
||||
value = CSkillHandler::encodeSkill(bonusID);
|
||||
handler.serializeString("rewardSkill", value);
|
||||
break;
|
||||
case SPELL:
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "../mapObjects/CGHeroInstance.h"
|
||||
#include "../CGeneralTextHandler.h"
|
||||
#include "../spells/CSpellHandler.h"
|
||||
#include "../CSkillHandler.h"
|
||||
#include "CMapEditManager.h"
|
||||
#include "../serializer/JsonSerializeFormat.h"
|
||||
|
||||
@ -240,7 +241,7 @@ CMap::CMap()
|
||||
guardingCreaturePositions(nullptr)
|
||||
{
|
||||
allHeroes.resize(allowedHeroes.size());
|
||||
allowedAbilities = VLC->heroh->getDefaultAllowedAbilities();
|
||||
allowedAbilities = VLC->skillh->getDefaultAllowed();
|
||||
allowedArtifact = VLC->arth->getDefaultAllowed();
|
||||
allowedSpell = VLC->spellh->getDefaultAllowed();
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "../CStopWatch.h"
|
||||
#include "../filesystem/Filesystem.h"
|
||||
#include "../spells/CSpellHandler.h"
|
||||
#include "../CSkillHandler.h"
|
||||
#include "../CCreatureHandler.h"
|
||||
#include "../CGeneralTextHandler.h"
|
||||
#include "../CHeroHandler.h"
|
||||
@ -1144,14 +1145,18 @@ void CMapLoaderH3M::readObjects()
|
||||
}
|
||||
}
|
||||
}
|
||||
// enable new (modded) skills
|
||||
if(wh->allowedAbilities.size() != 1)
|
||||
{
|
||||
for(int skillID = GameConstants::SKILL_QUANTITY; skillID < VLC->skillh->size(); ++skillID)
|
||||
wh->allowedAbilities.push_back(skillID);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// RoE map
|
||||
for(int gg = 0; gg < GameConstants::SKILL_QUANTITY; ++gg)
|
||||
{
|
||||
wh->allowedAbilities.push_back(gg);
|
||||
}
|
||||
for(int skillID = 0; skillID < VLC->skillh->size(); ++skillID)
|
||||
wh->allowedAbilities.push_back(skillID);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "../mapObjects/CGHeroInstance.h"
|
||||
#include "../mapObjects/CGTownInstance.h"
|
||||
#include "../spells/CSpellHandler.h"
|
||||
#include "../CSkillHandler.h"
|
||||
#include "../StringConstants.h"
|
||||
#include "../serializer/JsonDeserializer.h"
|
||||
#include "../serializer/JsonSerializer.h"
|
||||
@ -807,7 +808,7 @@ void CMapFormatJson::serializeOptions(JsonSerializeFormat & handler)
|
||||
|
||||
serializePredefinedHeroes(handler);
|
||||
|
||||
handler.serializeLIC("allowedAbilities", &CHeroHandler::decodeSkill, &CHeroHandler::encodeSkill, VLC->heroh->getDefaultAllowedAbilities(), map->allowedAbilities);
|
||||
handler.serializeLIC("allowedAbilities", &CSkillHandler::decodeSkill, &CSkillHandler::encodeSkill, VLC->skillh->getDefaultAllowed(), map->allowedAbilities);
|
||||
|
||||
handler.serializeLIC("allowedArtifacts", &ArtifactID::decode, &ArtifactID::encode, VLC->arth->getDefaultAllowed(), map->allowedArtifact);
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
#include "../ConstTransitivePtr.h"
|
||||
#include "../GameConstants.h"
|
||||
|
||||
const ui32 SERIALIZATION_VERSION = 784;
|
||||
const ui32 SERIALIZATION_VERSION = 785;
|
||||
const ui32 MINIMAL_SERIALIZATION_VERSION = 753;
|
||||
const std::string SAVEGAME_MAGIC = "VCMISVG";
|
||||
|
||||
|
@ -707,9 +707,10 @@ std::vector<JsonNode> CSpellHandler::loadLegacyData(size_t dataSize)
|
||||
return legacyData;
|
||||
}
|
||||
|
||||
const std::string CSpellHandler::getTypeName() const
|
||||
const std::vector<std::string> & CSpellHandler::getTypeNames() const
|
||||
{
|
||||
return "spell";
|
||||
static const std::vector<std::string> typeNames = { "spell" };
|
||||
return typeNames;
|
||||
}
|
||||
|
||||
CSpell * CSpellHandler::loadFromJson(const JsonNode & json, const std::string & identifier, size_t index)
|
||||
|
@ -441,7 +441,7 @@ public:
|
||||
*/
|
||||
std::vector<bool> getDefaultAllowed() const override;
|
||||
|
||||
const std::string getTypeName() const override;
|
||||
const std::vector<std::string> & getTypeNames() const override;
|
||||
|
||||
template <typename Handler> void serialize(Handler & h, const int version)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user