ソースを参照

- moved json-related functions (e.g. ParseBonus) into JsonUtils namespace
- replaced JsonNode::toStdVector with more universal convertTo
- some renaming in StartInfo

Ivan Savenko 13 年 前
コミット
c9dd80ea6d

+ 1 - 1
client/AdventureMapClasses.cpp

@@ -294,7 +294,7 @@ void CTownList::CTownItem::update()
 {
 	size_t iconIndex = town->town->clientInfo.icons[town->hasFort()][town->builded >= CGI->modh->settings.MAX_BUILDING_PER_TURN];
 
-	picture->setFrame(iconIndex + 2);
+	picture->setFrame(iconIndex);
 	redraw();
 }
 

+ 2 - 0
client/CAnimation.cpp

@@ -1202,6 +1202,8 @@ void CAnimImage::setFrame(size_t Frame, size_t Group)
 			pos.h = img->height();
 		}
 	}
+	else
+		tlog1 << "Error: accessing unavailable frame " << Group << ":" << Frame << " in CAnimation!\n";
 }
 
 void CAnimImage::playerColored(int currPlayer)

+ 1 - 1
client/CMT.cpp

@@ -860,7 +860,7 @@ void startGame(StartInfo * options, CConnection *serv/* = NULL*/)
 	{
 		for(auto it = options->playerInfos.begin(); it != options->playerInfos.end(); ++it)
 		{
-			it->second.human = false;
+			it->second.playerID = PlayerSettings::PLAYER_AI;
 		}
 	}
 /*	const JsonNode& res = settings["video"]["screenRes"];

+ 33 - 33
client/CPreGame.cpp

@@ -120,12 +120,12 @@ static void setPlayersFromGame()
 
 static void swapPlayers(PlayerSettings &a, PlayerSettings &b)
 {
-	std::swap(a.human, b.human);
+	std::swap(a.playerID, b.playerID);
 	std::swap(a.name, b.name);
 
-	if(a.human == 1)
+	if(a.playerID == 1)
 		playerColor = a.color;
-	else if(b.human == 1)
+	else if(b.playerID == 1)
 		playerColor = b.color;
 }
 
@@ -136,7 +136,7 @@ void setPlayer(PlayerSettings &pset, TPlayerColor player, const std::map<TPlayer
 	else
 		pset.name = CGI->generaltexth->allTexts[468];//Computer
 
-	pset.human = player;
+	pset.playerID = player;
 	if(player == playerNames.begin()->first)
 		playerColor = pset.color;
 }
@@ -844,7 +844,7 @@ void CSelectionScreen::startGame()
 		//there must be at least one human player before game can be started
 		std::map<TPlayerColor, PlayerSettings>::const_iterator i;
 		for(i = SEL->sInfo.playerInfos.cbegin(); i != SEL->sInfo.playerInfos.cend(); i++)
-			if(i->second.human)
+			if(i->second.playerID != PlayerSettings::PLAYER_AI)
 				break;
 
 		if(i == SEL->sInfo.playerInfos.cend())
@@ -951,7 +951,7 @@ void CSelectionScreen::setSInfo(const StartInfo &si)
 	std::map<TPlayerColor, PlayerSettings>::const_iterator i;
 	for(i = si.playerInfos.cbegin(); i != si.playerInfos.cend(); i++)
 	{
-		if(i->second.human == myNameID)
+		if(i->second.playerID == myNameID)
 		{
 			playerColor = i->first;
 			break;
@@ -1988,10 +1988,10 @@ void InfoCard::showAll(SDL_Surface * to)
 			int playerSoFar = 0;
 			for (auto i = SEL->sInfo.playerInfos.cbegin(); i != SEL->sInfo.playerInfos.cend(); i++)
 			{
-				if(i->second.human)
+				if(i->second.playerID != PlayerSettings::PLAYER_AI)
 				{
 					printAtLoc(i->second.name, 24, 285 + playerSoFar++ * graphics->fonts[FONT_SMALL]->height, FONT_SMALL, Colors::WHITE, to);
-					playerNames.erase(i->second.human);
+					playerNames.erase(i->second.playerID);
 				}
 			}
 
@@ -2244,7 +2244,7 @@ void OptionsTab::nextCastle( int player, int dir )
 	}
 
 	PlayerSettings &s = SEL->sInfo.playerInfos[player];
-	si32 &cur = s.castle;
+	si16 &cur = s.castle;
 	auto & allowed = SEL->current->mapHeader->players[s.color].allowedFactions;
 
 	if (cur == -2) //no castle - no change
@@ -2274,8 +2274,8 @@ void OptionsTab::nextCastle( int player, int dir )
 
 	if(s.hero >= 0)
 		s.hero = -1;
-	if(cur < 0  &&  s.bonus == PlayerSettings::bresource)
-		s.bonus = PlayerSettings::brandom;
+	if(cur < 0  &&  s.bonus == PlayerSettings::RESOURCE)
+		s.bonus = PlayerSettings::RANDOM;
 
 	entries[player]->selectButtons();
 
@@ -2293,7 +2293,7 @@ void OptionsTab::nextHero( int player, int dir )
 
 	PlayerSettings &s = SEL->sInfo.playerInfos[player];
 	int old = s.hero;
-	if (s.castle < 0  ||  !s.human  ||  s.hero == -2)
+	if (s.castle < 0  ||  s.playerID == PlayerSettings::PLAYER_AI  ||  s.hero == PlayerSettings::NONE)
 		return;
 
 	if (s.hero == -1) //random => first/last available
@@ -2359,23 +2359,23 @@ void OptionsTab::nextBonus( int player, int dir )
 	PlayerSettings &s = SEL->sInfo.playerInfos[player];
 	si8 &ret = s.bonus += dir;
 
-	if (s.hero==-2 && !SEL->current->mapHeader->players[s.color].heroesNames.size() && ret==PlayerSettings::bartifact) //no hero - can't be artifact
+	if (s.hero==-2 && !SEL->current->mapHeader->players[s.color].heroesNames.size() && ret==PlayerSettings::ARTIFACT) //no hero - can't be artifact
 	{
 		if (dir<0)
-			ret=PlayerSettings::brandom;
-		else ret=PlayerSettings::bgold;
+			ret=PlayerSettings::RANDOM;
+		else ret=PlayerSettings::GOLD;
 	}
 
-	if(ret > PlayerSettings::bresource)
-		ret = PlayerSettings::brandom;
-	if(ret < PlayerSettings::brandom)
-		ret = PlayerSettings::bresource;
+	if(ret > PlayerSettings::RESOURCE)
+		ret = PlayerSettings::RANDOM;
+	if(ret < PlayerSettings::RANDOM)
+		ret = PlayerSettings::RESOURCE;
 
-	if (s.castle==-1 && ret==PlayerSettings::bresource) //random castle - can't be resource
+	if (s.castle==-1 && ret==PlayerSettings::RESOURCE) //random castle - can't be resource
 	{
 		if (dir<0)
-			ret=PlayerSettings::bgold;
-		else ret=PlayerSettings::brandom;
+			ret=PlayerSettings::GOLD;
+		else ret=PlayerSettings::RANDOM;
 	}
 
 	SEL->propagateOptions();
@@ -2427,7 +2427,7 @@ void OptionsTab::flagPressed( int color )
 	else
 	{
 		//identify clicked player
-		int clickedNameID = clicked.human; //human is a number of player, zero means AI
+		int clickedNameID = clicked.playerID; //human is a number of player, zero means AI
 
 		if(clickedNameID > 0  &&  playerToRestore.id == clickedNameID) //player to restore is about to being replaced -> put him back to the old place
 		{
@@ -2463,10 +2463,10 @@ void OptionsTab::flagPressed( int color )
 		{
 			for(auto i = SEL->sInfo.playerInfos.begin(); i != SEL->sInfo.playerInfos.end(); i++)
 			{
-				int curNameID = i->second.human;
+				int curNameID = i->second.playerID;
 				if(i->first != color  &&  curNameID == newPlayer)
 				{
-					assert(i->second.human);
+					assert(i->second.playerID);
 					playerToRestore.color = i->first;
 					playerToRestore.id = newPlayer;
 					SEL->setPlayer(i->second, 0); //set computer
@@ -2584,7 +2584,7 @@ void OptionsTab::PlayerOptionsEntry::selectButtons()
 		btns[1]->enable();
 	}
 
-	if( (pi.defaultHero() != -1  ||  !s.human  ||  s.castle < 0) //fixed hero
+	if( (pi.defaultHero() != -1  ||  !s.playerID  ||  s.castle < 0) //fixed hero
 		|| (SEL->isGuest() && s.color != playerColor))//or not our player
 	{
 		btns[2]->disable();
@@ -2792,20 +2792,20 @@ void OptionsTab::SelectedBox::clickRight( tribool down, bool previousState )
 			{
 				switch(val)
 				{
-				case PlayerSettings::brandom:
+				case PlayerSettings::RANDOM:
 					title = &CGI->generaltexth->allTexts[86]; //{Random Bonus}
 					description = &CGI->generaltexth->allTexts[94]; //Gold, wood and ore, or an artifact is randomly chosen as your starting bonus
 					break;
-				case PlayerSettings::bartifact:
+				case PlayerSettings::ARTIFACT:
 					title = &CGI->generaltexth->allTexts[83]; //{Artifact Bonus}
 					description = &CGI->generaltexth->allTexts[90]; //An artifact is randomly chosen and equipped to your starting hero
 					break;
-				case PlayerSettings::bgold:
+				case PlayerSettings::GOLD:
 					title = &CGI->generaltexth->allTexts[84]; //{Gold Bonus}
 					subTitle = &CGI->generaltexth->allTexts[87]; //500-1000
 					description = &CGI->generaltexth->allTexts[92]; //At the start of the game, 500-1000 gold is added to your Kingdom's resource pool
 					break;
-				case PlayerSettings::bresource:
+				case PlayerSettings::RESOURCE:
 					{
 						title = &CGI->generaltexth->allTexts[85]; //{Resource Bonus}
 						switch(CGI->townh->towns[s.castle].primaryRes)
@@ -2909,7 +2909,7 @@ CScenarioInfo::CScenarioInfo(const CMapHeader *mapHeader, const StartInfo *start
 
 	for(auto it = startInfo->playerInfos.cbegin(); it != startInfo->playerInfos.cend(); ++it)
 	{
-		if(it->second.human)
+		if(it->second.playerID)
 		{
 			playerColor = it->first;
 		}
@@ -3406,7 +3406,7 @@ void CBonusSelection::updateBonusSelection()
 					int faction = -1;
 					for(auto it = sInfo.playerInfos.begin(); it != sInfo.playerInfos.end(); ++it)
 					{
-						if (it->second.human)
+						if (it->second.playerID)
 						{
 							faction = it->second.castle;
 							break;
@@ -3775,7 +3775,7 @@ void PlayerJoined::apply(CSelectionScreen *selScreen)
 	//put new player in first slot with AI
 	for(auto i = SEL->sInfo.playerInfos.begin(); i != SEL->sInfo.playerInfos.end(); i++)
 	{
-		if(!i->second.human)
+		if(!i->second.playerID)
 		{
 			selScreen->setPlayer(i->second, connectionID);
 			selScreen->opt->entries[i->second.color]->selectButtons();

+ 4 - 4
client/CPreGame.h

@@ -449,10 +449,10 @@ public:
 
 	void processPacks();
 	void setSInfo(const StartInfo &si);
-	void update() OVERRIDE;
-	void propagateOptions() OVERRIDE;
-	void postRequest(ui8 what, ui8 dir) OVERRIDE;
-	void postChatMessage(const std::string &txt) OVERRIDE;
+	void update() override;
+	void propagateOptions() override;
+	void postRequest(ui8 what, ui8 dir) override;
+	void postChatMessage(const std::string &txt) override;
 	void propagateNames();
 	void showAll(SDL_Surface *to);
 };

+ 4 - 4
client/Client.cpp

@@ -304,9 +304,9 @@ void CClient::newGame( CConnection *con, StartInfo *si )
 
 	for(auto it = si->playerInfos.begin(); it != si->playerInfos.end(); ++it)
 	{
-		if((networkMode == SINGLE)												//single - one client has all player
-		   || (networkMode != SINGLE && serv->connectionID == it->second.human)	//multi - client has only "its players"
-		   || (networkMode == HOST && it->second.human == false))				//multi - host has all AI players
+		if((networkMode == SINGLE)                                                      //single - one client has all player
+		   || (networkMode != SINGLE && serv->connectionID == it->second.playerID)      //multi - client has only "its players"
+		   || (networkMode == HOST && it->second.playerID == PlayerSettings::PLAYER_AI))//multi - host has all AI players
 		{
 			myPlayers.insert(it->first); //add player
 		}
@@ -368,7 +368,7 @@ void CClient::newGame( CConnection *con, StartInfo *si )
 		if(si->mode != StartInfo::DUEL)
 		{
 			auto cb = make_shared<CCallback>(gs,color,this);
-			if(!it->second.human) 
+			if(it->second.playerID == PlayerSettings::PLAYER_AI)
 			{
 				std::string AItoGive = settings["server"]["playerAI"].String();
 				if(!sensibleAILimit)

+ 3 - 4
lib/CArtHandler.cpp

@@ -24,7 +24,6 @@ using namespace boost::assign;
  */
 
 extern boost::rand48 ran;
-extern Bonus * ParseBonus (const JsonVector &ability_vec);
 
 const std::string & CArtifact::Name() const
 {
@@ -366,11 +365,11 @@ void CArtHandler::loadArtifacts(bool onlyTxt)
 			auto ga = dynamic_cast <CGrowingArtifact *>(artifacts[artifact["id"].Float()].get());
 			BOOST_FOREACH (auto b, artifact["bonusesPerLevel"].Vector())
 			{
-				ga->bonusesPerLevel.push_back (std::pair <ui16, Bonus> (b["level"].Float(), *ParseBonus (b["bonus"].Vector())));
+				ga->bonusesPerLevel.push_back (std::pair <ui16, Bonus> (b["level"].Float(), *JsonUtils::parseBonus (b["bonus"].Vector())));
 			}
 			BOOST_FOREACH (auto b, artifact["thresholdBonuses"].Vector())
 			{
-				ga->thresholdBonuses.push_back (std::pair <ui16, Bonus> (b["level"].Float(), *ParseBonus (b["bonus"].Vector())));
+				ga->thresholdBonuses.push_back (std::pair <ui16, Bonus> (b["level"].Float(), *JsonUtils::parseBonus (b["bonus"].Vector())));
 			}
 		}
 	}
@@ -614,7 +613,7 @@ void CArtHandler::addBonuses()
 		
 		BOOST_FOREACH (auto b, artifact["bonuses"].Vector())
 		{
-			ga->addNewBonus(ParseBonus (b));
+			ga->addNewBonus(JsonUtils::parseBonus (b));
 		}
 		if(artifact["type"].String() == "Creature")
 			makeItCreatureArt(ga->id);

+ 2 - 2
lib/CConfigHandler.cpp

@@ -59,7 +59,7 @@ void SettingsStorage::init()
 {
 	JsonNode(ResourceID("config/settings.json")).swap(config);
 	JsonNode schema(ResourceID("config/defaultSettings.json"));
-	config.validate(schema);
+	JsonUtils::validate(config, schema);
 }
 
 void SettingsStorage::invalidateNode(const std::vector<std::string> &changedPath)
@@ -71,7 +71,7 @@ void SettingsStorage::invalidateNode(const std::vector<std::string> &changedPath
 	JsonNode schema(ResourceID("config/defaultSettings.json"));
 
 	savedConf.Struct().erase("session");
-	savedConf.minimize(schema);
+	JsonUtils::minimize(savedConf, schema);
 
 	CResourceHandler::get()->createResource("CONFIG/settings.json");
 

+ 4 - 4
lib/CCreatureHandler.cpp

@@ -500,7 +500,7 @@ void CCreatureHandler::loadCreatures()
 	}
 	BOOST_FOREACH (auto bonus, config3["bonusPerLevel"].Vector())
 	{
-		commanderLevelPremy.push_back(ParseBonus (bonus.Vector()));
+		commanderLevelPremy.push_back(JsonUtils::parseBonus (bonus.Vector()));
 	}
 
 	int i = 0;
@@ -517,7 +517,7 @@ void CCreatureHandler::loadCreatures()
 	BOOST_FOREACH (auto ability, config3["abilityRequirements"].Vector())
 	{
 		std::pair <Bonus, std::pair <ui8, ui8> > a;
-		a.first = *ParseBonus (ability["ability"].Vector());
+		a.first = *JsonUtils::parseBonus (ability["ability"].Vector());
 		a.second.first = ability["skills"].Vector()[0].Float();
 		a.second.second = ability["skills"].Vector()[1].Float();
 		skillRequirements.push_back (a);
@@ -674,7 +674,7 @@ CCreature * CCreatureHandler::loadCreature(const JsonNode & node)
 
 	BOOST_FOREACH (const JsonNode &bonus, node["abilities"].Vector())
 	{
-		auto b = ParseBonus(bonus);
+		auto b = JsonUtils::parseBonus(bonus);
 		b->source = Bonus::CREATURE_ABILITY;
 		b->duration = Bonus::PERMANENT;
 		cre->addNewBonus(b);
@@ -682,7 +682,7 @@ CCreature * CCreatureHandler::loadCreature(const JsonNode & node)
 
 	BOOST_FOREACH (const JsonNode &exp, node["stackExperience"].Vector())
 	{
-		auto bonus = ParseBonus (exp["bonus"]);
+		auto bonus = JsonUtils::parseBonus (exp["bonus"]);
 		bonus->source = Bonus::STACK_EXPERIENCE;
 		bonus->duration = Bonus::PERMANENT;
 		const JsonVector &values = exp["values"].Vector();

+ 8 - 8
lib/CGameState.cpp

@@ -841,7 +841,7 @@ void CGameState::init(StartInfo * si)
 		for(auto it = scenarioOps->playerInfos.cbegin();
 			it != scenarioOps->playerInfos.cend(); ++it)
 		{
-			if(it->second.human)
+			if(it->second.playerID != PlayerSettings::PLAYER_AI)
 				ret.push_back(&it->second);
 		}
 
@@ -996,7 +996,7 @@ void CGameState::init(StartInfo * si)
 	{
 		std::pair<TPlayerColor,PlayerState> ins(it->first,PlayerState());
 		ins.second.color=ins.first;
-		ins.second.human = it->second.human;
+		ins.second.human = it->second.playerID;
 		ins.second.team = map->players[ins.first].team;
 		teams[ins.second.team].id = ins.second.team;//init team
 		teams[ins.second.team].players.insert(ins.first);//add player to team
@@ -1021,7 +1021,8 @@ void CGameState::init(StartInfo * si)
 		for(auto it = scenarioOps->playerInfos.begin(); it != scenarioOps->playerInfos.end(); ++it)
 		{
 			const PlayerInfo &p = map->players[it->first];
-			bool generateHero = (p.generateHeroAtMainTown || (it->second.human && campaignGiveHero)) && p.hasMainTown;
+			bool generateHero = (p.generateHeroAtMainTown ||
+			                     (it->second.playerID != PlayerSettings::PLAYER_AI && campaignGiveHero)) && p.hasMainTown;
 			if(generateHero && vstd::contains(scenarioOps->playerInfos, it->first))
 			{
 				int3 hpos = p.posOfMainTown;
@@ -1041,7 +1042,6 @@ void CGameState::init(StartInfo * si)
 		}
 	}
 
-
 	/*************************replace hero placeholders*****************************/
 	tlog4 << "\tReplacing hero placeholders";
 	if (scenarioOps->campState)
@@ -1301,14 +1301,14 @@ void CGameState::init(StartInfo * si)
 	for(auto k=players.begin(); k!=players.end(); ++k)
 	{
 		//starting bonus
-		if(scenarioOps->playerInfos[k->first].bonus==PlayerSettings::brandom)
+		if(scenarioOps->playerInfos[k->first].bonus==PlayerSettings::RANDOM)
 			scenarioOps->playerInfos[k->first].bonus = ran()%3;
 		switch(scenarioOps->playerInfos[k->first].bonus)
 		{
-		case PlayerSettings::bgold:
+		case PlayerSettings::GOLD:
 			k->second.resources[Res::GOLD] += 500 + (ran()%6)*100;
 			break;
-		case PlayerSettings::bresource:
+		case PlayerSettings::RESOURCE:
 			{
 				int res = VLC->townh->towns[scenarioOps->playerInfos[k->first].castle].primaryRes;
 				if(res == 127)
@@ -1322,7 +1322,7 @@ void CGameState::init(StartInfo * si)
 				}
 				break;
 			}
-		case PlayerSettings::bartifact:
+		case PlayerSettings::ARTIFACT:
 			{
  				if(!k->second.heroes.size())
 				{

+ 3 - 3
lib/CHeroHandler.cpp

@@ -106,9 +106,9 @@ void CHeroHandler::loadObstacles()
 			obi.defName = obs["defname"].String();
 			obi.width = obs["width"].Float();
 			obi.height = obs["height"].Float();
-			obi.allowedTerrains = obs["allowedTerrain"].StdVector<ui8>();
-			obi.allowedSpecialBfields = obs["specialBattlefields"].StdVector<ui8>();
-			obi.blockedTiles = obs["blockedTiles"].StdVector<si16>();
+			obi.allowedTerrains = obs["allowedTerrain"].convertTo<std::vector<ui8> >();
+			obi.allowedSpecialBfields = obs["specialBattlefields"].convertTo<std::vector<ui8> >();
+			obi.blockedTiles = obs["blockedTiles"].convertTo<std::vector<si16> >();
 			obi.isAbsoluteObstacle = absolute;
 		}
 	};

+ 1 - 1
lib/CObjectHandler.cpp

@@ -5363,7 +5363,7 @@ void CGEvent::onHeroVisit( const CGHeroInstance * h ) const
 {
 	if(!(availableFor & (1 << h->tempOwner)))
 		return;
-	if(cb->getPlayerSettings(h->tempOwner)->human)
+	if(cb->getPlayerSettings(h->tempOwner)->playerID)
 	{
 		if(humanActivate)
 			activated(h);

+ 1 - 1
lib/CSpellHandler.cpp

@@ -364,7 +364,7 @@ void CSpellHandler::loadSpells()
 		BOOST_FOREACH(const JsonNode &range, spell["ranges"].Vector())
 			s->range[idx++] = range.String();
 
-		s->counteredSpells = spell["counters"].StdVector<TSpell>();
+		s->counteredSpells = spell["counters"].convertTo<std::vector<TSpell> >();
 	}
 	//spell fixes
 

+ 6 - 6
lib/CTownHandler.cpp

@@ -394,7 +394,7 @@ void CTownHandler::loadTown(CTown &town, const JsonNode & source)
 	town.mageLevel = source["mageGuild"].Float();
 	town.primaryRes  = source["primaryResource"].Float();
 	town.warMachine = source["warMachine"].Float();
-	town.names = source["names"].StdVector<std::string>();
+	town.names = source["names"].convertTo<std::vector<std::string> >();
 
 	//  Horde building creature level
 	BOOST_FOREACH(const JsonNode &node, source["horde"].Vector())
@@ -515,7 +515,7 @@ void CTownHandler::load()
 					JsonNode & legacyBuilding = legacyBuildings[building["id"].Float()];
 
 					if (!legacyBuilding.isNull()) //merge if h3 config was found for this building
-						JsonNode::merge(building, legacyBuilding);
+						JsonUtils::merge(building, legacyBuilding);
 				}
 			}
 		}
@@ -523,12 +523,12 @@ void CTownHandler::load()
 	load(buildingsConf);
 }
 
-std::set<ui32> CTownHandler::getDefaultAllowedFactions() const
+std::set<TFaction> CTownHandler::getDefaultAllowedFactions() const
 {
-	std::set<ui32> allowedFactions;
-	for(int i = 0; i <= 8; ++i)
+	std::set<TFaction> allowedFactions;
+	BOOST_FOREACH(auto town, towns)
 	{
-		allowedFactions.insert(i);
+		allowedFactions.insert(town.first);
 	}
 	return allowedFactions;
 }

+ 1 - 1
lib/CTownHandler.h

@@ -225,7 +225,7 @@ public:
 	 *
 	 * @return a list of allowed factions, the index which is unique is the faction id
 	 */
-	std::set<ui32> getDefaultAllowedFactions() const;
+	std::set<TFaction> getDefaultAllowedFactions() const;
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{

+ 49 - 51
lib/JsonNode.cpp

@@ -4,7 +4,9 @@
 #include "HeroBonus.h"
 #include "Filesystem/CResourceLoader.h"
 
-const JsonNode JsonNode::nullNode;
+using namespace JsonDetail;
+
+static const JsonNode nullNode;
 
 JsonNode::JsonNode(JsonType Type):
 	type(DATA_NULL)
@@ -99,16 +101,6 @@ bool JsonNode::operator != (const JsonNode &other) const
 	return !(*this == other);
 }
 
-void JsonNode::minimize(const JsonNode& schema)
-{
-	JsonValidator validator(*this, schema, true);
-}
-
-void JsonNode::validate(const JsonNode& schema)
-{
-	JsonValidator validator(*this, schema, false);
-}
-
 JsonNode::JsonType JsonNode::getType() const
 {
 	return type;
@@ -238,39 +230,6 @@ const JsonNode & JsonNode::operator[](std::string child) const
 }
 ////////////////////////////////////////////////////////////////////////////////
 
-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);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
 template<typename Iterator>
 void JsonWriter::writeContainer(Iterator begin, Iterator end)
 {
@@ -830,7 +789,7 @@ bool JsonValidator::validateProperties(JsonNode &node, const JsonNode &schema)
 	{
 		if (nodeIter->first < schemaIter->first) //No schema for entry
 		{
-			validateNode(nodeIter->second, JsonNode::nullNode, nodeIter->first);
+			validateNode(nodeIter->second, nullNode, nodeIter->first);
 
 			JsonMap::iterator toRemove = nodeIter++;
 			node.Struct().erase(toRemove);
@@ -853,7 +812,7 @@ bool JsonValidator::validateProperties(JsonNode &node, const JsonNode &schema)
 	}
 	while (nodeIter != node.Struct().end())
 	{
-		validateNode(nodeIter->second, JsonNode::nullNode, nodeIter->first);
+		validateNode(nodeIter->second, nullNode, nodeIter->first);
 		JsonMap::iterator toRemove = nodeIter++;
 		node.Struct().erase(toRemove);
 	}
@@ -910,7 +869,7 @@ JsonValidator::JsonValidator(JsonNode &root, const JsonNode &schema, bool Minimi
 	tlog3<<errors;
 }
 
-Bonus * ParseBonus (const JsonVector &ability_vec) //TODO: merge with AddAbility, create universal parser for all bonus properties
+Bonus * JsonUtils::parseBonus (const JsonVector &ability_vec) //TODO: merge with AddAbility, create universal parser for all bonus properties
 {
 	Bonus * b = new Bonus();
 	std::string type = ability_vec[0].String();
@@ -950,7 +909,7 @@ const T & parseByMap(const std::map<std::string, T> & map, const JsonNode * val,
 		return defaultValue;
 };
 
-Bonus * ParseBonus (const JsonNode &ability)
+Bonus * JsonUtils::parseBonus (const JsonNode &ability)
 {
 
 	Bonus * b = new Bonus();
@@ -1029,7 +988,7 @@ Key reverseMapFirst(const Val & val, const std::map<Key, Val> map)
 	return "";
 }
 
-DLL_LINKAGE void UnparseBonus( JsonNode &node, const Bonus * bonus )
+void JsonUtils::unparseBonus( JsonNode &node, const Bonus * bonus )
 {
 	node["type"].String() = reverseMapFirst<std::string, int>(bonus->type, bonusNameMap);
 	node["subtype"].Float() = bonus->subtype;
@@ -1050,6 +1009,45 @@ DLL_LINKAGE void UnparseBonus( JsonNode &node, const Bonus * bonus )
 	{
 		node["propagator"].String() = reverseMapFirst<std::string, TPropagatorPtr>(bonus->propagator, bonusPropagatorMap);
 	}
-	
-	
 }
+
+void JsonUtils::minimize(JsonNode & node, const JsonNode& schema)
+{
+	JsonValidator validator(node, schema, true);
+}
+
+void JsonUtils::validate(JsonNode & node, const JsonNode& schema)
+{
+	JsonValidator validator(node, schema, false);
+}
+
+void JsonUtils::merge(JsonNode & dest, JsonNode & source)
+{
+	switch (source.getType())
+	{
+		break; case JsonNode::DATA_NULL:   dest.setType(JsonNode::DATA_NULL);
+		break; case JsonNode::DATA_BOOL:   std::swap(dest.Bool(), source.Bool());
+		break; case JsonNode::DATA_FLOAT:  std::swap(dest.Float(), source.Float());
+		break; case JsonNode::DATA_STRING: std::swap(dest.String(), source.String());
+		break; case JsonNode::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 JsonNode::DATA_STRUCT:
+		{
+			//recursively merge all entries from struct
+			BOOST_FOREACH(auto & node, source.Struct())
+				merge(dest[node.first], node.second);
+		}
+	}
+}
+
+void JsonUtils::mergeCopy(JsonNode & dest, JsonNode source)
+{
+	// uses copy created in stack to safely merge two nodes
+	merge(dest, source);
+}

+ 182 - 127
lib/JsonNode.h

@@ -53,11 +53,6 @@ public:
 	bool operator == (const JsonNode &other) const;
 	bool operator != (const JsonNode &other) const;
 
-	//removes all nodes that are identical to default entry in schema
-	void minimize(const JsonNode& schema);
-	//check schema
-	void validate(const JsonNode& schema);
-
 	//Convert node to another type. Converting to NULL will clear all data
 	void setType(JsonType Type);
 	JsonType getType() const;
@@ -78,29 +73,19 @@ public:
 	const JsonVector & Vector() const;
 	const JsonMap & Struct() const;
 
-	template<typename T>
-	std::vector<T> StdVector() const;
+	/// convert json tree into specified type. Json tree must have same type as Type
+	/// Valid types: bool, string, any numeric, map and vector
+	/// example: convertTo< std::map< std::vector<int> > >();
+	template<typename Type>
+	Type convertTo() const;
 
 	//operator [], for structs only - get child node by name
 	JsonNode & operator[](std::string child);
 	const JsonNode & operator[](std::string child) const;
 
-	//error value for const operator[]
-	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);
-
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
+		// simple saving - save json in its string interpretation
 		if (h.saving)
 		{
 			std::ostringstream stream;
@@ -117,129 +102,199 @@ public:
 	}
 };
 
-template<>
-inline std::vector<std::string> JsonNode::StdVector() const
+namespace JsonUtils
 {
-	std::vector<std::string> ret;
-	BOOST_FOREACH(const JsonNode &node, Vector())
-	{
-		ret.push_back(node.String());
-	}
-	return ret;
+	DLL_LINKAGE Bonus * parseBonus (const JsonVector &ability_vec);
+	DLL_LINKAGE Bonus * parseBonus (const JsonNode &bonus);
+	DLL_LINKAGE void unparseBonus (JsonNode &node, const Bonus * bonus);
+
+	/// 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
+	DLL_LINKAGE void merge(JsonNode & dest, JsonNode & source);
+	/// this function will preserve data stored in source by creating copy
+	DLL_LINKAGE void mergeCopy(JsonNode & dest, JsonNode source);
+
+	/// removes all nodes that are identical to default entry in schema
+	DLL_LINKAGE void minimize(JsonNode & node, const JsonNode& schema);
+
+	/// check schema
+	DLL_LINKAGE void validate(JsonNode & node, const JsonNode& schema);
 }
 
-template<typename T>
-std::vector<T> JsonNode::StdVector() const
+//////////////////////////////////////////////////////////////////////////////////////////////////////
+// End of public section of the file. Anything below should be only used internally in JsonNode.cpp //
+//////////////////////////////////////////////////////////////////////////////////////////////////////
+
+namespace JsonDetail
 {
-	static_assert(std::is_arithmetic<T>::value, "This works with numbers only.");
-	std::vector<T> ret;
-	BOOST_FOREACH(const JsonNode &node, Vector())
+	// convertion helpers for JsonNode::convertTo (partial template function instantiation is illegal in c++)
+	template<typename Type>
+	struct JsonConverter
 	{
-		ret.push_back(node.Float());
-	}
-	return ret;
-}
+		static Type convert(const JsonNode & node)
+		{
+			///this should be triggered only for numeric types
+			static_assert(std::is_arithmetic<Type>::value, "Unsupported type for JsonNode::convertTo()!");
+			return node.Float();
+		}
+	};
 
-class JsonWriter
-{
-	//prefix for each line (tabulation)
-	std::string prefix;
-	std::ostream &out;
-public:
-	template<typename Iterator>
-	void writeContainer(Iterator begin, Iterator end);
-	void writeEntry(JsonMap::const_iterator entry);
-	void writeEntry(JsonVector::const_iterator entry);
-	void writeString(const std::string &string);
-	void writeNode(const JsonNode &node);
-	JsonWriter(std::ostream &output, const JsonNode &node);
-};
+	template<typename Type>
+	struct JsonConverter<std::map<std::string, Type> >
+	{
+		static std::map<std::string, Type> convert(const JsonNode & node)
+		{
+			std::map<std::string, Type> ret;
+			BOOST_FOREACH(auto entry, node.Struct())
+			{
+				ret.insert(entry.first, entry.second.convertTo<Type>());
+			}
+			return ret;
 
-//Tiny string class that uses const char* as data for speed, members are private
-//for ease of debugging and some compatibility with std::string
-class constString
-{
-	const char *data;
-	const size_t datasize;
+		}
+	};
 
-public:
-	constString(const char * inputString, size_t stringSize):
-		data(inputString),
-		datasize(stringSize)
+	template<typename Type>
+	struct JsonConverter<std::vector<Type> >
 	{
-	}
+		static std::vector<Type> convert(const JsonNode & node)
+		{
+			std::vector<Type> ret;
+			BOOST_FOREACH(auto entry, node.Vector())
+			{
+				ret.push_back(entry.convertTo<Type>());
+			}
+			return ret;
+		}
+	};
 
-	inline size_t size() const
+	template<>
+	struct JsonConverter<std::string>
 	{
-		return datasize;
+		static std::string convert(const JsonNode & node)
+		{
+			return node.String();
+		}
 	};
 
-	inline const char& operator[] (size_t position)
+	template<>
+	struct JsonConverter<bool>
 	{
-		assert (position < datasize);
-		return data[position];
-	}
-};
+		static bool convert(const JsonNode & node)
+		{
+			return node.Bool();
+		}
+	};
 
-//Internal class for string -> JsonNode conversion
-class JsonParser
-{
-	std::string errors;     // Contains description of all encountered errors
-	constString input;      // Input data
-	ui32 lineCount; // Currently parsed line, starting from 1
-	size_t lineStart;       // Position of current line start
-	size_t pos;             // Current position of parser
-
-	//Helpers
-	bool extractEscaping(std::string &str);
-	bool extractLiteral(const std::string &literal);
-	bool extractString(std::string &string);
-	bool extractWhitespace(bool verbose = true);
-	bool extractSeparator();
-	bool extractElement(JsonNode &node, char terminator);
-
-	//Methods for extracting JSON data
-	bool extractArray(JsonNode &node);
-	bool extractFalse(JsonNode &node);
-	bool extractFloat(JsonNode &node);
-	bool extractNull(JsonNode &node);
-	bool extractString(JsonNode &node);
-	bool extractStruct(JsonNode &node);
-	bool extractTrue(JsonNode &node);
-	bool extractValue(JsonNode &node);
-
-	//Add error\warning message to list
-	bool error(const std::string &message, bool warning=false);
+	class JsonWriter
+	{
+		//prefix for each line (tabulation)
+		std::string prefix;
+		std::ostream &out;
+	public:
+		template<typename Iterator>
+		void writeContainer(Iterator begin, Iterator end);
+		void writeEntry(JsonMap::const_iterator entry);
+		void writeEntry(JsonVector::const_iterator entry);
+		void writeString(const std::string &string);
+		void writeNode(const JsonNode &node);
+		JsonWriter(std::ostream &output, const JsonNode &node);
+	};
 
-public:
-	JsonParser(const char * inputString, size_t stringSize, JsonNode &root);
-};
+	//Tiny string class that uses const char* as data for speed, members are private
+	//for ease of debugging and some compatibility with std::string
+	class constString
+	{
+		const char *data;
+		const size_t datasize;
 
-//Internal class for Json validation, used automaticaly in JsonNode constructor. Behaviour:
-// - "schema" entry from root node is used for validation and will be removed
-// - any missing entries will be replaced with default value from schema (if present)
-// - if entry uses different type than defined in schema it will be removed
-// - entries nod described in schema will be kept unchanged
-class JsonValidator
-{
-	std::string errors;     // Contains description of all encountered errors
-	std::list<std::string> currentPath; // path from root node to current one
-	bool minimize;
+	public:
+		constString(const char * inputString, size_t stringSize):
+			data(inputString),
+			datasize(stringSize)
+		{
+		}
 
-	bool validateType(JsonNode &node, const JsonNode &schema, JsonNode::JsonType type);
-	bool validateSchema(JsonNode::JsonType &type, const JsonNode &schema);
-	bool validateNode(JsonNode &node, const JsonNode &schema, const std::string &name);
-	bool validateItems(JsonNode &node, const JsonNode &schema);
-	bool validateProperties(JsonNode &node, const JsonNode &schema);
+		inline size_t size() const
+		{
+			return datasize;
+		};
 
-	bool addMessage(const std::string &message);
-public:
-	// validate node with "schema" entry
-	JsonValidator(JsonNode &root, bool minimize=false);
-	// validate with external schema
-	JsonValidator(JsonNode &root, const JsonNode &schema, bool minimize=false);
-};
+		inline const char& operator[] (size_t position)
+		{
+			assert (position < datasize);
+			return data[position];
+		}
+	};
 
-DLL_LINKAGE Bonus * ParseBonus (const JsonVector &ability_vec);
-DLL_LINKAGE Bonus * ParseBonus (const JsonNode &bonus);
-DLL_LINKAGE void UnparseBonus (JsonNode &node, const Bonus * bonus);
+	//Internal class for string -> JsonNode conversion
+	class JsonParser
+	{
+		std::string errors;     // Contains description of all encountered errors
+		constString input;      // Input data
+		ui32 lineCount; // Currently parsed line, starting from 1
+		size_t lineStart;       // Position of current line start
+		size_t pos;             // Current position of parser
+
+		//Helpers
+		bool extractEscaping(std::string &str);
+		bool extractLiteral(const std::string &literal);
+		bool extractString(std::string &string);
+		bool extractWhitespace(bool verbose = true);
+		bool extractSeparator();
+		bool extractElement(JsonNode &node, char terminator);
+
+		//Methods for extracting JSON data
+		bool extractArray(JsonNode &node);
+		bool extractFalse(JsonNode &node);
+		bool extractFloat(JsonNode &node);
+		bool extractNull(JsonNode &node);
+		bool extractString(JsonNode &node);
+		bool extractStruct(JsonNode &node);
+		bool extractTrue(JsonNode &node);
+		bool extractValue(JsonNode &node);
+
+		//Add error\warning message to list
+		bool error(const std::string &message, bool warning=false);
+
+	public:
+		JsonParser(const char * inputString, size_t stringSize, JsonNode &root);
+	};
+
+	//Internal class for Json validation, used automaticaly in JsonNode constructor. Behaviour:
+	// - "schema" entry from root node is used for validation and will be removed
+	// - any missing entries will be replaced with default value from schema (if present)
+	// - if entry uses different type than defined in schema it will be removed
+	// - entries nod described in schema will be kept unchanged
+	class JsonValidator
+	{
+		std::string errors;     // Contains description of all encountered errors
+		std::list<std::string> currentPath; // path from root node to current one
+		bool minimize;
+
+		bool validateType(JsonNode &node, const JsonNode &schema, JsonNode::JsonType type);
+		bool validateSchema(JsonNode::JsonType &type, const JsonNode &schema);
+		bool validateNode(JsonNode &node, const JsonNode &schema, const std::string &name);
+		bool validateItems(JsonNode &node, const JsonNode &schema);
+		bool validateProperties(JsonNode &node, const JsonNode &schema);
+
+		bool addMessage(const std::string &message);
+	public:
+		// validate node with "schema" entry
+		JsonValidator(JsonNode &root, bool minimize=false);
+		// validate with external schema
+		JsonValidator(JsonNode &root, const JsonNode &schema, bool minimize=false);
+	};
+
+} // namespace JsonDetail
+
+template<typename Type>
+Type JsonNode::convertTo() const
+{
+	return JsonDetail::JsonConverter<Type>::convert(*this);
+}

+ 1 - 1
lib/Map/CMap.h

@@ -102,7 +102,7 @@ struct DLL_LINKAGE PlayerInfo
 	EAiTactic::EAiTactic aiTactic;
 
 	/** A list of unique IDs of allowed factions. */
-	std::set<ui32> allowedFactions;
+	std::set<TFaction> allowedFactions;
 
 	/** Unused. True if the faction should be chosen randomly. */
 	bool isFactionRandom;

+ 1 - 1
lib/Map/CMapInfo.cpp

@@ -25,7 +25,7 @@ void CMapInfo::countPlayers()
 
 	if(scenarioOpts)
 		for (auto i = scenarioOpts->playerInfos.cbegin(); i != scenarioOpts->playerInfos.cend(); i++)
-			if(i->second.human)
+			if(i->second.playerID != PlayerSettings::PLAYER_AI)
 				actualHumanPlayers++;
 }
 

+ 23 - 10
lib/StartInfo.h

@@ -19,19 +19,31 @@ class CCampaignState;
 /// Struct which describes the name, the color, the starting bonus of a player
 struct PlayerSettings
 {
-	enum Ebonus {brandom=-1,bartifact, bgold, bresource};
+	enum { PLAYER_AI = 0 }; // for use in playerID
+
+	enum Ebonus {
+		NONE     = -2,
+		RANDOM   = -1,
+		ARTIFACT =  0,
+		GOLD     =  1,
+		RESOURCE =  2
+	};
+
+	//uses enum type Ebonus
+	si8 bonus;
+	si16 castle;
+	si32 hero,
+	     heroPortrait; //-1 if default, else ID
 
-	si32 castle, hero,  //ID, if -1 then random, if -2 then none
-		heroPortrait; //-1 if default, else ID
 	std::string heroName;
-	si8 bonus; //uses enum type Ebonus
 	TPlayerColor color; //from 0 - 
 	ui8 handicap;//0-no, 1-mild, 2-severe
 	ui8 team;
 
 	std::string name;
-	ui8 human; //0 - AI, non-0 serves as player id
-	template <typename Handler> 	void serialize(Handler &h, const int version)
+	ui8 playerID; //0 - AI, non-0 serves as player id
+	template <typename Handler>
+	void serialize(Handler &h, const int version)
 	{
 		h & castle;
 		h & hero;
@@ -41,13 +53,13 @@ struct PlayerSettings
 		h & color;
 		h & handicap;
 		h & name;
-		h & human;
+		h & playerID;
 		h & team;
 	}
 
 	PlayerSettings()
 	{
-		bonus = brandom;
+		bonus = RANDOM;
 		castle = -2;
 		heroPortrait = -1;
 	}
@@ -85,13 +97,14 @@ struct StartInfo
 	PlayerSettings *getPlayersSettings(const ui8 nameID)
 	{
 		for(auto it=playerInfos.begin(); it != playerInfos.end(); ++it)
-			if(it->second.human == nameID)
+			if(it->second.playerID == nameID)
 				return &it->second;
 
 		return NULL;
 	}
 
-	template <typename Handler> void serialize(Handler &h, const int version)
+	template <typename Handler>
+	void serialize(Handler &h, const int version)
 	{
 		h & mode;
 		h & difficulty;