瀏覽代碼

- 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

Ivan Savenko 13 年之前
父節點
當前提交
f7915d9e61

+ 3 - 2
client/CBitmapHandler.cpp

@@ -146,13 +146,14 @@ SDL_Surface * BitmapHandler::loadBitmapFromDir(std::string path, std::string fna
 				//set correct value for alpha\unused channel
 				for (int i=0; i< ret->format->palette->ncolors; i++)
 					ret->format->palette->colors[i].unused = 255;
-			}			
+			}
 		}
 		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;
 }
 

+ 8 - 2
client/CCastleInterface.cpp

@@ -1152,7 +1152,10 @@ void CCastleInterface::keyPressed( const SDL_KeyboardEvent & key )
 			builds = new CCastleBuildings(town);
 
 			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;
 	case SDLK_KP_MINUS:
@@ -1165,7 +1168,10 @@ void CCastleInterface::keyPressed( const SDL_KeyboardEvent & key )
 			builds = new CCastleBuildings(town);
 
 			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;

+ 1 - 1
client/CMT.cpp

@@ -778,7 +778,7 @@ static void listenForEvents()
 				delete CGI->dobjinfo.get();
 				const_cast<CGameInfo*>(CGI)->dobjinfo = new CDefObjInfoHandler; 
 				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)

+ 5 - 3
client/Graphics.cpp

@@ -346,7 +346,9 @@ SDL_Surface * Graphics::getPic(int ID, bool fort, bool builded)
 	{
 		assert(vstd::contains(CGI->townh->towns, ID));
 		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 )
 {
-	return advmapobjGraphics[obj->defInfo->id][obj->defInfo->subid][obj->defInfo->name];
+	return advmapobjGraphics[obj->defInfo->name];
 }
 
 CDefEssential * Graphics::getDef( const CGDefInfo * info )
 {
-	return advmapobjGraphics[info->id][info->subid][info->name];
+	return advmapobjGraphics[info->name];
 }
 
 void Graphics::loadErmuToPicture()

+ 1 - 2
client/Graphics.h

@@ -54,11 +54,10 @@ public:
 	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 *> 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 * 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 CGDefInfo * info);
 	//creatures

+ 3 - 3
client/NetPacksClient.cpp

@@ -403,11 +403,11 @@ void NewStructures::applyCl( CClient *cl )
 	{
 		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)
 		{
-			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))
 			cl->playerint[town->tempOwner]->buildChanged(town,id,1);
@@ -420,7 +420,7 @@ void RazeStructures::applyCl (CClient *cl)
 	{
 		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))
 			cl->playerint[town->tempOwner]->buildChanged (town,id,2);

+ 2 - 1
client/UIFramework/SDL_Extensions.cpp

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

+ 43 - 54
client/mapHandler.cpp

@@ -240,6 +240,36 @@ void CMapHandler::borderAndTerrainBitmapInit()
 	}
 	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()
 {
 	//initializing objects / rects
@@ -249,11 +279,15 @@ void CMapHandler::initObjectRects()
 		if(	!obj
 			|| (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->defInfo
-			|| !graphics->getDef(obj)) //no graphic...
+			|| !obj->defInfo )
 		{
 			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;
 		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)
 {
-    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()
 {
 	CStopWatch th;
 	th.getDiff();
 
-    graphics->advmapobjGraphics[8][0]["AB01_.DEF"] = graphics->boatAnims[0];
-    graphics->advmapobjGraphics[8][1]["AB02_.DEF"] = graphics->boatAnims[1];
-    graphics->advmapobjGraphics[8][2]["AB03_.DEF"] = graphics->boatAnims[2];
+	graphics->advmapobjGraphics["AB01_.DEF"] = graphics->boatAnims[0];
+	graphics->advmapobjGraphics["AB02_.DEF"] = graphics->boatAnims[1];
+	graphics->advmapobjGraphics["AB03_.DEF"] = graphics->boatAnims[2];
 	// Size of visible terrain.
 	int mapW = conf.go()->ac.advmapW;
 	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
 	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();
 	roadsRiverTerrainInit();	//road's and river's DefHandlers; and simple values initialization
 	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
 	SDL_Rect rtile = { 0, 0, 32, 32 };
-									
+
 	// Absolute coords of the first pixel in the top left corner
 	int srx_init = offsetX + extRect->x;
 	int sry_init = offsetY + extRect->y;

+ 8 - 0
lib/CConsoleHandler.h

@@ -30,8 +30,16 @@ public:
 
 	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);
 		std::cout << data << std::flush;
 		setColor(-1);
+#ifndef _WIN32
+		funlockfile(stdout);
+#endif
 	}
 };

+ 157 - 2
lib/CCreatureHandler.cpp

@@ -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
 {
 	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)
 {
-	return v[retreiveRandNum(randGen) % v.size()];
+	return v.at(retreiveRandNum(randGen) % v.size());
 }
 
 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);
 			int creid = static_cast<const CCreature*>(b)->idNumber;
 			if(!vstd::contains(notUsedMonsters, creid))
-
 				allowed.push_back(creid);
 		}
 

+ 19 - 6
lib/CCreatureHandler.h

@@ -140,27 +140,40 @@ public:
 	si8 expAfterUpgrade;//multiplier in %
 
 	//Commanders
-	std::map <ui8, ui32> factionCommanders;
+	std::map <TFaction, TCreature> factionCommanders;
 	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::pair <Bonus, std::pair <ui8, ui8> > > skillRequirements; // first - Bonus, second - which two skills are needed to use it
 
-	void deserializationFix();
+	/// loading functions
+
+	/// load all creatures from H3 files
 	void loadCreatures();
+	/// 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);
-	int stringToNumber(std::string & s);//help function for parsing CREXPBON.txt
+	/// help function for parsing CREXPBON.txt
+	int stringToNumber(std::string & s);
+
+	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);
 
-	CCreatureHandler();
-	~CCreatureHandler();
-
 	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)

+ 5 - 2
lib/CDefObjInfoHandler.h

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

+ 24 - 60
lib/CGameState.cpp

@@ -660,11 +660,11 @@ void CGameState::randomizeObject(CGObjectInstance *cur)
 			CGTownInstance *t = dynamic_cast<CGTownInstance*>(cur);
 			t->town = &VLC->townh->towns[t->subID];
 			if(t->hasCapitol())
-				t->defInfo = capitols[t->subID];
+				t->defInfo = VLC->dobjinfo->capitols[t->subID];
 			else if(t->hasFort())
-				t->defInfo = forts[t->subID];
+				t->defInfo = VLC->dobjinfo->gobjs[Obj::TOWN][t->subID];
 			else
-				t->defInfo = villages[t->subID];
+				t->defInfo = VLC->dobjinfo->villages[t->subID];
 		}
 		return;
 	}
@@ -685,13 +685,14 @@ void CGameState::randomizeObject(CGObjectInstance *cur)
 		if(!t) {tlog2<<"Wrong random town at "<<cur->pos<<std::endl; return;}
 		cur->ID = ran.first;
 		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())
-			t->defInfo = capitols[t->subID];
+			t->defInfo = VLC->dobjinfo->capitols[t->subID];
 		else if(t->hasFort())
-			t->defInfo = forts[t->subID];
+			t->defInfo = VLC->dobjinfo->gobjs[Obj::TOWN][t->subID];
 		else
-			t->defInfo = villages[t->subID];
+			t->defInfo = VLC->dobjinfo->villages[t->subID];
 		t->randomizeArmy(t->subID);
 		map->towns.push_back(t);
 		return;
@@ -700,7 +701,7 @@ void CGameState::randomizeObject(CGObjectInstance *cur)
 	cur->ID = ran.first;
 	cur->subID = ran.second;
 	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)
 	{
 		tlog1<<"*BIG* WARNING: Missing def declaration for "<<cur->ID<<" "<<cur->subID<<std::endl;
@@ -761,10 +762,6 @@ CGameState::~CGameState()
 	//delete initialOpts;
 	delete applierGs;
 	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)
@@ -866,18 +863,18 @@ void CGameState::init(StartInfo * si)
 	switch(scenarioOps->mode)
 	{
 	case StartInfo::NEW_GAME:
-        tlog0 << "Open map file: " << scenarioOps->mapname << std::endl;
-        map = CMapService::loadMap(scenarioOps->mapname).release();
+		tlog0 << "Open map file: " << scenarioOps->mapname << std::endl;
+		map = CMapService::loadMap(scenarioOps->mapname).release();
 		break;
 	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;
 			assert(vstd::contains(campaign->camp->mapPieces, scenarioOps->campState->currentMap));
 
-            std::string & mapContent = campaign->camp->mapPieces[scenarioOps->campState->currentMap];
-            auto buffer = reinterpret_cast<const ui8 *>(mapContent.data());
-            map = CMapService::loadMap(buffer, mapContent.size()).release();
+			std::string & mapContent = campaign->camp->mapPieces[scenarioOps->campState->currentMap];
+			auto buffer = reinterpret_cast<const ui8 *>(mapContent.data());
+			map = CMapService::loadMap(buffer, mapContent.size()).release();
 		}
 		break;
 	case StartInfo::DUEL:
@@ -906,7 +903,6 @@ void CGameState::init(StartInfo * si)
 		scenarioOps->mapfileChecksum = map->checksum;
 
 	day = 0;
-	loadTownDInfos();
 
 	tlog4 << "Initialization:";
 	tlog4 << "\tPicking grail position";
@@ -920,14 +916,14 @@ void CGameState::init(StartInfo * si)
  		std::vector<int3> allowedPos;
 
 		// add all not blocked tiles in range
- 		for (int i = 0; i < map->width ; i++)
- 		{
- 			for (int j = 0; j < map->height ; j++)
- 			{
- 				for (int k = 0; k <= map->twoLevel ; k++)
- 				{
- 					const TerrainTile &t = map->terrain[i][j][k];
- 					if(!t.blocked
+		for (int i = 0; i < map->width ; i++)
+		{
+			for (int j = 0; j < map->height ; j++)
+			{
+				for (int k = 0; k <= map->twoLevel ; k++)
+				{
+					const TerrainTile &t = map->terrain[i][j][k];
+					if(!t.blocked
 						&& !t.visitable
                         && t.terType != ETerrainType::WATER
                         && t.terType != ETerrainType::ROCK
@@ -946,7 +942,7 @@ void CGameState::init(StartInfo * si)
 			map->grailPos = allowedPos[ran() % allowedPos.size()];
 		else
 			tlog2 << "Warning: Grail cannot be placed, no appropriate tile found!\n";
- 	}
+	}
 
 	//picking random factions for players
 	tlog4 << "\tPicking random factions for players";
@@ -1771,38 +1767,6 @@ int CGameState::getPlayerRelations( ui8 color1, ui8 color2 )
 	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)
 {
 	static const int3 dirs[] = { int3(0,1,0),int3(0,-1,0),int3(-1,0,0),int3(+1,0,0),

+ 0 - 8
lib/CGameState.h

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

+ 50 - 233
lib/CModHandler.cpp

@@ -30,26 +30,14 @@ CModHandler::CModHandler()
 	VLC->modh = this;
 
 	loadConfigFromFile ("defaultMods");
+	findAvailableMods();
 	//CResourceHandler::loadModsFilesystems(); //scan for all mods
 	//TODO: mod filesystem is already initialized at LibClasses launch
 	//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)
 {
-
 	const JsonNode config(ResourceID("config/" + name + ".json"));
 	const JsonNode & hardcodedFeatures = config["hardcodedFeatures"];
 
@@ -67,28 +55,6 @@ void CModHandler::loadConfigFromFile (std::string name)
 	modules.MITHRIL = gameModules["MITHRIL"].Bool();
 
 	//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)
@@ -105,229 +71,80 @@ void CModHandler::saveConfigToFile (std::string name)
 	//file << savedConf;
 }
 
-CCreature * CModHandler::loadCreature (const JsonNode &node)
-{
-	CCreature * cre = new CCreature();
-	const JsonNode *value; //optional value
-
-	//TODO: ref name?
-	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"]);
+void CModHandler::findAvailableMods()
+{
+	//TODO: read mods from Mods/ folder
 
-	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
+	auto & configList = CResourceHandler::get()->getResourcesWithName (ResourceID("CONFIG/mod.json"));
 
-	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);
+	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());
 
-	auto & amounts = node ["advMapAmount"];
-	cre->ammMin = amounts["min"].Float();
-	cre->ammMax = amounts["max"].Float();
+		tlog3 << "\t\tFound mod file: " << entry.getResourceName() << "\n";
+		allMods[allMods.size()].config.reset(new JsonNode((char*)textData.get(), stream->getSize()));
+	}
+}
 
-	//optional
-	BOOST_FOREACH (auto & str, node["upgrades"].Vector())
+void CModHandler::loadActiveMods()
+{
+	BOOST_FOREACH(auto & mod, allMods)
 	{
-		cre->upgradeNames.insert (str.String());
-	}
+		const JsonNode & config = *mod.second.config;
 
-	value = &node["shots"];
-	if (!value->isNull())
-		cre->addBonus(value->Float(), Bonus::SHOTS);
+		VLC->townh->load(config["factions"]);
+		VLC->creh->load(config["creatures"]);
+	}
+	VLC->creh->buildBonusTreeForTiers(); //do that after all new creatures are loaded
+}
 
-	value = &node["spellPoints"];
-	if (!value->isNull())
-		cre->addBonus(value->Float(), Bonus::CASTS);
+void CModHandler::reload()
+{
+	{
+		assert(!VLC->dobjinfo->gobjs[Obj::MONSTER].empty()); //make sure that at least some def info was found
 
-	cre->doubleWide = node["doubleWide"].Bool();
+		const CGDefInfo * baseInfo = VLC->dobjinfo->gobjs[Obj::MONSTER].begin()->second;
 
-	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(auto & crea, VLC->creh->creatures)
 		{
-			BOOST_FOREACH (const JsonNode &val, values)
+			if (!vstd::contains(VLC->dobjinfo->gobjs[Obj::MONSTER], crea->idNumber)) // no obj info for this type
 			{
-				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;
+				CGDefInfo * info = new CGDefInfo(*baseInfo);
+				info->subid = crea->idNumber;
+				info->name = crea->advMapDef;
+
+				VLC->dobjinfo->gobjs[Obj::MONSTER][crea->idNumber] = info;
 			}
 		}
 	}
-	//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
+		assert(!VLC->dobjinfo->gobjs[Obj::TOWN].empty()); //make sure that at least some def info was found
 
-	creatures.push_back(cre);
+		const CGDefInfo * baseInfo = VLC->dobjinfo->gobjs[Obj::TOWN].begin()->second;
+		auto & townInfos = VLC->dobjinfo->gobjs[Obj::TOWN];
 
-	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()
-{
-	//TODO: consider some template magic to unify all handlers?
-
-	//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
-		BOOST_FOREACH (auto bonus, creature->getBonusList())
+		BOOST_FOREACH(auto & town, VLC->townh->towns)
 		{
-			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;
+			auto & cientInfo = town.second.clientInfo;
 
-	}
-	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())
+			if (!vstd::contains(VLC->dobjinfo->gobjs[Obj::TOWN], town.first)) // no obj info for this type
 			{
-				creature->upgrades.insert (it->second);
-			}
-		}
-	}
+				CGDefInfo * info = new CGDefInfo(*baseInfo);
+				info->subid = town.first;
 
-	VLC->creh->buildBonusTreeForTiers(); //do that after all new creatures are loaded
-
-	BOOST_FOREACH (auto mod, activeMods) //inactive part
-	{
-		BOOST_FOREACH (auto art, allMods[mod].artifacts)
-		{
-			VLC->arth->artifacts.push_back (artifacts[art]);
+				townInfos[town.first] = info;
+			}
+			townInfos[town.first]->name = cientInfo.advMapCastle;
 
-			//TODO: recreate types / limiters based on string id
-		}
-		BOOST_FOREACH (auto creature, allMods[mod].creatures)
-		{
-			VLC->creh->creatures.push_back (creatures[creature]);
-			//TODO VLC->creh->notUsedMonster.push_back (creatures[creature]);
+			VLC->dobjinfo->villages[town.first] = new CGDefInfo(*townInfos[town.first]);
+			VLC->dobjinfo->villages[town.first]->name = cientInfo.advMapVillage;
 
-			//TODO: recreate upgrades and other properties based on string id
+			VLC->dobjinfo->capitols[town.first] = new CGDefInfo(*townInfos[town.first]);
+			VLC->dobjinfo->capitols[town.first]->name = cientInfo.advMapCapitol;
 		}
 	}
 }
-
-CModHandler::~CModHandler()
-{
-}

+ 22 - 44
lib/CModHandler.h

@@ -20,65 +20,46 @@
 class CModHandler;
 class CModIndentifier;
 class CModInfo;
+class JsonNode;
 
-typedef si32 artID;
-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;
-	}
-};
-
+typedef si32 TModID;
 
 class DLL_LINKAGE CModInfo
 {
 public:
-	std::vector <CModIdentifier> requirements;
-	std::vector <ResourceID> usedFiles;
-	//TODO: config options?
+	/// TODO: list of mods that should be loaded before this one
+	std::vector <TModID> requirements;
 
-	//items added by this mod
-	std::vector <artID> artifacts;
-	std::vector <creID> creatures;
-
-	//TODO: some additional scripts?
+	/// mod configuration (mod.json).
+	std::unique_ptr<JsonNode> config;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & requirements & artifacts & creatures;
-		//h & usedFiles; //TODO: make seralizable?
+		h & requirements & config;
 	}
 };
 
 class DLL_LINKAGE CModHandler
 {
 public:
-	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::set <CModIdentifier> activeMods;
+	//std::string currentConfig; //save settings in this file
 
-	//create unique object indentifier
-	artID addNewArtifact (CArtifact * art);
-	creID addNewCreature (CCreature * cre);
+	std::map <TModID, CModInfo> allMods;
+	std::set <TModID> activeMods;//TODO: use me
 
-	void loadConfigFromFile (std::string name);
+	/// management of game settings config
+	void loadConfigFromFile (std::string name);	
 	void saveConfigToFile (std::string name);
-	CCreature * loadCreature (const JsonNode &node);
-	void recreateAdvMapDefs();
-	void recreateHandlers();
+
+	/// find all available mods and load them into FS
+	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
 	{
@@ -110,12 +91,9 @@ public:
 	} modules;
 
 	CModHandler();
-	~CModHandler();
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & currentConfig;
-		h & creatures & artifacts;
 		h & allMods & activeMods & settings & modules;
 	}
 };

+ 4 - 2
lib/CTownHandler.cpp

@@ -442,7 +442,7 @@ void CTownHandler::loadPuzzle(CFaction &faction, const JsonNode &source)
 	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())
 	{
@@ -469,6 +469,8 @@ void CTownHandler::loadFactions(const JsonNode &source)
 		}
 		if (!node.second["puzzleMap"].isNull())
 			loadPuzzle(faction, node.second["puzzleMap"]);
+
+		tlog3 << "Added faction: " << node.first << "\n";
 	}
 }
 
@@ -518,5 +520,5 @@ void CTownHandler::load()
 			}
 		}
 	}
-	loadFactions(buildingsConf);
+	load(buildingsConf);
 }

+ 1 - 2
lib/CTownHandler.h

@@ -209,12 +209,11 @@ public:
 
 	/// 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
-	void loadFactions(const JsonNode & source);
+	void load(const JsonNode & source);
 
 	/// "entry point" for loading of OH3 town.
 	/// reads legacy txt's from H3 + vcmi json, merges them
 	/// and loads resulting structure to game using loadTowns method
-	/// in future may require loaded Creature Handler
 	void load();
 
 	template <typename Handler> void serialize(Handler &h, const int version)

+ 19 - 2
lib/JsonNode.h

@@ -4,6 +4,8 @@ class JsonNode;
 typedef std::map <std::string, JsonNode> JsonMap;
 typedef std::vector <JsonNode> JsonVector;
 
+DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const JsonNode &node);
+
 struct Bonus;
 class ResourceID;
 
@@ -96,6 +98,23 @@ public:
 	static void merge(JsonNode & dest, JsonNode & source);
 	/// this function will preserve data stored in source by creating copy
 	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<>
@@ -136,8 +155,6 @@ public:
 	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
 //for ease of debugging and some compatibility with std::string
 class constString

+ 0 - 1
lib/RegisterTypes.h

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

+ 2 - 1
lib/VCMI_Lib.cpp

@@ -101,7 +101,8 @@ void LibClasses::init()
 	spellh->loadSpells();
 	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
 	//TODO: This should be done every time mod config changes