mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
- support for new heroes and hero classes
- moved hero-specific data from text handler to CHero - moved hero classes-specific data into heroClasses.json
This commit is contained in:
parent
99e7177d57
commit
e36bc50504
@ -239,10 +239,13 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
|
||||
//loading hero animations
|
||||
if(hero1) // attacking hero
|
||||
{
|
||||
int type = hero1->type->heroClass->id;
|
||||
if ( type % 2 ) type--;
|
||||
if ( hero1->sex ) type++;
|
||||
attackingHero = new CBattleHero(graphics->battleHeroes[type], false, hero1->tempOwner, hero1->tempOwner == curInt->playerID ? hero1 : NULL, this);
|
||||
std::string battleImage;
|
||||
if ( hero1->sex )
|
||||
battleImage = hero1->type->heroClass->imageBattleFemale;
|
||||
else
|
||||
battleImage = hero1->type->heroClass->imageBattleMale;
|
||||
|
||||
attackingHero = new CBattleHero(battleImage, false, hero1->tempOwner, hero1->tempOwner == curInt->playerID ? hero1 : NULL, this);
|
||||
attackingHero->pos = genRect(attackingHero->dh->ourImages[0].bitmap->h, attackingHero->dh->ourImages[0].bitmap->w, pos.x - 43, pos.y - 19);
|
||||
}
|
||||
else
|
||||
@ -251,10 +254,13 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
|
||||
}
|
||||
if(hero2) // defending hero
|
||||
{
|
||||
int type = hero2->type->heroClass->id;
|
||||
if ( type % 2 ) type--;
|
||||
if ( hero2->sex ) type++;
|
||||
defendingHero = new CBattleHero(graphics->battleHeroes[type ], true, hero2->tempOwner, hero2->tempOwner == curInt->playerID ? hero2 : NULL, this);
|
||||
std::string battleImage;
|
||||
if ( hero2->sex )
|
||||
battleImage = hero1->type->heroClass->imageBattleFemale;
|
||||
else
|
||||
battleImage = hero1->type->heroClass->imageBattleMale;
|
||||
|
||||
defendingHero = new CBattleHero(battleImage, true, hero2->tempOwner, hero2->tempOwner == curInt->playerID ? hero2 : NULL, this);
|
||||
defendingHero->pos = genRect(defendingHero->dh->ourImages[0].bitmap->h, defendingHero->dh->ourImages[0].bitmap->w, pos.x + 693, pos.y - 19);
|
||||
}
|
||||
else
|
||||
|
@ -175,8 +175,8 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded /*= fals
|
||||
|
||||
assert(hero == curHero);
|
||||
|
||||
specArea->text = CGI->generaltexth->hTxts[curHero->subID].longBonus;
|
||||
specImage->setFrame(curHero->subID);
|
||||
specArea->text = curHero->type->specDescr;
|
||||
specImage->setFrame(curHero->type->imageIndex);
|
||||
|
||||
tacticsButton->callback.clear();
|
||||
tacticsButton->callback2.clear();
|
||||
@ -378,7 +378,7 @@ void CHeroWindow::showAll(SDL_Surface * to)
|
||||
|
||||
//printing special ability
|
||||
printAtLoc(CGI->generaltexth->jktexts[5].substr(1, CGI->generaltexth->jktexts[5].size()-2), 69, 183, FONT_SMALL, Colors::YELLOW, to);
|
||||
printAtLoc(CGI->generaltexth->hTxts[curHero->subID].bonusName, 69, 205, FONT_SMALL, Colors::WHITE, to);
|
||||
printAtLoc(curHero->type->specName, 69, 205, FONT_SMALL, Colors::WHITE, to);
|
||||
|
||||
//printing necessery texts
|
||||
printAtLoc(CGI->generaltexth->jktexts[6].substr(1, CGI->generaltexth->jktexts[6].size()-2), 69, 232, FONT_SMALL, Colors::YELLOW, to);
|
||||
|
@ -171,7 +171,7 @@ std::string InfoBoxAbstractHeroData::getNameText()
|
||||
return text.substr(begin, end-begin);
|
||||
}
|
||||
case HERO_SPECIAL:
|
||||
return CGI->generaltexth->hTxts[getSubID()].bonusName;
|
||||
return CGI->heroh->heroes[getSubID()]->specName;
|
||||
case HERO_SECONDARY_SKILL:
|
||||
if (getValue())
|
||||
return CGI->generaltexth->skillName[getSubID()];
|
||||
@ -237,6 +237,7 @@ size_t InfoBoxAbstractHeroData::getImageIndex()
|
||||
switch (type)
|
||||
{
|
||||
case HERO_SPECIAL:
|
||||
return VLC->heroh->heroes[getSubID()]->imageIndex;
|
||||
case HERO_PRIMARY_SKILL:
|
||||
return getSubID();
|
||||
case HERO_MANA:
|
||||
@ -262,7 +263,7 @@ bool InfoBoxAbstractHeroData::prepareMessage(std::string &text, CComponent **com
|
||||
switch (type)
|
||||
{
|
||||
case HERO_SPECIAL:
|
||||
text = CGI->generaltexth->hTxts[getSubID()].longBonus;
|
||||
text = CGI->heroh->heroes[getSubID()]->specDescr;
|
||||
*comp = NULL;
|
||||
return true;
|
||||
case HERO_PRIMARY_SKILL:
|
||||
@ -918,7 +919,7 @@ CHeroItem::CHeroItem(const CGHeroInstance* Hero, CArtifactsOfHero::SCommonPart *
|
||||
|
||||
garr = new CGarrisonInt(6, 78, 4, Point(), NULL, Point(), hero, NULL, true, true);
|
||||
|
||||
portrait = new CAnimImage("PortraitsLarge", hero->subID, 0, 5, 6);
|
||||
portrait = new CAnimImage("PortraitsLarge", hero->portrait, 0, 5, 6);
|
||||
heroArea = new CHeroArea(5, 6, hero);
|
||||
|
||||
name = new CLabel(73, 7, FONT_SMALL, TOPLEFT, Colors::WHITE, hero->name);
|
||||
|
@ -2640,7 +2640,7 @@ size_t OptionsTab::CPlayerSettingsHelper::getImageIndex()
|
||||
{
|
||||
if(settings.heroPortrait >= 0)
|
||||
return settings.heroPortrait;
|
||||
return settings.hero;
|
||||
return CGI->heroh->heroes[settings.hero]->imageIndex;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2870,10 +2870,10 @@ void OptionsTab::CPregameTooltipBox::genHeroWindow()
|
||||
genHeader();
|
||||
|
||||
// speciality
|
||||
new CAnimImage("UN44", settings.hero, 0, pos.w / 2 - 22, 134);
|
||||
new CAnimImage("UN44", CGI->heroh->heroes[settings.hero]->imageIndex, 0, pos.w / 2 - 22, 134);
|
||||
|
||||
new CLabel(pos.w / 2 + 4, 117, FONT_MEDIUM, CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[78]);
|
||||
new CLabel(pos.w / 2, 188, FONT_SMALL, CENTER, Colors::WHITE, CGI->generaltexth->hTxts[settings.hero].bonusName);
|
||||
new CLabel(pos.w / 2, 188, FONT_SMALL, CENTER, Colors::WHITE, CGI->heroh->heroes[settings.hero]->specName);
|
||||
}
|
||||
|
||||
void OptionsTab::CPregameTooltipBox::genBonusWindow()
|
||||
|
@ -943,7 +943,7 @@ size_t CComponent::getIndex()
|
||||
case morale: return val+3;
|
||||
case luck: return val+3;
|
||||
case building: return val;
|
||||
case hero: return subtype;
|
||||
case hero: return CGI->heroh->heroes[subtype]->imageIndex;
|
||||
case flag: return subtype;
|
||||
}
|
||||
assert(0);
|
||||
@ -3706,7 +3706,7 @@ CTavernWindow::HeroPortrait::HeroPortrait(int &sel, int id, int x, int y, const
|
||||
h->name.c_str(), h->level, h->type->heroClass->name.c_str(), artifs);
|
||||
descr[sizeof(descr)-1] = '\0';
|
||||
|
||||
new CAnimImage("portraitsLarge", h->subID);
|
||||
new CAnimImage("portraitsLarge", h->portrait);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4965,7 +4965,7 @@ void CExchangeWindow::prepareBackground()
|
||||
}
|
||||
|
||||
//hero's specialty
|
||||
new CAnimImage("UN32", heroInst[b]->subID, 0, 67 + 490*b, 45);
|
||||
new CAnimImage("UN32", heroInst[b]->type->imageIndex, 0, 67 + 490*b, 45);
|
||||
|
||||
//experience
|
||||
new CAnimImage("PSKIL32", 4, 0, 103 + 490*b, 45);
|
||||
@ -5042,7 +5042,7 @@ CExchangeWindow::CExchangeWindow(si32 hero1, si32 hero2):
|
||||
speciality[b] = new LRClickableAreaWText();
|
||||
speciality[b]->pos = genRect(32, 32, pos.x + 69 + 490*b, pos.y + 45);
|
||||
speciality[b]->hoverText = CGI->generaltexth->heroscrn[27];
|
||||
speciality[b]->text = CGI->generaltexth->hTxts[heroInst[b]->subID].longBonus;
|
||||
speciality[b]->text = heroInst[b]->type->specDescr;
|
||||
|
||||
experience[b] = new LRClickableAreaWText();
|
||||
experience[b]->pos = genRect(32, 32, pos.x + 105 + 490*b, pos.y + 45);
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "CGameInfo.h"
|
||||
#include "../lib/VCMI_Lib.h"
|
||||
#include "../CCallback.h"
|
||||
#include "../lib/CHeroHandler.h"
|
||||
#include "../lib/CTownHandler.h"
|
||||
#include "../lib/CObjectHandler.h"
|
||||
#include "../lib/CGeneralTextHandler.h"
|
||||
@ -103,16 +104,6 @@ void Graphics::initializeBattleGraphics()
|
||||
idx++;
|
||||
}
|
||||
|
||||
//initializing battle hero animation
|
||||
idx = config["heroes"].Vector().size();
|
||||
battleHeroes.resize(idx);
|
||||
|
||||
idx = 0;
|
||||
BOOST_FOREACH(const JsonNode &h, config["heroes"].Vector()) {
|
||||
battleHeroes[idx] = h.String();
|
||||
idx ++;
|
||||
}
|
||||
|
||||
//initialization of AC->def name mapping
|
||||
BOOST_FOREACH(const JsonNode &ac, config["ac_mapping"].Vector()) {
|
||||
int ACid = ac["id"].Float();
|
||||
@ -169,22 +160,26 @@ void Graphics::loadHeroAnims()
|
||||
std::vector<std::pair<int,int> > rotations; //first - group number to be rotated1, second - group number after rotation1
|
||||
rotations += std::make_pair(6,10), std::make_pair(7,11), std::make_pair(8,12), std::make_pair(1,13),
|
||||
std::make_pair(2,14), std::make_pair(3,15);
|
||||
for(size_t i=0; i<GameConstants::F_NUMBER * 2; ++i)
|
||||
|
||||
for(size_t i=0; i<CGI->heroh->classes.heroClasses.size(); ++i)
|
||||
{
|
||||
std::ostringstream nm;
|
||||
nm << "AH" << std::setw(2) << std::setfill('0') << i << "_.DEF";
|
||||
loadHeroAnim(nm.str(), rotations, &Graphics::heroAnims);
|
||||
const CHeroClass * hc = CGI->heroh->classes.heroClasses[i];
|
||||
|
||||
if (!vstd::contains(heroAnims, hc->imageMapFemale))
|
||||
heroAnims[hc->imageMapFemale] = loadHeroAnim(hc->imageMapFemale, rotations);
|
||||
|
||||
if (!vstd::contains(heroAnims, hc->imageMapMale))
|
||||
heroAnims[hc->imageMapMale] = loadHeroAnim(hc->imageMapMale, rotations);
|
||||
}
|
||||
|
||||
loadHeroAnim("AB01_.DEF", rotations, &Graphics::boatAnims);
|
||||
loadHeroAnim("AB02_.DEF", rotations, &Graphics::boatAnims);
|
||||
loadHeroAnim("AB03_.DEF", rotations, &Graphics::boatAnims);
|
||||
boatAnims.push_back(loadHeroAnim("AB01_.DEF", rotations));
|
||||
boatAnims.push_back(loadHeroAnim("AB02_.DEF", rotations));
|
||||
boatAnims.push_back(loadHeroAnim("AB03_.DEF", rotations));
|
||||
}
|
||||
|
||||
void Graphics::loadHeroAnim( const std::string &name, const std::vector<std::pair<int,int> > &rotations, std::vector<CDefEssential *> Graphics::*dst )
|
||||
CDefEssential * Graphics::loadHeroAnim( const std::string &name, const std::vector<std::pair<int,int> > &rotations)
|
||||
{
|
||||
CDefEssential *anim = CDefHandler::giveDefEss(name);
|
||||
(this->*dst).push_back(anim);
|
||||
int pom = 0; //how many groups has been rotated
|
||||
for(int o=7; pom<6; ++o)
|
||||
{
|
||||
@ -216,6 +211,7 @@ void Graphics::loadHeroAnim( const std::string &name, const std::vector<std::pai
|
||||
{
|
||||
CSDL_Ext::alphaTransform(anim->ourImages[ff].bitmap);
|
||||
}
|
||||
return anim;
|
||||
}
|
||||
|
||||
void Graphics::loadHeroFlags(std::pair<std::vector<CDefEssential *> Graphics::*, std::vector<const char *> > &pr, bool mode)
|
||||
|
@ -49,7 +49,7 @@ public:
|
||||
CDefEssential * resources32; //resources 32x32
|
||||
CDefEssential * flags;
|
||||
CDefEssential * heroMoveArrows;
|
||||
std::vector<CDefEssential *> heroAnims; // [class id: 0 - 17] //added group 10: up - left, 11 - left and 12 - left down // 13 - up-left standing; 14 - left standing; 15 - left down standing
|
||||
std::map<std::string, CDefEssential *> heroAnims; // [hero class def name] //added group 10: up - left, 11 - left and 12 - left down // 13 - up-left standing; 14 - left standing; 15 - left down standing
|
||||
std::vector<CDefEssential *> boatAnims; // [boat type: 0 - 3] //added group 10: up - left, 11 - left and 12 - left down // 13 - up-left standing; 14 - left standing; 15 - left down standing
|
||||
CDefHandler * FoWfullHide; //for Fog of War
|
||||
CDefHandler * FoWpartialHide; //for For of War
|
||||
@ -63,7 +63,6 @@ public:
|
||||
std::map<int, std::string> ERMUtoPicture[GameConstants::F_NUMBER]; //maps building ID to it's picture's name for each town type
|
||||
//for battles
|
||||
std::vector< std::vector< std::string > > battleBacks; //battleBacks[terType] - vector of possible names for certain terrain type
|
||||
std::vector< std::string > battleHeroes; //battleHeroes[hero type] - name of def that has hero animation for battle
|
||||
std::map< int, std::vector < std::string > > battleACToDef; //maps AC format to vector of appropriate def names
|
||||
CDefEssential * spellEffectsPics; //bitmaps representing spells affecting a stack in battle
|
||||
//spells
|
||||
@ -75,7 +74,7 @@ public:
|
||||
void loadHeroFlags();
|
||||
void loadHeroFlags(std::pair<std::vector<CDefEssential *> Graphics::*, std::vector<const char *> > &pr, bool mode);
|
||||
void loadHeroAnims();
|
||||
void loadHeroAnim(const std::string &name, const std::vector<std::pair<int,int> > &rotations, std::vector<CDefEssential *> Graphics::*dst);
|
||||
CDefEssential * loadHeroAnim(const std::string &name, const std::vector<std::pair<int,int> > &rotations);
|
||||
void loadErmuToPicture();
|
||||
void blueToPlayersAdv(SDL_Surface * sur, int player); //replaces blue interface colour with a color of player
|
||||
void loadTrueType();
|
||||
|
@ -566,9 +566,12 @@ void CMapHandler::terrainRect( int3 top_tile, ui8 anim, const std::vector< std::
|
||||
dir = themp->moveDir;
|
||||
|
||||
//pick graphics of hero (or boat if hero is sailing)
|
||||
iv = (themp->boat)
|
||||
? &graphics->boatAnims[themp->boat->subID]->ourImages
|
||||
: &graphics->heroAnims[themp->type->heroClass->id]->ourImages;
|
||||
if (themp->boat)
|
||||
iv = &graphics->boatAnims[themp->boat->subID]->ourImages;
|
||||
else if (themp->sex)
|
||||
iv = &graphics->heroAnims[themp->type->heroClass->imageMapFemale]->ourImages;
|
||||
else
|
||||
iv = &graphics->heroAnims[themp->type->heroClass->imageMapMale]->ourImages;
|
||||
|
||||
//pick appropriate flag set
|
||||
if(themp->boat)
|
||||
|
@ -28,29 +28,6 @@
|
||||
"CMBKDECK.BMP"
|
||||
],
|
||||
|
||||
// Hero animation used in battles.
|
||||
// Each 2 def represent male and female heroes for each race
|
||||
"heroes": [
|
||||
"CH00.DEF",
|
||||
"CH01.DEF",
|
||||
"CH02.DEF",
|
||||
"CH03.DEF",
|
||||
"CH05.DEF",
|
||||
"CH04.DEF",
|
||||
"CH06.DEF",
|
||||
"CH07.DEF",
|
||||
"CH08.DEF",
|
||||
"CH09.DEF",
|
||||
"CH010.DEF",
|
||||
"CH11.DEF",
|
||||
"CH013.DEF",
|
||||
"CH012.DEF",
|
||||
"CH014.DEF",
|
||||
"CH015.DEF",
|
||||
"CH16.DEF",
|
||||
"CH17.DEF"
|
||||
],
|
||||
|
||||
// WoG_Ac_format_to_def_names_mapping
|
||||
"ac_mapping": [
|
||||
{ "id": 0, "defnames": [ "C10SPW.DEF" ] },
|
||||
|
38
config/heroClasses.json
Normal file
38
config/heroClasses.json
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
// battle animations for heroes, ordered by faction
|
||||
"heroBattleAnim" :
|
||||
[
|
||||
{ "male" : "CH00.DEF", "female" : "CH01.DEF" },
|
||||
{ "male" : "CH02.DEF", "female" : "CH03.DEF" },
|
||||
{ "male" : "CH05.DEF", "female" : "CH04.DEF" },
|
||||
{ "male" : "CH06.DEF", "female" : "CH07.DEF" },
|
||||
{ "male" : "CH08.DEF", "female" : "CH09.DEF" },
|
||||
{ "male" : "CH010.DEF", "female" : "CH11.DEF" },
|
||||
{ "male" : "CH013.DEF", "female" : "CH012.DEF" },
|
||||
{ "male" : "CH014.DEF", "female" : "CH015.DEF" },
|
||||
{ "male" : "CH16.DEF", "female" : "CH17.DEF" }
|
||||
],
|
||||
|
||||
// map animations for heroes, ordered by hero class
|
||||
"heroMapAnim" :
|
||||
[
|
||||
"AH00_.def",
|
||||
"AH01_.def",
|
||||
"AH02_.def",
|
||||
"AH03_.def",
|
||||
"AH04_.def",
|
||||
"AH05_.def",
|
||||
"AH06_.def",
|
||||
"AH07_.def",
|
||||
"AH08_.def",
|
||||
"AH09_.def",
|
||||
"AH10_.def",
|
||||
"AH11_.def",
|
||||
"AH12_.def",
|
||||
"AH13_.def",
|
||||
"AH14_.def",
|
||||
"AH15_.def",
|
||||
"AH16_.def",
|
||||
"AH17_.def"
|
||||
]
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -189,25 +189,6 @@ void CGeneralTextHandler::load()
|
||||
}
|
||||
while (parser.endLine());
|
||||
}
|
||||
{
|
||||
CLegacyConfigParser parser("DATA/HEROSPEC.TXT");
|
||||
CLegacyConfigParser bioParser("DATA/HEROBIOS.TXT");
|
||||
|
||||
//skip header
|
||||
parser.endLine();
|
||||
parser.endLine();
|
||||
|
||||
do
|
||||
{
|
||||
HeroTexts texts;
|
||||
texts.bonusName = parser.readString();
|
||||
texts.shortBonus = parser.readString();
|
||||
texts.longBonus = parser.readString();
|
||||
texts.biography = bioParser.readString();
|
||||
hTxts.push_back(texts);
|
||||
}
|
||||
while (parser.endLine() && bioParser.endLine());
|
||||
}
|
||||
{
|
||||
CLegacyConfigParser nameParser("DATA/MINENAME.TXT");
|
||||
CLegacyConfigParser eventParser("DATA/MINEEVNT.TXT");
|
||||
|
@ -58,14 +58,6 @@ public:
|
||||
class DLL_LINKAGE CGeneralTextHandler //Handles general texts
|
||||
{
|
||||
public:
|
||||
class HeroTexts
|
||||
{
|
||||
public:
|
||||
std::string bonusName, shortBonus, longBonus; //for special abilities
|
||||
std::string biography; //biography, of course
|
||||
};
|
||||
|
||||
std::vector<HeroTexts> hTxts;
|
||||
std::vector<std::string> allTexts;
|
||||
|
||||
std::vector<std::string> arraytxt;
|
||||
|
@ -20,12 +20,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
CHeroClass::CHeroClass()
|
||||
{
|
||||
}
|
||||
CHeroClass::~CHeroClass()
|
||||
{
|
||||
}
|
||||
int CHeroClass::chooseSecSkill(const std::set<int> & possibles) const //picks secondary skill out from given possibilities
|
||||
{
|
||||
if(possibles.size()==1)
|
||||
@ -119,17 +113,81 @@ void CHeroClassHandler::load()
|
||||
VLC->modh->identifiers.registerObject("heroClass." + GameConstants::HERO_CLASSES_NAMES[hc->id], hc->id);
|
||||
}
|
||||
while (parser.endLine() && !parser.isNextEntryEmpty());
|
||||
|
||||
const JsonNode & heroGraphics = JsonNode(ResourceID("config/heroClasses.json"));
|
||||
|
||||
for (size_t i=0; i<heroClasses.size(); i++)
|
||||
{
|
||||
const JsonNode & battle = heroGraphics["heroBattleAnim"].Vector()[i/2];
|
||||
|
||||
heroClasses[i]->imageBattleFemale = battle["female"].String();
|
||||
heroClasses[i]->imageBattleMale = battle["male"].String();
|
||||
|
||||
const JsonNode & map = heroGraphics["heroMapAnim"].Vector()[i];
|
||||
|
||||
heroClasses[i]->imageMapMale = map.String();
|
||||
heroClasses[i]->imageMapFemale = map.String();
|
||||
}
|
||||
}
|
||||
|
||||
void CHeroClassHandler::load(const JsonNode & classes)
|
||||
{
|
||||
//TODO
|
||||
BOOST_FOREACH(auto & entry, classes.Struct())
|
||||
{
|
||||
if (!entry.second.isNull()) // may happens if mod removed creature by setting json entry to null
|
||||
{
|
||||
CHeroClass * heroClass = loadClass(entry.second);
|
||||
heroClass->identifier = entry.first;
|
||||
heroClass->id = heroClasses.size();
|
||||
|
||||
heroClasses.push_back(heroClass);
|
||||
tlog3 << "Added hero class: " << entry.first << "\n";
|
||||
VLC->modh->identifiers.registerObject("heroClass." + heroClass->identifier, heroClass->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CHeroClass *CHeroClassHandler::loadClass(const JsonNode & heroClass)
|
||||
CHeroClass *CHeroClassHandler::loadClass(const JsonNode & node)
|
||||
{
|
||||
//TODO
|
||||
return new CHeroClass;
|
||||
CHeroClass * heroClass = new CHeroClass;
|
||||
|
||||
heroClass->imageBattleFemale = node["animation"]["battle"]["female"].String();
|
||||
heroClass->imageBattleMale = node["animation"]["battle"]["male"].String();
|
||||
heroClass->imageMapFemale = node["animation"]["map"]["female"].String();
|
||||
heroClass->imageMapMale = node["animation"]["map"]["male"].String();
|
||||
|
||||
heroClass->name = node["name"].String();
|
||||
|
||||
BOOST_FOREACH(const std::string & pSkill, PrimarySkill::names)
|
||||
{
|
||||
heroClass->primarySkillInitial.push_back(node["primarySkills"][pSkill].Float());
|
||||
heroClass->primarySkillLowLevel.push_back(node["lowLevelChance"][pSkill].Float());
|
||||
heroClass->primarySkillHighLevel.push_back(node["highLevelChance"][pSkill].Float());
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const std::string & secSkill, SecondarySkill::names)
|
||||
{
|
||||
heroClass->secSkillProbability.push_back(node["secondarySkills"][secSkill].Float());
|
||||
}
|
||||
|
||||
BOOST_FOREACH(auto & tavern, node["tavern"].Struct())
|
||||
{
|
||||
int value = tavern.second.Float();
|
||||
|
||||
VLC->modh->identifiers.requestIdentifier("faction." + tavern.first,
|
||||
[=](si32 factionID)
|
||||
{
|
||||
heroClass->selectionProbability[factionID] = value;
|
||||
});
|
||||
}
|
||||
|
||||
VLC->modh->identifiers.requestIdentifier("faction." + node["faction"].String(),
|
||||
[=](si32 factionID)
|
||||
{
|
||||
heroClass->faction = factionID;
|
||||
});
|
||||
|
||||
return heroClass;
|
||||
}
|
||||
|
||||
CHeroClassHandler::~CHeroClassHandler()
|
||||
@ -149,21 +207,102 @@ CHeroHandler::~CHeroHandler()
|
||||
CHeroHandler::CHeroHandler()
|
||||
{}
|
||||
|
||||
void CHeroHandler::load(const JsonNode & heroes)
|
||||
void CHeroHandler::load(const JsonNode & input)
|
||||
{
|
||||
//TODO
|
||||
BOOST_FOREACH(auto & entry, input.Struct())
|
||||
{
|
||||
if (!entry.second.isNull()) // may happens if mod removed creature by setting json entry to null
|
||||
{
|
||||
CHero * hero = loadHero(entry.second);
|
||||
hero->ID = heroes.size();
|
||||
|
||||
heroes.push_back(hero);
|
||||
tlog3 << "Added hero : " << entry.first << "\n";
|
||||
VLC->modh->identifiers.registerObject("hero." + entry.first, hero->ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CHero * CHeroHandler::loadHero(const JsonNode & hero)
|
||||
CHero * CHeroHandler::loadHero(const JsonNode & node)
|
||||
{
|
||||
//TODO
|
||||
return new CHero;
|
||||
CHero * hero = new CHero;
|
||||
|
||||
hero->name = node["texts"]["name"].String();
|
||||
hero->biography = node["texts"]["biography"].String();
|
||||
hero->specName = node["texts"]["specialty"]["name"].String();
|
||||
hero->specTooltip = node["texts"]["specialty"]["tooltip"].String();
|
||||
hero->specDescr = node["texts"]["specialty"]["description"].String();
|
||||
|
||||
hero->imageIndex = node["images"]["index"].Float();
|
||||
hero->iconSpecSmall = node["images"]["specialtySmall"].String();
|
||||
hero->iconSpecLarge = node["images"]["specialtyLarge"].String();
|
||||
hero->portraitSmall = node["images"]["small"].String();
|
||||
hero->portraitLarge = node["images"]["large"].String();
|
||||
|
||||
assert(node["army"].Vector().size() <= 3); // anything bigger is useless - army initialization uses up to 3 slots
|
||||
hero->initialArmy.resize(node["army"].Vector().size());
|
||||
|
||||
for (size_t i=0; i< hero->initialArmy.size(); i++)
|
||||
{
|
||||
const JsonNode & source = node["army"].Vector()[i];
|
||||
|
||||
hero->initialArmy[i].minAmount = source["min"].Float();
|
||||
hero->initialArmy[i].maxAmount = source["max"].Float();
|
||||
|
||||
assert(hero->initialArmy[i].minAmount <= hero->initialArmy[i].maxAmount);
|
||||
|
||||
VLC->modh->identifiers.requestIdentifier(std::string("creature.") + source["creature"].String(), [=](si32 creature)
|
||||
{
|
||||
hero->initialArmy[i].creature = creature;
|
||||
});
|
||||
}
|
||||
|
||||
loadHeroJson(hero, node);
|
||||
return hero;
|
||||
}
|
||||
|
||||
void CHeroHandler::loadHeroJson(CHero * hero, const JsonNode & node)
|
||||
{
|
||||
// sex: 0=male, 1=female
|
||||
hero->sex = !!node["female"].Bool();
|
||||
|
||||
BOOST_FOREACH(const JsonNode &set, node["skills"].Vector())
|
||||
{
|
||||
int skillID = boost::range::find(SecondarySkill::names, set["skill"].String()) - boost::begin(SecondarySkill::names);
|
||||
int skillLevel = boost::range::find(SecondarySkill::levels, set["level"].String()) - boost::begin(SecondarySkill::levels);
|
||||
|
||||
hero->secSkillsInit.push_back(std::make_pair(skillID, skillLevel));
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const JsonNode & spell, node["spellbook"].Vector())
|
||||
{
|
||||
hero->spells.insert(spell.Float());
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const JsonNode &specialty, node["specialties"].Vector())
|
||||
{
|
||||
SSpecialtyInfo spec;
|
||||
|
||||
spec.type = specialty["type"].Float();
|
||||
spec.val = specialty["val"].Float();
|
||||
spec.subtype = specialty["subtype"].Float();
|
||||
spec.additionalinfo = specialty["info"].Float();
|
||||
|
||||
hero->spec.push_back(spec); //put a copy of dummy
|
||||
}
|
||||
|
||||
VLC->modh->identifiers.requestIdentifier("heroClass." + node["class"].String(),
|
||||
[=](si32 classID)
|
||||
{
|
||||
hero->heroClass = classes.heroClasses[classID];
|
||||
});
|
||||
}
|
||||
|
||||
void CHeroHandler::load()
|
||||
{
|
||||
classes.load();
|
||||
loadHeroes();
|
||||
loadHeroTexts();
|
||||
loadObstacles();
|
||||
loadTerrains();
|
||||
loadBallistics();
|
||||
@ -233,6 +372,7 @@ void CHeroHandler::loadHeroes()
|
||||
CHero * hero = new CHero;
|
||||
hero->name = parser.readString();
|
||||
|
||||
hero->initialArmy.resize(3);
|
||||
for(int x=0;x<3;x++)
|
||||
{
|
||||
hero->initialArmy[x].minAmount = parser.readNumber();
|
||||
@ -248,6 +388,7 @@ void CHeroHandler::loadHeroes()
|
||||
parser.endLine();
|
||||
|
||||
hero->ID = heroes.size();
|
||||
hero->imageIndex = hero->ID;
|
||||
heroes.push_back(hero);
|
||||
}
|
||||
|
||||
@ -255,42 +396,31 @@ void CHeroHandler::loadHeroes()
|
||||
const JsonNode config(ResourceID("config/heroes.json"));
|
||||
BOOST_FOREACH(const JsonNode &hero, config["heroes"].Vector())
|
||||
{
|
||||
CHero * currentHero = heroes[hero["id"].Float()];
|
||||
|
||||
// sex: 0=male, 1=female
|
||||
currentHero->sex = !!hero["female"].Bool();
|
||||
|
||||
BOOST_FOREACH(const JsonNode &set, hero["skill_set"].Vector())
|
||||
{
|
||||
int skillID = boost::range::find(SecondarySkill::names, set["skill"].String()) - boost::begin(SecondarySkill::names);
|
||||
int skillLevel = boost::range::find(SecondarySkill::levels, set["level"].String()) - boost::begin(SecondarySkill::levels);
|
||||
currentHero->secSkillsInit.push_back(std::make_pair(skillID, skillLevel));
|
||||
}
|
||||
|
||||
if (!hero["spell"].isNull()) {
|
||||
currentHero->startingSpell = hero["spell"].Float();
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const JsonNode &specialty, hero["specialties"].Vector())
|
||||
{
|
||||
SSpecialtyInfo dummy;
|
||||
|
||||
dummy.type = specialty["type"].Float();
|
||||
dummy.val = specialty["val"].Float();
|
||||
dummy.subtype = specialty["subtype"].Float();
|
||||
dummy.additionalinfo = specialty["info"].Float();
|
||||
|
||||
currentHero->spec.push_back(dummy); //put a copy of dummy
|
||||
}
|
||||
|
||||
VLC->modh->identifiers.requestIdentifier("heroClass." + hero["class"].String(),
|
||||
[=](si32 classID)
|
||||
{
|
||||
currentHero->heroClass = classes.heroClasses[classID];
|
||||
});
|
||||
loadHeroJson(heroes[hero["id"].Float()], hero);
|
||||
}
|
||||
}
|
||||
|
||||
void CHeroHandler::loadHeroTexts()
|
||||
{
|
||||
CLegacyConfigParser parser("DATA/HEROSPEC.TXT");
|
||||
CLegacyConfigParser bioParser("DATA/HEROBIOS.TXT");
|
||||
|
||||
//skip header
|
||||
parser.endLine();
|
||||
parser.endLine();
|
||||
|
||||
int i=0;
|
||||
do
|
||||
{
|
||||
CHero * hero = heroes[i++];
|
||||
hero->specName = parser.readString();
|
||||
hero->specTooltip = parser.readString();
|
||||
hero->specDescr = parser.readString();
|
||||
hero->biography = bioParser.readString();
|
||||
}
|
||||
while (parser.endLine() && bioParser.endLine() && heroes.size() < i);
|
||||
}
|
||||
|
||||
void CHeroHandler::loadBallistics()
|
||||
{
|
||||
CLegacyConfigParser ballParser("DATA/BALLIST.TXT");
|
||||
@ -360,15 +490,4 @@ std::vector<ui8> CHeroHandler::getDefaultAllowedHeroes() const
|
||||
allowedHeroes[4] = 0;
|
||||
allowedHeroes[25] = 0;
|
||||
return allowedHeroes;
|
||||
}
|
||||
|
||||
CHero::CHero()
|
||||
{
|
||||
startingSpell = -1;
|
||||
sex = 0xff;
|
||||
}
|
||||
|
||||
CHero::~CHero()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "../lib/ConstTransitivePtr.h"
|
||||
#include "GameConstants.h"
|
||||
|
||||
@ -13,6 +12,7 @@
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
|
||||
class CHeroClass;
|
||||
class CDefHandler;
|
||||
class CGameInfo;
|
||||
@ -46,23 +46,35 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
std::string name; //name of hero
|
||||
si32 ID;
|
||||
si32 imageIndex;
|
||||
|
||||
InitialArmyStack initialArmy[3];
|
||||
std::vector<InitialArmyStack> initialArmy;
|
||||
|
||||
CHeroClass * heroClass;
|
||||
std::vector<std::pair<ui8,ui8> > secSkillsInit; //initial secondary skills; first - ID of skill, second - level of skill (1 - basic, 2 - adv., 3 - expert)
|
||||
std::vector<SSpecialtyInfo> spec;
|
||||
si32 startingSpell; //-1 if none
|
||||
std::set<si32> spells;
|
||||
ui8 sex; // default sex: 0=male, 1=female
|
||||
|
||||
CHero();
|
||||
~CHero();
|
||||
/// Localized texts
|
||||
std::string name; //name of hero
|
||||
std::string biography;
|
||||
std::string specName;
|
||||
std::string specDescr;
|
||||
std::string specTooltip;
|
||||
|
||||
/// Graphics
|
||||
std::string iconSpecSmall;
|
||||
std::string iconSpecLarge;
|
||||
std::string portraitSmall;
|
||||
std::string portraitLarge;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
h & name & ID & initialArmy & heroClass & secSkillsInit & spec & startingSpell & sex;
|
||||
h & ID & imageIndex & initialArmy & heroClass & secSkillsInit & spec & spells & sex;
|
||||
h & name & biography & specName & specDescr & specTooltip;
|
||||
h & iconSpecSmall & iconSpecLarge & portraitSmall & portraitLarge;
|
||||
}
|
||||
};
|
||||
|
||||
@ -83,9 +95,12 @@ public:
|
||||
|
||||
std::map<TFaction, int> selectionProbability; //probability of selection in towns
|
||||
|
||||
std::string imageBattleMale;
|
||||
std::string imageBattleFemale;
|
||||
std::string imageMapMale;
|
||||
std::string imageMapFemale;
|
||||
|
||||
int chooseSecSkill(const std::set<int> & possibles) const; //picks secondary skill out from given possibilities
|
||||
CHeroClass(); //c-tor
|
||||
~CHeroClass(); //d-tor
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
{
|
||||
@ -93,6 +108,7 @@ public:
|
||||
h & primarySkillInitial & primarySkillLowLevel;
|
||||
h & primarySkillHighLevel & secSkillProbability;
|
||||
h & selectionProbability;
|
||||
h & imageBattleMale & imageBattleFemale & imageMapMale & imageMapFemale;
|
||||
}
|
||||
EAlignment::EAlignment getAlignment() const;
|
||||
};
|
||||
@ -130,7 +146,7 @@ public:
|
||||
void load(const JsonNode & classes);
|
||||
|
||||
/// load one class from json
|
||||
CHeroClass * loadClass(const JsonNode & heroClass);
|
||||
CHeroClass * loadClass(const JsonNode & node);
|
||||
|
||||
~CHeroClassHandler();
|
||||
|
||||
@ -146,6 +162,8 @@ class DLL_LINKAGE CHeroHandler
|
||||
/// consists of 201 values. Any higher levels require experience larger that ui64 can hold
|
||||
std::vector<ui64> expPerLevel;
|
||||
|
||||
/// common function for loading heroes from mods and from H3
|
||||
void loadHeroJson(CHero * hero, const JsonNode & node);
|
||||
public:
|
||||
CHeroClassHandler classes;
|
||||
|
||||
@ -177,12 +195,13 @@ public:
|
||||
void load(const JsonNode & heroes);
|
||||
|
||||
/// Load single hero from json
|
||||
CHero * loadHero(const JsonNode & hero);
|
||||
CHero * loadHero(const JsonNode & node);
|
||||
|
||||
/// Load everything (calls functions below + classes.load())
|
||||
void load();
|
||||
|
||||
void loadHeroes();
|
||||
void loadHeroTexts();
|
||||
void loadExperience();
|
||||
void loadBallistics();
|
||||
void loadTerrains();
|
||||
|
@ -708,19 +708,23 @@ void CGHeroInstance::initHero()
|
||||
initHeroDefInfo();
|
||||
if(!type)
|
||||
type = VLC->heroh->heroes[subID];
|
||||
if(!vstd::contains(spells, 0xffffffff) && type->startingSpell >= 0) //hero starts with a spell
|
||||
spells.insert(type->startingSpell);
|
||||
|
||||
if(!vstd::contains(spells, 0xffffffff)) //hero starts with a spell
|
||||
{
|
||||
BOOST_FOREACH(auto spellID, type->spells)
|
||||
spells.insert(spellID);
|
||||
}
|
||||
else //remove placeholder
|
||||
spells -= 0xffffffff;
|
||||
|
||||
if(!getArt(ArtifactPosition::MACH4) && !getArt(ArtifactPosition::SPELLBOOK) && type->startingSpell >= 0) //no catapult means we haven't read pre-existent set -> use default rules for spellbook
|
||||
if(!getArt(ArtifactPosition::MACH4) && !getArt(ArtifactPosition::SPELLBOOK) && !type->spells.empty()) //no catapult means we haven't read pre-existent set -> use default rules for spellbook
|
||||
putArtifact(ArtifactPosition::SPELLBOOK, CArtifactInstance::createNewArtifactInstance(0));
|
||||
|
||||
if(!getArt(ArtifactPosition::MACH4))
|
||||
putArtifact(ArtifactPosition::MACH4, CArtifactInstance::createNewArtifactInstance(3)); //everyone has a catapult
|
||||
|
||||
if(portrait < 0 || portrait == 255)
|
||||
portrait = subID;
|
||||
portrait = type->imageIndex;
|
||||
if(!hasBonus(Selector::sourceType(Bonus::HERO_BASE_SKILL)))
|
||||
{
|
||||
for(int g=0; g<GameConstants::PRIMARY_SKILLS; ++g)
|
||||
@ -781,6 +785,8 @@ void CGHeroInstance::initArmy(IArmyDescriptor *dst /*= NULL*/)
|
||||
else
|
||||
howManyStacks = 3;
|
||||
|
||||
vstd::amin(howManyStacks, type->initialArmy.size());
|
||||
|
||||
for(int stackNo=0; stackNo < howManyStacks; stackNo++)
|
||||
{
|
||||
auto & stack = type->initialArmy[stackNo];
|
||||
@ -892,8 +898,7 @@ const std::string & CGHeroInstance::getBiography() const
|
||||
{
|
||||
if (biography.length())
|
||||
return biography;
|
||||
else
|
||||
return VLC->generaltexth->hTxts[subID].biography;
|
||||
return type->biography;
|
||||
}
|
||||
void CGHeroInstance::initObj()
|
||||
{
|
||||
|
@ -472,7 +472,13 @@ void CTownHandler::load(const JsonNode &source)
|
||||
{
|
||||
BOOST_FOREACH(auto & node, source.Struct())
|
||||
{
|
||||
int id = node.second["index"].Float();
|
||||
int id;
|
||||
|
||||
if (node.second["index"].isNull())
|
||||
id = factions.rbegin()->first + 1;
|
||||
else
|
||||
id = node.second["index"].Float();
|
||||
|
||||
CFaction & faction = factions[id];
|
||||
|
||||
faction.factionID = id;
|
||||
|
@ -416,16 +416,16 @@ bool JsonParser::extractWhitespace(bool verbose)
|
||||
|
||||
bool JsonParser::extractEscaping(std::string &str)
|
||||
{
|
||||
switch(input[pos++])
|
||||
switch(input[pos])
|
||||
{
|
||||
break; case '\"': str += '\"';
|
||||
break; case '\\': str += '\\';
|
||||
break; case '/': str += '/';
|
||||
break; case '\b': str += '\b';
|
||||
break; case '\f': str += '\f';
|
||||
break; case '\n': str += '\n';
|
||||
break; case '\r': str += '\r';
|
||||
break; case '\t': str += '\t';
|
||||
break; case 'b': str += '\b';
|
||||
break; case 'f': str += '\f';
|
||||
break; case 'n': str += '\n';
|
||||
break; case 'r': str += '\r';
|
||||
break; case 't': str += '\t';
|
||||
break; default: return error("Unknown escape sequence!", true);
|
||||
};
|
||||
return true;
|
||||
|
Loading…
Reference in New Issue
Block a user