1
0
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:
Henning Koehler 2018-03-31 18:56:40 +13:00 committed by ArseniyShestakov
parent b09a54fa9c
commit 6ddcb079a4
21 changed files with 207 additions and 124 deletions

View File

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

View File

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

View File

@ -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",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -67,22 +67,22 @@ 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;
registerObject(scope,type_name, name, object->id);
for(auto type_name : getTypeNames())
registerObject(scope, type_name, name, object->id);
}
ConstTransitivePtr<_Object> operator[] (const _ObjectID id) const
@ -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;
};

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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