2
0
Эх сурвалжийг харах

first part of town configuration:
- moved almost all loading to TownHandler
- CBuildings and CStructures are now part of CTown
- merged hall.json into buildings.json

Should not cause any crashes or glitches

Ivan Savenko 13 жил өмнө
parent
commit
44cc848edc

+ 2 - 2
AI/VCAI/VCAI.cpp

@@ -1267,7 +1267,7 @@ bool VCAI::tryBuildStructure(const CGTownInstance * t, int building, unsigned in
 
 
 	BOOST_FOREACH(int buildID, toBuild)
 	BOOST_FOREACH(int buildID, toBuild)
 	{
 	{
-		const CBuilding *b = VLC->buildh->buildings[t->subID][buildID];
+		const CBuilding *b = t->town->buildings[buildID];
 
 
 		int canBuild = cb->canBuildStructure(t, buildID);
 		int canBuild = cb->canBuildStructure(t, buildID);
 		if(canBuild == EBuildingState::ALLOWED)
 		if(canBuild == EBuildingState::ALLOWED)
@@ -1282,7 +1282,7 @@ bool VCAI::tryBuildStructure(const CGTownInstance * t, int building, unsigned in
 		}
 		}
 		else if(canBuild == EBuildingState::NO_RESOURCES)
 		else if(canBuild == EBuildingState::NO_RESOURCES)
 		{
 		{
-			TResources cost = VLC->buildh->buildings[t->subID][buildID]->resources;
+			TResources cost = t->town->buildings[buildID]->resources;
 			for (int i = 0; i < GameConstants::RESOURCE_QUANTITY; i++)
 			for (int i = 0; i < GameConstants::RESOURCE_QUANTITY; i++)
 			{
 			{
 				int diff = currentRes[i] - cost[i] + income[i];
 				int diff = currentRes[i] - cost[i] + income[i];

+ 28 - 31
client/CCastleInterface.cpp

@@ -49,7 +49,7 @@ int hordeToDwellingID(int bid)//helper, converts horde buiding ID into correspon
 	}
 	}
 }
 }
 
 
-CBuildingRect::CBuildingRect(CCastleBuildings * Par, const CGTownInstance *Town, const Structure *Str)
+CBuildingRect::CBuildingRect(CCastleBuildings * Par, const CGTownInstance *Town, const CStructure *Str)
 	:CShowableAnim(0, 0, Str->defName, CShowableAnim::BASE | CShowableAnim::USE_RLE),
 	:CShowableAnim(0, 0, Str->defName, CShowableAnim::BASE | CShowableAnim::USE_RLE),
 	parent(Par),
 	parent(Par),
 	town(Town),
 	town(Town),
@@ -120,7 +120,7 @@ void CBuildingRect::clickRight(tribool down, bool previousState)
 	if( !CSDL_Ext::isTransparent(area, GH.current->motion.x-pos.x, GH.current->motion.y-pos.y) ) //inside building image
 	if( !CSDL_Ext::isTransparent(area, GH.current->motion.x-pos.x, GH.current->motion.y-pos.y) ) //inside building image
 	{
 	{
 		int bid = hordeToDwellingID(str->ID);
 		int bid = hordeToDwellingID(str->ID);
-		const CBuilding *bld = CGI->buildh->buildings[str->townID].find(bid)->second;
+		const CBuilding *bld = town->town->buildings[bid];
 		if (bid < EBuilding::DWELL_FIRST)
 		if (bid < EBuilding::DWELL_FIRST)
 		{
 		{
 			std::vector<CComponent*> comps(1, new CComponent(CComponent::building, bld->tid, bld->bid));
 			std::vector<CComponent*> comps(1, new CComponent(CComponent::building, bld->tid, bld->bid));
@@ -214,7 +214,7 @@ std::string getBuildingSubtitle(int tid, int bid)//hover text for building
 	bid = hordeToDwellingID(bid);
 	bid = hordeToDwellingID(bid);
 
 
 	if (bid<30)//non-dwellings - only buiding name
 	if (bid<30)//non-dwellings - only buiding name
-		return CGI->buildh->buildings[tid].find(bid)->second->Name();
+		return CGI->townh->towns[tid].buildings[bid]->Name();
 	else//dwellings - recruit %creature%
 	else//dwellings - recruit %creature%
 	{
 	{
 		int creaID = t->creatures[(bid-30)%GameConstants::CREATURES_PER_TOWN].second.back();//taking last of available creatures
 		int creaID = t->creatures[(bid-30)%GameConstants::CREATURES_PER_TOWN].second.back();//taking last of available creatures
@@ -445,7 +445,7 @@ public:
 };
 };
 
 
 SORTHELP<CBuildingRect> buildSorter;
 SORTHELP<CBuildingRect> buildSorter;
-SORTHELP<Structure> structSorter;
+SORTHELP<CStructure> structSorter;
 
 
 CCastleBuildings::CCastleBuildings(const CGTownInstance* Town):
 CCastleBuildings::CCastleBuildings(const CGTownInstance* Town):
 	town(Town),
 	town(Town),
@@ -459,10 +459,9 @@ CCastleBuildings::CCastleBuildings(const CGTownInstance* Town):
 	//Generate buildings list
 	//Generate buildings list
 	for (std::set<si32>::const_iterator building=town->builtBuildings.begin(); building!=town->builtBuildings.end(); building++)
 	for (std::set<si32>::const_iterator building=town->builtBuildings.begin(); building!=town->builtBuildings.end(); building++)
 	{
 	{
-		std::map<int, Structure*>::iterator structure;
-		structure = CGI->townh->structures[town->subID].find(*building);
+		auto structure = town->town->clientInfo.structures.find(*building);
 
 
-		if(structure != CGI->townh->structures[town->subID].end() && structure->second)
+		if(structure != town->town->clientInfo.structures.end() && structure->second)
 		{
 		{
 			if(structure->second->group<0) // no group - just add it
 			if(structure->second->group<0) // no group - just add it
 				buildings.push_back(new CBuildingRect(this, town, structure->second));
 				buildings.push_back(new CBuildingRect(this, town, structure->second));
@@ -471,18 +470,18 @@ CCastleBuildings::CCastleBuildings(const CGTownInstance* Town):
 		}
 		}
 	}
 	}
 
 
-	Structure * shipyard = CGI->townh->structures[town->subID][6];
+	CStructure * shipyard = town->town->clientInfo.structures[6];
 	//ship in shipyard
 	//ship in shipyard
 	if(shipyard && vstd::contains(groups, shipyard->group))
 	if(shipyard && vstd::contains(groups, shipyard->group))
 	{
 	{
 		std::vector <const CGObjectInstance *> vobjs = LOCPLINT->cb->getVisitableObjs(town->bestLocation());
 		std::vector <const CGObjectInstance *> vobjs = LOCPLINT->cb->getVisitableObjs(town->bestLocation());
 		if(!vobjs.empty() && (vobjs.front()->ID == 8 || vobjs.front()->ID == GameConstants::HEROI_TYPE)) //there is visitable obj at shipyard output tile and it's a boat or hero (on boat)
 		if(!vobjs.empty() && (vobjs.front()->ID == 8 || vobjs.front()->ID == GameConstants::HEROI_TYPE)) //there is visitable obj at shipyard output tile and it's a boat or hero (on boat)
 		{
 		{
-			groups[shipyard->group].push_back(CGI->townh->structures[town->subID][20]);
+			groups[shipyard->group].push_back(town->town->clientInfo.structures[20]);
 		}
 		}
 	}
 	}
 	//Create building for each group
 	//Create building for each group
-	for (std::map< int, std::vector<const Structure*> >::iterator group = groups.begin(); group != groups.end(); group++)
+	for (std::map< int, std::vector<const CStructure*> >::iterator group = groups.begin(); group != groups.end(); group++)
 	{
 	{
 		std::sort(group->second.begin(), group->second.end(), structSorter);
 		std::sort(group->second.begin(), group->second.end(), structSorter);
 		buildings.push_back(new CBuildingRect(this, town, group->second.back()));
 		buildings.push_back(new CBuildingRect(this, town, group->second.back()));
@@ -521,10 +520,10 @@ void CCastleBuildings::checkRules()
 		
 		
 		int buildingID = animRule[i].buildID;
 		int buildingID = animRule[i].buildID;
 		//check if this building have been upgraded (Ship is upgrade of Shipyard)
 		//check if this building have been upgraded (Ship is upgrade of Shipyard)
-		int groupID = CGI->townh->structures[town->subID][animRule[i].buildID]->group;
+		int groupID = town->town->clientInfo.structures[animRule[i].buildID]->group;
 		if (groupID != -1)
 		if (groupID != -1)
 		{
 		{
-			std::map< int, std::vector<const Structure*> >::const_iterator git= groups.find(groupID);
+			std::map< int, std::vector<const CStructure*> >::const_iterator git= groups.find(groupID);
 			if ( git == groups.end() || git->second.empty() )
 			if ( git == groups.end() || git->second.empty() )
 				continue;
 				continue;
 			buildingID  = git->second.back()->ID;
 			buildingID  = git->second.back()->ID;
@@ -548,10 +547,9 @@ void CCastleBuildings::checkRules()
 void CCastleBuildings::addBuilding(int building)
 void CCastleBuildings::addBuilding(int building)
 {
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	std::map<int, Structure*>::const_iterator structure;
-	structure = CGI->townh->structures[town->subID].find(building);
+	auto structure = town->town->clientInfo.structures.find(building);
 
 
-	if(structure != CGI->townh->structures[town->subID].end()) //we have info about that structure
+	if(structure != town->town->clientInfo.structures.end()) //we have info about that structure
 	{
 	{
 		if(structure->second->group<0) //no group - just add it
 		if(structure->second->group<0) //no group - just add it
 		{
 		{
@@ -586,10 +584,9 @@ void CCastleBuildings::addBuilding(int building)
 void CCastleBuildings::removeBuilding(int building)
 void CCastleBuildings::removeBuilding(int building)
 {
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
-	std::map<int, Structure*>::const_iterator structure;
-	structure = CGI->townh->structures[town->subID].find(building);
+	auto structure = town->town->clientInfo.structures.find(building);
 
 
-	if(structure != CGI->townh->structures[town->subID].end()) //we have info about that structure
+	if(structure != town->town->clientInfo.structures.end()) //we have info about that structure
 	{
 	{
 		if(structure->second->group<0) //no group - just add it
 		if(structure->second->group<0) //no group - just add it
 		{
 		{
@@ -642,7 +639,7 @@ void CCastleBuildings::buildingClicked(int building)
 {
 {
 	tlog5<<"You've clicked on "<<building<<std::endl;
 	tlog5<<"You've clicked on "<<building<<std::endl;
 	building = hordeToDwellingID(building);
 	building = hordeToDwellingID(building);
-	const CBuilding *b = CGI->buildh->buildings[town->subID].find(building)->second;
+	const CBuilding *b = town->town->buildings.find(building)->second;
 
 
 	if(building >= EBuilding::DWELL_FIRST)
 	if(building >= EBuilding::DWELL_FIRST)
 	{
 	{
@@ -784,7 +781,7 @@ void CCastleBuildings::enterBlacksmith(int ArtifactID)
 	const CGHeroInstance *hero = town->visitingHero;
 	const CGHeroInstance *hero = town->visitingHero;
 	if(!hero)
 	if(!hero)
 	{
 	{
-		LOCPLINT->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[273]) % CGI->buildh->buildings[town->subID].find(16)->second->Name()));
+		LOCPLINT->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[273]) % town->town->buildings.find(16)->second->Name()));
 		return;
 		return;
 	}
 	}
 	int price = CGI->arth->artifacts[ArtifactID]->price;
 	int price = CGI->arth->artifacts[ArtifactID]->price;
@@ -797,7 +794,7 @@ void CCastleBuildings::enterBuilding(int building)
 	std::vector<CComponent*> comps(1, new CComponent(CComponent::building, town->subID, building));
 	std::vector<CComponent*> comps(1, new CComponent(CComponent::building, town->subID, building));
 
 
 	LOCPLINT->showInfoDialog(
 	LOCPLINT->showInfoDialog(
-		CGI->buildh->buildings[town->subID].find(building)->second->Description(),comps);
+		town->town->buildings.find(building)->second->Description(),comps);
 }
 }
 
 
 void CCastleBuildings::enterCastleGate()
 void CCastleBuildings::enterCastleGate()
@@ -833,9 +830,9 @@ void CCastleBuildings::enterFountain(int building)
 {
 {
 	std::vector<CComponent*> comps(1, new CComponent(CComponent::building,town->subID,building));
 	std::vector<CComponent*> comps(1, new CComponent(CComponent::building,town->subID,building));
 
 
-	std::string descr = CGI->buildh->buildings[town->subID].find(building)->second->Description();
+	std::string descr = town->town->buildings.find(building)->second->Description();
 	if ( building == 21)//we need description for mystic pond as well
 	if ( building == 21)//we need description for mystic pond as well
-		descr += "\n\n"+CGI->buildh->buildings[town->subID].find(17)->second->Description();
+		descr += "\n\n"+town->town->buildings.find(17)->second->Description();
 	if (town->bonusValue.first == 0)//fountain was builded this week
 	if (town->bonusValue.first == 0)//fountain was builded this week
 		descr += "\n\n"+ CGI->generaltexth->allTexts[677];
 		descr += "\n\n"+ CGI->generaltexth->allTexts[677];
 	else//fountain produced something;
 	else//fountain produced something;
@@ -1182,7 +1179,7 @@ CTownInfo::CTownInfo(int posX, int posY, const CGTownInstance* Town, bool townHa
 			return;
 			return;
 		picture = new CAnimImage("ITMCL.DEF", town->fortLevel()-1);
 		picture = new CAnimImage("ITMCL.DEF", town->fortLevel()-1);
 	}
 	}
-	building = CGI->buildh->buildings[town->subID][buildID];
+	building = town->town->buildings[buildID];
 	pos = picture->pos;
 	pos = picture->pos;
 }
 }
 
 
@@ -1330,7 +1327,7 @@ CHallInterface::CBuildingBox::CBuildingBox(int x, int y, const CGTownInstance *
 }
 }
 
 
 CHallInterface::CHallInterface(const CGTownInstance *Town):
 CHallInterface::CHallInterface(const CGTownInstance *Town):
-    CWindowObject(PLAYER_COLORED | BORDERED, CGI->buildh->hall[Town->subID].first),
+    CWindowObject(PLAYER_COLORED | BORDERED, Town->town->clientInfo.hallBackground),
 	town(Town)
 	town(Town)
 {
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
@@ -1341,12 +1338,12 @@ CHallInterface::CHallInterface(const CGTownInstance *Town):
 	Rect barRect(5, 556, 740, 18);
 	Rect barRect(5, 556, 740, 18);
 	statusBar = new CGStatusBar(new CPicture(*background, barRect, 5, 556, false));
 	statusBar = new CGStatusBar(new CPicture(*background, barRect, 5, 556, false));
 
 
-	title = new CLabel(399, 12, FONT_MEDIUM, CENTER, Colors::Cornsilk, CGI->buildh->buildings[town->subID][town->hallLevel()+EBuilding::VILLAGE_HALL]->Name());
+	title = new CLabel(399, 12, FONT_MEDIUM, CENTER, Colors::Cornsilk, town->town->buildings[town->hallLevel()+EBuilding::VILLAGE_HALL]->Name());
 	exit = new CAdventureMapButton(CGI->generaltexth->hcommands[8], "", 
 	exit = new CAdventureMapButton(CGI->generaltexth->hcommands[8], "", 
 	           boost::bind(&CHallInterface::close,this), 748, 556, "TPMAGE1.DEF", SDLK_RETURN);
 	           boost::bind(&CHallInterface::close,this), 748, 556, "TPMAGE1.DEF", SDLK_RETURN);
 	exit->assignedKeys.insert(SDLK_ESCAPE);
 	exit->assignedKeys.insert(SDLK_ESCAPE);
 
 
-	const std::vector< std::vector< std::vector<int> > > &boxList = CGI->buildh->hall[town->subID].second;
+	auto & boxList = town->town->clientInfo.hallSlots;
 	boxes.resize(boxList.size());
 	boxes.resize(boxList.size());
 	for(size_t row=0; row<boxList.size(); row++) //for each row
 	for(size_t row=0; row<boxList.size(); row++) //for each row
 	{
 	{
@@ -1356,7 +1353,7 @@ CHallInterface::CHallInterface(const CGTownInstance *Town):
 			for(size_t item=0; item<boxList[row][col].size(); item++)//we are looking for the first not build structure
 			for(size_t item=0; item<boxList[row][col].size(); item++)//we are looking for the first not build structure
 			{
 			{
 				int buildingID = boxList[row][col][item];
 				int buildingID = boxList[row][col][item];
-				building = CGI->buildh->buildings[town->subID][buildingID];
+				building = town->town->buildings[buildingID];
 
 
 				if (buildingID == 18 || buildingID == 24)
 				if (buildingID == 18 || buildingID == 24)
 				{
 				{
@@ -1407,7 +1404,7 @@ std::string CBuildWindow::getTextForState(int state)
 			{
 			{
 				if (vstd::contains(town->builtBuildings, *i))
 				if (vstd::contains(town->builtBuildings, *i))
 					continue;//skipping constructed buildings
 					continue;//skipping constructed buildings
-				ret+= CGI->buildh->buildings[town->subID][*i]->Name() + ", ";
+				ret+= town->town->buildings[*i]->Name() + ", ";
 			}
 			}
 			ret.erase(ret.size()-2);
 			ret.erase(ret.size()-2);
 		}
 		}
@@ -1479,7 +1476,7 @@ CFortScreen::CFortScreen(const CGTownInstance * town):
 	if (fortSize > GameConstants::CREATURES_PER_TOWN && town->creatures.back().second.empty())
 	if (fortSize > GameConstants::CREATURES_PER_TOWN && town->creatures.back().second.empty())
 		fortSize--;
 		fortSize--;
 	
 	
-	const CBuilding *fortBuilding = CGI->buildh->buildings[town->subID][town->fortLevel()+6];
+	const CBuilding *fortBuilding = town->town->buildings[town->fortLevel()+6];
 	title = new CLabel(400, 12, FONT_BIG, CENTER, Colors::Cornsilk, fortBuilding->Name());
 	title = new CLabel(400, 12, FONT_BIG, CENTER, Colors::Cornsilk, fortBuilding->Name());
 	
 	
 	std::string text = boost::str(boost::format(CGI->generaltexth->fcommands[6]) % fortBuilding->Name());
 	std::string text = boost::str(boost::format(CGI->generaltexth->fcommands[6]) % fortBuilding->Name());
@@ -1610,7 +1607,7 @@ CFortScreen::RecruitArea::RecruitArea(int posX, int posY, const CGTownInstance *
 	values.push_back(new LabeledValue(sizes, CGI->generaltexth->allTexts[194], CGI->generaltexth->fcommands[5], town->creatureGrowth(level)));
 	values.push_back(new LabeledValue(sizes, CGI->generaltexth->allTexts[194], CGI->generaltexth->fcommands[5], town->creatureGrowth(level)));
 
 
 	creatureName = new CLabel(78,  11, FONT_SMALL, CENTER, Colors::Cornsilk, creature->namePl);
 	creatureName = new CLabel(78,  11, FONT_SMALL, CENTER, Colors::Cornsilk, creature->namePl);
-	dwellingName = new CLabel(78, 101, FONT_SMALL, CENTER, Colors::Cornsilk, CGI->buildh->buildings[town->subID][buildingID]->Name());
+	dwellingName = new CLabel(78, 101, FONT_SMALL, CENTER, Colors::Cornsilk, town->town->buildings[buildingID]->Name());
 
 
 	if (vstd::contains(town->builtBuildings, buildingID))
 	if (vstd::contains(town->builtBuildings, buildingID))
 	{
 	{

+ 4 - 4
client/CCastleInterface.h

@@ -17,7 +17,7 @@ class CResDataBar;
 class CSpell;
 class CSpell;
 class CTextBox;
 class CTextBox;
 class CTownList;
 class CTownList;
-struct Structure;
+struct CStructure;
 class CGHeroInstance;
 class CGHeroInstance;
 class CGarrisonInt;
 class CGarrisonInt;
 class CCreature;
 class CCreature;
@@ -39,13 +39,13 @@ class CBuildingRect : public CShowableAnim
 public:
 public:
 	CCastleBuildings * parent;
 	CCastleBuildings * parent;
 	const CGTownInstance * town;
 	const CGTownInstance * town;
-	const Structure* str;
+	const CStructure* str;
 	SDL_Surface* border;
 	SDL_Surface* border;
 	SDL_Surface* area;
 	SDL_Surface* area;
 	
 	
 	ui32 stateCounter;//For building construction - current stage in animation
 	ui32 stateCounter;//For building construction - current stage in animation
 	
 	
-	CBuildingRect(CCastleBuildings * Par, const CGTownInstance *Town, const Structure *Str); //c-tor
+	CBuildingRect(CCastleBuildings * Par, const CGTownInstance *Town, const CStructure *Str); //c-tor
 	~CBuildingRect(); //d-tor
 	~CBuildingRect(); //d-tor
 	bool operator<(const CBuildingRect & p2) const;
 	bool operator<(const CBuildingRect & p2) const;
 	void hover(bool on);
 	void hover(bool on);
@@ -115,7 +115,7 @@ class CCastleBuildings : public CIntObject
 {
 {
 	CPicture *background;
 	CPicture *background;
 	//List of buildings for each group
 	//List of buildings for each group
-	std::map< int, std::vector<const Structure*> > groups;
+	std::map< int, std::vector<const CStructure*> > groups;
 	//Vector with all blittable buildings
 	//Vector with all blittable buildings
 	std::vector<CBuildingRect*> buildings;
 	std::vector<CBuildingRect*> buildings;
 
 

+ 0 - 1
client/CGameInfo.cpp

@@ -32,5 +32,4 @@ void CGameInfo::setFromLib()
 	objh = VLC->objh;
 	objh = VLC->objh;
 	spellh = VLC->spellh;
 	spellh = VLC->spellh;
 	dobjinfo = VLC->dobjinfo;
 	dobjinfo = VLC->dobjinfo;
-	buildh = VLC->buildh;
 }
 }

+ 0 - 1
client/CGameInfo.h

@@ -61,7 +61,6 @@ public:
 	ConstTransitivePtr<CDefObjInfoHandler> dobjinfo;
 	ConstTransitivePtr<CDefObjInfoHandler> dobjinfo;
 	CGeneralTextHandler * generaltexth;
 	CGeneralTextHandler * generaltexth;
 	CMapHandler * mh;
 	CMapHandler * mh;
-	ConstTransitivePtr<CBuildingHandler> buildh;
 	CTownHandler * townh;
 	CTownHandler * townh;
 	//CTownHandler * townh;
 	//CTownHandler * townh;
 
 

+ 2 - 3
client/CPreGame.cpp

@@ -3067,9 +3067,8 @@ void CBonusSelection::updateBonusSelection()
 					picName = graphics->ERMUtoPicture[faction][buildID];
 					picName = graphics->ERMUtoPicture[faction][buildID];
 					picNumber = -1;
 					picNumber = -1;
 
 
-					tlog1<<CGI->buildh->buildings.size()<<"\t"<<faction<<"\t"<<CGI->buildh->buildings[faction].size()<<"\t"<<buildID<<"\n";
-					if (vstd::contains(CGI->buildh->buildings[faction], buildID))
-						desc = CGI->buildh->buildings[faction].find(buildID)->second->Description();
+					if (vstd::contains(CGI->townh->towns[faction].buildings, buildID))
+						desc = CGI->townh->towns[faction].buildings.find(buildID)->second->Description();
 				}
 				}
 				break;
 				break;
 			case 3: //artifact
 			case 3: //artifact

+ 5 - 5
client/GUIClasses.cpp

@@ -904,7 +904,7 @@ std::string CComponent::getDescription()
 	case spell:      return CGI->spellh->spells[subtype]->descriptions[val];
 	case spell:      return CGI->spellh->spells[subtype]->descriptions[val];
 	case morale:     return CGI->generaltexth->heroscrn[ 4 - (val>0) + (val<0)];
 	case morale:     return CGI->generaltexth->heroscrn[ 4 - (val>0) + (val<0)];
 	case luck:       return CGI->generaltexth->heroscrn[ 7 - (val>0) + (val<0)];
 	case luck:       return CGI->generaltexth->heroscrn[ 7 - (val>0) + (val<0)];
-	case building:   return CGI->buildh->buildings[subtype][val]->Description();
+	case building:   return CGI->townh->towns[subtype].buildings[val]->Description();
 	case hero:       return CGI->heroh->heroes[subtype]->name;
 	case hero:       return CGI->heroh->heroes[subtype]->name;
 	case flag:       return "";
 	case flag:       return "";
 	}
 	}
@@ -936,7 +936,7 @@ std::string CComponent::getSubtitleInternal()
 	case spell:      return CGI->spellh->spells[subtype]->name;
 	case spell:      return CGI->spellh->spells[subtype]->name;
 	case morale:     return "";
 	case morale:     return "";
 	case luck:       return "";
 	case luck:       return "";
-	case building:   return CGI->buildh->buildings[subtype][val]->Name();
+	case building:   return CGI->townh->towns[subtype].buildings[val]->Name();
 	case hero:       return CGI->heroh->heroes[subtype]->name;
 	case hero:       return CGI->heroh->heroes[subtype]->name;
 	case flag:       return CGI->generaltexth->capColors[subtype];
 	case flag:       return CGI->generaltexth->capColors[subtype];
 	}
 	}
@@ -2437,9 +2437,9 @@ CMarketplaceWindow::CMarketplaceWindow(const IMarket *Market, const CGHeroInstan
 	{
 	{
 		switch (mode)
 		switch (mode)
 		{
 		{
-		break; case EMarketMode::CREATURE_RESOURCE: title = CGI->buildh->buildings[6][21]->Name();
-		break; case EMarketMode::RESOURCE_ARTIFACT: title = CGI->buildh->buildings[market->o->subID][17]->Name();
-		break; case EMarketMode::ARTIFACT_RESOURCE: title = CGI->buildh->buildings[market->o->subID][17]->Name();
+		break; case EMarketMode::CREATURE_RESOURCE: title = CGI->townh->towns[6].buildings[21]->Name();
+		break; case EMarketMode::RESOURCE_ARTIFACT: title = CGI->townh->towns[market->o->subID].buildings[17]->Name();
+		break; case EMarketMode::ARTIFACT_RESOURCE: title = CGI->townh->towns[market->o->subID].buildings[17]->Name();
 		break; default: title = CGI->generaltexth->allTexts[158];
 		break; default: title = CGI->generaltexth->allTexts[158];
 		}
 		}
 	}
 	}

+ 320 - 209
config/buildings.json

@@ -1,95 +1,9 @@
-// Town properties, ordered by city type (0 to 8)
-
-//  defnames: Buildings coordinates inside a city
-//  blit_order: Buildings not mentioned in the file will be blitted first.
-//              Then buildings in the list will be drawn in that order.
-//  creatures_basic: ids of the basic creatures in each dwelling, ordered by level. 8th is WoG and is ignored.
-//  creatures_upgraded: ids of the upgraded creatures in each dwelling, ordered by level
-//  horde: horde building creature levels (-1 if not present)
-//  mage_guild: maximum level of the mage guild
-//  primary_resource: (1,3,4,5 for rares and 127 for wood+ore)
-//  war_machine: type of war machine that this city can build
-
 {
 {
-	"schema" :
-	{
-		"town_type" :
-		{
-			"type" : "array",
-			"items" :
-			{
-				"type" : "object",
-				"properties" :
-				{
-					"blit_order" :        { "type" : "array", "items" : {"type":"number"}, "default" :[] },
-					"creatures"  :  { "type" : "array", "items" : { "type" : "array", "items" : {"type":"number"} } },
-					"horde" :             { "type" : "array", "items" : {"type":"number", "default" : -1} },
-					"primary_resource" :  { "type" : "number", "default" : 127},
-					"mage_guild" :        { "type" : "number", "default" : 5},
-					"war_machine" :       { "type" : "number"},
-					"defnames" :
-					{
-						"type" : "array",
-						"items" :
-						{
-							"type" : "object",
-							"properties" :
-							{
-								"id" :      { "type" : "number" },
-								"x" :       { "type" : "number" },
-								"y" :       { "type" : "number" },
-								"defname" : { "type" : "string" },
-								"border" :  { "type" : "string", "default" : ""},
-								"area" :    { "type" : "string", "default" : ""}
-							}
-						}
-					},
-					"building_requirements" :
-					{
-						"type" : "array",
-						"items" :
-						{
-							"type" : "object",
-							"properties" :
-							{
-								"id" :
-								{
-									"type" : "number"
-								},
-								"requires" :
-								{
-									"type" : "array",
-									"items" : {"type":"number"}
-								}
-							}
-						}
-					}
-				}
-			}
-		},
-		"town_groups" :
-		{
-			"type" : "array",
-			"items" :
-			{
-				"type" : "object",
-				"properties" :
-				{
-					"id" : { "type" : "number" },
-					"groups" :
-					{
-						"type" : "array",
-						"items" : { "type" : "array", "items" : {"type":"number"}, }
-					}
-				}
-			}
-		}
-	},
-	"town_type" :
+	"towns" :
 	[
 	[
 		{
 		{
 			// 0 - Castle
 			// 0 - Castle
-			"defnames" :
+			"structures" :
 			[
 			[
 				{ "id" : 16, "defname" : "TBCSBLAK.def", "x" : 213, "y" : 251, "border" : "TOCSBLAK.bmp", "area" : "TZCSBLAK.bmp" },
 				{ "id" : 16, "defname" : "TBCSBLAK.def", "x" : 213, "y" : 251, "border" : "TOCSBLAK.bmp", "area" : "TZCSBLAK.bmp" },
 				{ "id" : 8,  "defname" : "TBCSCAS2.def", "x" : 478, "y" : 66,  "border" : "TOCSCAS2.bmp", "area" : "TZCSCAS2.bmp" },
 				{ "id" : 8,  "defname" : "TBCSCAS2.def", "x" : 478, "y" : 66,  "border" : "TOCSCAS2.bmp", "area" : "TZCSCAS2.bmp" },
@@ -130,30 +44,63 @@
 				{ "id" : 43, "defname" : "TBCSUP_6.def", "x" : 303, "y" : 0,   "border" : "TOCSANG2.bmp", "area" : "TZCSANG2.bmp" },
 				{ "id" : 43, "defname" : "TBCSUP_6.def", "x" : 303, "y" : 0,   "border" : "TOCSANG2.bmp", "area" : "TZCSANG2.bmp" },
 				{ "id" : 20, "defname" : "TBCSBOAT.def", "x" : 478, "y" : 134, "border" : "TOCSDKMN.bmp", "area" : "TZCSDKMN.bmp" }
 				{ "id" : 20, "defname" : "TBCSBOAT.def", "x" : 478, "y" : 134, "border" : "TOCSDKMN.bmp", "area" : "TZCSDKMN.bmp" }
 			],
 			],
+			"groups" :
+			[
+				[ 0, 1, 2, 3, 4 ],
+				[ 6, 20 ],
+				[ 7, 8, 9 ],
+				[ 10, 11, 12, 13 ],
+				[ 30, 37 ],
+				[ 31, 38 ],
+				[ 32, 39, 18, 19 ],
+				[ 33, 40 ],
+				[ 34, 41 ],
+				[ 35, 42 ],
+				[ 36, 43 ]
+			],
+			"hallBackground": "TPTHBKCS.BMP",
+			"hallSlots":
+			[
+				[ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5, 22 ], [ 16 ] ],
+				[ [ 14, 15 ], [ 0, 1, 2, 3 ], [ 6, 17 ] ],
+				[ [ 21 ], [ 18, 19 ] ],
+				[ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ],
+				[ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ]
+			],
+
 			"blit_order" : [ 0, 1, 2, 3, 10, 11, 12, 13, 5, 22, 30, 37, 16, 6, 20, 18, 19, 34, 41 ],
 			"blit_order" : [ 0, 1, 2, 3, 10, 11, 12, 13, 5, 22, 30, 37, 16, 6, 20, 18, 19, 34, 41 ],
 			"creatures" : [ [0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10, 11], [12, 13] ],
 			"creatures" : [ [0, 1], [2, 3], [4, 5], [6, 7], [8, 9], [10, 11], [12, 13] ],
-			"horde" : [ 2, null ],
+			"horde" : [ 2, -1 ],
+			"primary_resource" : 127,
 			"mage_guild" : 4,
 			"mage_guild" : 4,
 			"war_machine" : 4,
 			"war_machine" : 4,
 
 
-			"building_requirements" :
+			"buildings" :
 			[
 			[
+				{ "id" : 0 },
 				{ "id" : 1,  "requires" : [ 0 ] },
 				{ "id" : 1,  "requires" : [ 0 ] },
 				{ "id" : 2,  "requires" : [ 1 ] },
 				{ "id" : 2,  "requires" : [ 1 ] },
 				{ "id" : 3,  "requires" : [ 2 ] },
 				{ "id" : 3,  "requires" : [ 2 ] },
 				{ "id" : 4,  "requires" : [ 3 ] },
 				{ "id" : 4,  "requires" : [ 3 ] },
+				{ "id" : 5 },
+				{ "id" : 6 },
+				{ "id" : 7 },
 				{ "id" : 8,  "requires" : [ 7 ] },
 				{ "id" : 8,  "requires" : [ 7 ] },
 				{ "id" : 9,  "requires" : [ 8 ] },
 				{ "id" : 9,  "requires" : [ 8 ] },
+				{ "id" : 10 },
 				{ "id" : 11, "requires" : [ 10, 5 ] },
 				{ "id" : 11, "requires" : [ 10, 5 ] },
 				{ "id" : 12, "requires" : [ 11, 0, 14, 16 ] },
 				{ "id" : 12, "requires" : [ 11, 0, 14, 16 ] },
 				{ "id" : 13, "requires" : [ 12, 9 ] },
 				{ "id" : 13, "requires" : [ 12, 9 ] },
+				{ "id" : 14 },
 				{ "id" : 15, "requires" : [ 14 ] },
 				{ "id" : 15, "requires" : [ 14 ] },
+				{ "id" : 16 },
 				{ "id" : 17, "requires" : [ 6 ] },
 				{ "id" : 17, "requires" : [ 6 ] },
 				{ "id" : 18, "requires" : [ 32 ] },
 				{ "id" : 18, "requires" : [ 32 ] },
 				{ "id" : 19, "requires" : [ 39 ] },
 				{ "id" : 19, "requires" : [ 39 ] },
-				{ "id" : 20, "requires" : [ 6 ] },
+				{ "id" : 20 },
 				{ "id" : 21, "requires" : [ 33 ] },
 				{ "id" : 21, "requires" : [ 33 ] },
 				{ "id" : 22, "requires" : [ 5 ] },
 				{ "id" : 22, "requires" : [ 5 ] },
+				{ "id" : 26 },
 				{ "id" : 30, "requires" : [ 7 ] },
 				{ "id" : 30, "requires" : [ 7 ] },
 				{ "id" : 31, "requires" : [ 30 ] },
 				{ "id" : 31, "requires" : [ 30 ] },
 				{ "id" : 32, "requires" : [ 33 ] },
 				{ "id" : 32, "requires" : [ 33 ] },
@@ -173,7 +120,7 @@
 
 
 		{
 		{
 			// 1 - Rampart
 			// 1 - Rampart
-			"defnames" :
+			"structures" :
 			[
 			[
 				{ "id" : 16, "defname" : "TBRMBLAK.def", "x" : 558, "y" : 105, "border" : "TORAID.bmp",   "area" : "TZRAID.bmp" },
 				{ "id" : 16, "defname" : "TBRMBLAK.def", "x" : 558, "y" : 105, "border" : "TORAID.bmp",   "area" : "TZRAID.bmp" },
 				{ "id" : 9,  "defname" : "TBRMCAS3.def", "x" : 79,  "y" : 18,  "border" : "TORCAS2.bmp",  "area" : "TZRCAS2.bmp" },
 				{ "id" : 9,  "defname" : "TBRMCAS3.def", "x" : 79,  "y" : 18,  "border" : "TORCAS2.bmp",  "area" : "TZRCAS2.bmp" },
@@ -218,6 +165,30 @@
 				{ "id" : 12, "defname" : "TBRMHAL3.def", "x" : 538, "y" : 187, "border" : "TORHAL3.bmp",  "area" : "TZRHAL3.bmp" },
 				{ "id" : 12, "defname" : "TBRMHAL3.def", "x" : 538, "y" : 187, "border" : "TORHAL3.bmp",  "area" : "TZRHAL3.bmp" },
 				{ "id" : 11, "defname" : "TBRMHAL2.def", "x" : 538, "y" : 187, "border" : "TORHAL2.bmp",  "area" : "TZRHAL2.bmp" }
 				{ "id" : 11, "defname" : "TBRMHAL2.def", "x" : 538, "y" : 187, "border" : "TORHAL2.bmp",  "area" : "TZRHAL2.bmp" }
 			],
 			],
+			"groups" :
+			[
+				[ 0, 1, 2, 3, 4 ],
+				[ 6, 20 ],
+				[ 7, 8, 9 ],
+				[ 10, 11, 12, 13 ],
+				[ 30, 37 ],
+				[ 32, 39 ],
+				[ 33, 40 ],
+				[ 35, 42 ],
+				[ 36, 43 ],
+				[ 24, 25, 34, 41 ],
+				[ 17, 21 ],
+				[ 31, 18, 38, 19 ]
+			],
+			"hallBackground": "TPTHBKRM.BMP",
+			"hallSlots":
+			[
+				[ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ],
+				[ [ 14, 15 ], [ 0, 1, 2, 3, 4 ], [ 17, 21 ] ],
+				[ [ 22 ], [ 24, 25 ], [ 18, 19 ] ],
+				[ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ],
+				[ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ]
+			],
 			"blit_order" : [ 33, 40, 35, 42, 16, 32, 39, 0, 1, 2, 3, 4, 31, 18, 38, 19, 34, 24, 41, 25, 5, 30, 37, 14, 10, 11, 12, 13, 17, 21, 22, -1, 27, 28, 29, 15 ],
 			"blit_order" : [ 33, 40, 35, 42, 16, 32, 39, 0, 1, 2, 3, 4, 31, 18, 38, 19, 34, 24, 41, 25, 5, 30, 37, 14, 10, 11, 12, 13, 17, 21, 22, -1, 27, 28, 29, 15 ],
 			"creatures" : [ [14, 15], [16, 17], [18, 19], [20, 21], [22, 23], [24, 25], [26, 27] ],
 			"creatures" : [ [14, 15], [16, 17], [18, 19], [20, 21], [22, 23], [24, 25], [26, 27] ],
 			"horde" : [ 1, 4 ],
 			"horde" : [ 1, 4 ],
@@ -225,24 +196,32 @@
 			"primary_resource" : 4,
 			"primary_resource" : 4,
 			"war_machine" : 6,
 			"war_machine" : 6,
 
 
-			"building_requirements" :
+			"buildings" :
 			[
 			[
+				{ "id" : 0 },
 				{ "id" : 1,  "requires" : [ 0 ] },
 				{ "id" : 1,  "requires" : [ 0 ] },
 				{ "id" : 2,  "requires" : [ 1 ] },
 				{ "id" : 2,  "requires" : [ 1 ] },
 				{ "id" : 3,  "requires" : [ 2 ] },
 				{ "id" : 3,  "requires" : [ 2 ] },
 				{ "id" : 4,  "requires" : [ 3 ] },
 				{ "id" : 4,  "requires" : [ 3 ] },
+				{ "id" : 5 },
+				{ "id" : 7 },
 				{ "id" : 8,  "requires" : [ 7 ] },
 				{ "id" : 8,  "requires" : [ 7 ] },
 				{ "id" : 9,  "requires" : [ 8 ] },
 				{ "id" : 9,  "requires" : [ 8 ] },
+				{ "id" : 10 },
 				{ "id" : 11, "requires" : [ 10, 5 ] },
 				{ "id" : 11, "requires" : [ 10, 5 ] },
 				{ "id" : 12, "requires" : [ 11, 0, 14, 16 ] },
 				{ "id" : 12, "requires" : [ 11, 0, 14, 16 ] },
 				{ "id" : 13, "requires" : [ 12, 9 ] },
 				{ "id" : 13, "requires" : [ 12, 9 ] },
+				{ "id" : 14 },
 				{ "id" : 15, "requires" : [ 14 ] },
 				{ "id" : 15, "requires" : [ 14 ] },
+				{ "id" : 16 },
+				{ "id" : 17 },
 				{ "id" : 18, "requires" : [ 31 ] },
 				{ "id" : 18, "requires" : [ 31 ] },
 				{ "id" : 19, "requires" : [ 38 ] },
 				{ "id" : 19, "requires" : [ 38 ] },
 				{ "id" : 21, "requires" : [ 17 ] },
 				{ "id" : 21, "requires" : [ 17 ] },
 				{ "id" : 22, "requires" : [ 18 ] },
 				{ "id" : 22, "requires" : [ 18 ] },
 				{ "id" : 24, "requires" : [ 34 ] },
 				{ "id" : 24, "requires" : [ 34 ] },
 				{ "id" : 25, "requires" : [ 41 ] },
 				{ "id" : 25, "requires" : [ 41 ] },
+				{ "id" : 26 },
 				{ "id" : 30, "requires" : [ 7 ] },
 				{ "id" : 30, "requires" : [ 7 ] },
 				{ "id" : 31, "requires" : [ 30 ] },
 				{ "id" : 31, "requires" : [ 30 ] },
 				{ "id" : 32, "requires" : [ 30 ] },
 				{ "id" : 32, "requires" : [ 30 ] },
@@ -262,7 +241,7 @@
 
 
 		{
 		{
 			// 2 - Tower
 			// 2 - Tower
-			"defnames" :
+			"structures" :
 			[
 			[
 				{ "id" : 16, "defname" : "TBTWBLAK.def", "x" : 478, "y" : 211, "border" : "TOTBLKA.bmp",  "area" : "TZTBLKA.bmp" },
 				{ "id" : 16, "defname" : "TBTWBLAK.def", "x" : 478, "y" : 211, "border" : "TOTBLKA.bmp",  "area" : "TZTBLKA.bmp" },
 				{ "id" : 9,  "defname" : "TBTWCAS3.def", "x" : 301, "y" : 0,   "border" : "TOTCAS3.bmp",  "area" : "TZTCAS3.bmp" },
 				{ "id" : 9,  "defname" : "TBTWCAS3.def", "x" : 301, "y" : 0,   "border" : "TOTCAS3.bmp",  "area" : "TZTCAS3.bmp" },
@@ -302,30 +281,61 @@
 				{ "id" : 43, "defname" : "TBTWUP_6.def", "x" : 75,  "y" : 91,  "border" : "TOTTIT2.bmp",  "area" : "TZTTIT2.bmp" },
 				{ "id" : 43, "defname" : "TBTWUP_6.def", "x" : 75,  "y" : 91,  "border" : "TOTTIT2.bmp",  "area" : "TZTTIT2.bmp" },
 				{ "id" : 8,  "defname" : "TBTWCAS2.def", "x" : 301, "y" : 0,   "border" : "TOTCAS2.bmp",  "area" : "TZTCAS2.bmp" }
 				{ "id" : 8,  "defname" : "TBTWCAS2.def", "x" : 301, "y" : 0,   "border" : "TOTCAS2.bmp",  "area" : "TZTCAS2.bmp" }
 			],
 			],
+			"groups" :
+			[
+				[ 0, 1, 2, 3, 4 ],
+				[ 6, 20 ],
+				[ 7, 8, 9 ],
+				[ 10, 11, 12, 13 ],
+				[ 30, 37 ],
+				[ 32, 39 ],
+				[ 33, 40 ],
+				[ 34, 41 ],
+				[ 35, 42 ],
+				[ 36, 43 ],
+				[ 18, 19, 31, 38 ]
+			],
+			"hallBackground": "TPTHBKTW.BMP",
+			"hallSlots":
+			[
+				[ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ],
+				[ [ 14, 15 ], [ 0, 1, 2, 3, 4 ], [ 22 ], [ 23 ] ],
+				[ [ 17 ], [ 21 ], [ 18, 19 ] ],
+				[ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ],
+				[ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ]
+			],
 			"blit_order" : [ 36, 43, 32, 39, 10, 11, 12, 13, 32, 35, 42, 15, 5, 18, 19 ],
 			"blit_order" : [ 36, 43, 32, 39, 10, 11, 12, 13, 32, 35, 42, 15, 5, 18, 19 ],
 			"creatures" : [ [28, 29], [30, 31], [32, 33], [34, 35], [36, 37], [38, 39], [40, 41] ],
 			"creatures" : [ [28, 29], [30, 31], [32, 33], [34, 35], [36, 37], [38, 39], [40, 41] ],
-			"horde" : [ 1, null ],
+			"horde" : [ 1, -1 ],
 			"primary_resource" : 5,
 			"primary_resource" : 5,
+			"mage_guild" : 5,
 			"war_machine" : 5,
 			"war_machine" : 5,
 
 
-			"building_requirements" :
+			"buildings" :
 			[
 			[
+				{ "id" : 0 },
 				{ "id" : 1,  "requires" : [ 0 ] },
 				{ "id" : 1,  "requires" : [ 0 ] },
 				{ "id" : 2,  "requires" : [ 1 ] },
 				{ "id" : 2,  "requires" : [ 1 ] },
 				{ "id" : 3,  "requires" : [ 2 ] },
 				{ "id" : 3,  "requires" : [ 2 ] },
 				{ "id" : 4,  "requires" : [ 3 ] },
 				{ "id" : 4,  "requires" : [ 3 ] },
+				{ "id" : 5 },
+				{ "id" : 7 },
 				{ "id" : 8,  "requires" : [ 7 ] },
 				{ "id" : 8,  "requires" : [ 7 ] },
 				{ "id" : 9,  "requires" : [ 8 ] },
 				{ "id" : 9,  "requires" : [ 8 ] },
+				{ "id" : 10 },
 				{ "id" : 11, "requires" : [ 10, 5 ] },
 				{ "id" : 11, "requires" : [ 10, 5 ] },
 				{ "id" : 12, "requires" : [ 11, 0, 14, 16 ] },
 				{ "id" : 12, "requires" : [ 11, 0, 14, 16 ] },
 				{ "id" : 13, "requires" : [ 12, 9 ] },
 				{ "id" : 13, "requires" : [ 12, 9 ] },
+				{ "id" : 14 },
 				{ "id" : 15, "requires" : [ 14 ] },
 				{ "id" : 15, "requires" : [ 14 ] },
+				{ "id" : 16 },
 				{ "id" : 17, "requires" : [ 14 ] },
 				{ "id" : 17, "requires" : [ 14 ] },
 				{ "id" : 18, "requires" : [ 31 ] },
 				{ "id" : 18, "requires" : [ 31 ] },
 				{ "id" : 19, "requires" : [ 38 ] },
 				{ "id" : 19, "requires" : [ 38 ] },
 				{ "id" : 21, "requires" : [ 7 ] },
 				{ "id" : 21, "requires" : [ 7 ] },
 				{ "id" : 22, "requires" : [ 0 ] },
 				{ "id" : 22, "requires" : [ 0 ] },
 				{ "id" : 23, "requires" : [ 0 ] },
 				{ "id" : 23, "requires" : [ 0 ] },
+				{ "id" : 26 },
 				{ "id" : 30, "requires" : [ 7 ] },
 				{ "id" : 30, "requires" : [ 7 ] },
 				{ "id" : 31, "requires" : [ 30 ] },
 				{ "id" : 31, "requires" : [ 30 ] },
 				{ "id" : 32, "requires" : [ 30 ] },
 				{ "id" : 32, "requires" : [ 30 ] },
@@ -345,7 +355,7 @@
 
 
 		{
 		{
 			// 3 - Inferno
 			// 3 - Inferno
-			"defnames" :
+			"structures" :
 			[
 			[
 				{ "id" : 16, "defname" : "TBINBLAK.def", "x" : 684, "y" : 253, "border" : "TOIBLKA.bmp",  "area" : "TZIBLKA.bmp" },
 				{ "id" : 16, "defname" : "TBINBLAK.def", "x" : 684, "y" : 253, "border" : "TOIBLKA.bmp",  "area" : "TZIBLKA.bmp" },
 				{ "id" : 9,  "defname" : "TBINCAS3.def", "x" : 222, "y" : 18,  "border" : "TOICAS3A.bmp", "area" : "TZICAS3A.bmp" },
 				{ "id" : 9,  "defname" : "TBINCAS3.def", "x" : 222, "y" : 18,  "border" : "TOICAS3A.bmp", "area" : "TZICAS3A.bmp" },
@@ -386,24 +396,55 @@
 				{ "id" : 43, "defname" : "TBINUP_6.def", "x" : 420, "y" : 105, "border" : "TOIDVL2.bmp",  "area" : "TZIDVL2.bmp" },
 				{ "id" : 43, "defname" : "TBINUP_6.def", "x" : 420, "y" : 105, "border" : "TOIDVL2.bmp",  "area" : "TZIDVL2.bmp" },
 				{ "id" : 8,  "defname" : "TBINCAS2.def", "x" : 222, "y" : 44,  "border" : "TOICAS1A.bmp", "area" : "TZICAS1A.bmp" }
 				{ "id" : 8,  "defname" : "TBINCAS2.def", "x" : 222, "y" : 44,  "border" : "TOICAS1A.bmp", "area" : "TZICAS1A.bmp" }
 			],
 			],
+			"groups" :
+			[
+				[ 0, 1, 2, 3, 4 ],
+				[ 6, 20 ],
+				[ 7, 8, 9 ],
+				[ 10, 11, 12, 13 ],
+				[ 30, 37 ],
+				[ 31, 38 ],
+				[ 33, 40 ],
+				[ 34, 41 ],
+				[ 35, 42 ],
+				[ 36, 43 ],
+				[ 18, 19, 30, 37 ],
+				[ 32, 39, 24, 25 ]
+			],
+			"hallBackground": "TPTHBKIN.BMP",
+			"hallSlots":
+			[
+				[ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ],
+				[ [ 14, 15 ], [ 0, 1, 2, 3, 4 ], [ 23 ], [ 21 ] ],
+				[ [ 22 ], [ 18, 19 ], [ 24, 25 ] ],
+				[ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ],
+				[ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ]
+			],
 			"blit_order" : [ 26, 21, 7, 8, 9, 22, 31, 38, 36, 43, 10, 11, 12, 13, 5, 32, 39, 24, 25, 33, 40, 34, 41, 30, 37, 18, 19, 14, 15, 16, 35, 42 ],
 			"blit_order" : [ 26, 21, 7, 8, 9, 22, 31, 38, 36, 43, 10, 11, 12, 13, 5, 32, 39, 24, 25, 33, 40, 34, 41, 30, 37, 18, 19, 14, 15, 16, 35, 42 ],
 			"creatures" : [ [42, 43], [44, 45], [46, 47], [48, 49], [50, 51], [52, 53], [54, 55] ],
 			"creatures" : [ [42, 43], [44, 45], [46, 47], [48, 49], [50, 51], [52, 53], [54, 55] ],
 			"horde" : [ 0, 2 ],
 			"horde" : [ 0, 2 ],
+			"mage_guild" : 5,
 			"primary_resource" : 1,
 			"primary_resource" : 1,
 			"war_machine" : 5,
 			"war_machine" : 5,
 
 
-			"building_requirements" :
+			"buildings" :
 			[
 			[
+				{ "id" : 0 },
 				{ "id" : 1,  "requires" : [ 0 ] },
 				{ "id" : 1,  "requires" : [ 0 ] },
 				{ "id" : 2,  "requires" : [ 1 ] },
 				{ "id" : 2,  "requires" : [ 1 ] },
 				{ "id" : 3,  "requires" : [ 2 ] },
 				{ "id" : 3,  "requires" : [ 2 ] },
 				{ "id" : 4,  "requires" : [ 3 ] },
 				{ "id" : 4,  "requires" : [ 3 ] },
+				{ "id" : 5 },
+				{ "id" : 7 },
 				{ "id" : 8,  "requires" : [ 7 ] },
 				{ "id" : 8,  "requires" : [ 7 ] },
 				{ "id" : 9,  "requires" : [ 8 ] },
 				{ "id" : 9,  "requires" : [ 8 ] },
+				{ "id" : 10 },
 				{ "id" : 11, "requires" : [ 10, 5 ] },
 				{ "id" : 11, "requires" : [ 10, 5 ] },
 				{ "id" : 12, "requires" : [ 11, 0, 14, 16 ] },
 				{ "id" : 12, "requires" : [ 11, 0, 14, 16 ] },
 				{ "id" : 13, "requires" : [ 12, 9 ] },
 				{ "id" : 13, "requires" : [ 12, 9 ] },
+				{ "id" : 14 },
 				{ "id" : 15, "requires" : [ 14 ] },
 				{ "id" : 15, "requires" : [ 14 ] },
+				{ "id" : 16 },
 				{ "id" : 18, "requires" : [ 30 ] },
 				{ "id" : 18, "requires" : [ 30 ] },
 				{ "id" : 19, "requires" : [ 37 ] },
 				{ "id" : 19, "requires" : [ 37 ] },
 				{ "id" : 21, "requires" : [ 7 ] },
 				{ "id" : 21, "requires" : [ 7 ] },
@@ -411,6 +452,7 @@
 				{ "id" : 23, "requires" : [ 0 ] },
 				{ "id" : 23, "requires" : [ 0 ] },
 				{ "id" : 24, "requires" : [ 32 ] },
 				{ "id" : 24, "requires" : [ 32 ] },
 				{ "id" : 25, "requires" : [ 39 ] },
 				{ "id" : 25, "requires" : [ 39 ] },
+				{ "id" : 26 },
 				{ "id" : 30, "requires" : [ 7 ] },
 				{ "id" : 30, "requires" : [ 7 ] },
 				{ "id" : 31, "requires" : [ 30 ] },
 				{ "id" : 31, "requires" : [ 30 ] },
 				{ "id" : 32, "requires" : [ 30 ] },
 				{ "id" : 32, "requires" : [ 30 ] },
@@ -430,7 +472,7 @@
 
 
 		{
 		{
 			// 4 - Necropolis
 			// 4 - Necropolis
-			"defnames" :
+			"structures" :
 			[
 			[
 				{ "id" : 16, "defname" : "TBNCBLAK.def", "x" : 382, "y" : 252, "border" : "TONSMITA.bmp", "area" : "TZNSMITA.bmp" },
 				{ "id" : 16, "defname" : "TBNCBLAK.def", "x" : 382, "y" : 252, "border" : "TONSMITA.bmp", "area" : "TZNSMITA.bmp" },
 				{ "id" : 8,  "defname" : "TBNCCAS2.def", "x" : 139, "y" : 66,  "border" : "TONCAS2.bmp",  "area" : "TZNCAS2.bmp" },
 				{ "id" : 8,  "defname" : "TBNCCAS2.def", "x" : 139, "y" : 66,  "border" : "TONCAS2.bmp",  "area" : "TZNCAS2.bmp" },
@@ -475,29 +517,63 @@
 				{ "id" : 43, "defname" : "TBNCUP_6.def", "x" : 662, "y" : 23,  "border" : "TONBON2.bmp",  "area" : "TZNBON2.bmp" },
 				{ "id" : 43, "defname" : "TBNCUP_6.def", "x" : 662, "y" : 23,  "border" : "TONBON2.bmp",  "area" : "TZNBON2.bmp" },
 				{ "id" : 20, "defname" : "TBNCBOAT.def", "x" : 617, "y" : 265, "border" : "TONSHPNA.bmp", "area" : "TZNSHPNA.bmp" }
 				{ "id" : 20, "defname" : "TBNCBOAT.def", "x" : 617, "y" : 265, "border" : "TONSHPNA.bmp", "area" : "TZNSHPNA.bmp" }
 			],
 			],
+			"groups" :
+			[
+				[ 0, 1, 2, 3, 4 ],
+				[ 6, 20 ],
+				[ 7, 8, 9 ],
+				[ 10, 11, 12, 13 ],
+				[ 31, 38 ],
+				[ 32, 39 ],
+				[ 33, 40 ],
+				[ 34, 41 ],
+				[ 35, 42 ],
+				[ 36, 43 ],
+				[ 30, 37, 18, 19 ]
+			],
+			"hallBackground": "TPTHBKNC.BMP",
+			"hallSlots":
+			[
+				[ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ],
+				[ [ 14, 15 ], [ 0, 1, 2, 3, 4 ], [ 21 ], [ 6 ] ],
+				[ [ 17 ], [ 22 ], [ 18, 19 ] ],
+				[ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ],
+				[ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ]
+			],
 			"blit_order" : [ 17, 0, 1, 2, 3, 4, 7, 8, 9, 32, 39, 26, 15, 14, 34, 41, 16, 5, 33, 40, 31, 38, 6, 30, 18, 37, 19, 22, 20 ],
 			"blit_order" : [ 17, 0, 1, 2, 3, 4, 7, 8, 9, 32, 39, 26, 15, 14, 34, 41, 16, 5, 33, 40, 31, 38, 6, 30, 18, 37, 19, 22, 20 ],
 			"creatures" : [ [56, 57], [58, 59], [60, 61], [62, 63], [64, 65], [66, 67], [68, 69] ],
 			"creatures" : [ [56, 57], [58, 59], [60, 61], [62, 63], [64, 65], [66, 67], [68, 69] ],
-			"horde" : [ 0, null ],
+			"horde" : [ 0, -1 ],
+			"mage_guild" : 5,
+			"primary_resource" : 127,
 			"war_machine" : 6,
 			"war_machine" : 6,
+			
 
 
-			"building_requirements" :
+			"buildings" :
 			[
 			[
+				{ "id" : 0 },
 				{ "id" : 1,  "requires" : [ 0 ] },
 				{ "id" : 1,  "requires" : [ 0 ] },
 				{ "id" : 2,  "requires" : [ 1 ] },
 				{ "id" : 2,  "requires" : [ 1 ] },
 				{ "id" : 3,  "requires" : [ 2 ] },
 				{ "id" : 3,  "requires" : [ 2 ] },
 				{ "id" : 4,  "requires" : [ 3 ] },
 				{ "id" : 4,  "requires" : [ 3 ] },
+				{ "id" : 5 },
+				{ "id" : 6 },
+				{ "id" : 7 },
 				{ "id" : 8,  "requires" : [ 7 ] },
 				{ "id" : 8,  "requires" : [ 7 ] },
 				{ "id" : 9,  "requires" : [ 8 ] },
 				{ "id" : 9,  "requires" : [ 8 ] },
+				{ "id" : 10 },
 				{ "id" : 11, "requires" : [ 10, 5 ] },
 				{ "id" : 11, "requires" : [ 10, 5 ] },
 				{ "id" : 12, "requires" : [ 11, 0, 14, 16 ] },
 				{ "id" : 12, "requires" : [ 11, 0, 14, 16 ] },
 				{ "id" : 13, "requires" : [ 12, 9 ] },
 				{ "id" : 13, "requires" : [ 12, 9 ] },
+				{ "id" : 14 },
 				{ "id" : 15, "requires" : [ 14 ] },
 				{ "id" : 15, "requires" : [ 14 ] },
+				{ "id" : 16 },
 				{ "id" : 17, "requires" : [ 7 ] },
 				{ "id" : 17, "requires" : [ 7 ] },
 				{ "id" : 18, "requires" : [ 22, 30 ] },
 				{ "id" : 18, "requires" : [ 22, 30 ] },
 				{ "id" : 19, "requires" : [ 22, 37 ] },
 				{ "id" : 19, "requires" : [ 22, 37 ] },
-				{ "id" : 20, "requires" : [ 6 ] },
+				{ "id" : 20 },
 				{ "id" : 21, "requires" : [ 0 ] },
 				{ "id" : 21, "requires" : [ 0 ] },
 				{ "id" : 22, "requires" : [ 30 ] },
 				{ "id" : 22, "requires" : [ 30 ] },
+				{ "id" : 26 },
 				{ "id" : 30, "requires" : [ 7 ] },
 				{ "id" : 30, "requires" : [ 7 ] },
 				{ "id" : 31, "requires" : [ 30 ] },
 				{ "id" : 31, "requires" : [ 30 ] },
 				{ "id" : 32, "requires" : [ 30 ] },
 				{ "id" : 32, "requires" : [ 30 ] },
@@ -517,7 +593,7 @@
 
 
 		{
 		{
 			// 5 - Dungeon
 			// 5 - Dungeon
-			"defnames" :
+			"structures" :
 			[
 			[
 				{ "id" : 16, "defname" : "TBDNBLAK.def", "x" : 544, "y" : 248, "border" : "TODSMITH.bmp", "area" : "TZDSMITH.bmp" },
 				{ "id" : 16, "defname" : "TBDNBLAK.def", "x" : 544, "y" : 248, "border" : "TODSMITH.bmp", "area" : "TZDSMITH.bmp" },
 				{ "id" : 9,  "defname" : "TBDNCAS3.def", "x" : 363, "y" : 87,  "border" : "TODCAS3.bmp",  "area" : "TZDCAS3.bmp" },
 				{ "id" : 9,  "defname" : "TBDNCAS3.def", "x" : 363, "y" : 87,  "border" : "TODCAS3.bmp",  "area" : "TZDCAS3.bmp" },
@@ -557,28 +633,61 @@
 				{ "id" : 43, "defname" : "TBDNUP_6.def", "x" : 550, "y" : 0,   "border" : "TODDRA2A.bmp", "area" : "TZDDRA2A.bmp" },
 				{ "id" : 43, "defname" : "TBDNUP_6.def", "x" : 550, "y" : 0,   "border" : "TODDRA2A.bmp", "area" : "TZDDRA2A.bmp" },
 				{ "id" : 8,  "defname" : "TBDNCAS2.def", "x" : 363, "y" : 87,  "border" : "TODCAS2.bmp",  "area" : "TZDCAS2.bmp" }
 				{ "id" : 8,  "defname" : "TBDNCAS2.def", "x" : 363, "y" : 87,  "border" : "TODCAS2.bmp",  "area" : "TZDCAS2.bmp" }
 			],
 			],
+			"groups" :
+			[
+				[ 0, 1, 2, 3, 4 ],
+				[ 6, 20 ],
+				[ 7, 8, 9 ],
+				[ 10, 11, 12, 13 ],
+				[ 31, 38 ],
+				[ 32, 39 ],
+				[ 33, 40 ],
+				[ 34, 41 ],
+				[ 35, 42 ],
+				[ 36, 43 ],
+				[ 30, 37, 18, 19 ]
+			],
+			"hallBackground": "TPTHBKDG.BMP",
+			"hallSlots":
+			[
+				[ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ],
+				[ [ 14, 15 ], [ 0, 1, 2, 3, 4 ], [ 21 ], [ 22 ] ],
+				[ [ 17 ], [ 23 ], [ 18, 19 ] ],
+				[ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ],
+				[ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ]
+			],
 			"blit_order" : [ 0, 1, 2, 3, 4, 21, 35, 42, 5, 30, 18, 37, 19, 32, 39, 26, 7, 8, 9, 23 ],
 			"blit_order" : [ 0, 1, 2, 3, 4, 21, 35, 42, 5, 30, 18, 37, 19, 32, 39, 26, 7, 8, 9, 23 ],
 			"creatures" : [ [70, 71], [72, 73], [74, 75], [76, 77], [78, 79], [80, 81], [82, 83] ],
 			"creatures" : [ [70, 71], [72, 73], [74, 75], [76, 77], [78, 79], [80, 81], [82, 83] ],
-			"horde" : [ 0, null ],
+			"horde" : [ 0, -1 ],
+			"mage_guild" : 5,
 			"primary_resource" : 3,
 			"primary_resource" : 3,
 			"war_machine" : 4,
 			"war_machine" : 4,
 
 
-			"building_requirements" :
+			"buildings" :
 			[
 			[
+				{ "id" : 0 },
 				{ "id" : 1,  "requires" : [ 0 ] },
 				{ "id" : 1,  "requires" : [ 0 ] },
 				{ "id" : 2,  "requires" : [ 1 ] },
 				{ "id" : 2,  "requires" : [ 1 ] },
 				{ "id" : 3,  "requires" : [ 2 ] },
 				{ "id" : 3,  "requires" : [ 2 ] },
 				{ "id" : 4,  "requires" : [ 3 ] },
 				{ "id" : 4,  "requires" : [ 3 ] },
+				{ "id" : 5 },
+				{ "id" : 7 },
 				{ "id" : 8,  "requires" : [ 7 ] },
 				{ "id" : 8,  "requires" : [ 7 ] },
 				{ "id" : 9,  "requires" : [ 8 ] },
 				{ "id" : 9,  "requires" : [ 8 ] },
+				{ "id" : 10 },
 				{ "id" : 11, "requires" : [ 10, 5 ] },
 				{ "id" : 11, "requires" : [ 10, 5 ] },
 				{ "id" : 12, "requires" : [ 11, 0, 14, 16 ] },
 				{ "id" : 12, "requires" : [ 11, 0, 14, 16 ] },
 				{ "id" : 13, "requires" : [ 12, 9 ] },
 				{ "id" : 13, "requires" : [ 12, 9 ] },
+				{ "id" : 14 },
 				{ "id" : 15, "requires" : [ 14 ] },
 				{ "id" : 15, "requires" : [ 14 ] },
+				{ "id" : 16 },
 				{ "id" : 17, "requires" : [ 14 ] },
 				{ "id" : 17, "requires" : [ 14 ] },
 				{ "id" : 18, "requires" : [ 30 ] },
 				{ "id" : 18, "requires" : [ 30 ] },
 				{ "id" : 19, "requires" : [ 37 ] },
 				{ "id" : 19, "requires" : [ 37 ] },
 				{ "id" : 21, "requires" : [ 0 ] },
 				{ "id" : 21, "requires" : [ 0 ] },
+				{ "id" : 22 },
+				{ "id" : 23 },
+				{ "id" : 26 },
 				{ "id" : 30, "requires" : [ 7 ] },
 				{ "id" : 30, "requires" : [ 7 ] },
 				{ "id" : 31, "requires" : [ 30 ] },
 				{ "id" : 31, "requires" : [ 30 ] },
 				{ "id" : 32, "requires" : [ 30 ] },
 				{ "id" : 32, "requires" : [ 30 ] },
@@ -598,7 +707,7 @@
 
 
 		{
 		{
 		// 6 - Stronghold
 		// 6 - Stronghold
-			"defnames" :
+			"structures" :
 			[
 			[
 				{ "id" : 31, "defname" : "TBSTDW_1.def", "x" : 266, "y" : 246, "border" : "TOSWOL1.bmp",  "area" : "TZSWOL1.bmp" },
 				{ "id" : 31, "defname" : "TBSTDW_1.def", "x" : 266, "y" : 246, "border" : "TOSWOL1.bmp",  "area" : "TZSWOL1.bmp" },
 				{ "id" : 43, "defname" : "TBSTUP_6.def", "x" : 604, "y" : 0,   "border" : "TOSBEH2A.bmp", "area" : "TZSBEH2A.bmp" },
 				{ "id" : 43, "defname" : "TBSTUP_6.def", "x" : 604, "y" : 0,   "border" : "TOSBEH2A.bmp", "area" : "TZSBEH2A.bmp" },
@@ -637,30 +746,61 @@
 				{ "id" : 42, "defname" : "TBSTUP_5.def", "x" : 616, "y" : 93,  "border" : "TOSCYC2A.bmp", "area" : "TZSCYC2A.bmp" },
 				{ "id" : 42, "defname" : "TBSTUP_5.def", "x" : 616, "y" : 93,  "border" : "TOSCYC2A.bmp", "area" : "TZSCYC2A.bmp" },
 				{ "id" : 16, "defname" : "TBSTBLAK.def", "x" : 660, "y" : 286, "border" : "TOSBLK1.bmp",  "area" : "TZSBLK1.bmp" }
 				{ "id" : 16, "defname" : "TBSTBLAK.def", "x" : 660, "y" : 286, "border" : "TOSBLK1.bmp",  "area" : "TZSBLK1.bmp" }
 			],
 			],
+			"groups" :
+			[
+				[ 0, 1, 2, 3, 4 ],
+				[ 6, 20 ],
+				[ 7, 8, 9 ],
+				[ 10, 11, 12, 13 ],
+				[ 31, 38 ],
+				[ 32, 39 ],
+				[ 33, 40 ],
+				[ 34, 41 ],
+				[ 35, 42 ],
+				[ 36, 43 ],
+				[ 30, 37, 18, 19 ]
+			],
+			"hallBackground": "TPTHBKTW.BMP",
+			"hallSlots":
+			[
+				[ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ],
+				[ [ 14, 15 ], [ 0, 1, 2 ], [ 23 ], [ 17 ] ],
+				[ [ 21 ], [ 22 ], [ 18, 19 ] ],
+				[ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ],
+				[ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ]
+			],
 			"blit_order" : [ 33, 40, 30, 18, 37, 19, 31, 38, 23, 26, 5, 32, 39, 15, 14, 21, 16, 22 ],
 			"blit_order" : [ 33, 40, 30, 18, 37, 19, 31, 38, 23, 26, 5, 32, 39, 15, 14, 21, 16, 22 ],
 			"creatures" : [ [84, 85], [86, 87], [88, 89], [90, 91], [92, 93], [94, 95], [96, 97] ],
 			"creatures" : [ [84, 85], [86, 87], [88, 89], [90, 91], [92, 93], [94, 95], [96, 97] ],
-			"horde" : [ 0, null ],
+			"horde" : [ 0, -1 ],
 			"mage_guild" : 3,
 			"mage_guild" : 3,
+			"primary_resource" : 127,
 			"war_machine" : 5,
 			"war_machine" : 5,
 
 
-			"building_requirements" :
+			"buildings" :
 			[
 			[
+				{ "id" : 0 },
 				{ "id" : 1,  "requires" : [ 0 ] },
 				{ "id" : 1,  "requires" : [ 0 ] },
 				{ "id" : 2,  "requires" : [ 1 ] },
 				{ "id" : 2,  "requires" : [ 1 ] },
 				{ "id" : 3,  "requires" : [ 2 ] },
 				{ "id" : 3,  "requires" : [ 2 ] },
 				{ "id" : 4,  "requires" : [ 3 ] },
 				{ "id" : 4,  "requires" : [ 3 ] },
+				{ "id" : 5 },
+				{ "id" : 7 },
 				{ "id" : 8,  "requires" : [ 7 ] },
 				{ "id" : 8,  "requires" : [ 7 ] },
 				{ "id" : 9,  "requires" : [ 8 ] },
 				{ "id" : 9,  "requires" : [ 8 ] },
+				{ "id" : 10 },
 				{ "id" : 11, "requires" : [ 10, 5 ] },
 				{ "id" : 11, "requires" : [ 10, 5 ] },
 				{ "id" : 12, "requires" : [ 11, 0, 14, 16 ] },
 				{ "id" : 12, "requires" : [ 11, 0, 14, 16 ] },
 				{ "id" : 13, "requires" : [ 12, 9 ] },
 				{ "id" : 13, "requires" : [ 12, 9 ] },
+				{ "id" : 14 },
 				{ "id" : 15, "requires" : [ 14 ] },
 				{ "id" : 15, "requires" : [ 14 ] },
+				{ "id" : 16 },
 				{ "id" : 17, "requires" : [ 7 ] },
 				{ "id" : 17, "requires" : [ 7 ] },
 				{ "id" : 18, "requires" : [ 30 ] },
 				{ "id" : 18, "requires" : [ 30 ] },
 				{ "id" : 19, "requires" : [ 37 ] },
 				{ "id" : 19, "requires" : [ 37 ] },
 				{ "id" : 21, "requires" : [ 14 ] },
 				{ "id" : 21, "requires" : [ 14 ] },
 				{ "id" : 22, "requires" : [ 16 ] },
 				{ "id" : 22, "requires" : [ 16 ] },
 				{ "id" : 23, "requires" : [ 7 ] },
 				{ "id" : 23, "requires" : [ 7 ] },
+				{ "id" : 26 },
 				{ "id" : 30, "requires" : [ 7 ] },
 				{ "id" : 30, "requires" : [ 7 ] },
 				{ "id" : 31, "requires" : [ 30 ] },
 				{ "id" : 31, "requires" : [ 30 ] },
 				{ "id" : 32, "requires" : [ 30 ] },
 				{ "id" : 32, "requires" : [ 30 ] },
@@ -680,7 +820,7 @@
 
 
 		{
 		{
 		// 7 - Fortress
 		// 7 - Fortress
-			"defnames" :
+			"structures" :
 			[
 			[
 				{ "id" : 16, "defname" : "TBFRBLAK.def", "x" : 360, "y" : 160, "border" : "TOFAIDA.bmp",  "area" : "TZFAIDA.bmp" },
 				{ "id" : 16, "defname" : "TBFRBLAK.def", "x" : 360, "y" : 160, "border" : "TOFAIDA.bmp",  "area" : "TZFAIDA.bmp" },
 				{ "id" : 8,  "defname" : "TBFRCAS2.def", "x" : 368, "y" : 98,  "border" : "TOFCAS2.bmp",  "area" : "TZFCAS2.bmp" },
 				{ "id" : 8,  "defname" : "TBFRCAS2.def", "x" : 368, "y" : 98,  "border" : "TOFCAS2.bmp",  "area" : "TZFCAS2.bmp" },
@@ -721,29 +861,62 @@
 				{ "id" : 29, "defname" : "TBFRWTRW.def", "x" : 320, "y" : 141 },
 				{ "id" : 29, "defname" : "TBFRWTRW.def", "x" : 320, "y" : 141 },
 				{ "id" : 20, "defname" : "TBFRBOAT.def", "x" : 197, "y" : 294, "border" : "TOFDCK1.bmp",  "area" : "TZFDCK1.bmp" }
 				{ "id" : 20, "defname" : "TBFRBOAT.def", "x" : 197, "y" : 294, "border" : "TOFDCK1.bmp",  "area" : "TZFDCK1.bmp" }
 			],
 			],
+			"groups" :
+			[
+				[ 0, 1, 2, 3, 4 ],
+				[ 6, 20 ],
+				[ 7, 8, 9 ],
+				[ 10, 11, 12, 13 ],
+				[ 31, 38 ],
+				[ 32, 39 ],
+				[ 33, 40 ],
+				[ 34, 41 ],
+				[ 35, 42 ],
+				[ 36, 43 ],
+				[ 30, 37, 18, 19 ]
+			],
+			"hallBackground": "TPTHBKFR.BMP",
+			"hallSlots":
+			[
+				[ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ],
+				[ [ 14, 15 ], [ 0, 1, 2 ], [ 6 ] ],
+				[ [ 17 ], [ 21, 22 ], [ 18, 19 ] ],
+				[ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ],
+				[ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ]
+			],
 			"blit_order" : [ 16, 15, 14, 34, 41, 31, 38, 10, 11, 12, 13, 29, 0, 1, 2, 33, 40, 30, 18, 37, 19, 5, 36, 43, 26 ],
 			"blit_order" : [ 16, 15, 14, 34, 41, 31, 38, 10, 11, 12, 13, 29, 0, 1, 2, 33, 40, 30, 18, 37, 19, 5, 36, 43, 26 ],
 			"creatures" : [ [98, 99], [100, 101], [104, 105], [106, 107], [102, 103], [108, 109], [110, 111] ],
 			"creatures" : [ [98, 99], [100, 101], [104, 105], [106, 107], [102, 103], [108, 109], [110, 111] ],
-			"horde" : [ 0, null ],
+			"horde" : [ 0, -1 ],
 			"mage_guild" : 3,
 			"mage_guild" : 3,
+			"primary_resource" : 127,
 			"war_machine" : 6,
 			"war_machine" : 6,
 
 
-			"building_requirements" :
+			"buildings" :
 			[
 			[
+				{ "id" : 0 },
 				{ "id" : 1,  "requires" : [ 0 ] },
 				{ "id" : 1,  "requires" : [ 0 ] },
 				{ "id" : 2,  "requires" : [ 1 ] },
 				{ "id" : 2,  "requires" : [ 1 ] },
 				{ "id" : 3,  "requires" : [ 2 ] },
 				{ "id" : 3,  "requires" : [ 2 ] },
 				{ "id" : 4,  "requires" : [ 3 ] },
 				{ "id" : 4,  "requires" : [ 3 ] },
+				{ "id" : 5 },
+				{ "id" : 6 },
+				{ "id" : 7 },
 				{ "id" : 8,  "requires" : [ 7 ] },
 				{ "id" : 8,  "requires" : [ 7 ] },
 				{ "id" : 9,  "requires" : [ 8 ] },
 				{ "id" : 9,  "requires" : [ 8 ] },
+				{ "id" : 10 },
 				{ "id" : 11, "requires" : [ 10, 5 ] },
 				{ "id" : 11, "requires" : [ 10, 5 ] },
 				{ "id" : 12, "requires" : [ 11, 0, 14, 16 ] },
 				{ "id" : 12, "requires" : [ 11, 0, 14, 16 ] },
 				{ "id" : 13, "requires" : [ 12, 9 ] },
 				{ "id" : 13, "requires" : [ 12, 9 ] },
+				{ "id" : 14 },
 				{ "id" : 15, "requires" : [ 14 ] },
 				{ "id" : 15, "requires" : [ 14 ] },
+				{ "id" : 16 },
 				{ "id" : 17, "requires" : [ 11, 21 ] },
 				{ "id" : 17, "requires" : [ 11, 21 ] },
 				{ "id" : 18, "requires" : [ 30 ] },
 				{ "id" : 18, "requires" : [ 30 ] },
 				{ "id" : 19, "requires" : [ 37 ] },
 				{ "id" : 19, "requires" : [ 37 ] },
+				{ "id" : 20 },
 				{ "id" : 21, "requires" : [ 7 ] },
 				{ "id" : 21, "requires" : [ 7 ] },
 				{ "id" : 22, "requires" : [ 21 ] },
 				{ "id" : 22, "requires" : [ 21 ] },
+				{ "id" : 26 },
 				{ "id" : 30, "requires" : [ 7 ] },
 				{ "id" : 30, "requires" : [ 7 ] },
 				{ "id" : 31, "requires" : [ 30 ] },
 				{ "id" : 31, "requires" : [ 30 ] },
 				{ "id" : 32, "requires" : [ 30 ] },
 				{ "id" : 32, "requires" : [ 30 ] },
@@ -763,7 +936,7 @@
 
 
 		{
 		{
 			// 8 - Conflux
 			// 8 - Conflux
-			"defnames" :
+			"structures" :
 			[
 			[
 				{ "id" : 16, "defname" : "TBELBLAK.def", "x" : 449, "y" : 151, "border" : "TOELBLAK.bmp", "area" : "TZELBLAK.bmp" },
 				{ "id" : 16, "defname" : "TBELBLAK.def", "x" : 449, "y" : 151, "border" : "TOELBLAK.bmp", "area" : "TZELBLAK.bmp" },
 				{ "id" : 8,  "defname" : "TBELCAS2.def", "x" : 349, "y" : 101, "border" : "TOELCAS2.bmp", "area" : "TZELCAS2.bmp" },
 				{ "id" : 8,  "defname" : "TBELCAS2.def", "x" : 349, "y" : 101, "border" : "TOELCAS2.bmp", "area" : "TZELCAS2.bmp" },
@@ -808,28 +981,61 @@
 				{ "id" : 43, "defname" : "TBELUP_6.def", "x" : 43,  "y" : 0,   "border" : "TOELUP_6.bmp", "area" : "TZELUP_6.bmp" },
 				{ "id" : 43, "defname" : "TBELUP_6.def", "x" : 43,  "y" : 0,   "border" : "TOELUP_6.bmp", "area" : "TZELUP_6.bmp" },
 				{ "id" : 20, "defname" : "TBELBOAT.def", "x" : 239, "y" : 215, "border" : "TOELBOAT.bmp", "area" : "TZELBOAT.bmp" }
 				{ "id" : 20, "defname" : "TBELBOAT.def", "x" : 239, "y" : 215, "border" : "TOELBOAT.bmp", "area" : "TZELBOAT.bmp" }
 			],
 			],
+			"groups" :
+			[
+				[ 0, 1, 2, 3, 4 ],
+				[ 6, 20 ],
+				[ 7, 8, 9 ],
+				[ 10, 11, 12, 13 ],
+				[ 31, 38 ],
+				[ 32, 39 ],
+				[ 33, 40 ],
+				[ 34, 41 ],
+				[ 35, 42 ],
+				[ 36, 43 ],
+				[ 30, 37, 18, 19 ]
+			],
+			"hallBackground": "TPTHBKFR.BMP",
+			"hallSlots":
+			[
+				[ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ],
+				[ [ 14, 15 ], [ 0, 1, 2, 3, 4 ], [ 6 ] ],
+				[ [ 21 ], [ 17 ], [ 18, 19 ] ],
+				[ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ],
+				[ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ]
+			],
 			"blit_order" : [ -1, 27, 28, 16, 34, 41, 6, 20, 33, 40, 36, 43, 21, 0, 1, 2, 3, 4, 5, 15, 14, 17, 35, 42, 30, 18, 37, 19, 10, 11, 12, 13, 29 ],
 			"blit_order" : [ -1, 27, 28, 16, 34, 41, 6, 20, 33, 40, 36, 43, 21, 0, 1, 2, 3, 4, 5, 15, 14, 17, 35, 42, 30, 18, 37, 19, 10, 11, 12, 13, 29 ],
 			"creatures" : [ [118, 119], [112, 127], [115, 123], [114, 129], [113, 125], [120, 121], [130, 131] ],
 			"creatures" : [ [118, 119], [112, 127], [115, 123], [114, 129], [113, 125], [120, 121], [130, 131] ],
-			"horde" : [ 0, null ],
+			"horde" : [ 0, -1 ],
+			"mage_guild" : 5,
 			"primary_resource" : 1,
 			"primary_resource" : 1,
 			"war_machine" : 4,
 			"war_machine" : 4,
 
 
-			"building_requirements" :
+			"buildings" :
 			[
 			[
+				{ "id" : 0 },
 				{ "id" : 1,  "requires" : [ 0 ] },
 				{ "id" : 1,  "requires" : [ 0 ] },
 				{ "id" : 2,  "requires" : [ 1 ] },
 				{ "id" : 2,  "requires" : [ 1 ] },
 				{ "id" : 3,  "requires" : [ 2 ] },
 				{ "id" : 3,  "requires" : [ 2 ] },
 				{ "id" : 4,  "requires" : [ 3 ] },
 				{ "id" : 4,  "requires" : [ 3 ] },
+				{ "id" : 5 },
+				{ "id" : 6 },
+				{ "id" : 7 },
 				{ "id" : 8,  "requires" : [ 7 ] },
 				{ "id" : 8,  "requires" : [ 7 ] },
 				{ "id" : 9,  "requires" : [ 8 ] },
 				{ "id" : 9,  "requires" : [ 8 ] },
+				{ "id" : 10 },
 				{ "id" : 11, "requires" : [ 10, 5 ] },
 				{ "id" : 11, "requires" : [ 10, 5 ] },
 				{ "id" : 12, "requires" : [ 11, 0, 14, 16 ] },
 				{ "id" : 12, "requires" : [ 11, 0, 14, 16 ] },
 				{ "id" : 13, "requires" : [ 12, 9 ] },
 				{ "id" : 13, "requires" : [ 12, 9 ] },
+				{ "id" : 14 },
 				{ "id" : 15, "requires" : [ 14 ] },
 				{ "id" : 15, "requires" : [ 14 ] },
+				{ "id" : 16 },
 				{ "id" : 17, "requires" : [ 14 ] },
 				{ "id" : 17, "requires" : [ 14 ] },
 				{ "id" : 18, "requires" : [ 30 ] },
 				{ "id" : 18, "requires" : [ 30 ] },
 				{ "id" : 19, "requires" : [ 37 ] },
 				{ "id" : 19, "requires" : [ 37 ] },
+				{ "id" : 20 },
 				{ "id" : 21, "requires" : [ 0 ] },
 				{ "id" : 21, "requires" : [ 0 ] },
+				{ "id" : 26 },
 				{ "id" : 30, "requires" : [ 7 ] },
 				{ "id" : 30, "requires" : [ 7 ] },
 				{ "id" : 31, "requires" : [ 30, 0 ] },
 				{ "id" : 31, "requires" : [ 30, 0 ] },
 				{ "id" : 32, "requires" : [ 30, 0 ] },
 				{ "id" : 32, "requires" : [ 30, 0 ] },
@@ -846,100 +1052,5 @@
 				{ "id" : 43, "requires" : [ 36 ] }
 				{ "id" : 43, "requires" : [ 36 ] }
 			]
 			]
 		}
 		}
-	],
-
-	//A group contains a vector of building IDs
-	//In the town screen only the last built structure from the group is displayed
-	//Eg. when there is Mage Guild Level 3, then we don't display Mage Guild Level 1 and 2
-	"town_groups" :
-	[
-		{
-			// Applies to all castles
-			"id" : -1,
-			"groups" :
-			[
-				[ 0, 1, 2, 3, 4 ],
-				[ 6, 20 ],
-				[ 7, 8, 9 ],
-				[ 10, 11, 12, 13 ],
-				[ 30, 37 ],
-				[ 31, 38 ],
-				[ 32, 39 ],
-				[ 33, 40 ],
-				[ 34, 41 ],
-				[ 35, 42 ],
-				[ 36, 43 ],
-				[ 24, 25 ],
-				[ 18, 19 ]
-			]
-		},
-
-		{
-			"id" : 1,
-			"groups" :
-			[
-				[ 24, 25, 34, 41 ],
-				[ 17, 21 ],
-				[ 31, 18, 38, 19 ]
-			]
-		},
-
-		{
-			"id" : 2,
-			"groups" :
-			[
-				[ 18, 19, 31, 38 ]
-			]
-		},
-
-		{
-			"id" : 3,
-			"groups" :
-			[
-				[ 18, 19, 30, 37 ],
-				[ 32, 39, 24, 25 ]
-			]
-		},
-
-		{
-			"id" : 4,
-			"groups" :
-			[
-				[ 30, 37, 18, 19 ]
-			]
-		},
-
-		{
-			"id" : 5,
-			"groups" :
-			[
-				[ 30, 37, 18, 19 ]
-			]
-		},
-
-		{
-			"id" : 6,
-			"groups" :
-			[
-				[ 21 ],
-				[ 30, 37, 18, 19 ]
-			]
-		},
-
-		{
-			"id" : 7,
-			"groups" :
-			[
-				[ 30, 37, 18, 19 ]
-			]
-		},
-
-		{
-			"id" : 8,
-			"groups" :
-			[
-				[ 30, 37, 18, 19 ]
-			]
-		}
 	]
 	]
 }
 }

+ 0 - 114
config/hall.json

@@ -1,114 +0,0 @@
-{
-	// for each castle:
-	//  id: town ID
-	//  boxes: row buildings containing sets of ids for each box
-	"town": [
-		{
-			"id": 0,
-			"image": "TPTHBKCS.BMP",
-			"boxes": [
-				[ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5, 22 ], [ 16 ] ],
-				[ [ 14, 15 ], [ 0, 1, 2, 3 ], [ 6, 17 ] ],
-				[ [ 21 ], [ 18, 19 ] ],
-				[ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ],
-				[ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ]
-			]
-		},
-
-		{
-			"id": 1,
-			"image": "TPTHBKRM.BMP",
-			"boxes": [
-				[ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ],
-				[ [ 14, 15 ], [ 0, 1, 2, 3, 4 ], [ 17, 21 ] ],
-				[ [ 22 ], [ 24, 25 ], [ 18, 19 ] ],
-				[ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ],
-				[ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ]
-			]
-		},
-
-		{
-			"id": 2,
-			"image": "TPTHBKTW.BMP",
-			"boxes": [
-				[ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ],
-				[ [ 14, 15 ], [ 0, 1, 2, 3, 4 ], [ 22 ], [ 23 ] ],
-				[ [ 17 ], [ 21 ], [ 18, 19 ] ],
-				[ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ],
-				[ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ]
-			]
-		},
-
-		{
-			"id": 3,
-			"image": "TPTHBKIN.BMP",
-			"boxes": [
-				[ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ],
-				[ [ 14, 15 ], [ 0, 1, 2, 3, 4 ], [ 23 ], [ 21 ] ],
-				[ [ 22 ], [ 18, 19 ], [ 24, 25 ] ],
-				[ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ],
-				[ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ]
-			]
-		},
-
-		{
-			"id": 4,
-			"image": "TPTHBKNC.BMP",
-			"boxes": [
-				[ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ],
-				[ [ 14, 15 ], [ 0, 1, 2, 3, 4 ], [ 21 ], [ 6 ] ],
-				[ [ 17 ], [ 22 ], [ 18, 19 ] ],
-				[ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ],
-				[ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ]
-			]
-		},
-
-		{
-			"id": 5,
-			"image": "TPTHBKDG.BMP",
-			"boxes": [
-				[ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ],
-				[ [ 14, 15 ], [ 0, 1, 2, 3, 4 ], [ 21 ], [ 22 ] ],
-				[ [ 17 ], [ 23 ], [ 18, 19 ] ],
-				[ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ],
-				[ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ]
-			]
-		},
-
-		{
-			"id": 6,
-			"image": "TPTHBKTW.BMP",
-			"boxes": [
-				[ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ],
-				[ [ 14, 15 ], [ 0, 1, 2 ], [ 23 ], [ 17 ] ],
-				[ [ 21 ], [ 22 ], [ 18, 19 ] ],
-				[ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ],
-				[ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ]
-			]
-		},
-
-		{
-			"id": 7,
-			"image": "TPTHBKFR.BMP",
-			"boxes": [
-				[ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ],
-				[ [ 14, 15 ], [ 0, 1, 2 ], [ 6 ] ],
-				[ [ 17 ], [ 21, 22 ], [ 18, 19 ] ],
-				[ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ],
-				[ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ]
-			]
-		},
-
-		{
-			"id": 8,
-			"image": "TPTHBKFR.BMP",
-			"boxes": [
-				[ [ 10, 11, 12, 13 ], [ 7, 8, 9 ], [ 5 ], [ 16 ] ],
-				[ [ 14, 15 ], [ 0, 1, 2, 3, 4 ], [ 6 ] ],
-				[ [ 21 ], [ 17 ], [ 18, 19 ] ],
-				[ [ 30, 37 ], [ 31, 38 ], [ 32, 39 ], [ 33, 40 ] ],
-				[ [ 34, 41 ], [ 35, 42 ], [ 36, 43 ] ]
-			]
-		}
-	]
-}

+ 0 - 173
lib/CBuildingHandler.cpp

@@ -1,10 +1,6 @@
 #include "StdInc.h"
 #include "StdInc.h"
 #include "CBuildingHandler.h"
 #include "CBuildingHandler.h"
 
 
-#include "CGeneralTextHandler.h"
-#include "VCMI_Lib.h"
-#include "Filesystem/CResourceLoader.h"
-#include "JsonNode.h"
 #include "GameConstants.h"
 #include "GameConstants.h"
 
 
 /*
 /*
@@ -17,175 +13,6 @@
  *
  *
  */
  */
 
 
-CBuilding * readBuilding(CLegacyConfigParser & parser, int townID, int buildID)
-{
-	CBuilding * ret = new CBuilding;
-	ret->tid = townID;
-	ret->bid = buildID;
-	for (size_t i=0; i< ret->resources.size(); i++)
-		ret->resources[i] = parser.readNumber();
-
-	parser.endLine();
-	return ret;
-}
-
-void CBuildingHandler::loadBuildings()
-{
-	CLegacyConfigParser parser("DATA/BUILDING.TXT");
-	buildings.resize(GameConstants::F_NUMBER);
-
-	parser.endLine(); // header
-	parser.endLine();
-
-	//Unique buildings
-	for (size_t town=0; town<GameConstants::F_NUMBER; town++)
-	{
-		parser.endLine(); //header
-		parser.endLine();
-
-		int buildID = 17;
-		do
-		{
-			buildings[town][buildID] = readBuilding(parser, town, buildID);
-			buildID++;
-		}
-		while (!parser.isNextEntryEmpty());
-	}
-
-	// Common buildings
-	parser.endLine(); // header
-	parser.endLine();
-	parser.endLine();
-
-	int buildID = 0;
-	do
-	{
-		buildings[0][buildID] = readBuilding(parser, 0, buildID);
-
-		for (size_t town=1; town<GameConstants::F_NUMBER; town++)
-		{
-			buildings[town][buildID] = new CBuilding(*buildings[0][buildID]);
-			buildings[town][buildID]->tid = town;
-		}
-		buildID++;
-	}
-	while (!parser.isNextEntryEmpty());
-
-	parser.endLine(); //header
-	parser.endLine();
-
-	//Dwellings
-	for (size_t town=0; town<GameConstants::F_NUMBER; town++)
-	{
-		parser.endLine(); //header
-		parser.endLine();
-
-		int buildID = 30;
-		do
-		{
-			buildings[town][buildID] = readBuilding(parser, town, buildID);
-			buildID++;
-		}
-		while (!parser.isNextEntryEmpty());
-	}
-
-	// Grail. It may not have entries in building.txt
-	for (size_t town=0; town<GameConstants::F_NUMBER; town++)
-	{
-		if (!vstd::contains(buildings[town], 26))
-		{
-			buildings[town][26] = new CBuilding();
-			buildings[town][26]->tid = town;
-			buildings[town][26]->bid = 26;
-		}
-	}
-
-	/////done reading BUILDING.TXT*****************************
-	const JsonNode config(ResourceID("config/hall.json"));
-
-	BOOST_FOREACH(const JsonNode &town, config["town"].Vector())
-	{
-		int tid = town["id"].Float();
-
-		hall[tid].first = town["image"].String();
-		(hall[tid].second).resize(5); //rows
-
-		int row_num = 0;
-		BOOST_FOREACH(const JsonNode &row, town["boxes"].Vector())
-		{
-			BOOST_FOREACH(const JsonNode &box, row.Vector())
-			{
-				(hall[tid].second)[row_num].push_back(std::vector<int>()); //push new box
-				std::vector<int> &box_vec = (hall[tid].second)[row_num].back();
-
-				BOOST_FOREACH(const JsonNode &value, box.Vector())
-				{
-					box_vec.push_back(value.Float());
-				}
-			}
-			row_num ++;
-		}
-		assert (row_num == 5);
-	}
-
-	// Buildings dependencies. Which building depend on which other building.
-	const JsonNode buildingsConf(ResourceID("config/buildings.json"));
-
-	// Iterate for each city type
-	int townID = 0;
-	BOOST_FOREACH(const JsonNode &town_node, buildingsConf["town_type"].Vector())
-	{
-		BOOST_FOREACH(const JsonNode &node, town_node["building_requirements"].Vector())
-		{
-			int id = node["id"].Float();
-			CBuilding * build = buildings[townID][id];
-			if (build)
-			{
-				BOOST_FOREACH(const JsonNode &building, node["requires"].Vector())
-				{
-					build->requirements.insert(building.Float());
-				}
-			}
-		}
-		townID++;
-	}
-}
-
-CBuildingHandler::~CBuildingHandler()
-{
-	for(std::vector< bmap<int, ConstTransitivePtr<CBuilding> > >::iterator i=buildings.begin(); i!=buildings.end(); i++)
-		for(std::map<int, ConstTransitivePtr<CBuilding> >::iterator j=i->begin(); j!=i->end(); j++)
-			j->second.dellNull();
-}
-
-static std::string emptyStr = "";
-
-const std::string & CBuilding::Name() const
-{
-	if(name.length())
-		return name;
-	else if(vstd::contains(VLC->generaltexth->buildings,tid) && vstd::contains(VLC->generaltexth->buildings[tid],bid))
-		return VLC->generaltexth->buildings[tid][bid].first;
-	tlog2 << "Warning: Cannot find name text for building " << bid << "for " << tid << "town.\n";
-	return emptyStr;
-}
-
-const std::string & CBuilding::Description() const
-{
-	if(description.length())
-		return description;
-	else if(vstd::contains(VLC->generaltexth->buildings,tid) && vstd::contains(VLC->generaltexth->buildings[tid],bid))
-		return VLC->generaltexth->buildings[tid][bid].second;
-	tlog2 << "Warning: Cannot find description text for building " << bid << "for " << tid << "town.\n";
-	return emptyStr;
-}
-
-CBuilding::CBuilding( int TID, int BID )
-{
-	tid = TID;
-	bid = BID;
-}
-
 int CBuildingHandler::campToERMU( int camp, int townType, std::set<si32> builtBuildings )
 int CBuildingHandler::campToERMU( int camp, int townType, std::set<si32> builtBuildings )
 {
 {
 	using namespace boost::assign;
 	using namespace boost::assign;

+ 0 - 35
lib/CBuildingHandler.h

@@ -1,9 +1,5 @@
 #pragma once
 #pragma once
 
 
-
-#include "../lib/ConstTransitivePtr.h"
-#include "ResourceSet.h"
-
 /*
 /*
  * CBuildingHandler.h, part of VCMI engine
  * CBuildingHandler.h, part of VCMI engine
  *
  *
@@ -14,39 +10,8 @@
  *
  *
  */
  */
 
 
-//enum EbuildingType {NEUTRAL=-1, CASTLE, RAMPART, TOWER, INFERNO, NECROPOLIS, DUNGEON, STRONGHOLD, FORTRESS, CONFLUX};
-class DLL_LINKAGE CBuilding //a typical building encountered in every castle ;]
-{
-public:
-	si32 tid, bid; //town ID and structure ID
-	TResources resources;
-	std::string name;
-	std::string description;
-	std::set<int> requirements; //set of required buildings
-
-	const std::string &Name() const;
-	const std::string &Description() const;
-
-	template <typename Handler> void serialize(Handler &h, const int version)
-	{
-		h & tid & bid & resources & name & description & requirements;
-	}
-	CBuilding(int TID = -1, int BID = -1);
-};
-
 class DLL_LINKAGE CBuildingHandler
 class DLL_LINKAGE CBuildingHandler
 {
 {
 public:
 public:
-	typedef bmap<int, ConstTransitivePtr<CBuilding> > TBuildingsMap;
-	std::vector< TBuildingsMap > buildings; ///< vector by castle ID, second the building ID (in ERM-U format)
-	bmap<int, std::pair<std::string,std::vector< std::vector< std::vector<int> > > > > hall; //map<castle ID, pair<hall bg name, std::vector< std::vector<building id> >[5]> - external vector is the vector of buildings in the row, internal is the list of buildings for the specific slot
-
-	void loadBuildings(); //main loader
-	~CBuildingHandler(); //d-tor
 	static int campToERMU(int camp, int townType, std::set<si32> builtBuildings);
 	static int campToERMU(int camp, int townType, std::set<si32> builtBuildings);
-
-	template <typename Handler> void serialize(Handler &h, const int version)
-	{
-		h & buildings & hall;
-	}
 };
 };

+ 3 - 21
lib/CGameState.cpp

@@ -1053,30 +1053,12 @@ void CGameState::init(StartInfo * si)
 	}
 	}
 
 
 	/******************RESOURCES****************************************************/
 	/******************RESOURCES****************************************************/
-	TResources startresAI, startresHuman;
 	const JsonNode config(ResourceID("config/startres.json"));
 	const JsonNode config(ResourceID("config/startres.json"));
 	const JsonVector &vector = config["difficulty"].Vector();
 	const JsonVector &vector = config["difficulty"].Vector();
 	const JsonNode &level = vector[scenarioOps->difficulty];
 	const JsonNode &level = vector[scenarioOps->difficulty];
-	const JsonNode &human = level["human"];
-	const JsonNode &ai = level["ai"];
-
-	startresHuman[0] = human["wood"].Float();
-	startresHuman[1] = human["mercury"].Float();
-	startresHuman[2] = human["ore"].Float();
-	startresHuman[3] = human["sulfur"].Float();
-	startresHuman[4] = human["crystal"].Float();
-	startresHuman[5] = human["gems"].Float();
-	startresHuman[6] = human["gold"].Float();
-	startresHuman[7] = human["mithril"].Float();
-
-	startresAI[0] = ai["wood"].Float();
-	startresAI[1] = ai["mercury"].Float();
-	startresAI[2] = ai["ore"].Float();
-	startresAI[3] = ai["sulfur"].Float();
-	startresAI[4] = ai["crystal"].Float();
-	startresAI[5] = ai["gems"].Float();
-	startresAI[6] = ai["gold"].Float();
-	startresAI[7] = ai["mithril"].Float();
+
+	TResources startresAI(level["ai"]);
+	TResources startresHuman(level["human"]);
 
 
 	for (std::map<ui8,PlayerState>::iterator i = players.begin(); i!=players.end(); i++)
 	for (std::map<ui8,PlayerState>::iterator i = players.begin(); i!=players.end(); i++)
 	{
 	{

+ 1 - 1
lib/CObjectHandler.cpp

@@ -7267,7 +7267,7 @@ GrowthInfo::Entry::Entry(const std::string &format, int _count)
 GrowthInfo::Entry::Entry(int subID, EBuilding::EBuilding building, int _count)
 GrowthInfo::Entry::Entry(int subID, EBuilding::EBuilding building, int _count)
 	: count(_count)
 	: count(_count)
 {
 {
-	description = boost::str(boost::format("%s %+d") % VLC->buildh->buildings[subID][building]->Name() % count);
+	description = boost::str(boost::format("%s %+d") % VLC->townh->towns[subID].buildings[building]->Name() % count);
 }
 }
 
 
 CTownAndVisitingHero::CTownAndVisitingHero()
 CTownAndVisitingHero::CTownAndVisitingHero()

+ 265 - 126
lib/CTownHandler.cpp

@@ -17,162 +17,301 @@
  *
  *
  */
  */
 
 
+static std::string emptyStr = "";
+
+const std::string & CBuilding::Name() const
+{
+	if(name.length())
+		return name;
+	else if(vstd::contains(VLC->generaltexth->buildings,tid) && vstd::contains(VLC->generaltexth->buildings[tid],bid))
+		return VLC->generaltexth->buildings[tid][bid].first;
+	tlog2 << "Warning: Cannot find name text for building " << bid << "for " << tid << "town.\n";
+	return emptyStr;
+}
+
+const std::string & CBuilding::Description() const
+{
+	if(description.length())
+		return description;
+	else if(vstd::contains(VLC->generaltexth->buildings,tid) && vstd::contains(VLC->generaltexth->buildings[tid],bid))
+		return VLC->generaltexth->buildings[tid][bid].second;
+	tlog2 << "Warning: Cannot find description text for building " << bid << "for " << tid << "town.\n";
+	return emptyStr;
+}
+
+const std::string & CTown::Name() const
+{
+	if(name.length())
+		return name;
+	else
+		return VLC->generaltexth->townTypes[typeID];
+}
+
+const std::vector<std::string> & CTown::Names() const
+{
+	if(names.size())
+		return names;
+	else
+		return VLC->generaltexth->townNames[typeID];
+}
+
 CTownHandler::CTownHandler()
 CTownHandler::CTownHandler()
 {
 {
 	VLC->townh = this;
 	VLC->townh = this;
 }
 }
-CTownHandler::~CTownHandler()
+
+JsonNode readBuilding(CLegacyConfigParser & parser)
 {
 {
-	for( std::vector<std::map<int, Structure*> >::iterator i= structures.begin(); i!=structures.end(); i++)
-		for( std::map<int, Structure*>::iterator j = i->begin(); j!=i->end(); j++)
-			delete j->second;
+	JsonNode ret;
+	JsonNode & cost = ret["cost"];
+
+	const std::string resources [] = {"wood", "mercury", "ore", "sulfur", "crystal", "gems", "gold"};
+
+	BOOST_FOREACH(const std::string & resID, resources)
+		cost[resID].Float() = parser.readNumber();
+
+	parser.endLine();
+	return ret;
 }
 }
-void CTownHandler::loadStructures()
+
+void CTownHandler::loadLegacyData(JsonNode & dest)
 {
 {
-	int townID;
+	CLegacyConfigParser parser("DATA/BUILDING.TXT");
+	dest.Vector().resize(GameConstants::F_NUMBER);
+
+	parser.endLine(); // header
+	parser.endLine();
 
 
-	for (townID=0; townID<GameConstants::F_NUMBER; townID++)
+	//Unique buildings
+	for (size_t town=0; town<GameConstants::F_NUMBER; town++)
 	{
 	{
-		CTown town;
-		town.typeID=townID;
-		town.bonus=towns.size();
-		if (town.bonus==8) town.bonus=3;
-		towns.push_back(town);
-	}
+		JsonVector & buildList = dest.Vector()[town].Vector();
+
+		buildList.resize( 30 ); //prepare vector for first set of buildings
 
 
-	for(int x=0;x<towns.size();x++)
-		towns[x].creatures.resize(GameConstants::CREATURES_PER_TOWN);
-
-	structures.resize(GameConstants::F_NUMBER);
-
-	// read city properties
-	const JsonNode config(ResourceID("config/buildings.json"));
-
-	// Iterate for each city type
-	townID = 0;
-	BOOST_FOREACH(const JsonNode &town_node, config["town_type"].Vector()) {
-		int level;
-		std::map<int, Structure*> &town = structures[townID];
-
-		// Read buildings coordinates for that city
-		BOOST_FOREACH(const JsonNode &node, town_node["defnames"].Vector()) {
-			Structure *vinya = new Structure;
-			const JsonNode *value;
-
-			vinya->group = -1;
-			vinya->townID = townID;
-			vinya->ID = node["id"].Float();
-			vinya->defName = node["defname"].String();
-			vinya->name = vinya->defName; //TODO - use normal names
-			vinya->pos.x = node["x"].Float();
-			vinya->pos.y = node["y"].Float();
-			vinya->pos.z = 0;
-			
-			value = &node["border"];
-			if (!value->isNull())
-				vinya->borderName = value->String();
-
-			value = &node["area"];
-			if (!value->isNull())
-				vinya->areaName = value->String();
-
-			town[vinya->ID] = vinya;
+		parser.endLine(); //header
+		parser.endLine();
+
+		int buildID = 17;
+		do
+		{
+			buildList[buildID] = readBuilding(parser);
+			buildID++;
 		}
 		}
+		while (!parser.isNextEntryEmpty());
+	}
+
+	// Common buildings
+	parser.endLine(); // header
+	parser.endLine();
+	parser.endLine();
+
+	int buildID = 0;
+	do
+	{
+		JsonNode building = readBuilding(parser);
 
 
-		// Read buildings blit order for that city
-		int itr = 1;
-		BOOST_FOREACH(const JsonNode &node, town_node["blit_order"].Vector()) {
-			int buildingID = node.Float();
-
-			/* Find the building and set its order. */
-			std::map<int, Structure*>::iterator i2 = town.find(buildingID);
-			if (i2 != (town.end()))
-				i2->second->pos.z = itr++;
-			else
-				tlog3 << "Warning1: No building " << buildingID << " in the castle " << townID << std::endl;
+		for (size_t town=0; town<GameConstants::F_NUMBER; town++)
+			dest.Vector()[town].Vector()[buildID] = building;
+
+		buildID++;
+	}
+	while (!parser.isNextEntryEmpty());
+
+	parser.endLine(); //header
+	parser.endLine();
+
+	//Dwellings
+	for (size_t town=0; town<GameConstants::F_NUMBER; town++)
+	{
+		parser.endLine(); //header
+		parser.endLine();
+
+		do
+		{
+			dest.Vector()[town].Vector().push_back(readBuilding(parser));
 		}
 		}
+		while (!parser.isNextEntryEmpty());
+	}
+}
+
+void CTownHandler::loadBuilding(CTown &town, const JsonNode & source)
+{
+	CBuilding * ret = new CBuilding;
+
+	ret->name = source["name"].String();
+	ret->description = source["description"].String();
+
+	ret->tid = town.typeID;
+	ret->bid = source["id"].Float();
+
+	ret->resources = TResources(source["cost"]);
+
+	BOOST_FOREACH(const JsonNode &building, source["requires"].Vector())
+		ret->requirements.insert(building.Float());
+
+	town.buildings[ret->bid] = ret;
+}
+
+void CTownHandler::loadBuildings(CTown &town, const JsonNode & source)
+{
+	BOOST_FOREACH(const JsonNode &node, source.Vector())
+	{
+		loadBuilding(town, node);
+	}
+}
 
 
-		// Read creatures belonging to that city
-		level = 0;
-		BOOST_FOREACH(const JsonNode &list, town_node["creatures"].Vector())
+void CTownHandler::loadStructure(CTown &town, const JsonNode & source)
+{
+	CStructure * ret = new CStructure;
+
+	ret->ID = source["id"].Float();
+	ret->pos.x = source["x"].Float();
+	ret->pos.y = source["y"].Float();
+	ret->pos.z = 0;
+
+	ret->defName = source["defname"].String();
+	ret->borderName = source["border"].String();
+	ret->areaName = source["area"].String();
+
+	ret->group = -1;
+	ret->townID = town.typeID;
+
+	town.clientInfo.structures[ret->ID] = ret;
+}
+
+void CTownHandler::loadStructures(CTown &town, const JsonNode & source)
+{
+	BOOST_FOREACH(const JsonNode &node, source["structures"].Vector())
+	{
+		loadStructure(town, node);
+	}
+
+	// Read buildings blit order for that city
+	int itr = 1;
+	BOOST_FOREACH(const JsonNode &node, source["blit_order"].Vector())
+	{
+		int buildingID = node.Float();
+
+		/* Find the building and set its order. */
+		auto i2 = town.clientInfo.structures.find(buildingID);
+		if (i2 != (town.clientInfo.structures.end()))
+			i2->second->pos.z = itr++;
+	}
+
+	// Iterate for each group for that city
+	int groupID = 0;
+	BOOST_FOREACH(const JsonNode &group, source["groups"].Vector())
+	{
+		groupID++;
+
+		// Iterate for each bulding value in the group
+		BOOST_FOREACH(const JsonNode &value, group.Vector())
 		{
 		{
-			BOOST_FOREACH(const JsonNode &node, list.Vector())
+			auto buildingIter = town.clientInfo.structures.find(value.Float());
+
+			if (buildingIter != town.clientInfo.structures.end())
 			{
 			{
-				towns[townID].creatures[level].push_back(node.Float());
+				buildingIter->second->group = groupID;
 			}
 			}
-			level ++;
 		}
 		}
+	}
+}
 
 
-		//  Horde building creature level
-		level = 0;
-		BOOST_FOREACH(const JsonNode &node, town_node["horde"].Vector()) {
-			towns[townID].hordeLvl[level] = node.Float();
-			level ++;
+void CTownHandler::loadTownHall(CTown &town, const JsonNode & source)
+{
+	BOOST_FOREACH(const JsonNode &row, source.Vector())
+	{
+		std::vector< std::vector<int> > hallRow;
+
+		BOOST_FOREACH(const JsonNode &box, row.Vector())
+		{
+			std::vector<int> hallBox;
+
+			BOOST_FOREACH(const JsonNode &value, box.Vector())
+			{
+				hallBox.push_back(value.Float());
+			}
+			hallRow.push_back(hallBox);
 		}
 		}
+		town.clientInfo.hallSlots.push_back(hallRow);
+	}
+}
+
+void CTownHandler::loadTown(std::vector<CTown> &towns, const JsonNode & source)
+{
+	towns.push_back(CTown());
+	CTown & town = towns.back();
 
 
-		// Misc.
-		towns[townID].mageLevel = town_node["mage_guild"].Float();
-		towns[townID].primaryRes  = town_node["primary_resource"].Float();
-		towns[townID].warMachine = town_node["war_machine"].Float();
+	//TODO: allow loading name and names vector from json and from h3 txt's
 
 
-		townID ++;
+	town.typeID = towns.size() - 1;
+
+	town.bonus = town.typeID;
+	if (town.bonus==8)
+		town.bonus=3;
+
+	town.clientInfo.hallBackground = source["hallBackground"].String();
+	town.mageLevel = source["mage_guild"].Float();
+	town.primaryRes  = source["primary_resource"].Float();
+	town.warMachine = source["war_machine"].Float();
+
+	//  Horde building creature level
+	BOOST_FOREACH(const JsonNode &node, source["horde"].Vector())
+	{
+		town.hordeLvl[town.hordeLvl.size()] = node.Float();
 	}
 	}
 
 
-	int group_num=0;
-
-	// Iterate for each city
-	BOOST_FOREACH(const JsonNode &town_node, config["town_groups"].Vector()) {
-		townID = town_node["id"].Float();
-
-		// Iterate for each group for that city
-		BOOST_FOREACH(const JsonNode &group, town_node["groups"].Vector()) {
-
-			group_num ++;
-		
-			// Iterate for each bulding value in the group
-			BOOST_FOREACH(const JsonNode &value, group.Vector()) {
-				int buildingID = value.Float();
-
-				std::vector<std::map<int, Structure*> >::iterator i;
-				std::map<int, Structure*>::iterator i2;
-
-				if (townID >= 0) {
-					if ((i = structures.begin() + townID) != structures.end()) {
-						if ((i2=(i->find(buildingID)))!=(i->end()))
-							i2->second->group = group_num;
-						else
-							tlog3 << "Warning3: No building "<<buildingID<<" in the castle "<<townID<<std::endl;
-					} 
-					else
-						tlog3 << "Warning3: Castle "<<townID<<" not defined."<<std::endl;
-				} else {
-					// Set group for selected building in ALL castles
-					for (i=structures.begin();i!=structures.end();i++) {
-						for(i2=i->begin(); i2!=i->end(); i2++) {
-							if(i2->first == buildingID)	{
-								i2->second->group = group_num;
-								break;
-							}
-						}
-					}
-				}
-			}
+	BOOST_FOREACH(const JsonNode &list, source["creatures"].Vector())
+	{
+		std::vector<si32> level;
+		BOOST_FOREACH(const JsonNode &node, list.Vector())
+		{
+			level.push_back(node.Float());
 		}
 		}
+		town.creatures.push_back(level);
 	}
 	}
+
+	loadTownHall(town,   source["hallSlots"]);
+	loadBuildings(town,  source["buildings"]);
+	loadStructures(town, source);
 }
 }
 
 
-const std::string & CTown::Name() const
+void CTownHandler::loadTowns(std::vector<CTown> &towns, const JsonNode & source)
 {
 {
-	if(name.length())
-		return name;
-	else
-		return VLC->generaltexth->townTypes[typeID];
+	BOOST_FOREACH(const JsonNode & node, source.Vector())
+	{
+		loadTown(towns, node);
+	}
+
+	// ensure that correct number of town have been loaded. Safe to remove
+	assert(towns.size() == GameConstants::F_NUMBER);
 }
 }
 
 
-const std::vector<std::string> & CTown::Names() const
+void CTownHandler::load()
 {
 {
-	if(names.size())
-		return names;
-	else 
-		return VLC->generaltexth->townNames[typeID];
+	JsonNode buildingsConf(ResourceID("config/buildings.json"));
+
+	JsonNode legacyConfig;
+	loadLegacyData(legacyConfig);
+
+	// semi-manually merge legacy config with towns json
+	// legacy config have only one item: town buildings stored in 2d vector
+	size_t townsToMerge = std::min(buildingsConf["towns"].Vector().size(), legacyConfig.Vector().size());
+	for (size_t i=0; i< townsToMerge; i++)
+	{
+		JsonNode & buildings = buildingsConf["towns"].Vector()[i]["buildings"];
+		BOOST_FOREACH(JsonNode & building, buildings.Vector())
+		{
+			if (vstd::contains(building.Struct(), "id"))
+			{
+				JsonNode & legacyBuilding = legacyConfig.Vector()[i].Vector()[building["id"].Float()];
+
+				if (!legacyBuilding.isNull())
+					JsonNode::merge(building, legacyBuilding);
+			}
+		}
+	}
+
+	loadTowns(towns, buildingsConf["towns"]);
 }
 }

+ 103 - 31
lib/CTownHandler.h

@@ -1,6 +1,7 @@
 #pragma once
 #pragma once
 
 
-
+#include "ConstTransitivePtr.h"
+#include "ResourceSet.h"
 #include "int3.h"
 #include "int3.h"
 
 
 /*
 /*
@@ -13,66 +14,137 @@
  *
  *
  */
  */
 
 
-class CBuilding;
-class CSpell;
-class CHero;
-class CGTownInstance;
-class DLL_LINKAGE CTown
-{
-	std::string name; //name of type
-public:
-
-	std::vector<std::string> names; //names of the town instances
-	std::vector<std::vector<int> > creatures; //level (from 0) -> list of creatures on this tier
-	std::map<int,int> hordeLvl; //[0] - first horde building creature level; [1] - second horde building (-1 if not present)
-	ui32 mageLevel; //max available mage guild level
-	int bonus; //pic number
-	ui16 primaryRes, warMachine;
-	ui8 typeID;
+class CLegacyConfigParser;
+class JsonNode;
 
 
+/// a typical building encountered in every castle ;]
+/// this is structure available to both client and server
+/// contains all mechanics-related data about town structures
+class DLL_LINKAGE CBuilding
+{
+	std::string name;
+	std::string description;
 
 
-	const std::vector<std::string> & Names() const;
-	const std::string & Name() const;
-	void Name(const std::string & val) { name = val; }
+public:
+	si32 tid, bid; //town ID and structure ID
+	TResources resources;
+	std::set<int> requirements; //set of required buildings
 
 
+	const std::string &Name() const;
+	const std::string &Description() const;
 
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 	{
-		h & names & creatures & hordeLvl & mageLevel & bonus
-			& primaryRes & warMachine & typeID;
+		h & tid & bid & resources & name & description & requirements;
 	}
 	}
+
+	friend class CTownHandler;
 };
 };
 
 
-struct DLL_LINKAGE Structure
+/// This is structure used only by client
+/// Consists of all gui-related data about town structures
+/// Should be mode from lib to client
+struct DLL_LINKAGE CStructure
 {
 {
 	int ID;
 	int ID;
 	int3 pos;
 	int3 pos;
-	std::string defName, borderName, areaName, name;
+	std::string defName, borderName, areaName;
 	int townID, group;
 	int townID, group;
 
 
-	bool operator<(const Structure & p2) const
+	bool operator<(const CStructure & p2) const
 	{
 	{
 		if(pos.z != p2.pos.z)
 		if(pos.z != p2.pos.z)
 			return (pos.z) < (p2.pos.z);
 			return (pos.z) < (p2.pos.z);
 		else
 		else
 			return (ID) < (p2.ID);
 			return (ID) < (p2.ID);
 	}
 	}
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & ID & pos & defName & borderName & areaName & townID & group;
+	}
+};
+
+class DLL_LINKAGE CTown
+{
+	std::string name; //name of type
+	std::vector<std::string> names; //names of the town instances
+
+public:
+	ui32 typeID;
+
+	/// level -> list of creatures on this tier
+	/// TODO: replace with pointers to CCreature?
+	std::vector<std::vector<si32> > creatures;
+
+	bmap<int, ConstTransitivePtr<CBuilding> > buildings;
+
+	// should be removed at least from configs in favour of auto-detection
+	std::map<int,int> hordeLvl; //[0] - first horde building creature level; [1] - second horde building (-1 if not present)
+	ui32 mageLevel; //max available mage guild level
+	int bonus; //pic number
+	ui16 primaryRes, warMachine;
+
+	// Client-only data. Should be moved away from lib
+	struct ClientInfo
+	{
+		std::string hallBackground;
+		std::vector< std::vector< std::vector<int> > > hallSlots; /// vector[row][column] = list of buildings in this slot
+		bmap<int, ConstTransitivePtr<CStructure> > structures;
+
+		template <typename Handler> void serialize(Handler &h, const int version)
+		{
+			h & hallBackground & hallSlots & structures;
+		}
+	} clientInfo;
+
+	const std::vector<std::string> & Names() const;
+	const std::string & Name() const;
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & name & names & typeID & creatures & buildings & hordeLvl & mageLevel & bonus
+			& primaryRes & warMachine & clientInfo;
+	}
+
+	friend class CTownHandler;
 };
 };
 
 
 class DLL_LINKAGE CTownHandler
 class DLL_LINKAGE CTownHandler
 {
 {
+	/// loads CBuilding's into town
+	void loadBuilding(CTown &town, const JsonNode & source);
+	void loadBuildings(CTown &town, const JsonNode & source);
+
+	/// loads CStructure's into town
+	void loadStructure(CTown &town, const JsonNode & source);
+	void loadStructures(CTown &town, const JsonNode & source);
+
+	/// loads town hall vector (hallSlots)
+	void loadTownHall(CTown &town, const JsonNode & source);
+
+	/// load town and insert it into towns vector
+	void loadTown(std::vector<CTown> &towns, const JsonNode & source);
+
+	/// main loading function, 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 loadTowns(std::vector<CTown> &towns, const JsonNode & source);
+
+	/// load all available data from h3 txt(s) into json structure using format similar to vcmi configs
+	/// returns 2d array [townID] [buildID] of buildings
+	void loadLegacyData(JsonNode & dest);
 public:
 public:
 	std::vector<CTown> towns;
 	std::vector<CTown> towns;
-	std::vector<std::map<int, Structure*> > structures; // <town ID, <structure ID, structure>>
 
 
-	CTownHandler(); //c-tor
-	~CTownHandler(); //d-tor
-	void loadStructures();
+	CTownHandler(); //c-tor, set pointer in VLC to this
+
+	/// "entry point" for towns loading.
+	/// reads legacy txt's from H3 + vcmi json, merges them
+	/// and loads resulting structure to game using loadTowns method
+	void load();
 
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 	{
 		h & towns;
 		h & towns;
-		if(!h.saving)
-			loadStructures();
 	}
 	}
 };
 };

+ 4 - 4
lib/IGameCallback.cpp

@@ -547,7 +547,7 @@ int CGameInfoCallback::canBuildStructure( const CGTownInstance *t, int ID )
 	if(t->builded >= GameConstants::MAX_BUILDING_PER_TURN)
 	if(t->builded >= GameConstants::MAX_BUILDING_PER_TURN)
 		ret = EBuildingState::CANT_BUILD_TODAY; //building limit
 		ret = EBuildingState::CANT_BUILD_TODAY; //building limit
 
 
-	CBuilding * pom = VLC->buildh->buildings[t->subID][ID];
+	CBuilding * pom = t->town->buildings[ID];
 
 
 	if(!pom)
 	if(!pom)
 		return EBuildingState::BUILDING_ERROR;
 		return EBuildingState::BUILDING_ERROR;
@@ -603,7 +603,7 @@ std::set<int> CGameInfoCallback::getBuildingRequiments( const CGTownInstance *t,
 
 
 	std::set<int> used;
 	std::set<int> used;
 	used.insert(ID);
 	used.insert(ID);
-	std::set<int> reqs = VLC->buildh->buildings[t->subID][ID]->requirements;
+	std::set<int> reqs = t->town->buildings[ID]->requirements;
 
 
 	while(true)
 	while(true)
 	{
 	{
@@ -614,8 +614,8 @@ std::set<int> CGameInfoCallback::getBuildingRequiments( const CGTownInstance *t,
 			{
 			{
 				used.insert(*i);
 				used.insert(*i);
 				for(
 				for(
-					std::set<int>::iterator j=VLC->buildh->buildings[t->subID][*i]->requirements.begin();
-					j!= VLC->buildh->buildings[t->subID][*i]->requirements.end();
+					std::set<int>::iterator j= t->town->buildings[*i]->requirements.begin();
+					j!= t->town->buildings[*i]->requirements.end();
 				j++)
 				j++)
 				{
 				{
 					reqs.insert(*j);//creating full list of requirements
 					reqs.insert(*j);//creating full list of requirements

+ 32 - 0
lib/JsonNode.cpp

@@ -236,6 +236,38 @@ const JsonNode & JsonNode::operator[](std::string child) const
 		return it->second;
 		return it->second;
 	return nullNode;
 	return nullNode;
 }
 }
+////////////////////////////////////////////////////////////////////////////////
+
+void JsonNode::merge(JsonNode & dest, JsonNode & source)
+{
+	switch (source.getType())
+	{
+		break; case DATA_NULL:   dest.setType(DATA_NULL);
+		break; case DATA_BOOL:   std::swap(dest.Bool(), source.Bool());
+		break; case DATA_FLOAT:  std::swap(dest.Float(), source.Float());
+		break; case DATA_STRING: std::swap(dest.String(), source.String());
+		break; case DATA_VECTOR:
+		{
+			//reserve place and *move* data from source to dest
+			source.Vector().reserve(source.Vector().size() + dest.Vector().size());
+
+			std::move(source.Vector().begin(), source.Vector().end(),
+			          std::back_inserter(dest.Vector()));
+		}
+		break; case DATA_STRUCT:
+		{
+			//recursively merge all entries from struct
+			BOOST_FOREACH(auto & node, source.Struct())
+				merge(dest[node.first], node.second);
+		}
+	}
+}
+
+void JsonNode::mergeCopy(JsonNode & dest, JsonNode source)
+{
+	// uses copy created in stack to safely merge two nodes
+	merge(dest, source);
+}
 
 
 ////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////
 
 

+ 11 - 0
lib/JsonNode.h

@@ -94,6 +94,17 @@ public:
 
 
 	//error value for const operator[]
 	//error value for const operator[]
 	static const JsonNode nullNode;
 	static const JsonNode nullNode;
+
+	/// recursivly merges source into dest, replacing identical fields
+	/// struct : recursively calls this function
+	/// arrays : append array in dest with data from source
+	/// values : value in source will replace value in dest
+	/// null   : if value in source is present but set to null it will delete entry in dest
+
+	/// this function will destroy data in source
+	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);
 };
 };
 
 
 class JsonWriter
 class JsonWriter

+ 15 - 1
lib/ResourceSet.cpp

@@ -1,10 +1,24 @@
 #include "StdInc.h"
 #include "StdInc.h"
 #include "ResourceSet.h"
 #include "ResourceSet.h"
 #include "GameConstants.h"
 #include "GameConstants.h"
-
+#include "JsonNode.h"
+
 Res::ResourceSet::ResourceSet()
 Res::ResourceSet::ResourceSet()
 {
 {
 	resize(GameConstants::RESOURCE_QUANTITY, 0);
 	resize(GameConstants::RESOURCE_QUANTITY, 0);
+}
+
+Res::ResourceSet::ResourceSet(const JsonNode & node)
+{
+	resize(GameConstants::RESOURCE_QUANTITY, 0);
+	at(0) = node["wood"].Float();
+	at(1) = node["mercury"].Float();
+	at(2) = node["ore"].Float();
+	at(3) = node["sulfur"].Float();
+	at(4) = node["crystal"].Float();
+	at(5) = node["gems"].Float();
+	at(6) = node["gold"].Float();
+	at(7) = node["mithril"].Float();
 }
 }
 
 
 bool Res::ResourceSet::nonZero() const
 bool Res::ResourceSet::nonZero() const

+ 4 - 0
lib/ResourceSet.h

@@ -3,6 +3,8 @@
 typedef si32 TResource;
 typedef si32 TResource;
 typedef si64 TResourceCap; //to avoid overflow when adding integers. Signed values are easier to control.
 typedef si64 TResourceCap; //to avoid overflow when adding integers. Signed values are easier to control.
 
 
+class JsonNode;
+
 namespace Res
 namespace Res
 {
 {
 	class ResourceSet;
 	class ResourceSet;
@@ -18,6 +20,8 @@ namespace Res
 	{
 	{
 	public:
 	public:
 		DLL_LINKAGE ResourceSet();
 		DLL_LINKAGE ResourceSet();
+		// read resources set from json. Format example: { "gold": 500, "wood":5 }
+		DLL_LINKAGE ResourceSet(const JsonNode & node);
 
 
 
 
 #define scalarOperator(OPSIGN)									\
 #define scalarOperator(OPSIGN)									\

+ 1 - 7
lib/VCMI_Lib.cpp

@@ -87,7 +87,7 @@ void LibClasses::init()
 	tlog0<<"\tCreature handler: "<<pomtime.getDiff()<<std::endl;
 	tlog0<<"\tCreature handler: "<<pomtime.getDiff()<<std::endl;
 
 
 	townh = new CTownHandler;
 	townh = new CTownHandler;
-	townh->loadStructures();
+	townh->load();
 	tlog0<<"\tTown handler: "<<pomtime.getDiff()<<std::endl;
 	tlog0<<"\tTown handler: "<<pomtime.getDiff()<<std::endl;
 
 
 	objh = new CObjectHandler;
 	objh = new CObjectHandler;
@@ -98,10 +98,6 @@ void LibClasses::init()
 	dobjinfo->load();
 	dobjinfo->load();
 	tlog0<<"\tDef information handler: "<<pomtime.getDiff()<<std::endl;
 	tlog0<<"\tDef information handler: "<<pomtime.getDiff()<<std::endl;
 
 
-	buildh = new CBuildingHandler;
-	buildh->loadBuildings();
-	tlog0<<"\tBuilding handler: "<<pomtime.getDiff()<<std::endl;
-
 	spellh = new CSpellHandler;
 	spellh = new CSpellHandler;
 	spellh->loadSpells();
 	spellh->loadSpells();
 	tlog0<<"\tSpell handler: "<<pomtime.getDiff()<<std::endl;
 	tlog0<<"\tSpell handler: "<<pomtime.getDiff()<<std::endl;
@@ -118,7 +114,6 @@ void LibClasses::clear()
 	delete townh;
 	delete townh;
 	delete objh;
 	delete objh;
 	delete dobjinfo;
 	delete dobjinfo;
-	delete buildh;
 	delete spellh;
 	delete spellh;
 	delete modh;
 	delete modh;
 	makeNull();
 	makeNull();
@@ -133,7 +128,6 @@ void LibClasses::makeNull()
 	townh = NULL;
 	townh = NULL;
 	objh = NULL;
 	objh = NULL;
 	dobjinfo = NULL;
 	dobjinfo = NULL;
-	buildh = NULL;
 	spellh = NULL;
 	spellh = NULL;
 	modh = NULL;
 	modh = NULL;
 }
 }

+ 1 - 2
lib/VCMI_Lib.h

@@ -30,7 +30,6 @@ public:
 	CHeroHandler * heroh;
 	CHeroHandler * heroh;
 	CCreatureHandler * creh;
 	CCreatureHandler * creh;
 	CSpellHandler * spellh;
 	CSpellHandler * spellh;
-	CBuildingHandler * buildh;
 	CObjectHandler * objh;
 	CObjectHandler * objh;
 	CDefObjInfoHandler * dobjinfo;
 	CDefObjInfoHandler * dobjinfo;
 	CTownHandler * townh;
 	CTownHandler * townh;
@@ -48,7 +47,7 @@ public:
 	void callWhenDeserializing(); //should be called only by serialize !!!
 	void callWhenDeserializing(); //should be called only by serialize !!!
 	template <typename Handler> void serialize(Handler &h, const int version)
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 	{
-		h & heroh & arth & creh & townh & objh & dobjinfo & buildh & spellh & modh & IS_AI_ENABLED;;
+		h & heroh & arth & creh & townh & objh & dobjinfo & spellh & modh & IS_AI_ENABLED;;
 		if(!h.saving)
 		if(!h.saving)
 		{
 		{
 			callWhenDeserializing();
 			callWhenDeserializing();

+ 2 - 2
server/CGameHandler.cpp

@@ -2417,7 +2417,7 @@ bool CGameHandler::disbandCreature( si32 id, ui8 pos )
 bool CGameHandler::buildStructure( si32 tid, si32 bid, bool force /*=false*/ )
 bool CGameHandler::buildStructure( si32 tid, si32 bid, bool force /*=false*/ )
 {
 {
 	CGTownInstance * t = static_cast<CGTownInstance*>(gs->map->objects[tid].get());
 	CGTownInstance * t = static_cast<CGTownInstance*>(gs->map->objects[tid].get());
-	CBuilding * b = VLC->buildh->buildings[t->subID][bid];
+	CBuilding * b = t->town->buildings[bid];
 
 
 	if(!force)
 	if(!force)
 	{
 	{
@@ -3729,7 +3729,7 @@ void CGameHandler::playerMessage( ui8 player, const std::string &message )
 		CGTownInstance *town = gs->getTown(gs->getPlayer(player)->currentSelection);
 		CGTownInstance *town = gs->getTown(gs->getPlayer(player)->currentSelection);
 		if (town)
 		if (town)
 		{
 		{
-			BOOST_FOREACH (CBuildingHandler::TBuildingsMap::value_type &build, VLC->buildh->buildings[town->subID])
+			BOOST_FOREACH (auto & build, town->town->buildings)
 			{
 			{
 				if (!vstd::contains(town->builtBuildings, build.first)
 				if (!vstd::contains(town->builtBuildings, build.first)
 				 && !build.second->Name().empty())
 				 && !build.second->Name().empty())