Sfoglia il codice sorgente

- added battleAI to CMake, compile fixes
- icons config for towns and creatures

Ivan Savenko 13 anni fa
parent
commit
8f936cd34d

+ 4 - 3
AI/BattleAI/BattleAI.cpp

@@ -135,6 +135,7 @@ bool isCloser(const EnemyInfo & ei1, const EnemyInfo & ei2, const ReachabilityIn
 	return distToNearestNeighbour(ei1.s->position, dists) < distToNearestNeighbour(ei2.s->position, dists);
 }
 
+//FIXME: unused function
 static bool willSecondHexBlockMoreEnemyShooters(const BattleHex &h1, const BattleHex &h2)
 {
 	int shooters[2] = {0}; //count of shooters on hexes
@@ -167,7 +168,7 @@ struct ThreatMap
 	const CStack *endangered; 
 	std::array<int, GameConstants::BFIELD_SIZE> sufferedDamage; 
 
-	struct ThreatMap(const CStack *Endangered)
+	ThreatMap(const CStack *Endangered)
 		: endangered(Endangered)
 	{
 		sufferedDamage.fill(0);
@@ -491,7 +492,7 @@ BattleAction CBattleAI::goTowards(const CStack * stack, BattleHex destination)
 
 BattleAction CBattleAI::useCatapult(const CStack * stack)
 {
-	throw std::exception("The method or operation is not implemented.");
+	throw std::runtime_error("The method or operation is not implemented.");
 }
 
 bool isSupportedSpell(const CSpell *spell)
@@ -553,7 +554,7 @@ void CBattleAI::attemptCastingSpell()
 {
 	LOGL("Casting spells sounds like fun. Let's see...");
 
-	auto known = cb->battleGetFightingHero(side);
+	//auto known = cb->battleGetFightingHero(side);
 
 	//Get all spells we can cast
 	std::vector<const CSpell*> possibleSpells;

+ 5 - 5
AI/BattleAI/CMakeLists.txt

@@ -1,12 +1,12 @@
-project(stupidAI)
+project(battleAI)
 cmake_minimum_required(VERSION 2.6)
 
 include_directories(${CMAKE_HOME_DIRECTORY} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_HOME_DIRECTORY}/lib)
 
-set(stupidAI_SRCS
-        StupidAI.cpp
+set(battleAI_SRCS
+        BattleAI.cpp
         main.cpp
 )
 
-add_library(StupidAI SHARED ${stupidAI_SRCS})
-target_link_libraries(StupidAI vcmi)
+add_library(BattleAI SHARED ${battleAI_SRCS})
+target_link_libraries(BattleAI vcmi)

+ 1 - 0
AI/CMakeLists.txt

@@ -2,6 +2,7 @@ project(AI)
 cmake_minimum_required(VERSION 2.6)
 
 add_subdirectory(FuzzyLite)
+add_subdirectory(BattleAI)
 add_subdirectory(StupidAI)
 add_subdirectory(EmptyAI)
 add_subdirectory(VCAI)

+ 2 - 6
client/AdventureMapClasses.cpp

@@ -9,6 +9,7 @@
 #include "../lib/CObjectHandler.h"
 #include "../lib/CGameState.h"
 #include "../lib/CGeneralTextHandler.h"
+#include "../lib/CTownHandler.h"
 #include "../lib/NetPacks.h"
 #include "../lib/CHeroHandler.h"
 #include "CAdvmapInterface.h"
@@ -291,12 +292,7 @@ CIntObject * CTownList::CTownItem::genSelection()
 
 void CTownList::CTownItem::update()
 {
-	size_t iconIndex = town->subID*2;
-	if (!town->hasFort())
-		iconIndex += GameConstants::F_NUMBER*2;
-
-	if(town->builded >= CGI->modh->settings.MAX_BUILDING_PER_TURN)
-		iconIndex++;
+	size_t iconIndex = town->town->clientInfo.icons[town->hasFort()][town->builded >= CGI->modh->settings.MAX_BUILDING_PER_TURN];
 
 	picture->setFrame(iconIndex + 2);
 	redraw();

+ 1 - 1
client/BattleInterface/CBattleInterface.cpp

@@ -283,7 +283,7 @@ CBattleInterface::CBattleInterface(const CCreatureSet * army1, const CCreatureSe
 	//loading projectiles for units
 	BOOST_FOREACH(const CStack *s, stacks)
 	{
-		int creID = (s->getCreature()->idNumber == 149) ? CGI->creh->factionToTurretCreature[siegeH->town->town->typeID] : s->getCreature()->idNumber; //id of creature whose shots should be loaded
+		//int creID = (s->getCreature()->idNumber == 149) ? CGI->creh->factionToTurretCreature[siegeH->town->town->typeID] : s->getCreature()->idNumber; //id of creature whose shots should be loaded
 		if(s->getCreature()->isShooting())
 		{
 			CDefHandler *&projectile = idToProjectile[s->getCreature()->idNumber];

+ 3 - 3
client/BattleInterface/CBattleInterfaceClasses.cpp

@@ -371,7 +371,7 @@ CBattleResultWindow::CBattleResultWindow(const BattleResult &br, const SDL_Rect
 				bestMonsterID = it->second->type->idNumber;
 			}
 		}
-		new CAnimImage("TWCRPORT", bestMonsterID+2, 0, 392, 38);
+		new CAnimImage("TWCRPORT", CGI->creh->creatures[bestMonsterID]->iconIndex, 0, 392, 38);
 		//setting defenderName
 		defenderName =  CGI->creh->creatures[bestMonsterID]->namePl;
 	}
@@ -394,7 +394,7 @@ CBattleResultWindow::CBattleResultWindow(const BattleResult &br, const SDL_Rect
 			int yPos = 344 + step*97;
 			for(std::map<ui32,si32>::const_iterator it=br.casualties[step].begin(); it!=br.casualties[step].end(); ++it)
 			{
-				new CAnimImage("CPRSMALL", it->first+2, 0, xPos, yPos);
+				new CAnimImage("CPRSMALL", CGI->creh->creatures[it->first]->iconIndex, 0, xPos, yPos);
 				std::ostringstream amount;
 				amount<<it->second;
 				new CLabel( xPos+16, yPos + 42, FONT_SMALL, CENTER, Colors::Cornsilk, amount.str());
@@ -689,7 +689,7 @@ void CStackQueue::StackBox::setStack( const CStack *stack )
 {
 	this->stack = stack;
 	assert(stack);
-	icon->setFrame(stack->getCreature()->idNumber + 2);
+	icon->setFrame(stack->getCreature()->iconIndex);
 }
 
 CStackQueue::StackBox::StackBox(bool small):

+ 2 - 7
client/CCastleInterface.cpp

@@ -937,12 +937,7 @@ void CCastleInterface::recreateIcons()
 	delete fort;
 	delete hall;
 
-	size_t iconIndex = town->subID*2;
-	if (!town->hasFort())
-		iconIndex += GameConstants::F_NUMBER*2;
-
-	if(town->builded >= CGI->modh->settings.MAX_BUILDING_PER_TURN)
-		iconIndex++;
+	size_t iconIndex = town->town->clientInfo.icons[town->hasFort()][town->builded >= CGI->modh->settings.MAX_BUILDING_PER_TURN];
 
 	icon->setFrame(iconIndex);
 	income->setTxt(boost::lexical_cast<std::string>(town->dailyIncome()));
@@ -981,7 +976,7 @@ CCreaInfo::CCreaInfo(Point position, const CGTownInstance *Town, int Level, bool
 	ui32 creatureID = town->creatures[level].second.back();
 	creature = CGI->creh->creatures[creatureID];
 
-	picture = new CAnimImage("CPRSMALL", creatureID+2, 0, 8, 0);
+	picture = new CAnimImage("CPRSMALL", creature->iconIndex, 0, 8, 0);
 
 	std::string value;
 	if (showAvailable)

+ 2 - 6
client/CKingdomInterface.cpp

@@ -7,6 +7,7 @@
 #include "../lib/CModHandler.h" //for buildings per turn
 #include "../lib/CObjectHandler.h" //Hero/Town objects
 #include "../lib/CHeroHandler.h" // only for calculating required xp? worth it?
+#include "../lib/CTownHandler.h"
 #include "CAnimation.h" //CAnimImage
 #include "CAdvmapInterface.h" //CResDataBar
 #include "CCastleInterface.h" //various town-specific classes
@@ -794,12 +795,7 @@ CTownItem::CTownItem(const CGTownInstance* Town):
 	garr = new CGarrisonInt(313, 3, 4, Point(232,0),  NULL, Point(313,2), town->getUpperArmy(), town->visitingHero, true, true, true);
 	heroes = new HeroSlots(town, Point(244,6), Point(475,6), garr, false);
 
-	size_t iconIndex = town->subID*2;
-	if (!town->hasFort())
-		iconIndex += GameConstants::F_NUMBER*2;
-
-	if(town->builded >= CGI->modh->settings.MAX_BUILDING_PER_TURN)
-		iconIndex++;
+	size_t iconIndex = town->town->clientInfo.icons[town->hasFort()][town->builded >= CGI->modh->settings.MAX_BUILDING_PER_TURN];
 
 	picture = new CAnimImage("ITPT", iconIndex, 0, 5, 6);
 	townArea = new LRClickableAreaOpenTown;

+ 3 - 0
client/CMusicHandler.cpp

@@ -155,6 +155,9 @@ Mix_Chunk *CSoundHandler::GetSoundChunk(soundBase::soundID soundID)
 
 Mix_Chunk *CSoundHandler::GetSoundChunk(std::string &sound)
 {
+	if (sound.empty())
+		return nullptr;
+
 	// Load and insert
 	try
 	{

+ 4 - 8
client/GUIClasses.cpp

@@ -160,13 +160,9 @@ void CTownTooltip::init(const InfoAboutTown &town)
 
 	assert(town.tType);
 
-	size_t imageIndex = town.tType->typeID * 2;
-	if (town.fortLevel == 0)
-		imageIndex += GameConstants::F_NUMBER * 2;
-	if (town.built >= CGI->modh->settings.MAX_BUILDING_PER_TURN)
-		imageIndex++;
+	size_t iconIndex = town.tType->clientInfo.icons[town.fortLevel > 0][town.built >= CGI->modh->settings.MAX_BUILDING_PER_TURN];
 
-	new CAnimImage("itpt", imageIndex, 0, 3, 2);
+	new CAnimImage("itpt", iconIndex, 0, 3, 2);
 
 	if(town.details)
 	{
@@ -877,7 +873,7 @@ size_t CComponent::getIndex()
 	case primskill:  return subtype;
 	case secskill:   return subtype*3 + 3 + val - 1;
 	case resource:   return subtype;
-	case creature:   return subtype+2;
+	case creature:   return CGI->creh->creatures[subtype]->iconIndex;
 	case artifact:   return subtype;
 	case experience: return 4;
 	case spell:      return subtype;
@@ -900,7 +896,7 @@ std::string CComponent::getDescription()
 	case secskill:   return CGI->generaltexth->skillInfoTexts[subtype][val-1];
 	case resource:   return CGI->generaltexth->allTexts[242];
 	case creature:   return "";
-	case artifact:   return  CGI->arth->artifacts[subtype]->Description();
+	case artifact:   return CGI->arth->artifacts[subtype]->Description();
 	case experience: return CGI->generaltexth->allTexts[241];
 	case spell:      return CGI->spellh->spells[subtype]->descriptions[val];
 	case morale:     return CGI->generaltexth->heroscrn[ 4 - (val>0) + (val<0)];

+ 3 - 13
client/Graphics.cpp

@@ -360,21 +360,11 @@ SDL_Surface * Graphics::getPic(int ID, bool fort, bool builded)
 		return smallIcons->ourImages[1].bitmap;
 	else if (ID==-3)
 		return smallIcons->ourImages[2+GameConstants::F_NUMBER*4].bitmap;
-	else if (ID>GameConstants::F_NUMBER || ID<-3)
-#ifndef __GNUC__
-		throw new std::exception("Invalid ID");
-#else
-		throw new std::exception();
-#endif
 	else
 	{
-		int pom = 3;
-		if(!fort)
-			pom+=GameConstants::F_NUMBER*2;
-		pom += ID*2;
-		if (!builded)
-			pom--;
-		return smallIcons->ourImages[pom].bitmap;
+		assert(vstd::contains(CGI->townh->towns, ID));
+		int pom = CGI->townh->towns[ID].clientInfo.icons[fort][builded];
+		return smallIcons->ourImages[pom + 2].bitmap;
 	}
 }
 

+ 48 - 0
config/buildings.json

@@ -107,6 +107,12 @@
 				{ "id" : 43, "animation" : "TBCSUP_6.def", "x" : 303, "y" : 0,   "z" : -1, "border" : "TOCSANG2.bmp", "area" : "TZCSANG2.bmp" },
 
 			],
+			"icons" :
+			{
+				"village" : {"normal" : 18, "built" : 19 },
+				"fort"    : {"normal" : 0,  "built" : 1 }
+			},
+
 			"musicTheme" : "music/CstleTown",
 
 			"townBackground": "TBCSBACK.bmp",
@@ -285,6 +291,12 @@
 				{ "id" : 42, "animation" : "TBRMUP_5.def", "x" : 362, "y" : 90,  "z" : -2, "border" : "TORUNI2.bmp",  "area" : "TZRUNI2.bmp" },
 				{ "id" : 43, "animation" : "TBRMUP_6.def", "x" : 502, "y" : 5,   "z" : -5, "border" : "TORDR2AA.bmp", "area" : "TZRDR2AA.bmp" }
 			],
+			"icons" :
+			{
+				"village" : {"normal" : 20, "built" : 21 },
+				"fort"    : {"normal" : 2,  "built" : 3 }
+			},
+
 			"musicTheme" : "music/Rampart",
 
 			"townBackground": "TBRMBACK.bmp",
@@ -458,6 +470,12 @@
 				{ "id" : 42, "animation" : "TBTWUP_5.def", "x" : 681, "y" : 157, "z" : 2,  "border" : "TOTNAG2.bmp",  "area" : "TZTNAG2.bmp" },
 				{ "id" : 43, "animation" : "TBTWUP_6.def", "x" : 75,  "y" : 91,  "z" : -1, "border" : "TOTTIT2.bmp",  "area" : "TZTTIT2.bmp" }
 			],
+			"icons" :
+			{
+				"village" : {"normal" : 22, "built" : 23 },
+				"fort"    : {"normal" : 4,  "built" : 5 }
+			},
+
 			"musicTheme" : "music/TowerTown",
 
 			"townBackground": "TBTWBACK.bmp",
@@ -630,6 +648,11 @@
 				{ "id" : 42, "animation" : "TBINUP_5.def", "x" : 220, "y" : 282, "z" : 5,  "border" : "TOIEFR2.bmp",  "area" : "TZIEFR2.bmp" },
 				{ "id" : 43, "animation" : "TBINUP_6.def", "x" : 420, "y" : 105, "z" : -1, "border" : "TOIDVL2.bmp",  "area" : "TZIDVL2.bmp" }
 			],
+			"icons" :
+			{
+				"village" : {"normal" : 24, "built" : 25 },
+				"fort"    : {"normal" : 6,  "built" : 7 }
+			},
 			"musicTheme" : "music/InfernoTown",
 
 			"townBackground": "TBINBACK.bmp",
@@ -808,6 +831,11 @@
 				{ "id" : 42, "animation" : "TBNCUP_5.def", "x" : 0,   "y" : 30,  "border" : "TONBKN2.bmp",  "area" : "TZNBKN2.bmp" },
 				{ "id" : 43, "animation" : "TBNCUP_6.def", "x" : 662, "y" : 23,  "border" : "TONBON2.bmp",  "area" : "TZNBON2.bmp" }
 			],
+			"icons" :
+			{
+				"village" : {"normal" : 26, "built" : 27 },
+				"fort"    : {"normal" : 8,  "built" : 9 }
+			},
 			"musicTheme" : "music/NecroTown",
 
 			"townBackground": "TBNCBACK.bmp",
@@ -980,6 +1008,11 @@
 				{ "id" : 42, "animation" : "TBDNUP_5.def", "x" : 270, "y" : 253, "z" : -1, "border" : "TODMAN2.bmp",  "area" : "TZDMAN2.bmp" },
 				{ "id" : 43, "animation" : "TBDNUP_6.def", "x" : 550, "y" : 0,   "z" : -1, "border" : "TODDRA2A.bmp", "area" : "TZDDRA2A.bmp" },
 			],
+			"icons" :
+			{
+				"village" : {"normal" : 28, "built" : 29 },
+				"fort"    : {"normal" : 10, "built" : 11 }
+			},
 			"musicTheme" : "music/Dungeon",
 
 			"townBackground": "TBDNBACK.bmp",
@@ -1150,6 +1183,11 @@
 				{ "id" : 42, "animation" : "TBSTUP_5.def", "x" : 616, "y" : 93,  "z" : -2, "border" : "TOSCYC2A.bmp", "area" : "TZSCYC2A.bmp" },
 				{ "id" : 43, "animation" : "TBSTUP_6.def", "x" : 604, "y" : 0,   "border" : "TOSBEH2A.bmp", "area" : "TZSBEH2A.bmp" }
 			],
+			"icons" :
+			{
+				"village" : {"normal" : 30, "built" : 31 },
+				"fort"    : {"normal" : 12, "built" : 13 }
+			},
 			"musicTheme" : "music/Stronghold",
 
 			"townBackground": "TBSTBACK.bmp",
@@ -1322,6 +1360,11 @@
 				{ "id" : 42, "animation" : "TBFRUP_5.def", "x" : 0,   "y" : 4,   "border" : "TOFWYV2.bmp",  "area" : "TZFWYV2.bmp" },
 				{ "id" : 43, "animation" : "TBFRUP_6.def", "x" : 587, "y" : 263, "z" : 5,  "border" : "TOFHYD2A.bmp", "area" : "TZFHYD2A.bmp" }
 			],
+			"icons" :
+			{
+				"village" : {"normal" : 32, "built" : 33 },
+				"fort"    : {"normal" : 14, "built" : 15 }
+			},
 			"musicTheme" : "music/FortressTown",
 
 			"townBackground": "TBFRBACK.bmp",
@@ -1499,6 +1542,11 @@
 				{ "id" : 42, "animation" : "TBELUP_5.def", "x" : 394, "y" : 283, "z" : 2,  "border" : "TOELUP_5.bmp", "area" : "TZELUP_5.bmp" },
 				{ "id" : 43, "animation" : "TBELUP_6.def", "x" : 43,  "y" : 0,   "z" : -2, "border" : "TOELUP_6.bmp", "area" : "TZELUP_6.bmp" },
 			],
+			"icons" :
+			{
+				"village" : {"normal" : 34, "built" : 35 },
+				"fort"    : {"normal" : 16, "built" : 17 }
+			},
 			"musicTheme" : "music/ElemTown",
 
 			"townBackground": "TBELBACK.bmp",

+ 26 - 69
lib/CCreatureHandler.cpp

@@ -148,10 +148,7 @@ std::string CCreature::nodeName() const
 
 bool CCreature::isItNativeTerrain(int terrain) const
 {
-	if (faction > -1)
-		return VLC->townh->factions[faction].nativeTerrain == terrain;
-	else
-		return VLC->townh->factions[0].nativeTerrain == terrain; //FIXME: handle neutral faction properly
+	return VLC->townh->factions[0].nativeTerrain == terrain; //FIXME: handle neutral faction properly
 }
 
 int readNumber(int & befi, int & i, int andame, std::string & buf) //helper function for void CCreatureHandler::loadCreatures() and loadUnitAnimInfo()
@@ -168,20 +165,6 @@ int readNumber(int & befi, int & i, int andame, std::string & buf) //helper func
 	return ret;
 }
 
-double readFloat(int & befi, int & i, int andame, std::string & buf) //helper function for void CCreatureHandler::loadUnitAnimInfo()
-{
-	befi=i;
-	for(; i<andame; ++i)
-	{
-		if(buf[i]=='\t')
-			break;
-	}
-	std::string tmp = buf.substr(befi, i-befi);
-	double ret = atof(buf.substr(befi, i-befi).c_str());
-	++i;
-	return ret;
-}
-
 /**
  * Determines if a faction is good.
  * @param ID of the faction.
@@ -287,6 +270,7 @@ void CCreatureHandler::loadCreatures()
 		ncre.idNumber = creatures.size();
 		ncre.cost.resize(GameConstants::RESOURCE_QUANTITY);
 		ncre.level=0;
+		ncre.iconIndex = ncre.idNumber + 2; // +2 for empty\selection images
 
 		int befi=i;
 		for(; i<andame; ++i)
@@ -624,73 +608,46 @@ void CCreatureHandler::loadCreatures()
 
 void CCreatureHandler::loadAnimationInfo()
 {
-	auto textFile = CResourceHandler::get()->loadData(ResourceID("DATA/CRANIM.TXT"));
-	std::string buf((char*)textFile.first.get(), textFile.second);
-	int andame = buf.size();
-	int i=0; //buf iterator
-	int hmcr=0;
-	for(; i<andame; ++i)
-	{
-		if(buf[i]=='\r')
-			++hmcr;
-		if(hmcr==2)
-			break;
-	}
-	i+=2;
-	for(int dd=0; dd<creatures.size(); ++dd)
-	{
-		//tlog5 << "\t\t\tReading animation info for creature " << dd << std::endl;
-		loadUnitAnimInfo(*creatures[dd], buf, i);
-	}
-	return;
-}
-
-void CCreatureHandler::loadUnitAnimInfo(CCreature & unit, std::string & src, int & i)
-{
-	int befi=i;
+	CLegacyConfigParser parser("DATA/CRANIM.TXT");
 
-	unit.timeBetweenFidgets = readFloat(befi, i, src.size(), src);
+	parser.endLine(); // header
+	parser.endLine();
 
-	while(unit.timeBetweenFidgets == 0.0)
+	for(int dd=0; dd<creatures.size(); ++dd)
 	{
-		for(; i<src.size(); ++i)
-		{
-			if(src[i]=='\r')
-				break;
-		}
-		i+=2;
+		while (parser.isNextEntryEmpty() && parser.endLine()) // skip empty lines
+			;
 
-		unit.timeBetweenFidgets = readFloat(befi, i, src.size(), src);
+		loadUnitAnimInfo(*creatures[dd], parser);
 	}
+}
 
-	unit.walkAnimationTime = readFloat(befi, i, src.size(), src);
-	unit.attackAnimationTime = readFloat(befi, i, src.size(), src);
-	unit.flightAnimationDistance = readFloat(befi, i, src.size(), src);
+void CCreatureHandler::loadUnitAnimInfo(CCreature & unit, CLegacyConfigParser & parser)
+{
+	unit.timeBetweenFidgets = parser.readNumber();
+	unit.walkAnimationTime = parser.readNumber();
+	unit.attackAnimationTime = parser.readNumber();
+	unit.flightAnimationDistance = parser.readNumber();
 	///////////////////////
 
-	unit.upperRightMissleOffsetX = readNumber(befi, i, src.size(), src);
-	unit.upperRightMissleOffsetY = readNumber(befi, i, src.size(), src);
-	unit.rightMissleOffsetX = readNumber(befi, i, src.size(), src);
-	unit.rightMissleOffsetY = readNumber(befi, i, src.size(), src);
-	unit.lowerRightMissleOffsetX = readNumber(befi, i, src.size(), src);
-	unit.lowerRightMissleOffsetY = readNumber(befi, i, src.size(), src);
+	unit.upperRightMissleOffsetX = parser.readNumber();
+	unit.upperRightMissleOffsetY = parser.readNumber();
+	unit.rightMissleOffsetX = parser.readNumber();
+	unit.rightMissleOffsetY = parser.readNumber();
+	unit.lowerRightMissleOffsetX = parser.readNumber();
+	unit.lowerRightMissleOffsetY = parser.readNumber();
 
 	///////////////////////
 
 	for(int jjj=0; jjj<12; ++jjj)
 	{
-		unit.missleFrameAngles[jjj] = readFloat(befi, i, src.size(), src);
+		unit.missleFrameAngles[jjj] = parser.readNumber();
 	}
 
-	unit.troopCountLocationOffset= readNumber(befi, i, src.size(), src);
-	unit.attackClimaxFrame = readNumber(befi, i, src.size(), src);
+	unit.troopCountLocationOffset= parser.readNumber();
+	unit.attackClimaxFrame = parser.readNumber();
 
-	for(; i<src.size(); ++i)
-	{
-		if(src[i]=='\r')
-			break;
-	}
-	i+=2;
+	parser.endLine();
 }
 
 void CCreatureHandler::loadSoundsInfo()

+ 2 - 1
lib/CCreatureHandler.h

@@ -38,6 +38,7 @@ public:
 	std::string animDefName;
 	std::string advMapDef; //for new creatures only
 	si32 idNumber;
+	si32 iconIndex; // index of icon in files like twcrport
 	si8 faction; //-1 = neutral
 	ui8 doubleWide;
 
@@ -149,7 +150,7 @@ public:
 	void loadCreatures();
 	void buildBonusTreeForTiers();
 	void loadAnimationInfo();
-	void loadUnitAnimInfo(CCreature & unit, std::string & src, int & i);
+	void loadUnitAnimInfo(CCreature & unit, CLegacyConfigParser &parser);
 	void loadSoundsInfo();
 	void loadStackExp(Bonus & b, BonusList & bl, CLegacyConfigParser &parser);
 	int stringToNumber(std::string & s);//help function for parsing CREXPBON.txt

+ 1 - 1
lib/CGameState.cpp

@@ -2789,7 +2789,7 @@ DuelParameters DuelParameters::fromJSON(const std::string &fname)
 
 		if(ss.heroId != -1)
 		{
-			auto spells = n["spells"];
+			const JsonNode & spells = n["spells"];
 			if(spells.getType() == JsonNode::DATA_STRING  &&  spells.String() == "all")
 				BOOST_FOREACH(auto spell, VLC->spellh->spells)
 					ss.spells.insert(spell->id);

+ 11 - 62
lib/CModHandler.cpp

@@ -84,7 +84,7 @@ void CModHandler::loadConfigFromFile (std::string name)
 		const JsonNode *value = &config["creatures"];
 		BOOST_FOREACH (auto creature, value->Vector())
 		{
-			auto cre = loadCreature (creature); //create and push back creature
+			auto cre = loadCreature (creature); //FIXME: unused variable 'cre' //create and push back creature
 		}
 	}
 }
@@ -114,51 +114,11 @@ CCreature * CModHandler::loadCreature (const JsonNode &node)
 	cre->namePl = name["plural"].String();
 	cre->nameRef = cre->nameSing;
 
-	//TODO: export resource set to separate function?
-	const JsonNode &  cost = node["cost"];
-	if (cost.getType() == JsonNode::DATA_FLOAT) //gold
-	{
-		cre->cost[Res::GOLD] = cost.Float();
-	}
-	else if (cost.getType() == JsonNode::DATA_VECTOR)
-	{
-		int i = 0;
-		BOOST_FOREACH (auto & val, cost.Vector())
-		{
-			cre->cost[i++] = val.Float();
-		}
-	}
-	else //damn you...
-	{
-		value = &cost["gold"];
-		if (!value->isNull())
-			cre->cost[Res::GOLD] = value->Float();
-		value = &cost["gems"];
-		if (!value->isNull())
-			cre->cost[Res::GEMS] = value->Float();
-		value = &cost["crystal"];
-		if (!value->isNull())
-			cre->cost[Res::CRYSTAL] = value->Float();
-		value = &cost["mercury"];
-		if (!value->isNull())
-			cre->cost[Res::MERCURY] = value->Float();
-		value = &cost["sulfur"];
-		if (!value->isNull())
-			cre->cost[Res::SULFUR] = value->Float();
-		value = &cost["ore"];
-		if (!value->isNull())
-			cre->cost[Res::ORE] = value->Float();
-		value = &cost["wood"];
-		if (!value->isNull())
-			cre->cost[Res::WOOD] = value->Float();
-		value = &cost["mithril"];
-		if (!value->isNull())
-			cre->cost[Res::MITHRIL] = value->Float();
-	}
+	cre->cost = Res::ResourceSet(node["cost"]);
 
 	cre->level = node["level"].Float();
-	cre->faction = -1; //neutral
-	//TODO: node["faction"].String() to id or just node["faction"].Float();
+	cre->faction = 9; //neutral faction is 9 for now. Will be replaced by string -> id conversion
+	//TODO: node["faction"].String() to id
 	cre->fightValue = node["fightValue"].Float();
 	cre->AIValue = node["aiValue"].Float();
 	cre->growth = node["growth"].Float();
@@ -176,13 +136,9 @@ CCreature * CModHandler::loadCreature (const JsonNode &node)
 	cre->ammMax = amounts["max"].Float();
 
 	//optional
-	value = &node["upgrades"];
-	if (!value->isNull())
+	BOOST_FOREACH (auto & str, node["upgrades"].Vector())
 	{
-		BOOST_FOREACH (auto & str, value->Vector())
-		{
-			cre->upgradeNames.insert (str.String());
-		}
+		cre->upgradeNames.insert (str.String());
 	}
 
 	value = &node["shots"];
@@ -193,19 +149,11 @@ CCreature * CModHandler::loadCreature (const JsonNode &node)
 	if (!value->isNull())
 		cre->addBonus(value->Float(), Bonus::CASTS);
 
-	value = &node["doubleWide"];
-	if (!value->isNull())
-		cre->doubleWide = value->Bool();
-	else
-		cre->doubleWide = false;
+	cre->doubleWide = node["doubleWide"].Bool();
 
-	value = &node["abilities"];
-	if (!value->isNull())
+	BOOST_FOREACH (const JsonNode &bonus, node["abilities"].Vector())
 	{
-		BOOST_FOREACH (const JsonNode &bonus, value->Vector())
-		{
-			cre->addNewBonus(ParseBonus(bonus));
-		}
+		cre->addNewBonus(ParseBonus(bonus));
 	}
 	//graphics
 
@@ -234,6 +182,7 @@ CCreature * CModHandler::loadCreature (const JsonNode &node)
 		cre->missleFrameAngles[i++] = angle.Float();
 	}
 	cre->advMapDef = graphics["map"].String();
+	cre->iconIndex = graphics["iconIndex"].Float();
 	
 	//TODO: parse
 	cre->projectile = "PLCBOWX.DEF";
@@ -241,7 +190,7 @@ CCreature * CModHandler::loadCreature (const JsonNode &node)
 
 	const JsonNode & sounds = node["sound"];
 
-#define GET_SOUND_VALUE(value_name) do { value = &sounds[#value_name]; if (!value->isNull()) cre->sounds.value_name = value->String(); } while(0)
+#define GET_SOUND_VALUE(value_name) do { cre->sounds.value_name = sounds[#value_name].String(); } while(0)
 	GET_SOUND_VALUE(attack);
 	GET_SOUND_VALUE(defend);
 	GET_SOUND_VALUE(killed);

+ 5 - 0
lib/CTownHandler.cpp

@@ -252,6 +252,11 @@ void CTownHandler::loadTownHall(CTown &town, const JsonNode & source)
 
 void CTownHandler::loadClientData(CTown &town, const JsonNode & source)
 {
+	town.clientInfo.icons[0][0] = source["icons"]["village"]["normal"].Float();
+	town.clientInfo.icons[0][1] = source["icons"]["village"]["built"].Float();
+	town.clientInfo.icons[1][0] = source["icons"]["fort"]["normal"].Float();
+	town.clientInfo.icons[1][1] = source["icons"]["fort"]["built"].Float();
+
 	town.clientInfo.hallBackground = source["hallBackground"].String();
 	town.clientInfo.musicTheme = source["musicTheme"].String();
 	town.clientInfo.townBackground = source["townBackground"].String();

+ 4 - 1
lib/CTownHandler.h

@@ -105,6 +105,9 @@ public:
 	// Client-only data. Should be moved away from lib
 	struct ClientInfo
 	{
+		//icons [fort is present?][build limit reached?] -> index of icon in def files
+		int icons[2][2];
+
 		std::string musicTheme;
 		std::string townBackground;
 		std::string guildWindow;
@@ -119,7 +122,7 @@ public:
 
 		template <typename Handler> void serialize(Handler &h, const int version)
 		{
-			h & musicTheme & townBackground & guildWindow & buildingsIcons & hallBackground & hallSlots & structures;
+			h & icons & musicTheme & townBackground & guildWindow & buildingsIcons & hallBackground & hallSlots & structures;
 		}
 	} clientInfo;