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

- it is possible to read json file with vector
- town configuration:
- - all town-related texts are now in TownHandler
- - alignments are now part of faction
- - removed CTown::bonus field

Ivan Savenko 13 жил өмнө
parent
commit
306d64b0c4

+ 1 - 0
AI/BattleAI/BattleAI.cpp

@@ -764,6 +764,7 @@ void CBattleAI::attemptCastingSpell()
 			}
 		default:
 			assert(0);
+			return 0;
 		}
 	};
 

+ 38 - 23
client/CPreGame.cpp

@@ -2293,6 +2293,41 @@ OptionsTab::SelectedBox::SelectedBox( SelType Which, ui8 Player )
 	addUsedEvents(RCLICK);
 }
 
+size_t OptionsTab::SelectedBox::getBonusImageIndex() const
+{
+	enum EBonusSelection //frames of bonuses file
+	{
+		WOOD_ORE = 0,   CRYSTAL = 1,    GEM  = 2,
+		MERCURY  = 3,   SULFUR  = 5,    GOLD = 8,
+		ARTIFACT = 9,   RANDOM  = 10,
+		WOOD = 0,       ORE     = 0,    MITHRIL = 10 // resources unavailable in bonuses file
+	};
+
+	const PlayerSettings &s = SEL->sInfo.playerInfos[player];
+	switch(s.bonus)
+	{
+	case -1: return RANDOM;
+	case 0:  return ARTIFACT;
+	case 1:  return GOLD;
+	case 2:
+		switch (CGI->townh->towns[s.castle].primaryRes)
+		{
+		case 127          : return WOOD_ORE;
+		case Res::WOOD    : return WOOD;
+		case Res::MERCURY : return MERCURY;
+		case Res::ORE     : return ORE;
+		case Res::SULFUR  : return SULFUR;
+		case Res::CRYSTAL : return CRYSTAL;
+		case Res::GEMS    : return GEM;
+		case Res::GOLD    : return GOLD;
+		case Res::MITHRIL : return MITHRIL;
+		}
+	default:
+		assert(0);
+		return 0;
+	}
+}
+
 SDL_Surface * OptionsTab::SelectedBox::getImg() const
 {
 	const PlayerSettings &s = SEL->sInfo.playerInfos[player];
@@ -2323,29 +2358,9 @@ SDL_Surface * OptionsTab::SelectedBox::getImg() const
 		}
 		break;
 	case BONUS:
-		{
-			int pom;
-			switch (s.bonus)
-			{
-			case -1:
-				pom=10;
-				break;
-			case 0:
-				pom=9;
-				break;
-			case 1:
-				pom=8;
-				break;
-			case 2:
-				pom=CGI->townh->towns[s.castle].bonus;
-				break;
-			default:
-				assert(0);
-			}
-			return CGP->bonuses->ourImages[pom].bitmap;
-		}
+			return CGP->bonuses->ourImages[getBonusImageIndex()].bitmap;
 	default:
-		return NULL;
+		return nullptr;
 	}
 }
 
@@ -2356,7 +2371,7 @@ const std::string * OptionsTab::SelectedBox::getText() const
 	{
 	case TOWN:
 		if (s.castle < GameConstants::F_NUMBER  &&  s.castle >= 0)
-			return &CGI->townh->towns[s.castle].Name();
+			return &CGI->townh->factions[s.castle].name;
 		else if (s.castle == -1)
 			return &CGI->generaltexth->allTexts[522];
 		else if (s.castle == -2)

+ 2 - 0
client/CPreGame.h

@@ -187,11 +187,13 @@ class OptionsTab : public CIntObject
 	CPicture *bg;
 public:
 	enum SelType {TOWN, HERO, BONUS};
+
 	struct SelectedBox : public CIntObject //img with current town/hero/bonus
 	{
 		SelType which;
 		ui8 player; //serial nr
 
+		size_t getBonusImageIndex() const;
 		SDL_Surface *getImg() const;
 		const std::string *getText() const;
 

+ 10 - 0
config/buildings.json

@@ -3,6 +3,7 @@
 	{
 		"index" : 0,
 		"nativeTerrain": "grass",
+		"alignment" : "good",
 		"creatureBackground" :
 		{
 			"120px" : "TPCASCAS",
@@ -183,6 +184,7 @@
 	{
 		"index" : 1,
 		"nativeTerrain": "grass",
+		"alignment" : "good",
 		"creatureBackground" :
 		{
 			"120px" : "TPCASRAM",
@@ -368,6 +370,7 @@
 	{
 		"index" : 2,
 		"nativeTerrain" : "snow",
+		"alignment" : "good",
 		"creatureBackground" :
 		{
 			"120px" : "TPCASTOW",
@@ -545,6 +548,7 @@
 	{
 		"index" : 3,
 		"nativeTerrain": "lava",
+		"alignment" : "evil",
 		"creatureBackground" :
 		{
 			"120px" : "TPCASINF",
@@ -724,6 +728,7 @@
 	{
 		"index" : 4,
 		"nativeTerrain": "dirt",
+		"alignment" : "evil",
 		"creatureBackground" :
 		{
 			"120px" : "TPCASNEC",
@@ -906,6 +911,7 @@
 	{
 		"index" : 5,
 		"nativeTerrain": "subterra",
+		"alignment" : "evil",
 		"creatureBackground" :
 		{
 			"120px" : "TPCASDUN",
@@ -1082,6 +1088,7 @@
 	{
 		"index" : 6,
 		"nativeTerrain": "rough",
+		"alignment" : "neutral",
 		"creatureBackground" :
 		{
 			"120px" : "TPCASSTR",
@@ -1257,6 +1264,7 @@
 	{
 		"index" : 7,
 		"nativeTerrain": "swamp",
+		"alignment" : "neutral",
 		"creatureBackground" :
 		{
 			"120px" : "TPCASFOR",
@@ -1435,6 +1443,7 @@
 	{
 		"index" : 8,
 		"nativeTerrain": "grass",
+		"alignment" : "neutral",
 		"creatureBackground" :
 		{
 			"120px" : "TPCASELE",
@@ -1615,6 +1624,7 @@
 	"neutral" :
 	{
 		"index" : 9,
+		"alignment" : "neutral",
 		"creatureBackground" :
 		{
 			"120px" : "TPCASNEU",

+ 3 - 28
lib/CCreatureHandler.cpp

@@ -24,12 +24,7 @@ CCreatureHandler::CCreatureHandler()
 {
 	VLC->creh = this;
 
-	// Set the faction alignments to the defaults:
-	// Good: Castle, Rampart, Tower
-	// Evil: Inferno, Necropolis, Dungeon
-	// Neutral: Stronghold, Fortess, Conflux, neutrals
-	factionAlignments += 1, 1, 1, -1, -1, -1, 0, 0, 0, 0;
-	doubledCreatures +=  4, 14, 20, 28, 44, 60, 70, 72, 85, 86, 100, 104; //according to Strategija
+	doubledCreatures +=  4, 14, 20, 28, 44, 60, 70, 72, 85, 86, 100, 104; //FIXME: move to creature config //according to Strategija
 
 	allCreatures.setDescription("All creatures");
 	creaturesOfLevel[0].setDescription("Creatures of unnormalized tier");
@@ -94,7 +89,7 @@ bool CCreature::isUndead() const
  */
 bool CCreature::isGood () const
 {
-	return VLC->creh->isGood(faction);
+	return VLC->townh->factions[faction].alignment == EAlignment::GOOD;
 }
 
 /**
@@ -103,7 +98,7 @@ bool CCreature::isGood () const
  */
 bool CCreature::isEvil () const
 {
-	return VLC->creh->isEvil(faction);
+	return VLC->townh->factions[faction].alignment == EAlignment::EVIL;
 }
 
 si32 CCreature::maxAmount(const std::vector<si32> &res) const //how many creatures can be bought
@@ -151,26 +146,6 @@ bool CCreature::isItNativeTerrain(int terrain) const
 	return VLC->townh->factions[faction].nativeTerrain == terrain;
 }
 
-/**
- * Determines if a faction is good.
- * @param ID of the faction.
- * @return true if the faction is good, false otherwise.
- */
-bool CCreatureHandler::isGood (si8 faction) const
-{
-	return factionAlignments[faction] == 1;
-}
-
-/**
- * Determines if a faction is evil.
- * @param ID of the faction.
- * @return true if the faction is evil, false otherwise.
- */
-bool CCreatureHandler::isEvil (si8 faction) const
-{
-	return factionAlignments[faction] == -1;
-}
-
 static void AddAbility(CCreature *cre, const JsonVector &ability_vec)
 {
 	Bonus *nsf = new Bonus();

+ 0 - 4
lib/CCreatureHandler.h

@@ -132,7 +132,6 @@ public:
 	std::set<TCreature> doubledCreatures; //they get double week
 	std::vector<ConstTransitivePtr<CCreature> > creatures; //creature ID -> creature info
 	bmap<std::string,int> nameToID;
-	std::vector<si8> factionAlignments; //1 for good, 0 for neutral and -1 for evil with faction ID as index
 	int factionToTurretCreature[GameConstants::F_NUMBER]; //which creature's animation should be used to dispaly creature in turret while siege
 
 	//stack exp
@@ -156,9 +155,6 @@ public:
 	void loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigParser &parser);
 	int stringToNumber(std::string & s);//help function for parsing CREXPBON.txt
 
-	bool isGood (si8 faction) const;
-	bool isEvil (si8 faction) const;
-
 	int pickRandomMonster(const boost::function<int()> &randGen = 0, int tier = -1) const; //tier <1 - CREATURES_PER_TOWN> or -1 for any
 	void addBonusForTier(int tier, Bonus *b); //tier must be <1-7>
 	void addBonusForAllCreatures(Bonus *b);

+ 2 - 2
lib/CGameState.cpp

@@ -389,7 +389,7 @@ CGHeroInstance * CGameState::HeroesPool::pickHeroFor(bool native, TPlayerColor p
 
 	if(player>=GameConstants::PLAYER_LIMIT)
 	{
-		tlog1 << "Cannot pick hero for " << town->Name() << ". Wrong owner!\n";
+		tlog1 << "Cannot pick hero for " << town->typeID << ". Wrong owner!\n";
 		return NULL;
 	}
 
@@ -1323,7 +1323,7 @@ void CGameState::init(StartInfo * si)
 		if(!vti->town)
 			vti->town = &VLC->townh->towns[vti->subID];
 		if (vti->name.length()==0) // if town hasn't name we draw it
-			vti->name = vti->town->Names()[ran()%vti->town->Names().size()];
+			vti->name = vti->town->names[ran()%vti->town->names.size()];
 
 		//init buildings
 		if(vti->builtBuildings.find(-50)!=vti->builtBuildings.end()) //give standard set of buildings

+ 0 - 87
lib/CGeneralTextHandler.cpp

@@ -209,93 +209,6 @@ void CGeneralTextHandler::load()
 		}
 		while (parser.endLine() && bioParser.endLine());
 	}
-	{
-		CLegacyConfigParser parser("DATA/BLDGNEUT.TXT");
-
-		for(int i=0; i<15; i++)
-		{
-			std::string name  = parser.readString();
-			std::string descr = parser.readString();
-			parser.endLine();
-
-			for(int j=0; j<GameConstants::F_NUMBER; j++)
-			{
-				buildings[j][i].first = name;
-				buildings[j][i].second = descr;
-			}
-		}
-		parser.endLine(); // silo
-		parser.endLine(); // blacksmith  //unused entries
-		parser.endLine(); // moat
-
-		//shipyard with the ship
-		std::string name  = parser.readString();
-		std::string descr = parser.readString();
-		parser.endLine();
-
-		for(int j=0; j<GameConstants::F_NUMBER; j++)
-		{
-			buildings[j][20].first = name;
-			buildings[j][20].second = descr;
-		}
-
-		//blacksmith
-		for(int j=0; j<GameConstants::F_NUMBER; j++)
-		{
-			buildings[j][16].first =  parser.readString();
-			buildings[j][16].second = parser.readString();
-			parser.endLine();
-		}
-	}
-	{
-		CLegacyConfigParser parser("DATA/BLDGSPEC.TXT");
-
-		for(int town=0; town<GameConstants::F_NUMBER; town++)
-		{
-			for(int build=0; build<9; build++)
-			{
-				buildings[town][17+build].first =  parser.readString();
-				buildings[town][17+build].second = parser.readString();
-				parser.endLine();
-			}
-			buildings[town][26].first =  parser.readString(); // Grail
-			buildings[town][26].second = parser.readString();
-			parser.endLine();
-
-			buildings[town][15].first =  parser.readString(); // Resource silo
-			buildings[town][15].second = parser.readString();
-			parser.endLine();
-		}
-	}
-	{
-		CLegacyConfigParser parser("DATA/DWELLING.TXT");
-
-		for(int town=0; town<GameConstants::F_NUMBER; town++)
-		{
-			for(int build=0; build<14; build++)
-			{
-				buildings[town][30+build].first =  parser.readString();
-				buildings[town][30+build].second = parser.readString();
-				parser.endLine();
-			}
-		}
-	}
-	{
-		CLegacyConfigParser typeParser("DATA/TOWNTYPE.TXT");
-		CLegacyConfigParser nameParser("DATA/TOWNNAME.TXT");
-		do
-		{
-			townTypes.push_back(typeParser.readString());
-
-			townNames.push_back(std::vector<std::string>());
-			for (int i=0; i<GameConstants::NAMES_PER_TOWN; i++)
-			{
-				townNames.back().push_back(nameParser.readString());
-				nameParser.endLine();
-			}
-		}
-		while (typeParser.endLine());
-	}
 	{
 		CLegacyConfigParser nameParser("DATA/MINENAME.TXT");
 		CLegacyConfigParser eventParser("DATA/MINEEVNT.TXT");

+ 0 - 3
lib/CGeneralTextHandler.h

@@ -75,9 +75,6 @@ public:
 	//towns
 	std::vector<std::string> tcommands, hcommands, fcommands; //texts for town screen, town hall screen and fort screen
 	std::vector<std::string> tavernInfo;
-	std::vector<std::vector<std::string> > townNames; //[type id] => vec of names of instances
-	std::vector<std::string> townTypes; //castle, rampart, tower, etc
-	std::map<int, std::map<int, std::pair<std::string, std::string> > > buildings; //map[town id][building id] => pair<name, description>
 
 	std::vector<std::pair<std::string,std::string> > zelp;
 	std::vector<std::string> lossCondtions;

+ 3 - 3
lib/CObjectHandler.cpp

@@ -2051,7 +2051,7 @@ void CGTownInstance::initObj()
 ///initialize town structures
 {
 	blockVisit = true;
-	hoverName = name + ", " + town->Name();
+	hoverName = name + ", " + VLC->townh->factions[town->typeID].name;
 
 	if (subID == ETownType::DUNGEON)
 		creatures.resize(GameConstants::CREATURES_PER_TOWN+1);//extra dwelling for Dungeon
@@ -2294,7 +2294,7 @@ std::vector<int> CGTownInstance::availableItemsIds(EMarketMode::EMarketMode mode
 
 std::string CGTownInstance::nodeName() const
 {
-	return "Town (" + (town ? town->Name() : "unknown") + ") of " +  name;
+	return "Town (" + (town ? VLC->townh->factions[town->typeID].name : "unknown") + ") of " +  name;
 }
 
 void CGTownInstance::deserializationFix()
@@ -2372,7 +2372,7 @@ bool CGTownInstance::addBonusIfBuilt(int building, int type, int val, TPropagato
 	if(hasBuilt(building))
 	{
 		std::ostringstream descr;
-		descr << VLC->generaltexth->buildings[subID][building].first << " ";
+		descr << town->buildings[building]->Name() << " ";
 		if(val > 0)
 			descr << "+";
 		else if(val < 0)

+ 131 - 52
lib/CTownHandler.cpp

@@ -19,21 +19,11 @@
 
 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 name;
 }
 
 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 description;
 }
 
@@ -60,22 +50,6 @@ si32 CBuilding::getDistance(CBuilding::BuildingType buildID) const
 	return -1;
 }
 
-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()
 {
 	VLC->townh = this;
@@ -105,7 +79,7 @@ void CTownHandler::loadLegacyData(JsonNode & dest)
 	//Unique buildings
 	for (size_t town=0; town<GameConstants::F_NUMBER; town++)
 	{
-		JsonVector & buildList = dest.Vector()[town].Vector();
+		JsonVector & buildList = dest.Vector()[town]["buildings"].Vector();
 
 		buildList.resize( 30 ); //prepare vector for first set of buildings
 
@@ -132,7 +106,7 @@ void CTownHandler::loadLegacyData(JsonNode & dest)
 		JsonNode building = readBuilding(parser);
 
 		for (size_t town=0; town<GameConstants::F_NUMBER; town++)
-			dest.Vector()[town].Vector()[buildID] = building;
+			dest.Vector()[town]["buildings"].Vector()[buildID] = building;
 
 		buildID++;
 	}
@@ -149,10 +123,108 @@ void CTownHandler::loadLegacyData(JsonNode & dest)
 
 		do
 		{
-			dest.Vector()[town].Vector().push_back(readBuilding(parser));
+			dest.Vector()[town]["buildings"].Vector().push_back(readBuilding(parser));
 		}
 		while (!parser.isNextEntryEmpty());
 	}
+	{
+		CLegacyConfigParser parser("DATA/BLDGNEUT.TXT");
+
+		for(int building=0; building<15; building++)
+		{
+			std::string name  = parser.readString();
+			std::string descr = parser.readString();
+			parser.endLine();
+
+			for(int j=0; j<GameConstants::F_NUMBER; j++)
+			{
+				JsonVector & buildings = dest.Vector()[j]["buildings"].Vector();
+				buildings[building]["name"].String() = name;
+				buildings[building]["description"].String() = descr;
+			}
+		}
+		parser.endLine(); // silo
+		parser.endLine(); // blacksmith  //unused entries
+		parser.endLine(); // moat
+
+		//shipyard with the ship
+		std::string name  = parser.readString();
+		std::string descr = parser.readString();
+		parser.endLine();
+
+		for(int town=0; town<GameConstants::F_NUMBER; town++)
+		{
+			JsonVector & buildings = dest.Vector()[town]["buildings"].Vector();
+			buildings[20]["name"].String() = name;
+			buildings[20]["description"].String() = descr;
+		}
+
+		//blacksmith
+		for(int town=0; town<GameConstants::F_NUMBER; town++)
+		{
+			JsonVector & buildings = dest.Vector()[town]["buildings"].Vector();
+			buildings[16]["name"].String() =  parser.readString();
+			buildings[16]["description"].String() = parser.readString();
+			parser.endLine();
+		}
+	}
+	{
+		CLegacyConfigParser parser("DATA/BLDGSPEC.TXT");
+
+		for(int town=0; town<GameConstants::F_NUMBER; town++)
+		{
+			JsonVector & buildings = dest.Vector()[town]["buildings"].Vector();
+			for(int build=0; build<9; build++)
+			{
+				buildings[17+build]["name"].String() =  parser.readString();
+				buildings[17+build]["description"].String() = parser.readString();
+				parser.endLine();
+			}
+			buildings[26]["name"].String() =  parser.readString(); // Grail
+			buildings[26]["description"].String() = parser.readString();
+			parser.endLine();
+
+			buildings[15]["name"].String() =  parser.readString(); // Resource silo
+			buildings[15]["description"].String() = parser.readString();
+			parser.endLine();
+		}
+	}
+	{
+		CLegacyConfigParser parser("DATA/DWELLING.TXT");
+
+		for(int town=0; town<GameConstants::F_NUMBER; town++)
+		{
+			JsonVector & buildings = dest.Vector()[town]["buildings"].Vector();
+			for(int build=0; build<14; build++)
+			{
+				buildings[30+build]["name"].String() =  parser.readString();
+				buildings[30+build]["description"].String() = parser.readString();
+				parser.endLine();
+			}
+		}
+	}
+	{
+		CLegacyConfigParser typeParser("DATA/TOWNTYPE.TXT");
+		CLegacyConfigParser nameParser("DATA/TOWNNAME.TXT");
+		size_t townID=0;
+		do
+		{
+			JsonNode & town = dest.Vector()[townID];
+
+			town["name"].String() = typeParser.readString();
+
+
+			for (int i=0; i<GameConstants::NAMES_PER_TOWN; i++)
+			{
+				JsonNode name;
+				name.String() = nameParser.readString();
+				town["names"].Vector().push_back(name);
+				nameParser.endLine();
+			}
+			townID++;
+		}
+		while (typeParser.endLine());
+	}
 }
 
 void CTownHandler::loadBuilding(CTown &town, const JsonNode & source)
@@ -269,13 +341,10 @@ void CTownHandler::loadClientData(CTown &town, const JsonNode & source)
 
 void CTownHandler::loadTown(CTown &town, const JsonNode & source)
 {
-	town.bonus = town.typeID;
-	if (town.bonus==8)
-		town.bonus=3;
-
 	town.mageLevel = source["mageGuild"].Float();
 	town.primaryRes  = source["primaryResource"].Float();
 	town.warMachine = source["warMachine"].Float();
+	town.names = source["names"].StdVector<std::string>();
 
 	//  Horde building creature level
 	BOOST_FOREACH(const JsonNode &node, source["horde"].Vector())
@@ -331,18 +400,17 @@ void CTownHandler::loadFactions(const JsonNode &source)
 		CFaction & faction = factions[id];
 
 		faction.factionID = id;
-		faction.name = node.first;
+		faction.name = node.second["name"].String();
 
 		faction.creatureBg120 = node.second["creatureBackground"]["120px"].String();
 		faction.creatureBg130 = node.second["creatureBackground"]["130px"].String();
 
-		if (!node.second["nativeTerrain"].isNull())
-		{
-			//get terrain as string and converto to numeric ID
-			faction.nativeTerrain = boost::find(GameConstants::TERRAIN_NAMES, node.second["nativeTerrain"].String()) - GameConstants::TERRAIN_NAMES;
-		}
+		faction.nativeTerrain = vstd::find_pos(GameConstants::TERRAIN_NAMES, node.second["nativeTerrain"].String());
+		int alignment = vstd::find_pos(EAlignment::names, node.second["alignment"].String());
+		if (alignment == -1)
+			faction.alignment = EAlignment::NEUTRAL;
 		else
-			faction.nativeTerrain = -1;
+			faction.alignment = alignment;
 
 		if (!node.second["town"].isNull())
 		{
@@ -361,7 +429,7 @@ void CTownHandler::load()
 	JsonNode legacyConfig;
 	loadLegacyData(legacyConfig);
 
-	//hardocoded list of H3 factions. Should be only used to convert H3 configs
+	//hardcoded list of H3 factions. Should be only used to convert H3 configs
 	static const std::string factionName [GameConstants::F_NUMBER] =
 	{
 		"castle", "rampart", "tower",
@@ -370,24 +438,35 @@ void CTownHandler::load()
 	};
 
 	// semi-manually merge legacy config with towns json
-	// legacy config have only one item: town buildings stored in 2d vector
 
 	for (size_t i=0; i< legacyConfig.Vector().size(); i++)
 	{
-		JsonNode & buildings = buildingsConf[factionName[i]]["town"]["buildings"];
-		BOOST_FOREACH(JsonNode & building, buildings.Vector())
+		JsonNode & legacyFaction = legacyConfig.Vector()[i];
+		JsonNode & outputFaction = buildingsConf[factionName[i]];
+
+		if (outputFaction["name"].isNull())
+			outputFaction["name"] = legacyFaction["name"];
+
+		if (!outputFaction["town"].isNull())
 		{
-			JsonNode & legacyFaction = legacyConfig.Vector()[i];
-			if (vstd::contains(building.Struct(), "id"))
-			{
-				//find same buildings in legacy and json configs
-				JsonNode & legacyBuilding = legacyFaction.Vector()[building["id"].Float()];
+			if (outputFaction["town"]["names"].isNull())
+				outputFaction["town"]["names"] = legacyFaction["names"];
 
-				if (!legacyBuilding.isNull()) //merge if h3 config was found for this building
-					JsonNode::merge(building, legacyBuilding);
+			JsonNode & outputBuildings = outputFaction["town"]["buildings"];
+			JsonVector & legacyBuildings = legacyFaction["buildings"].Vector();
+			BOOST_FOREACH(JsonNode & building, outputBuildings.Vector())
+			{
+				if (vstd::contains(building.Struct(), "id") &&
+				    legacyBuildings.size() > building["id"].Float() )
+				{
+					//find same buildings in legacy and json configs
+					JsonNode & legacyBuilding = legacyBuildings[building["id"].Float()];
+
+					if (!legacyBuilding.isNull()) //merge if h3 config was found for this building
+						JsonNode::merge(building, legacyBuilding);
+				}
 			}
 		}
 	}
-
 	loadFactions(buildingsConf);
 }

+ 7 - 12
lib/CTownHandler.h

@@ -83,14 +83,11 @@ struct DLL_LINKAGE CStructure
 
 class DLL_LINKAGE CTown
 {
-	std::string name;
-	std::string description;
+public:
+	TFaction typeID;//same as CFaction::factionID
 
 	std::vector<std::string> names; //names of the town instances
 
-public:
-	TFaction typeID;//also works as factionID
-
 	/// level -> list of creatures on this tier
 	// TODO: replace with pointers to CCreature
 	std::vector<std::vector<TCreature> > creatures;
@@ -100,7 +97,6 @@ public:
 	// 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
@@ -127,12 +123,9 @@ public:
 		}
 	} 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
+		h & names & typeID & creatures & buildings & hordeLvl & mageLevel
 			& primaryRes & warMachine & clientInfo;
 	}
 
@@ -155,10 +148,12 @@ struct DLL_LINKAGE SPuzzleInfo
 class CFaction
 {
 public:
-	std::string name; //reference name, usually lower case
+	std::string name; //town name, by default - from TownName.txt
+
 	TFaction factionID;
 
-	ui32 nativeTerrain;
+	ui8 nativeTerrain;
+	ui8 alignment; // uses EAlignment enum
 
 	std::string creatureBg120;
 	std::string creatureBg130;

+ 2 - 0
lib/GameConstants.h

@@ -110,6 +110,8 @@ namespace ELossConditionType
 namespace EAlignment
 {
 	enum EAlignment { GOOD, EVIL, NEUTRAL };
+
+	const std::string names [3] = {"good", "evil", "neutral"}; //for parsing from config file
 }
 
 namespace ETownType

+ 3 - 0
lib/JsonNode.cpp

@@ -882,6 +882,9 @@ bool JsonValidator::addMessage(const std::string &message)
 JsonValidator::JsonValidator(JsonNode &root, bool Minimize):
 	minimize(Minimize)
 {
+	if (root.getType() != JsonNode::DATA_STRUCT)
+		return;
+
 	JsonNode schema;
 	schema.swap(root["schema"]);
 	root.Struct().erase("schema");

+ 24 - 10
lib/JsonNode.h

@@ -77,16 +77,7 @@ public:
 	const JsonMap & Struct() const;
 
 	template<typename T>
-	std::vector<T> StdVector() const
-	{
-		static_assert(std::is_arithmetic<T>::value, "This works with numbers only.");
-		std::vector<T> ret;
-		BOOST_FOREACH(const JsonNode &node, Vector())
-		{
-			ret.push_back(node.Float());
-		}
-		return ret;
-	}
+	std::vector<T> StdVector() const;
 
 	//operator [], for structs only - get child node by name
 	JsonNode & operator[](std::string child);
@@ -107,6 +98,29 @@ public:
 	static void mergeCopy(JsonNode & dest, JsonNode source);
 };
 
+template<>
+inline std::vector<std::string> JsonNode::StdVector() const
+{
+	std::vector<std::string> ret;
+	BOOST_FOREACH(const JsonNode &node, Vector())
+	{
+		ret.push_back(node.String());
+	}
+	return ret;
+}
+
+template<typename T>
+std::vector<T> JsonNode::StdVector() const
+{
+	static_assert(std::is_arithmetic<T>::value, "This works with numbers only.");
+	std::vector<T> ret;
+	BOOST_FOREACH(const JsonNode &node, Vector())
+	{
+		ret.push_back(node.Float());
+	}
+	return ret;
+}
+
 class JsonWriter
 {
 	//prefix for each line (tabulation)