1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-12 02:28:11 +02:00

- removed creature-related code from ModHandler

- new towns can be loaded as mods
 - removed separate DefInfos for towns\capitals
 - a bit simpler handling of adventure map def's
This commit is contained in:
Ivan Savenko 2012-11-13 11:52:23 +00:00
parent c336abcf4a
commit f7915d9e61
21 changed files with 391 additions and 445 deletions

View File

@ -146,13 +146,14 @@ SDL_Surface * BitmapHandler::loadBitmapFromDir(std::string path, std::string fna
//set correct value for alpha\unused channel //set correct value for alpha\unused channel
for (int i=0; i< ret->format->palette->ncolors; i++) for (int i=0; i< ret->format->palette->ncolors; i++)
ret->format->palette->colors[i].unused = 255; ret->format->palette->colors[i].unused = 255;
} }
} }
else else
{ {
tlog1<<"Failed to open "<<fname<<" via SDL_Image\n"; tlog1<<"Failed to open "<<fname<<" via SDL_Image\n";
} }
} }
SDL_SetColorKey(ret, SDL_SRCCOLORKEY, SDL_MapRGB(ret->format, 0, 255, 255));
return ret; return ret;
} }

View File

@ -1152,7 +1152,10 @@ void CCastleInterface::keyPressed( const SDL_KeyboardEvent & key )
builds = new CCastleBuildings(town); builds = new CCastleBuildings(town);
BOOST_FOREACH(const CStructure * str, town->town->clientInfo.structures) BOOST_FOREACH(const CStructure * str, town->town->clientInfo.structures)
tlog1 << int(str->building->bid) << " -> " << int(str->pos.z) << "\n"; {
if (str->building)
tlog1 << int(str->building->bid) << " -> " << int(str->pos.z) << "\n";
}
} }
break; break;
case SDLK_KP_MINUS: case SDLK_KP_MINUS:
@ -1165,7 +1168,10 @@ void CCastleInterface::keyPressed( const SDL_KeyboardEvent & key )
builds = new CCastleBuildings(town); builds = new CCastleBuildings(town);
BOOST_FOREACH(const CStructure * str, town->town->clientInfo.structures) BOOST_FOREACH(const CStructure * str, town->town->clientInfo.structures)
tlog1 << int(str->building->bid) << " -> " << int(str->pos.z) << "\n"; {
if (str->building)
tlog1 << int(str->building->bid) << " -> " << int(str->pos.z) << "\n";
}
} }
break; break;

View File

@ -778,7 +778,7 @@ static void listenForEvents()
delete CGI->dobjinfo.get(); delete CGI->dobjinfo.get();
const_cast<CGameInfo*>(CGI)->dobjinfo = new CDefObjInfoHandler; const_cast<CGameInfo*>(CGI)->dobjinfo = new CDefObjInfoHandler;
const_cast<CGameInfo*>(CGI)->dobjinfo->load(); const_cast<CGameInfo*>(CGI)->dobjinfo->load();
const_cast<CGameInfo*>(CGI)->modh->recreateAdvMapDefs(); //add info about new creatures to dobjinfo const_cast<CGameInfo*>(CGI)->modh->reload(); //add info about new creatures to dobjinfo
}; };
switch(ev.user.code) switch(ev.user.code)

View File

@ -346,7 +346,9 @@ SDL_Surface * Graphics::getPic(int ID, bool fort, bool builded)
{ {
assert(vstd::contains(CGI->townh->towns, ID)); assert(vstd::contains(CGI->townh->towns, ID));
int pom = CGI->townh->towns[ID].clientInfo.icons[fort][builded]; int pom = CGI->townh->towns[ID].clientInfo.icons[fort][builded];
return smallIcons->ourImages[pom + 2].bitmap; if (smallIcons->ourImages.size() > pom + 2)
return smallIcons->ourImages[pom + 2].bitmap;
return nullptr;
} }
} }
@ -478,12 +480,12 @@ void Graphics::loadFonts()
CDefEssential * Graphics::getDef( const CGObjectInstance * obj ) CDefEssential * Graphics::getDef( const CGObjectInstance * obj )
{ {
return advmapobjGraphics[obj->defInfo->id][obj->defInfo->subid][obj->defInfo->name]; return advmapobjGraphics[obj->defInfo->name];
} }
CDefEssential * Graphics::getDef( const CGDefInfo * info ) CDefEssential * Graphics::getDef( const CGDefInfo * info )
{ {
return advmapobjGraphics[info->id][info->subid][info->name]; return advmapobjGraphics[info->name];
} }
void Graphics::loadErmuToPicture() void Graphics::loadErmuToPicture()

View File

@ -54,11 +54,10 @@ public:
CDefEssential * heroMoveArrows; 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::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::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 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
std::map<std::string, CDefEssential*> mapObjectDefs; //pointers to loaded defs (key is filename, uppercase)
CDefHandler * FoWfullHide; //for Fog of War CDefHandler * FoWfullHide; //for Fog of War
CDefHandler * FoWpartialHide; //for For of War CDefHandler * FoWpartialHide; //for For of War
std::map<int, std::map<int, std::map<std::string, CDefEssential *> > > advmapobjGraphics; std::map<std::string, CDefEssential *> advmapobjGraphics;
CDefEssential * getDef(const CGObjectInstance * obj); CDefEssential * getDef(const CGObjectInstance * obj);
CDefEssential * getDef(const CGDefInfo * info); CDefEssential * getDef(const CGDefInfo * info);
//creatures //creatures

View File

@ -403,11 +403,11 @@ void NewStructures::applyCl( CClient *cl )
{ {
if(id== EBuilding::CAPITOL) //fort or capitol if(id== EBuilding::CAPITOL) //fort or capitol
{ {
town->defInfo = GS(cl)->capitols[town->subID]; town->defInfo = const_cast<CGDefInfo*>(CGI->dobjinfo->capitols[town->subID].get());
} }
if(id == EBuilding::FORT) if(id == EBuilding::FORT)
{ {
town->defInfo = GS(cl)->forts[town->subID]; town->defInfo = const_cast<CGDefInfo*>(CGI->dobjinfo->gobjs[Obj::TOWN][town->subID].get());
} }
if(vstd::contains(cl->playerint,town->tempOwner)) if(vstd::contains(cl->playerint,town->tempOwner))
cl->playerint[town->tempOwner]->buildChanged(town,id,1); cl->playerint[town->tempOwner]->buildChanged(town,id,1);
@ -420,7 +420,7 @@ void RazeStructures::applyCl (CClient *cl)
{ {
if (id == 13) //fort or capitol if (id == 13) //fort or capitol
{ {
town->defInfo = GS(cl)->forts[town->subID]; town->defInfo = const_cast<CGDefInfo*>(CGI->dobjinfo->gobjs[Obj::TOWN][town->subID].get());
} }
if(vstd::contains (cl->playerint,town->tempOwner)) if(vstd::contains (cl->playerint,town->tempOwner))
cl->playerint[town->tempOwner]->buildChanged (town,id,2); cl->playerint[town->tempOwner]->buildChanged (town,id,2);

View File

@ -74,7 +74,8 @@ void blitAt(SDL_Surface * src, int x, int y, SDL_Surface * dst)
void blitAt(SDL_Surface * src, const SDL_Rect & pos, SDL_Surface * dst) void blitAt(SDL_Surface * src, const SDL_Rect & pos, SDL_Surface * dst)
{ {
blitAt(src,pos.x,pos.y,dst); if (src)
blitAt(src,pos.x,pos.y,dst);
} }
SDL_Color genRGB(int r, int g, int b, int a=0) SDL_Color genRGB(int r, int g, int b, int a=0)

View File

@ -240,6 +240,36 @@ void CMapHandler::borderAndTerrainBitmapInit()
} }
delete bord; delete bord;
} }
static void processDef (const CGDefInfo* def)
{
if(def->id == Obj::EVENT)
{
graphics->advmapobjGraphics[def->name] = NULL;
return;
}
CDefEssential * ourDef = graphics->getDef(def);
if(!ourDef) //if object has already set handler (eg. heroes) it should not be overwritten
{
if(def->name.size())
{
graphics->advmapobjGraphics[def->name] = CDefHandler::giveDefEss(def->name);
}
else
{
tlog2 << "No def name for " << def->id << " " << def->subid << std::endl;
return;
}
ourDef = graphics->getDef(def);
}
//alpha transformation
for(size_t yy=0; yy < ourDef->ourImages.size(); ++yy)
{
CSDL_Ext::alphaTransform(ourDef->ourImages[yy].bitmap);
}
}
void CMapHandler::initObjectRects() void CMapHandler::initObjectRects()
{ {
//initializing objects / rects //initializing objects / rects
@ -249,11 +279,15 @@ void CMapHandler::initObjectRects()
if( !obj if( !obj
|| (obj->ID==Obj::HERO && static_cast<const CGHeroInstance*>(obj)->inTownGarrison) //garrisoned hero || (obj->ID==Obj::HERO && static_cast<const CGHeroInstance*>(obj)->inTownGarrison) //garrisoned hero
|| (obj->ID==Obj::BOAT && static_cast<const CGBoat*>(obj)->hero) //boat with hero (hero graphics is used) || (obj->ID==Obj::BOAT && static_cast<const CGBoat*>(obj)->hero) //boat with hero (hero graphics is used)
|| !obj->defInfo || !obj->defInfo )
|| !graphics->getDef(obj)) //no graphic...
{ {
continue; continue;
} }
if (!graphics->getDef(obj)) //try to load it
processDef(obj->defInfo);
if (!graphics->getDef(obj)) // stil no graphics? exit
continue;
const SDL_Surface *bitmap = graphics->getDef(obj)->ourImages[0].bitmap; const SDL_Surface *bitmap = graphics->getDef(obj)->ourImages[0].bitmap;
for(int fx=0; fx<bitmap->w>>5; ++fx) //bitmap->w/32 for(int fx=0; fx<bitmap->w>>5; ++fx) //bitmap->w/32
{ {
@ -294,53 +328,20 @@ void CMapHandler::initObjectRects()
} }
} }
} }
static void processDef (const CGDefInfo* def)
{
if(def->id == Obj::EVENT)
{
graphics->advmapobjGraphics[def->id][def->subid][def->name] = NULL;
return;
}
CDefEssential * ourDef = graphics->getDef(def);
if(!ourDef) //if object has already set handler (eg. heroes) it should not be overwritten
{
if(def->name.size())
{
if(vstd::contains(graphics->mapObjectDefs, def->name))
{
graphics->advmapobjGraphics[def->id][def->subid][def->name] = graphics->mapObjectDefs[def->name];
}
else
{
graphics->mapObjectDefs[def->name] = graphics->advmapobjGraphics[def->id][def->subid][def->name] = CDefHandler::giveDefEss(def->name);
}
}
else
{
tlog2 << "No def name for " << def->id << " " << def->subid << std::endl;
return;
}
ourDef = graphics->getDef(def);
}
//alpha transformation
for(size_t yy=0; yy < ourDef->ourImages.size(); ++yy)
{
CSDL_Ext::alphaTransform(ourDef->ourImages[yy].bitmap);
}
}
void CMapHandler::initHeroDef(const CGHeroInstance * h) void CMapHandler::initHeroDef(const CGHeroInstance * h)
{ {
graphics->advmapobjGraphics[h->defInfo->id][h->defInfo->subid][h->defInfo->name] = graphics->flags1[0]; graphics->advmapobjGraphics[h->defInfo->name] = graphics->flags1[0];
} }
void CMapHandler::init() void CMapHandler::init()
{ {
CStopWatch th; CStopWatch th;
th.getDiff(); th.getDiff();
graphics->advmapobjGraphics[8][0]["AB01_.DEF"] = graphics->boatAnims[0]; graphics->advmapobjGraphics["AB01_.DEF"] = graphics->boatAnims[0];
graphics->advmapobjGraphics[8][1]["AB02_.DEF"] = graphics->boatAnims[1]; graphics->advmapobjGraphics["AB02_.DEF"] = graphics->boatAnims[1];
graphics->advmapobjGraphics[8][2]["AB03_.DEF"] = graphics->boatAnims[2]; graphics->advmapobjGraphics["AB03_.DEF"] = graphics->boatAnims[2];
// Size of visible terrain. // Size of visible terrain.
int mapW = conf.go()->ac.advmapW; int mapW = conf.go()->ac.advmapW;
int mapH = conf.go()->ac.advmapH; int mapH = conf.go()->ac.advmapH;
@ -381,18 +382,6 @@ void CMapHandler::init()
std::for_each(map->customDefs.begin(),map->customDefs.end(),processDef); //load h3m defs std::for_each(map->customDefs.begin(),map->customDefs.end(),processDef); //load h3m defs
tlog0<<"\tUnpacking and handling defs: "<<th.getDiff()<<std::endl; tlog0<<"\tUnpacking and handling defs: "<<th.getDiff()<<std::endl;
//it seems to be completely unnecessary and useless
// for(int i=0;i<PLAYER_LIMIT;i++)
// {
// for(size_t j=0; j < map->players[i].heroesNames.size(); ++j)
// {
// usedHeroes.insert(map->players[i].heroesNames[j].heroID);
// }
// }
// tlog0<<"\tChecking used heroes: "<<th.getDif()<<std::endl;
prepareFOWDefs(); prepareFOWDefs();
roadsRiverTerrainInit(); //road's and river's DefHandlers; and simple values initialization roadsRiverTerrainInit(); //road's and river's DefHandlers; and simple values initialization
borderAndTerrainBitmapInit(); borderAndTerrainBitmapInit();
@ -414,7 +403,7 @@ void CMapHandler::terrainRect( int3 top_tile, ui8 anim, const std::vector< std::
// Basic rectangle for a tile. Should be a const but conflicts with SDL headers // Basic rectangle for a tile. Should be a const but conflicts with SDL headers
SDL_Rect rtile = { 0, 0, 32, 32 }; SDL_Rect rtile = { 0, 0, 32, 32 };
// Absolute coords of the first pixel in the top left corner // Absolute coords of the first pixel in the top left corner
int srx_init = offsetX + extRect->x; int srx_init = offsetX + extRect->x;
int sry_init = offsetY + extRect->y; int sry_init = offsetY + extRect->y;

View File

@ -30,8 +30,16 @@ public:
template<typename T> void print(const T &data, int lvl) template<typename T> void print(const T &data, int lvl)
{ {
#ifndef _WIN32
// with love from ffmpeg - library is trying to print some warnings from separate thread
// this results in broken console on Linux. Lock stdout to print all our data at once
flockfile(stdout);
#endif
setColor(lvl); setColor(lvl);
std::cout << data << std::flush; std::cout << data << std::flush;
setColor(-1); setColor(-1);
#ifndef _WIN32
funlockfile(stdout);
#endif
} }
}; };

View File

@ -611,6 +611,162 @@ void CCreatureHandler::loadSoundsInfo()
} }
} }
void CCreatureHandler::load(const JsonNode & node)
{
BOOST_FOREACH(auto & entry, node.Struct())
{
if (!entry.second.isNull()) // may happens if mod removed creature by setting json entry to null
{
CCreature * creature = loadCreature(entry.second);
creature->nameRef = entry.first;
creature->idNumber = creatures.size();
nameToID[entry.first] = creatures.size();
creatures.push_back(creature);
tlog3 << "Added creature: " << entry.first << "\n";
//TODO: notify modHandler that this refName can be resolved to ID
}
}
}
CCreature * CCreatureHandler::loadCreature(const JsonNode & node)
{
CCreature * cre = new CCreature();
const JsonNode & name = node["name"];
cre->nameSing = name["singular"].String();
cre->namePl = name["plural"].String();
cre->cost = Res::ResourceSet(node["cost"]);
cre->level = node["level"].Float();
cre->faction = node["faction"].Float(); //TODO: replaced by string -> id conversion
cre->fightValue = node["fightValue"].Float();
cre->AIValue = node["aiValue"].Float();
cre->growth = node["growth"].Float();
cre->hordeGrowth = node["horde"].Float(); // Needed at least until configurable buildings
cre->addBonus(node["hitPoints"].Float(), Bonus::STACK_HEALTH);
cre->addBonus(node["speed"].Float(), Bonus::STACKS_SPEED);
cre->addBonus(node["attack"].Float(), Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK);
cre->addBonus(node["defense"].Float(), Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE);
const JsonNode & vec = node["damage"];
cre->addBonus(vec["min"].Float(), Bonus::CREATURE_DAMAGE, 1);
cre->addBonus(vec["max"].Float(), Bonus::CREATURE_DAMAGE, 2);
auto & amounts = node ["advMapAmount"];
cre->ammMin = amounts["min"].Float();
cre->ammMax = amounts["max"].Float();
//optional
BOOST_FOREACH (auto & str, node["upgrades"].Vector())
{
cre->upgradeNames.insert (str.String());
}
if (!node["shots"].isNull())
cre->addBonus(node["shots"].Float(), Bonus::SHOTS);
if (node["spellPoints"].isNull())
cre->addBonus(node["spellPoints"].Float(), Bonus::CASTS);
cre->doubleWide = node["doubleWide"].Bool();
BOOST_FOREACH (const JsonNode &bonus, node["abilities"].Vector())
{
auto b = ParseBonus(bonus);
b->source = Bonus::CREATURE_ABILITY;
b->duration = Bonus::PERMANENT;
cre->addNewBonus(b);
}
BOOST_FOREACH (const JsonNode &exp, node["stackExperience"].Vector())
{
auto bonus = ParseBonus (exp["bonus"]);
bonus->source = Bonus::STACK_EXPERIENCE;
bonus->duration = Bonus::PERMANENT;
const JsonVector &values = exp["values"].Vector();
int lowerLimit = 1;//, upperLimit = 255;
if (values[0].getType() == JsonNode::JsonType::DATA_BOOL)
{
BOOST_FOREACH (const JsonNode &val, values)
{
if (val.Bool() == true)
{
bonus->limiter = make_shared<RankRangeLimiter>(RankRangeLimiter(lowerLimit));
cre->addNewBonus (new Bonus(*bonus)); //bonuses must be unique objects
break; //TODO: allow bonuses to turn off?
}
++lowerLimit;
}
}
else
{
int lastVal = 0;
BOOST_FOREACH (const JsonNode &val, values)
{
if (val.Float() != lastVal)
{
bonus->val = val.Float() - lastVal;
bonus->limiter.reset (new RankRangeLimiter(lowerLimit));
cre->addNewBonus (new Bonus(*bonus));
}
lastVal = val.Float();
++lowerLimit;
}
}
}
//graphics
const JsonNode & graphics = node["graphics"];
cre->animDefName = graphics["animation"].String();
cre->timeBetweenFidgets = graphics["timeBetweenFidgets"].Float();
cre->troopCountLocationOffset = graphics["troopCountLocationOffset"].Float();
cre->attackClimaxFrame = graphics["attackClimaxFrame"].Float();
const JsonNode & animationTime = graphics["animationTime"];
cre->walkAnimationTime = animationTime["walk"].Float();
cre->attackAnimationTime = animationTime["attack"].Float();
cre->flightAnimationDistance = animationTime["flight"].Float(); //?
//TODO: background?
const JsonNode & missile = graphics["missile"];
//TODO: parse
cre->projectile = missile["projectile"].String();
cre->projectileSpin = missile["spinning"].Bool();
const JsonNode & offsets = missile["offset"];
cre->upperRightMissleOffsetX = offsets["upperX"].Float();
cre->upperRightMissleOffsetY = offsets["upperY"].Float();
cre->rightMissleOffsetX = offsets["middleX"].Float();
cre->rightMissleOffsetY = offsets["middleY"].Float();
cre->lowerRightMissleOffsetX = offsets["lowerX"].Float();
cre->lowerRightMissleOffsetY = offsets["lowerY"].Float();
int i = 0;
BOOST_FOREACH (auto & angle, missile["frameAngles"].Vector())
{
cre->missleFrameAngles[i++] = angle.Float();
}
cre->advMapDef = graphics["map"].String();
cre->iconIndex = graphics["iconIndex"].Float();
const JsonNode & sounds = node["sound"];
#define GET_SOUND_VALUE(value_name) do { cre->sounds.value_name = sounds[#value_name].String(); } while(0)
GET_SOUND_VALUE(attack);
GET_SOUND_VALUE(defend);
GET_SOUND_VALUE(killed);
GET_SOUND_VALUE(move);
GET_SOUND_VALUE(shoot);
GET_SOUND_VALUE(wince);
GET_SOUND_VALUE(ext1);
GET_SOUND_VALUE(ext2);
GET_SOUND_VALUE(startMoving);
GET_SOUND_VALUE(endMoving);
#undef GET_SOUND_VALUE
return cre;
}
void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigParser & parser) //help function for parsing CREXPBON.txt void CCreatureHandler::loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigParser & parser) //help function for parsing CREXPBON.txt
{ {
bool enable = false; //some bonuses are activated with values 2 or 1 bool enable = false; //some bonuses are activated with values 2 or 1
@ -914,7 +1070,7 @@ static int retreiveRandNum(const boost::function<int()> &randGen)
template <typename T> const T & pickRandomElementOf(const std::vector<T> &v, const boost::function<int()> &randGen) template <typename T> const T & pickRandomElementOf(const std::vector<T> &v, const boost::function<int()> &randGen)
{ {
return v[retreiveRandNum(randGen) % v.size()]; return v.at(retreiveRandNum(randGen) % v.size());
} }
int CCreatureHandler::pickRandomMonster(const boost::function<int()> &randGen, int tier) const int CCreatureHandler::pickRandomMonster(const boost::function<int()> &randGen, int tier) const
@ -936,7 +1092,6 @@ int CCreatureHandler::pickRandomMonster(const boost::function<int()> &randGen, i
assert(b->getNodeType() == CBonusSystemNode::CREATURE); assert(b->getNodeType() == CBonusSystemNode::CREATURE);
int creid = static_cast<const CCreature*>(b)->idNumber; int creid = static_cast<const CCreature*>(b)->idNumber;
if(!vstd::contains(notUsedMonsters, creid)) if(!vstd::contains(notUsedMonsters, creid))
allowed.push_back(creid); allowed.push_back(creid);
} }

View File

@ -140,27 +140,40 @@ public:
si8 expAfterUpgrade;//multiplier in % si8 expAfterUpgrade;//multiplier in %
//Commanders //Commanders
std::map <ui8, ui32> factionCommanders; std::map <TFaction, TCreature> factionCommanders;
BonusList commanderLevelPremy; //bonus values added with each level-up BonusList commanderLevelPremy; //bonus values added with each level-up
std::vector< std::vector <ui8> > skillLevels; //how much of a bonus will be given to commander with every level. SPELL_POWER also gives CASTS and RESISTANCE std::vector< std::vector <ui8> > skillLevels; //how much of a bonus will be given to commander with every level. SPELL_POWER also gives CASTS and RESISTANCE
std::vector <std::pair <Bonus, std::pair <ui8, ui8> > > skillRequirements; // first - Bonus, second - which two skills are needed to use it std::vector <std::pair <Bonus, std::pair <ui8, ui8> > > skillRequirements; // first - Bonus, second - which two skills are needed to use it
void deserializationFix(); /// loading functions
void loadCreatures();
void buildBonusTreeForTiers();
void loadAnimationInfo();
void loadUnitAnimInfo(CCreature & unit, CLegacyConfigParser &parser);
void loadSoundsInfo();
void loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigParser &parser);
int stringToNumber(std::string & s);//help function for parsing CREXPBON.txt
int pickRandomMonster(const boost::function<int()> &randGen = 0, int tier = -1) const; //tier <1 - CREATURES_PER_TOWN> or -1 for any /// load all creatures from H3 files
void addBonusForTier(int tier, Bonus *b); //tier must be <1-7> void loadCreatures();
void addBonusForAllCreatures(Bonus *b); /// load all creatures from json structure
void load(const JsonNode & node);
/// load one creature from json config
CCreature * loadCreature(const JsonNode & node);
/// generates tier-specific bonus tree entries
void buildBonusTreeForTiers();
/// read cranim.txt file from H3
void loadAnimationInfo();
/// read one line from cranim.txt
void loadUnitAnimInfo(CCreature & unit, CLegacyConfigParser &parser);
/// load cr_sounds.json config
void loadSoundsInfo();
/// parse crexpbon.txt file from H3
void loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigParser &parser);
/// help function for parsing CREXPBON.txt
int stringToNumber(std::string & s);
CCreatureHandler(); CCreatureHandler();
~CCreatureHandler(); ~CCreatureHandler();
void deserializationFix();
int pickRandomMonster(const boost::function<int()> &randGen = 0, int tier = -1) const; //tier <1 - CREATURES_PER_TOWN> or -1 for any
void addBonusForTier(int tier, Bonus *b); //tier must be <1-7>
void addBonusForAllCreatures(Bonus *b);
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
//TODO: should be optimized, not all these informations needs to be serialized (same for ccreature) //TODO: should be optimized, not all these informations needs to be serialized (same for ccreature)

View File

@ -1,6 +1,6 @@
#pragma once #pragma once
#include "GameConstants.h"
#include "../lib/ConstTransitivePtr.h" #include "../lib/ConstTransitivePtr.h"
/* /*
@ -50,11 +50,14 @@ class DLL_LINKAGE CDefObjInfoHandler
public: public:
bmap<int, bmap<int, ConstTransitivePtr<CGDefInfo> > > gobjs; bmap<int, bmap<int, ConstTransitivePtr<CGDefInfo> > > gobjs;
bmap<TFaction, ConstTransitivePtr<CGDefInfo> > capitols;
bmap<TFaction, ConstTransitivePtr<CGDefInfo> > villages;
void load(); void load();
~CDefObjInfoHandler(); ~CDefObjInfoHandler();
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
h & gobjs; h & gobjs & capitols & villages;
} }
}; };

View File

@ -660,11 +660,11 @@ void CGameState::randomizeObject(CGObjectInstance *cur)
CGTownInstance *t = dynamic_cast<CGTownInstance*>(cur); CGTownInstance *t = dynamic_cast<CGTownInstance*>(cur);
t->town = &VLC->townh->towns[t->subID]; t->town = &VLC->townh->towns[t->subID];
if(t->hasCapitol()) if(t->hasCapitol())
t->defInfo = capitols[t->subID]; t->defInfo = VLC->dobjinfo->capitols[t->subID];
else if(t->hasFort()) else if(t->hasFort())
t->defInfo = forts[t->subID]; t->defInfo = VLC->dobjinfo->gobjs[Obj::TOWN][t->subID];
else else
t->defInfo = villages[t->subID]; t->defInfo = VLC->dobjinfo->villages[t->subID];
} }
return; return;
} }
@ -685,13 +685,14 @@ void CGameState::randomizeObject(CGObjectInstance *cur)
if(!t) {tlog2<<"Wrong random town at "<<cur->pos<<std::endl; return;} if(!t) {tlog2<<"Wrong random town at "<<cur->pos<<std::endl; return;}
cur->ID = ran.first; cur->ID = ran.first;
cur->subID = ran.second; cur->subID = ran.second;
t->town = &VLC->townh->towns[ran.second]; //FIXME: copy-pasted from above
t->town = &VLC->townh->towns[t->subID];
if(t->hasCapitol()) if(t->hasCapitol())
t->defInfo = capitols[t->subID]; t->defInfo = VLC->dobjinfo->capitols[t->subID];
else if(t->hasFort()) else if(t->hasFort())
t->defInfo = forts[t->subID]; t->defInfo = VLC->dobjinfo->gobjs[Obj::TOWN][t->subID];
else else
t->defInfo = villages[t->subID]; t->defInfo = VLC->dobjinfo->villages[t->subID];
t->randomizeArmy(t->subID); t->randomizeArmy(t->subID);
map->towns.push_back(t); map->towns.push_back(t);
return; return;
@ -700,7 +701,7 @@ void CGameState::randomizeObject(CGObjectInstance *cur)
cur->ID = ran.first; cur->ID = ran.first;
cur->subID = ran.second; cur->subID = ran.second;
map->removeBlockVisTiles(cur); //recalculate blockvis tiles - picked object might have different than random placeholder map->removeBlockVisTiles(cur); //recalculate blockvis tiles - picked object might have different than random placeholder
map->customDefs.push_back(cur->defInfo = VLC->dobjinfo->gobjs[ran.first][ran.second]); map->customDefs.push_back(cur->defInfo = VLC->dobjinfo->gobjs[ran.first][ran.second]);
if(!cur->defInfo) if(!cur->defInfo)
{ {
tlog1<<"*BIG* WARNING: Missing def declaration for "<<cur->ID<<" "<<cur->subID<<std::endl; tlog1<<"*BIG* WARNING: Missing def declaration for "<<cur->ID<<" "<<cur->subID<<std::endl;
@ -761,10 +762,6 @@ CGameState::~CGameState()
//delete initialOpts; //delete initialOpts;
delete applierGs; delete applierGs;
delete objCaller; delete objCaller;
//TODO: delete properly that definfos
villages.clear();
capitols.clear();
} }
BattleInfo * CGameState::setupBattle(int3 tile, const CArmedInstance *armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance *town) BattleInfo * CGameState::setupBattle(int3 tile, const CArmedInstance *armies[2], const CGHeroInstance * heroes[2], bool creatureBank, const CGTownInstance *town)
@ -866,18 +863,18 @@ void CGameState::init(StartInfo * si)
switch(scenarioOps->mode) switch(scenarioOps->mode)
{ {
case StartInfo::NEW_GAME: case StartInfo::NEW_GAME:
tlog0 << "Open map file: " << scenarioOps->mapname << std::endl; tlog0 << "Open map file: " << scenarioOps->mapname << std::endl;
map = CMapService::loadMap(scenarioOps->mapname).release(); map = CMapService::loadMap(scenarioOps->mapname).release();
break; break;
case StartInfo::CAMPAIGN: case StartInfo::CAMPAIGN:
{ {
tlog0 << "Open campaign map file: " << scenarioOps->campState->currentMap << std::endl; tlog0 << "Open campaign map file: " << scenarioOps->campState->currentMap << std::endl;
auto campaign = scenarioOps->campState; auto campaign = scenarioOps->campState;
assert(vstd::contains(campaign->camp->mapPieces, scenarioOps->campState->currentMap)); assert(vstd::contains(campaign->camp->mapPieces, scenarioOps->campState->currentMap));
std::string & mapContent = campaign->camp->mapPieces[scenarioOps->campState->currentMap]; std::string & mapContent = campaign->camp->mapPieces[scenarioOps->campState->currentMap];
auto buffer = reinterpret_cast<const ui8 *>(mapContent.data()); auto buffer = reinterpret_cast<const ui8 *>(mapContent.data());
map = CMapService::loadMap(buffer, mapContent.size()).release(); map = CMapService::loadMap(buffer, mapContent.size()).release();
} }
break; break;
case StartInfo::DUEL: case StartInfo::DUEL:
@ -906,7 +903,6 @@ void CGameState::init(StartInfo * si)
scenarioOps->mapfileChecksum = map->checksum; scenarioOps->mapfileChecksum = map->checksum;
day = 0; day = 0;
loadTownDInfos();
tlog4 << "Initialization:"; tlog4 << "Initialization:";
tlog4 << "\tPicking grail position"; tlog4 << "\tPicking grail position";
@ -920,14 +916,14 @@ void CGameState::init(StartInfo * si)
std::vector<int3> allowedPos; std::vector<int3> allowedPos;
// add all not blocked tiles in range // add all not blocked tiles in range
for (int i = 0; i < map->width ; i++) for (int i = 0; i < map->width ; i++)
{ {
for (int j = 0; j < map->height ; j++) for (int j = 0; j < map->height ; j++)
{ {
for (int k = 0; k <= map->twoLevel ; k++) for (int k = 0; k <= map->twoLevel ; k++)
{ {
const TerrainTile &t = map->terrain[i][j][k]; const TerrainTile &t = map->terrain[i][j][k];
if(!t.blocked if(!t.blocked
&& !t.visitable && !t.visitable
&& t.terType != ETerrainType::WATER && t.terType != ETerrainType::WATER
&& t.terType != ETerrainType::ROCK && t.terType != ETerrainType::ROCK
@ -946,7 +942,7 @@ void CGameState::init(StartInfo * si)
map->grailPos = allowedPos[ran() % allowedPos.size()]; map->grailPos = allowedPos[ran() % allowedPos.size()];
else else
tlog2 << "Warning: Grail cannot be placed, no appropriate tile found!\n"; tlog2 << "Warning: Grail cannot be placed, no appropriate tile found!\n";
} }
//picking random factions for players //picking random factions for players
tlog4 << "\tPicking random factions for players"; tlog4 << "\tPicking random factions for players";
@ -1771,38 +1767,6 @@ int CGameState::getPlayerRelations( ui8 color1, ui8 color2 )
return 0; return 0;
} }
void CGameState::loadTownDInfos()
{
assert(!VLC->dobjinfo->gobjs[Obj::TOWN].empty()); //make sure that at least some def info was found
const CGDefInfo * baseInfo = VLC->dobjinfo->gobjs[Obj::TOWN].begin()->second;
auto & townInfos = VLC->dobjinfo->gobjs[Obj::TOWN];
BOOST_FOREACH(auto & town, VLC->townh->towns)
{
if (!vstd::contains(VLC->dobjinfo->gobjs[Obj::TOWN], town.first)) // no obj info for this town type
{
CGDefInfo * info = new CGDefInfo(*baseInfo);
info->subid = town.first;
townInfos[town.first] = info;
}
forts[town.first] = townInfos[town.first];
townInfos[town.first]->name = town.second.clientInfo.advMapCastle;
villages[town.first] = new CGDefInfo(*townInfos[town.first]);
villages[town.first]->name = town.second.clientInfo.advMapVillage;
capitols[town.first] = new CGDefInfo(*townInfos[town.first]);
capitols[town.first]->name = town.second.clientInfo.advMapCapitol;
map->customDefs.push_back(villages[town.first]);
map->customDefs.push_back(forts[town.first]);
map->customDefs.push_back(capitols[town.first]);
}
}
void CGameState::getNeighbours(const TerrainTile &srct, int3 tile, std::vector<int3> &vec, const boost::logic::tribool &onLand, bool limitCoastSailing) void CGameState::getNeighbours(const TerrainTile &srct, int3 tile, std::vector<int3> &vec, const boost::logic::tribool &onLand, bool limitCoastSailing)
{ {
static const int3 dirs[] = { int3(0,1,0),int3(0,-1,0),int3(-1,0,0),int3(+1,0,0), static const int3 dirs[] = { int3(0,1,0),int3(0,-1,0),int3(-1,0,0),int3(+1,0,0),

View File

@ -40,7 +40,6 @@ class CGHeroInstance;
class CGTownInstance; class CGTownInstance;
class CArmedInstance; class CArmedInstance;
class CGDwelling; class CGDwelling;
class CGDefInfo;
class CObjectScript; class CObjectScript;
class CGObjectInstance; class CGObjectInstance;
class CCreature; class CCreature;
@ -389,7 +388,6 @@ public:
ConstTransitivePtr<CMap> map; ConstTransitivePtr<CMap> map;
bmap<TPlayerColor, PlayerState> players; bmap<TPlayerColor, PlayerState> players;
bmap<TPlayerColor, TeamState> teams; bmap<TPlayerColor, TeamState> teams;
bmap<TPlayerColor, ConstTransitivePtr<CGDefInfo> > villages, forts, capitols; //def-info for town graphics
CBonusSystemNode globalEffects; CBonusSystemNode globalEffects;
bmap<const CGHeroInstance*, const CGObjectInstance*> ongoingVisits; bmap<const CGHeroInstance*, const CGObjectInstance*> ongoingVisits;
@ -411,7 +409,6 @@ public:
void init(StartInfo * si); void init(StartInfo * si);
void initDuel(); void initDuel();
void loadTownDInfos();
void randomizeObject(CGObjectInstance *cur); void randomizeObject(CGObjectInstance *cur);
std::pair<int,int> pickObject(CGObjectInstance *obj); //chooses type of object to be randomized, returns <type, subtype> std::pair<int,int> pickObject(CGObjectInstance *obj); //chooses type of object to be randomized, returns <type, subtype>
int pickHero(int owner); int pickHero(int owner);
@ -450,11 +447,6 @@ public:
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
h & scenarioOps & initialOpts & currentPlayer & day & map & players & teams & hpool & globalEffects; h & scenarioOps & initialOpts & currentPlayer & day & map & players & teams & hpool & globalEffects;
h & villages & forts & capitols;
if(!h.saving)
{
loadTownDInfos();
}
BONUS_TREE_DESERIALIZATION_FIX BONUS_TREE_DESERIALIZATION_FIX
} }

View File

@ -30,26 +30,14 @@ CModHandler::CModHandler()
VLC->modh = this; VLC->modh = this;
loadConfigFromFile ("defaultMods"); loadConfigFromFile ("defaultMods");
findAvailableMods();
//CResourceHandler::loadModsFilesystems(); //scan for all mods //CResourceHandler::loadModsFilesystems(); //scan for all mods
//TODO: mod filesystem is already initialized at LibClasses launch //TODO: mod filesystem is already initialized at LibClasses launch
//TODO: load default (last?) config //TODO: load default (last?) config
} }
artID CModHandler::addNewArtifact (CArtifact * art)
{
int id = artifacts.size();
artifacts.push_back (art);
return id;
}
creID CModHandler::addNewCreature (CCreature * cre)
{
int id = creatures.size();
creatures.push_back (cre);
return id;
}
void CModHandler::loadConfigFromFile (std::string name) void CModHandler::loadConfigFromFile (std::string name)
{ {
const JsonNode config(ResourceID("config/" + name + ".json")); const JsonNode config(ResourceID("config/" + name + ".json"));
const JsonNode & hardcodedFeatures = config["hardcodedFeatures"]; const JsonNode & hardcodedFeatures = config["hardcodedFeatures"];
@ -67,28 +55,6 @@ void CModHandler::loadConfigFromFile (std::string name)
modules.MITHRIL = gameModules["MITHRIL"].Bool(); modules.MITHRIL = gameModules["MITHRIL"].Bool();
//TODO: load only mods from the list //TODO: load only mods from the list
//TODO: read mods from Mods/ folder
auto & configList = CResourceHandler::get()->getResourcesWithName (ResourceID("CONFIG/mod.json"));
BOOST_FOREACH(auto & entry, configList)
{
auto stream = entry.getLoader()->load (entry.getResourceName());
std::unique_ptr<ui8[]> textData (new ui8[stream->getSize()]);
stream->read (textData.get(), stream->getSize());
tlog3 << "\t\tFound mod file: " << entry.getResourceName() << "\n";
const JsonNode config ((char*)textData.get(), stream->getSize());
VLC->townh->loadFactions(config["factions"]);
const JsonNode *value = &config["creatures"];
BOOST_FOREACH (auto creature, value->Vector())
{
loadCreature (creature);//create and push back creature
}
}
} }
void CModHandler::saveConfigToFile (std::string name) void CModHandler::saveConfigToFile (std::string name)
@ -105,229 +71,80 @@ void CModHandler::saveConfigToFile (std::string name)
//file << savedConf; //file << savedConf;
} }
CCreature * CModHandler::loadCreature (const JsonNode &node)
void CModHandler::findAvailableMods()
{ {
CCreature * cre = new CCreature(); //TODO: read mods from Mods/ folder
const JsonNode *value; //optional value
//TODO: ref name? auto & configList = CResourceHandler::get()->getResourcesWithName (ResourceID("CONFIG/mod.json"));
const JsonNode & name = node["name"];
cre->nameSing = name["singular"].String();
cre->namePl = name["plural"].String();
value = &name["reference"];
if (!value->isNull())
cre->nameRef = value->String();
else
cre->nameRef = cre->nameSing;
cre->cost = Res::ResourceSet(node["cost"]); BOOST_FOREACH(auto & entry, configList)
cre->level = node["level"].Float();
cre->faction = 9; //neutral faction is 9 for now. Will be replaced by string -> id conversion
//TODO: node["faction"].String() to id
cre->fightValue = node["fightValue"].Float();
cre->AIValue = node["aiValue"].Float();
cre->growth = node["growth"].Float();
cre->hordeGrowth = node["horde"].Float(); // Needed at least until configurable buildings
cre->addBonus(node["hitPoints"].Float(), Bonus::STACK_HEALTH);
cre->addBonus(node["speed"].Float(), Bonus::STACKS_SPEED);
cre->addBonus(node["attack"].Float(), Bonus::PRIMARY_SKILL, PrimarySkill::ATTACK);
cre->addBonus(node["defense"].Float(), Bonus::PRIMARY_SKILL, PrimarySkill::DEFENSE);
const JsonNode & vec = node["damage"];
cre->addBonus(vec["min"].Float(), Bonus::CREATURE_DAMAGE, 1);
cre->addBonus(vec["max"].Float(), Bonus::CREATURE_DAMAGE, 2);
auto & amounts = node ["advMapAmount"];
cre->ammMin = amounts["min"].Float();
cre->ammMax = amounts["max"].Float();
//optional
BOOST_FOREACH (auto & str, node["upgrades"].Vector())
{ {
cre->upgradeNames.insert (str.String()); auto stream = entry.getLoader()->load (entry.getResourceName());
} std::unique_ptr<ui8[]> textData (new ui8[stream->getSize()]);
stream->read (textData.get(), stream->getSize());
value = &node["shots"]; tlog3 << "\t\tFound mod file: " << entry.getResourceName() << "\n";
if (!value->isNull()) allMods[allMods.size()].config.reset(new JsonNode((char*)textData.get(), stream->getSize()));
cre->addBonus(value->Float(), Bonus::SHOTS);
value = &node["spellPoints"];
if (!value->isNull())
cre->addBonus(value->Float(), Bonus::CASTS);
cre->doubleWide = node["doubleWide"].Bool();
BOOST_FOREACH (const JsonNode &bonus, node["abilities"].Vector())
{
auto b = ParseBonus(bonus);
b->source = Bonus::CREATURE_ABILITY;
b->duration = Bonus::PERMANENT;
cre->addNewBonus(b);
}
BOOST_FOREACH (const JsonNode &exp, node["stackExperience"].Vector())
{
auto bonus = ParseBonus (exp["bonus"]);
bonus->source = Bonus::STACK_EXPERIENCE;
bonus->duration = Bonus::PERMANENT;
const JsonVector &values = exp["values"].Vector();
int lowerLimit = 1;//, upperLimit = 255;
if (values[0].getType() == JsonNode::JsonType::DATA_BOOL)
{
BOOST_FOREACH (const JsonNode &val, values)
{
if (val.Bool() == true)
{
bonus->limiter = make_shared<RankRangeLimiter>(RankRangeLimiter(lowerLimit));
cre->addNewBonus (new Bonus(*bonus)); //bonuses must be unique objects
break; //TODO: allow bonuses to turn off?
}
++lowerLimit;
}
}
else
{
int lastVal = 0;
BOOST_FOREACH (const JsonNode &val, values)
{
if (val.Float() != lastVal)
{
bonus->val = val.Float() - lastVal;
bonus->limiter.reset (new RankRangeLimiter(lowerLimit));
cre->addNewBonus (new Bonus(*bonus));
}
lastVal = val.Float();
++lowerLimit;
}
}
}
//graphics
const JsonNode & graphics = node["graphics"];
cre->animDefName = graphics["animation"].String();
cre->timeBetweenFidgets = graphics["timeBetweenFidgets"].Float();
cre->troopCountLocationOffset = graphics["troopCountLocationOffset"].Float();
cre->attackClimaxFrame = graphics["attackClimaxFrame"].Float();
const JsonNode & animationTime = graphics["animationTime"];
cre->walkAnimationTime = animationTime["walk"].Float();
cre->attackAnimationTime = animationTime["attack"].Float();
cre->flightAnimationDistance = animationTime["flight"].Float(); //?
//TODO: background?
const JsonNode & missile = graphics["missile"];
//TODO: parse
value = &missile["projectile"];
if (value->isNull())
cre->projectile = "PLCBOWX.DEF";
else
cre->projectile = value->String();
value = &missile["spinning"];
if (value->isNull())
cre->projectileSpin = false; //no animation by default to avoid crash
else
cre->projectileSpin = value->Bool();
const JsonNode & offsets = missile["offset"];
cre->upperRightMissleOffsetX = offsets["upperX"].Float();
cre->upperRightMissleOffsetY = offsets["upperY"].Float();
cre->rightMissleOffsetX = offsets["middleX"].Float();
cre->rightMissleOffsetY = offsets["middleY"].Float();
cre->lowerRightMissleOffsetX = offsets["lowerX"].Float();
cre->lowerRightMissleOffsetY = offsets["lowerY"].Float();
int i = 0;
BOOST_FOREACH (auto & angle, missile["frameAngles"].Vector())
{
cre->missleFrameAngles[i++] = angle.Float();
}
cre->advMapDef = graphics["map"].String();
cre->iconIndex = graphics["iconIndex"].Float();
const JsonNode & sounds = node["sound"];
#define GET_SOUND_VALUE(value_name) do { cre->sounds.value_name = sounds[#value_name].String(); } while(0)
GET_SOUND_VALUE(attack);
GET_SOUND_VALUE(defend);
GET_SOUND_VALUE(killed);
GET_SOUND_VALUE(move);
GET_SOUND_VALUE(shoot);
GET_SOUND_VALUE(wince);
GET_SOUND_VALUE(ext1);
GET_SOUND_VALUE(ext2);
GET_SOUND_VALUE(startMoving);
GET_SOUND_VALUE(endMoving);
#undef GET_SOUND_VALUE
creatures.push_back(cre);
tlog3 << "Added new creature " << cre->nameRef << "\n";
return cre;
}
void CModHandler::recreateAdvMapDefs()
{
BOOST_FOREACH (auto creature, creatures)
{
//generate adventure map object info & graphics
CGDefInfo* nobj = new CGDefInfo (*VLC->dobjinfo->gobjs[Obj::MONSTER][0]);//copy all typical properties
nobj->name = creature->advMapDef; //change only def name (?)
VLC->dobjinfo->gobjs[Obj::MONSTER][creature->idNumber] = nobj;
} }
} }
void CModHandler::recreateHandlers()
void CModHandler::loadActiveMods()
{ {
//TODO: consider some template magic to unify all handlers? BOOST_FOREACH(auto & mod, allMods)
//VLC->arth->artifacts.clear();
//VLC->creh->creatures.clear(); //TODO: what about items from original game?
BOOST_FOREACH (auto creature, creatures)
{ {
creature->idNumber = VLC->creh->creatures.size(); //calculate next index for every used creature const JsonNode & config = *mod.second.config;
BOOST_FOREACH (auto bonus, creature->getBonusList())
{
bonus->sid = creature->idNumber;
}
VLC->creh->creatures.push_back (creature);
//TODO: use refName?
//if (creature->nameRef.size())
// VLC->creh->nameToID[creature->nameRef] = creature->idNumber;
VLC->creh->nameToID[creature->nameSing] = creature->idNumber;
VLC->townh->load(config["factions"]);
VLC->creh->load(config["creatures"]);
} }
recreateAdvMapDefs();
BOOST_FOREACH (auto creature, VLC->creh->creatures) //populate upgrades described with string
{
BOOST_FOREACH (auto upgradeName, creature->upgradeNames)
{
auto it = VLC->creh->nameToID.find(upgradeName);
if (it != VLC->creh->nameToID.end())
{
creature->upgrades.insert (it->second);
}
}
}
VLC->creh->buildBonusTreeForTiers(); //do that after all new creatures are loaded VLC->creh->buildBonusTreeForTiers(); //do that after all new creatures are loaded
}
BOOST_FOREACH (auto mod, activeMods) //inactive part void CModHandler::reload()
{
{ {
BOOST_FOREACH (auto art, allMods[mod].artifacts) assert(!VLC->dobjinfo->gobjs[Obj::MONSTER].empty()); //make sure that at least some def info was found
{
VLC->arth->artifacts.push_back (artifacts[art]);
//TODO: recreate types / limiters based on string id const CGDefInfo * baseInfo = VLC->dobjinfo->gobjs[Obj::MONSTER].begin()->second;
BOOST_FOREACH(auto & crea, VLC->creh->creatures)
{
if (!vstd::contains(VLC->dobjinfo->gobjs[Obj::MONSTER], crea->idNumber)) // no obj info for this type
{
CGDefInfo * info = new CGDefInfo(*baseInfo);
info->subid = crea->idNumber;
info->name = crea->advMapDef;
VLC->dobjinfo->gobjs[Obj::MONSTER][crea->idNumber] = info;
}
} }
BOOST_FOREACH (auto creature, allMods[mod].creatures) }
{
VLC->creh->creatures.push_back (creatures[creature]);
//TODO VLC->creh->notUsedMonster.push_back (creatures[creature]);
//TODO: recreate upgrades and other properties based on string id {
assert(!VLC->dobjinfo->gobjs[Obj::TOWN].empty()); //make sure that at least some def info was found
const CGDefInfo * baseInfo = VLC->dobjinfo->gobjs[Obj::TOWN].begin()->second;
auto & townInfos = VLC->dobjinfo->gobjs[Obj::TOWN];
BOOST_FOREACH(auto & town, VLC->townh->towns)
{
auto & cientInfo = town.second.clientInfo;
if (!vstd::contains(VLC->dobjinfo->gobjs[Obj::TOWN], town.first)) // no obj info for this type
{
CGDefInfo * info = new CGDefInfo(*baseInfo);
info->subid = town.first;
townInfos[town.first] = info;
}
townInfos[town.first]->name = cientInfo.advMapCastle;
VLC->dobjinfo->villages[town.first] = new CGDefInfo(*townInfos[town.first]);
VLC->dobjinfo->villages[town.first]->name = cientInfo.advMapVillage;
VLC->dobjinfo->capitols[town.first] = new CGDefInfo(*townInfos[town.first]);
VLC->dobjinfo->capitols[town.first]->name = cientInfo.advMapCapitol;
} }
} }
} }
CModHandler::~CModHandler()
{
}

View File

@ -20,65 +20,46 @@
class CModHandler; class CModHandler;
class CModIndentifier; class CModIndentifier;
class CModInfo; class CModInfo;
class JsonNode;
typedef si32 artID; typedef si32 TModID;
typedef si32 creID;
class DLL_LINKAGE CModIdentifier
{
//TODO? are simple integer identifiers enough?
int id;
public:
// int operator ()() {return 0;};
bool operator < (CModIdentifier rhs) const {return true;}; //for map
template <typename Handler> void serialize(Handler &h, const int version)
{
h & id;
}
};
class DLL_LINKAGE CModInfo class DLL_LINKAGE CModInfo
{ {
public: public:
std::vector <CModIdentifier> requirements; /// TODO: list of mods that should be loaded before this one
std::vector <ResourceID> usedFiles; std::vector <TModID> requirements;
//TODO: config options?
//items added by this mod /// mod configuration (mod.json).
std::vector <artID> artifacts; std::unique_ptr<JsonNode> config;
std::vector <creID> creatures;
//TODO: some additional scripts?
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
h & requirements & artifacts & creatures; h & requirements & config;
//h & usedFiles; //TODO: make seralizable?
} }
}; };
class DLL_LINKAGE CModHandler class DLL_LINKAGE CModHandler
{ {
public: public:
std::string currentConfig; //save settings in this file //std::string currentConfig; //save settings in this file
//list of all possible objects in game, including inactive mods or not allowed
std::vector <ConstTransitivePtr<CCreature> > creatures;
std::vector <ConstTransitivePtr<CArtifact> > artifacts;
std::map <CModIdentifier, CModInfo> allMods; std::map <TModID, CModInfo> allMods;
std::set <CModIdentifier> activeMods; std::set <TModID> activeMods;//TODO: use me
//create unique object indentifier /// management of game settings config
artID addNewArtifact (CArtifact * art); void loadConfigFromFile (std::string name);
creID addNewCreature (CCreature * cre);
void loadConfigFromFile (std::string name);
void saveConfigToFile (std::string name); void saveConfigToFile (std::string name);
CCreature * loadCreature (const JsonNode &node);
void recreateAdvMapDefs(); /// find all available mods and load them into FS
void recreateHandlers(); void findAvailableMods();
/// load content from all available mods
void loadActiveMods();
/// actions that should be triggered on map restart
/// TODO: merge into appropriate handlers?
void reload();
struct DLL_LINKAGE hardcodedFeatures struct DLL_LINKAGE hardcodedFeatures
{ {
@ -110,12 +91,9 @@ public:
} modules; } modules;
CModHandler(); CModHandler();
~CModHandler();
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)
{ {
h & currentConfig;
h & creatures & artifacts;
h & allMods & activeMods & settings & modules; h & allMods & activeMods & settings & modules;
} }
}; };

View File

@ -442,7 +442,7 @@ void CTownHandler::loadPuzzle(CFaction &faction, const JsonNode &source)
assert(faction.puzzleMap.size() == GameConstants::PUZZLE_MAP_PIECES); assert(faction.puzzleMap.size() == GameConstants::PUZZLE_MAP_PIECES);
} }
void CTownHandler::loadFactions(const JsonNode &source) void CTownHandler::load(const JsonNode &source)
{ {
BOOST_FOREACH(auto & node, source.Struct()) BOOST_FOREACH(auto & node, source.Struct())
{ {
@ -469,6 +469,8 @@ void CTownHandler::loadFactions(const JsonNode &source)
} }
if (!node.second["puzzleMap"].isNull()) if (!node.second["puzzleMap"].isNull())
loadPuzzle(faction, node.second["puzzleMap"]); loadPuzzle(faction, node.second["puzzleMap"]);
tlog3 << "Added faction: " << node.first << "\n";
} }
} }
@ -518,5 +520,5 @@ void CTownHandler::load()
} }
} }
} }
loadFactions(buildingsConf); load(buildingsConf);
} }

View File

@ -209,12 +209,11 @@ public:
/// main loading function for mods, accepts merged JSON source and add all entries from it into game /// main loading function for mods, accepts merged JSON source and add all entries from it into game
/// all entries in JSON should be checked for validness before using this function /// all entries in JSON should be checked for validness before using this function
void loadFactions(const JsonNode & source); void load(const JsonNode & source);
/// "entry point" for loading of OH3 town. /// "entry point" for loading of OH3 town.
/// reads legacy txt's from H3 + vcmi json, merges them /// reads legacy txt's from H3 + vcmi json, merges them
/// and loads resulting structure to game using loadTowns method /// and loads resulting structure to game using loadTowns method
/// in future may require loaded Creature Handler
void load(); void load();
template <typename Handler> void serialize(Handler &h, const int version) template <typename Handler> void serialize(Handler &h, const int version)

View File

@ -4,6 +4,8 @@ class JsonNode;
typedef std::map <std::string, JsonNode> JsonMap; typedef std::map <std::string, JsonNode> JsonMap;
typedef std::vector <JsonNode> JsonVector; typedef std::vector <JsonNode> JsonVector;
DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const JsonNode &node);
struct Bonus; struct Bonus;
class ResourceID; class ResourceID;
@ -96,6 +98,23 @@ public:
static void merge(JsonNode & dest, JsonNode & source); static void merge(JsonNode & dest, JsonNode & source);
/// this function will preserve data stored in source by creating copy /// this function will preserve data stored in source by creating copy
static void mergeCopy(JsonNode & dest, JsonNode source); static void mergeCopy(JsonNode & dest, JsonNode source);
template <typename Handler> void serialize(Handler &h, const int version)
{
if (h.saving)
{
std::ostringstream stream;
stream << *this;
std::string str = stream.str();
h & str;
}
else
{
std::string str;
h & str;
JsonNode(str.c_str(), str.size()).swap(*this);
}
}
}; };
template<> template<>
@ -136,8 +155,6 @@ public:
JsonWriter(std::ostream &output, const JsonNode &node); JsonWriter(std::ostream &output, const JsonNode &node);
}; };
DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const JsonNode &node);
//Tiny string class that uses const char* as data for speed, members are private //Tiny string class that uses const char* as data for speed, members are private
//for ease of debugging and some compatibility with std::string //for ease of debugging and some compatibility with std::string
class constString class constString

View File

@ -86,7 +86,6 @@ void registerTypes1(Serializer &s)
s.template registerType<StackOwnerLimiter>(); s.template registerType<StackOwnerLimiter>();
s.template registerType<CModInfo>(); s.template registerType<CModInfo>();
s.template registerType<CModIdentifier>();
s.template registerType<CBonusSystemNode>(); s.template registerType<CBonusSystemNode>();
s.template registerType<CArtifact>(); s.template registerType<CArtifact>();

View File

@ -101,7 +101,8 @@ void LibClasses::init()
spellh->loadSpells(); spellh->loadSpells();
tlog0<<"\tSpell handler: "<<pomtime.getDiff()<<std::endl; tlog0<<"\tSpell handler: "<<pomtime.getDiff()<<std::endl;
modh->recreateHandlers(); //load all new creatures parsed in the meantime. modh->loadActiveMods();
modh->reload();
//FIXME: make sure that everything is ok after game restart //FIXME: make sure that everything is ok after game restart
//TODO: This should be done every time mod config changes //TODO: This should be done every time mod config changes