فهرست منبع

CButton GUI class (partial rewrite of CAdventureButton),
bugs fixes, warnings elimination

paracelsus 12 سال پیش
والد
کامیت
6cef1dd8d8

+ 1 - 1
client/BattleInterface/CBattleInterface.cpp

@@ -1658,7 +1658,7 @@ void CBattleInterface::spellCast( const BattleSpellCast * sc )
 			//displaying animation
 			CDefEssential * animDef = CDefHandler::giveDefEss(animToDisplay);
 
-			int steps = sqrt(static_cast<double>((destcoord.x - srccoord.x)*(destcoord.x - srccoord.x) + (destcoord.y - srccoord.y) * (destcoord.y - srccoord.y))) / 40;
+			int steps = (int)sqrt(static_cast<double>((destcoord.x - srccoord.x)*(destcoord.x - srccoord.x) + (destcoord.y - srccoord.y) * (destcoord.y - srccoord.y))) / 40;
 			if(steps <= 0)
 				steps = 1;
 

+ 4 - 6
client/BattleInterface/CBattleInterfaceClasses.cpp

@@ -263,11 +263,9 @@ CBattleOptionsWindow::CBattleOptionsWindow(const SDL_Rect & position, CBattleInt
 	animSpeeds->onChange = boost::bind(&CBattleInterface::setAnimSpeed, owner, _1);
 
 	setToDefault = new CAdventureMapButton (CGI->generaltexth->zelp[393], boost::bind(&CBattleOptionsWindow::bDefaultf,this), 246, 359, "codefaul.def");
-	setToDefault->swappedImages = true;
-	setToDefault->update();
+	setToDefault->swapImages();
 	exit = new CAdventureMapButton (CGI->generaltexth->zelp[392], boost::bind(&CBattleOptionsWindow::bExitf,this), 357, 359, "soretrn.def",SDLK_RETURN);
-	exit->swappedImages = true;
-	exit->update();
+	exit->swapImages();
 
 	//creating labels
 	labels.push_back(new CLabel(242,  32, FONT_BIG,    CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[392]));//window title
@@ -615,7 +613,7 @@ void CStackQueue::update()
 	owner->curInt->cb->battleGetStackQueue(stacksSorted, stackBoxes.size());
 	if(stacksSorted.size())
 	{
-		for (int i = 0; i < stackBoxes.size() ; i++)
+		for (size_t i = 0; i < stackBoxes.size(); ++i)
 		{
 			stackBoxes[i]->setStack(stacksSorted[i]);
 		}
@@ -646,7 +644,7 @@ CStackQueue::CStackQueue(bool Embedded, CBattleInterface * _owner)
 	}
 
 	stackBoxes.resize(QUEUE_SIZE);
-	for (int i = 0; i < stackBoxes.size(); i++)
+	for (size_t i = 0; i < stackBoxes.size(); ++i)
 	{
 		stackBoxes[i] = new StackBox(embedded);
 		stackBoxes[i]->moveBy(Point(1 + (embedded ? 36 : 80)*i, 0));

+ 0 - 1
client/CAdvmapInterface.cpp

@@ -543,7 +543,6 @@ void CAdvMapInt::updateSleepWake(const CGHeroInstance *h)
 	sleepWake.setIndex(state ? 1 : 0, true);
 	sleepWake.assignedKeys.clear();
 	sleepWake.assignedKeys.insert(state ? SDLK_w : SDLK_z);
-	sleepWake.update();
 }
 
 void CAdvMapInt::updateMoveHero(const CGHeroInstance *h, tribool hasPath)

+ 5 - 5
client/CPlayerInterface.cpp

@@ -959,7 +959,7 @@ void CPlayerInterface::showInfoDialog(const std::string &text, const std::vector
 		return;
 	}
 	std::vector<CComponent*> intComps;
-	for(int i=0;i<components.size();i++)
+	for(size_t i=0; i<components.size(); ++i)
 		intComps.push_back(new CComponent(*components[i]));
 	showInfoDialog(text,intComps,soundID);
 
@@ -1016,7 +1016,7 @@ void CPlayerInterface::showBlockingDialog( const std::string &text, const std::v
 	if(!selection && cancel) //simple yes/no dialog
 	{
 		std::vector<CComponent*> intComps;
-		for(int i=0;i<components.size();i++)
+		for(size_t i=0; i<components.size(); ++i)
 			intComps.push_back(new CComponent(components[i])); //will be deleted by close in window
 
 		showYesNoDialog(text, boost::bind(&CCallback::selectionMade,cb,1,askID),boost::bind(&CCallback::selectionMade,cb,0,askID),true, intComps);
@@ -1024,7 +1024,7 @@ void CPlayerInterface::showBlockingDialog( const std::string &text, const std::v
 	else if(selection)
 	{
 		std::vector<CSelectableComponent*> intComps;
-		for(int i=0;i<components.size();i++)
+		for(size_t i=0; i<components.size(); ++i)
 			intComps.push_back(new CSelectableComponent(components[i])); //will be deleted by CSelWindow::close
 
 		std::vector<std::pair<std::string,CFunctionList<void()> > > pom;
@@ -1438,7 +1438,7 @@ void CPlayerInterface::initializeHeroTownList()
 	wanderingHeroes = newWanderingHeroes;
 	newWanderingHeroes.clear();*/
 
-	for (int i = 0; i < allHeroes.size(); i++)
+	for (size_t i = 0; i < allHeroes.size(); ++i)
 		if (!allHeroes[i]->inTownGarrison)
 			wanderingHeroes += allHeroes[i];
 
@@ -1455,7 +1455,7 @@ void CPlayerInterface::initializeHeroTownList()
 	towns.clear();
 	towns = newTowns;
 	newTowns.clear();*/
-	for(int i = 0; i < allTowns.size(); i++)
+	for(size_t i = 0; i < allTowns.size(); ++i)
 		towns.push_back(allTowns[i]);
 
 	if (adventureInt)

+ 33 - 44
client/CPreGame.cpp

@@ -39,6 +39,7 @@
 #include "../lib/CThreadHelper.h"
 #include "../lib/CConfigHandler.h"
 #include "../lib/GameConstants.h"
+#include "Gfx/Basic.h"
 #include "UIFramework/GL2D.h"
 #include "UIFramework/CGuiHandler.h"
 #include "UIFramework/CIntObjectClasses.h"
@@ -368,23 +369,19 @@ static boost::function<void()> genCommand(CMenuScreen* menu, std::vector<std::st
 	return boost::function<void()>();
 }
 
-CAdventureMapButton* CMenuEntry::createButton(CMenuScreen* parent, const JsonNode& button)
+CButton* CMenuEntry::createButton(CMenuScreen* parent, const JsonNode& button)
 {
 	boost::function<void()> command = genCommand(parent, parent->menuNameToEntry, button["command"].String());
 
-	std::pair<std::string, std::string> help;
-	if (!button["help"].isNull() && button["help"].Float() > 0)
-		help = CGI->generaltexth->zelp[button["help"].Float()];
+	Gfx::Point point(button["x"].asInteger(), button["y"].asInteger());
 
-	int posx = button["x"].Float();
-	if (posx < 0)
-		posx = pos.w + posx;
+	if (point.x < 0) point.x += pos.w;
+	if (point.y < 0) point.y += pos.h;
 
-	int posy = button["y"].Float();
-	if (posy < 0)
-		posy = pos.h + posy;
+	const PairOfStrings * help = (button["help"].Float() > 0) ?
+		&( CGI->generaltexth->zelp[button["help"].asInteger()] ) : nullptr;
 
-	return new CAdventureMapButton(help, command, posx, posy, button["name"].String(), button["hotkey"].Float());
+	return new CButton(command, point, button["name"].String(), 0, 4, help, LCLICK|RCLICK|HOVER|KEYBOARD, button["hotkey"].asInteger());
 }
 
 CMenuEntry::CMenuEntry(CMenuScreen* parent, const JsonNode &config)
@@ -399,7 +396,6 @@ CMenuEntry::CMenuEntry(CMenuScreen* parent, const JsonNode &config)
 	BOOST_FOREACH(const JsonNode& node, config["buttons"].Vector())
 	{
 		buttons.push_back(createButton(parent, node));
-		buttons.back()->hoverable = true;
 		buttons.back()->type |= REDRAW_PARENT;
 	}
 }
@@ -610,32 +606,35 @@ CSelectionScreen::CSelectionScreen(CMenuScreen::EState Type, CMenuScreen::EMulti
 	sel = new SelectionTab(screenType, bind(&CSelectionScreen::changeSelection, this, _1), multiPlayer); //scenario selection tab
 	sel->recActions = DISPOSE;
 
+	auto & zelp = CGI->generaltexth->zelp;
+
 	switch(screenType)
 	{
 	case CMenuScreen::newGame:
 		{
 			card->difficulty->onChange = bind(&CSelectionScreen::difficultyChange, this, _1);
 			card->difficulty->select(1, 0);
-			CAdventureMapButton * select = new CAdventureMapButton(CGI->generaltexth->zelp[45], 0, 411, 80, "GSPBUTT.DEF", SDLK_s);
-			select->callback = [&]()
+
+			const CFunctionList<void()> selectCmd = [&]()
 			{
 				toggleTab(sel);
 				changeSelection(sel->getSelectedMapInfo());
 			};
+			CButton * select = new CButton(selectCmd, Gfx::Point(411, 80), "GSPBUTT", 0, 4, &(zelp[45]), LCLICK|RCLICK|KEYBOARD, SDLK_s);
 			select->addTextOverlay(CGI->generaltexth->allTexts[500], FONT_SMALL);
 
-			CAdventureMapButton *opts = new CAdventureMapButton(CGI->generaltexth->zelp[46], bind(&CSelectionScreen::toggleTab, this, opt), 411, 510, "GSPBUTT.DEF", SDLK_a);
-			opts->addTextOverlay(CGI->generaltexth->allTexts[501], FONT_SMALL);
-
-			CAdventureMapButton * randomBtn = new CAdventureMapButton(CGI->generaltexth->zelp[47], 0, 411, 105, "GSPBUTT.DEF", SDLK_r);
-			randomBtn->addTextOverlay(CGI->generaltexth->allTexts[740], FONT_SMALL);
-			randomBtn->callback = [&]()
+			const CFunctionList<void()> randomCmd = [&]()
 			{
 				toggleTab(randMapTab);
 				changeSelection(&randMapTab->getMapInfo());
 			};
+			CButton * randomBtn = new CButton(randomCmd, Gfx::Point(411, 105), "GSPBUTT", 0, 4, &(zelp[47]), LCLICK|RCLICK|KEYBOARD, SDLK_r);
+			randomBtn->addTextOverlay(CGI->generaltexth->allTexts[740], FONT_SMALL);
 
-			start  = new CAdventureMapButton(CGI->generaltexth->zelp[103], bind(&CSelectionScreen::startScenario, this), 411, 535, "SCNRBEG.DEF", SDLK_b);
+			CButton * opts = new CButton(bind(&CSelectionScreen::toggleTab, this, opt), Gfx::Point(411, 510), "GSPBUTT", 0, 4, &(zelp[46]), LCLICK|RCLICK|KEYBOARD, SDLK_a);
+			opts->addTextOverlay(CGI->generaltexth->allTexts[501], FONT_SMALL);
+
+			start = new CButton(bind(&CSelectionScreen::startScenario, this), Gfx::Point(411, 535), "SCNRBEG", 0, 4, &(zelp[103]), LCLICK|RCLICK|KEYBOARD, SDLK_b);
 
 			if(network)
 			{
@@ -656,31 +655,21 @@ CSelectionScreen::CSelectionScreen(CMenuScreen::EState Type, CMenuScreen::EMulti
 		break;
 	case CMenuScreen::loadGame:
 		sel->recActions = 255;
-		start  = new CAdventureMapButton(CGI->generaltexth->zelp[103], bind(&CSelectionScreen::startScenario, this), 411, 535, "SCNRLOD.DEF", SDLK_l);
+		start = new CButton(bind(&CSelectionScreen::startScenario, this), Gfx::Point(411, 535), "SCNRLOD", 0, 4, &(zelp[103]), LCLICK|RCLICK|KEYBOARD, SDLK_l);
 		break;
 	case CMenuScreen::saveGame:
 		sel->recActions = 255;
-		start  = new CAdventureMapButton("", CGI->generaltexth->zelp[103].second, bind(&CSelectionScreen::startScenario, this), 411, 535, "SCNRSAV.DEF");
+		start = new CButton(bind(&CSelectionScreen::startScenario, this), Gfx::Point(411, 535), "SCNRSAV", 0, 4, &(zelp[103]), LCLICK|RCLICK|KEYBOARD);
 		break;
 	case CMenuScreen::campaignList:
 		sel->recActions = 255;
-		start  = new CAdventureMapButton(std::pair<std::string, std::string>(), bind(&CSelectionScreen::startCampaign, this), 411, 535, "SCNRLOD.DEF", SDLK_b);
+		start = new CButton(bind(&CSelectionScreen::startCampaign, this), Gfx::Point(411, 535), "SCNRLOD", 0, 4, nullptr, LCLICK|RCLICK|KEYBOARD, SDLK_b);
 		break;
 	}
 
 	start->assignedKeys.insert(SDLK_RETURN);
 
-	std::string backName;
-	if(Type == CMenuScreen::campaignList)
-	{
-		backName = "SCNRBACK.DEF";
-	}
-	else
-	{
-		backName = "SCNRBACK.DEF";
-	}
-
-	back = new CAdventureMapButton("", CGI->generaltexth->zelp[105].second, bind(&CGuiHandler::popIntTotally, &GH, this), 581, 535, backName, SDLK_ESCAPE);
+	back = new CButton( bind(&CGuiHandler::popIntTotally, &GH, this), Gfx::Point(581, 535), "SCNRBACK", 0, 2, &(zelp[105]), LCLICK|RCLICK|KEYBOARD, SDLK_ESCAPE);
 
 	if(network)
 	{
@@ -1084,7 +1073,7 @@ std::vector<ResourceID> SelectionTab::getFiles(std::string dirURI, int resType)
 void SelectionTab::parseMaps(const std::vector<ResourceID> & files)
 {
 	allItems.clear();
-	for(int i = 0; i < files.size(); ++i)
+	for(size_t i = 0; i < files.size(); ++i)
 	{
 		try
 		{
@@ -1245,7 +1234,7 @@ SelectionTab::SelectionTab(CMenuScreen::EState Type, const boost::function<void(
 
 	slider = new CSlider(372, 86, tabType != CMenuScreen::saveGame ? 480 : 430, bind(&SelectionTab::sliderMove, this, _1), positions, curItems.size(), 0, false, 1);
 	slider->addUsedEvents(WHEEL);
-	slider->slider->keepFrame = true;
+//*	slider->slider->keepFrame = true;
 	format =  CDefHandler::giveDef("SCSELC.DEF");
 
 	sortingBy = _format;
@@ -1733,14 +1722,14 @@ void RandomMapTab::deactivateButtonsFrom(CHighlightableButtonsGroup * group, int
 			if(btn->isBlocked())
 			{
 				btn->setOffset(0);
-				btn->setState(CButtonBase::NORMAL);
+				btn->setState(CButton::NORMAL);
 			}
 		}
 		else
 		{
 			// Blocked state looks like frame 'selected'=1
 			btn->setOffset(-1);
-			btn->setState(CButtonBase::BLOCKED);
+			btn->setState(CButton::BLOCKED);
 		}
 	}
 }
@@ -3271,8 +3260,8 @@ void CBonusSelection::loadPositionsOfGraphics()
 			SCampPositions::SRegionDesc rd;
 
 			rd.infix = desc["infix"].String();
-			rd.xpos = desc["x"].Float();
-			rd.ypos = desc["y"].Float();
+			rd.xpos = desc["x"].asInteger();
+			rd.ypos = desc["y"].asInteger();
 			sc.regions.push_back(rd);
 		}
 
@@ -3634,9 +3623,9 @@ void CBonusSelection::changeDiff( bool increase )
 void CBonusSelection::updateStartButtonState( int selected /*= -1*/ )
 {
 	if(selected == -1)
-		startB->setState( ourCampaign->getCurrentScenario().travelOptions.bonusesToChoose.size() ? CButtonBase::BLOCKED : CButtonBase::NORMAL);
-	else if(startB->getState() == CButtonBase::BLOCKED)
-		startB->setState(CButtonBase::NORMAL);
+		startB->block( ourCampaign->getCurrentScenario().travelOptions.bonusesToChoose.size());
+	else if(startB->isBlocked())
+		startB->setState(CButton::NORMAL);
 }
 
 CBonusSelection::CRegion::CRegion( CBonusSelection * _owner, bool _accessible, bool _selectable, int _myNumber )

+ 3 - 3
client/CPreGame.h

@@ -80,9 +80,9 @@ public:
 class CMenuEntry : public CIntObject
 {
 	std::vector<CPicture*> images;
-	std::vector<CAdventureMapButton*> buttons;
+	std::vector<CButton*> buttons;
 
-	CAdventureMapButton* createButton(CMenuScreen* parent, const JsonNode& button);
+	CButton* createButton(CMenuScreen* parent, const JsonNode& button);
 public:
 	CMenuEntry(CMenuScreen* parent, const JsonNode &config);
 };
@@ -453,7 +453,7 @@ public:
 	InfoCard *card;
 	OptionsTab *opt;
     RandomMapTab * randMapTab;
-	CAdventureMapButton *start, *back;
+	CButton *start, *back;
 
 	SelectionTab *sel;
 	CIntObject *curTab;

+ 7 - 12
client/GUIClasses.cpp

@@ -3470,32 +3470,27 @@ CSystemOptionsWindow::CSystemOptionsWindow():
 	//setting up buttons
 	load = new CAdventureMapButton (CGI->generaltexth->zelp[321].first, CGI->generaltexth->zelp[321].second,
 									boost::bind(&CSystemOptionsWindow::bloadf, this), 246,  298, "SOLOAD.DEF", SDLK_l);
-	load->swappedImages = true;
-	load->update();
+	load->swapImages();
 
 	save = new CAdventureMapButton (CGI->generaltexth->zelp[322].first, CGI->generaltexth->zelp[322].second,
 	                                boost::bind(&CSystemOptionsWindow::bsavef, this), 357, 298, "SOSAVE.DEF", SDLK_s);
-	save->swappedImages = true;
-	save->update();
+	save->swapImages();
 
 	restart = new CAdventureMapButton (CGI->generaltexth->zelp[323].first, CGI->generaltexth->zelp[323].second,
 									   boost::bind(&CSystemOptionsWindow::brestartf, this), 246, 357, "SORSTRT", SDLK_r);
-	restart->swappedImages = true;
-	restart->update();
+	restart->swapImages();
 
 	mainMenu = new CAdventureMapButton (CGI->generaltexth->zelp[320].first, CGI->generaltexth->zelp[320].second,
 	                                    boost::bind(&CSystemOptionsWindow::bmainmenuf, this), 357, 357, "SOMAIN.DEF", SDLK_m);
-	mainMenu->swappedImages = true;
-	mainMenu->update();
+	mainMenu->swapImages();
 
 	quitGame = new CAdventureMapButton (CGI->generaltexth->zelp[324].first, CGI->generaltexth->zelp[324].second,
 	                                    boost::bind(&CSystemOptionsWindow::bquitf, this), 246, 415, "soquit.def", SDLK_q);
-	quitGame->swappedImages = true;
-	quitGame->update();
+	quitGame->swapImages();
+
 	backToMap = new CAdventureMapButton (CGI->generaltexth->zelp[325].first, CGI->generaltexth->zelp[325].second,
 	                                     boost::bind(&CSystemOptionsWindow::breturnf, this), 357, 415, "soretrn.def", SDLK_RETURN);
-	backToMap->swappedImages = true;
-	backToMap->update();
+	backToMap->swapImages();
 	backToMap->assignedKeys.insert(SDLK_ESCAPE);
 
 	heroMoveSpeed = new CHighlightableButtonsGroup(0);

+ 3 - 3
client/Gfx/Animations.h

@@ -11,7 +11,7 @@ class CImage;
 class CAnimation
 {
 protected:
-	ui32 framesCount;
+	size_t framesCount;
 	ui32 width;
 	ui32 height;
 
@@ -23,7 +23,7 @@ public:
 	virtual ~CAnimation();
 	virtual CImage* getFrame(ui32 fnr) = 0;
 
-	inline ui32 getFramesCount() { return framesCount; };
+	inline size_t getFramesCount() { return framesCount; };
 	inline ui32 getWidth() { return width; };
 	inline ui32 getHeight() { return height; };
 };
@@ -57,7 +57,7 @@ class CPalettedAnimation : CAnimation
 protected:
 	CPalettedAnimation(const SH3DefFile& def, size_t fileSize);
 
-	inline void* operator new(size_t size, ui32 frCount) {
+	inline void* operator new(size_t size, size_t frCount) {
 		return ::operator new(size + frCount * sizeof(void*));
 	}
 

+ 2 - 0
client/Gfx/Images.cpp

@@ -2,6 +2,8 @@
 #include <SDL_opengl.h>
 #include <SDL_endian.h>
 #include "Images.h"
+#include "../UIFramework/GL2D.h"
+
 
 namespace Gfx
 {

+ 1 - 24
client/Gfx/Images.h

@@ -1,31 +1,11 @@
 #pragma once
 
+#include "Basic.h"
 #include "CPaletteRGBA.h"
-#include "../UIFramework/GL2D.h"
-
 
 namespace Gfx
 {
 
-struct Point
-{
-	si32 x;
-	si32 y;
-
-	inline Point() {};
-	inline Point(si32 _x, si32 _y) : x(_x), y(_y) {};
-};
-
-struct Rect
-{
-	Point lt;
-	Point rb;
-
-	inline ui32 width() { return rb.x - lt.x; };
-	inline ui32 height() { return rb.y - lt.y; };
-};
-
-
 enum TransformFlags
 {
 	NONE = 0,
@@ -34,9 +14,6 @@ enum TransformFlags
 	ROTATE_90_DEG = 4
 };
 
-/* Color transform matrix for: grayscale, clone, bloodlust, etc */
-typedef float ColorMatrix[4][4];
-
 
 class CImage
 {

+ 123 - 62
client/UIFramework/CIntObjectClasses.cpp

@@ -199,95 +199,138 @@ void CFilledTexture::showAll()
 //*	CSDL_Ext::fillTexture(to, texture);
 }
 
-CButtonBase::CButtonBase()
+CButton::CButton() :
+	state(NORMAL),
+	images(nullptr),
+	state2image(),
+	text(nullptr)
 {
-	swappedImages = keepFrame = false;
-	bitmapOffset = 0;
-	state=NORMAL;
-	image = NULL;
-	text = NULL;
 }
 
-CButtonBase::~CButtonBase()
+
+CButton::CButton(const CFunctionList<void()> & flist, Gfx::Point position, const std::string & animName, size_t animOffs/*=0*/, size_t imagesNum/*=4*/,
+				 const PairOfStrings * helpStr, ui16 events/*=LCLICK|RCLICK|HOVER|KEYBOARD*/, int key/*=0*/) :
+	state(NORMAL),
+	images(Gfx::CManager::getAnimation(animName)),
+	callback(flist),
+	text(nullptr)
 {
+	pos.x = position.x;
+	pos.y = position.y;
+
+	if (helpStr != nullptr)
+	{
+		helpBox = helpStr->first;
+		status = helpStr->second;
+	}
+
+	if (images)
+	{
+		pos.w = images->getWidth();
+		pos.h = images->getHeight();
+
+		size_t i=0;
+		for (; i<imagesNum; ++i)
+		{
+			state2image[i] = images->getFrame(i + animOffs);
+			if (state2image[i] == nullptr)
+			{
+				tlog2 << "CButton warning: image " << animName << " : " << animOffs+i << " is missing\n";
+				state2image[i] = state2image[0]; //TODO set dummy image
+			}
+		}
+		for (; i<4; ++i)
+		{
+			state2image[i] = state2image[0];
+		}
+	}
+	else {
+		tlog1 << "CButton error: animation file '" << animName << "' is not loaded\n";
+	}
 
+	addUsedEvents(events);
+	if (key != SDLK_UNKNOWN) assignedKeys.insert(key);
 }
 
-void CButtonBase::update()
+
+CButton::~CButton()
 {
-	if (text)
+	delete text;
+}
+
+
+void CButton::clickLeft(tribool down, bool previousState)
+{
+	if (isBlocked()) return;
+
+	if (down)
 	{
-		if (state == PRESSED)
-			text->moveTo(Point(pos.x+pos.w/2+1, pos.y+pos.h/2+1));
-		else
-			text->moveTo(Point(pos.x+pos.w/2, pos.y+pos.h/2));
-	}
+		state == PRESSED;
+		CCS->soundh->playSound(soundBase::button);
 
-	int newPos = (int)state + bitmapOffset;
-	if (newPos < 0)
-		newPos = 0;
+		if (text) text->moveTo(Point(pos.x+pos.w/2+1, pos.y+pos.h/2+1));
+	}
+	else {
+		state = hovered ? HIGHLIGHTED : NORMAL;
 
-	if (state == HIGHLIGHTED && image->getFramesCount() < 4)
-		newPos = image->getFramesCount()-1;
+		if (text) text->moveTo(Point(pos.x+pos.w/2, pos.y+pos.h/2));
+	}
 
-	if (swappedImages)
+	if (previousState && (down==false))
 	{
-		if (newPos == 0) newPos = 1;
-		else if (newPos == 1) newPos = 0;
+		callback();
 	}
+}
 
-//*	if (!keepFrame)
-//*		image->setFrame(newPos);
 
-	if (active)
-		redraw();
+void CButton::clickRight(tribool down, bool previousState)
+{
+	if (down && helpBox.size()) //there is no point to show window with nothing inside...
+		CRClickPopup::createAndPush(helpBox);
+}
+
+
+void CButton::hover(bool on)
+{
+	if (isBlocked()) return;
+
+	state = on ? HIGHLIGHTED : NORMAL;
 }
 
-void CButtonBase::addTextOverlay( const std::string &Text, EFonts font, SDL_Color color)
+
+void CButton::addTextOverlay( const std::string &Text, EFonts font, SDL_Color color)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
 	delete text;
 	text = new CLabel(pos.w/2, pos.h/2, font, CENTER, color, Text);
-	update();
 }
 
-void CButtonBase::setOffset(int newOffset)
+void CButton::swapImages()
 {
-	if (bitmapOffset == newOffset)
-		return;
-	bitmapOffset = newOffset;
-	update();
+	Gfx::CImage* tmp = state2image[0];
+	state2image[0] = state2image[1];
+	state2image[1] = tmp;
 }
 
-void CButtonBase::setState(ButtonState newState)
+
+void CButton::setState(ButtonState newState)
 {
-	if (state == newState)
-		return;
 	state = newState;
-	update();
 }
 
-CButtonBase::ButtonState CButtonBase::getState()
-{
-	return state;
-}
 
-bool CButtonBase::isBlocked()
+void CButton::block(bool on)
 {
-	return state == BLOCKED;
+	setState(on ? BLOCKED : NORMAL);
 }
 
-bool CButtonBase::isHighlighted()
-{
-	return state == HIGHLIGHTED;
-}
 
-void CButtonBase::block(bool on)
+void CButton::showAll()
 {
-	setState(on?BLOCKED:NORMAL);
+	state2image[state]->putAt(Gfx::Point(pos.x, pos.y));
 }
 
-CAdventureMapButton::CAdventureMapButton ()
+CAdventureMapButton::CAdventureMapButton()
 {
 	hoverable = actOnDown = borderEnabled = soundDisabled = false;
 	borderColor.unused = 1; // represents a transparent color, used for HighlightableButton
@@ -347,7 +390,7 @@ void CAdventureMapButton::clickRight(tribool down, bool previousState)
 		CRClickPopup::createAndPush(helpBox);
 }
 
-void CAdventureMapButton::hover (bool on)
+void CAdventureMapButton::hover(bool on)
 {
 	if(hoverable)
 	{
@@ -390,7 +433,6 @@ void CAdventureMapButton::hover (bool on)
 
 void CAdventureMapButton::init(const CFunctionList<void()> &Callback, const std::map<int,std::string> &Name, const std::string &HelpBox, bool playerColoredButton, const std::string &defName, std::vector<std::string> * add, int x, int y, int key)
 {
-	currentImage = -1;
 	addUsedEvents(LCLICK | RCLICK | HOVER | KEYBOARD);
 	callback = Callback;
 	hoverable = actOnDown = borderEnabled = soundDisabled = false;
@@ -405,7 +447,31 @@ void CAdventureMapButton::init(const CFunctionList<void()> &Callback, const std:
 	pos.y += y;
 
 	if (!defName.empty())
+	{
 		imageNames.push_back(defName);
+
+		images = Gfx::CManager::getAnimation(defName);
+
+		if (images)
+		{
+			pos.w = images->getWidth();
+			pos.h = images->getHeight();
+
+			for (size_t i=0; i<4; ++i)
+			{
+				state2image[i] = images->getFrame(i);
+				if (state2image[i] == nullptr)
+				{
+					//tlog2 << "CAdventureMapButton warning: image " << defName << " : " << i << " is missing\n";
+					state2image[i] = state2image[0];
+				}
+			}
+		}
+		else {
+			tlog1 << "CAdventureMapButton error: animation file '" << defName << "' is not loaded\n";
+		}
+	}
+
 	if (add)
 		for (size_t i=0; i<add->size();i++ )
 			imageNames.push_back(add->at(i));
@@ -414,23 +480,19 @@ void CAdventureMapButton::init(const CFunctionList<void()> &Callback, const std:
 
 void CAdventureMapButton::setIndex(size_t index, bool playerColoredButton)
 {
-	if (index == currentImage || index>=imageNames.size())
-		return;
-	currentImage = index;
-	setImage(Gfx::CManager::getAnimation(imageNames[index]));
+
 }
 
 void CAdventureMapButton::setImage(Gfx::PAnimation anim, bool playerColoredButton, int animFlags)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
 
-	image = anim; //new CAnimImage(anim, getState(), 0, 0, 0, animFlags);
+//*	image = new CAnimImage(anim, getState(), 0, 0, 0, animFlags);
 //*	if (playerColoredButton)
 //*		image->playerColored(LOCPLINT->playerID);
 
-	pos.w = image->getWidth();
-	pos.h = image->getHeight();
-
+//*	pos.w = image->getWidth();
+//*	pos.h = image->getHeight();
 }
 
 void CAdventureMapButton::setPlayerColor(PlayerColor player)
@@ -441,8 +503,7 @@ void CAdventureMapButton::setPlayerColor(PlayerColor player)
 
 void CAdventureMapButton::showAll()
 {
-	image->getFrame(0)->putAt(Gfx::Point(pos.x, pos.y));
-
+	CButton::showAll();
 	CIntObject::showAll();
 
 //*	if (borderEnabled && borderColor.unused == 0)

+ 43 - 26
client/UIFramework/CIntObjectClasses.h

@@ -3,6 +3,7 @@
 #include "CIntObject.h"
 #include "SDL_Extensions.h"
 #include "../FunctionList.h"
+#include "../Gfx/Basic.h"
 #include "../Gfx/Manager.h"
 
 struct SDL_Surface;
@@ -77,56 +78,71 @@ public:
 	void showAll();
 };
 
-namespace config{struct ButtonInfo;}
+namespace config{ struct ButtonInfo; }
+
+typedef std::pair<std::string,std::string> PairOfStrings;
 
 /// Base class for buttons.
-class CButtonBase : public CKeyShortcut
+class CButton : public CKeyShortcut
 {
 public:
 	enum ButtonState
 	{
-		NORMAL=0,
-		PRESSED=1,
-		BLOCKED=2,
-		HIGHLIGHTED=3
+		NORMAL = 0,
+		PRESSED = 1,
+		BLOCKED = 2,
+		HIGHLIGHTED = 3
 	};
-private:
-	int bitmapOffset; // base offset of visible bitmap from animation
+
+protected:
 	ButtonState state;//current state of button from enum
+	Gfx::PAnimation images; //images for this button
+	Gfx::CImage* state2image[4];
+	std::string helpBox; //for right-click help
+	std::string status;
+	CButton(); //c-tor
 
 public:
-	bool swappedImages,//fix for some buttons: normal and pressed image are swapped
-		keepFrame; // don't change visual representation
+	CFunctionList<void()> callback;
+	CLabel * text; //text overlay
+
+	CButton(	const CFunctionList<void()> & flist,
+				Gfx::Point position,
+				const std::string & animName,
+				size_t animOffs = 0,
+				size_t imagesNum = 4,
+				const PairOfStrings * helpStr = nullptr,
+				ui16 events = LCLICK | RCLICK | HOVER | KEYBOARD,
+				int key = SDLK_UNKNOWN
+			);
+	virtual ~CButton(); //d-tor
+
+	void clickRight(tribool down, bool previousState);
+	void clickLeft(tribool down, bool previousState);
+	void hover(bool on);
 
     void addTextOverlay(const std::string &Text, EFonts font, SDL_Color color = Colors::WHITE);
-	void update();//to refresh button after image or text change
+	void swapImages();
 
-	void setOffset(int newOffset);
 	void setState(ButtonState newState);
-	ButtonState getState();
+	ButtonState getState() const { return state; };
 
 	//just to make code clearer
 	void block(bool on);
-	bool isBlocked();
-	bool isHighlighted();
+	bool isBlocked() const { return state == BLOCKED; };
+	bool isHighlighted() const { return state == HIGHLIGHTED; };
 
-	Gfx::PAnimation image; //image for this button
-	CLabel * text;//text overlay
-
-	CButtonBase(); //c-tor
-	virtual ~CButtonBase(); //d-tor
+	void showAll();
 };
 
 /// Typical Heroes 3 button which can be inactive or active and can 
 /// hold further information if you right-click it
-class CAdventureMapButton : public CButtonBase
+class CAdventureMapButton : public CButton
 {
 	std::vector<std::string> imageNames;//store list of images that can be used by this button
-	size_t currentImage;
+
 public:
 	std::map<int, std::string> hoverTexts; //text for statusbar
-	std::string helpBox; //for right-click help
-	CFunctionList<void()> callback;
 	bool actOnDown,//runs when mouse is pressed down over it, not when up
 		hoverable,//if true, button will be highlighted when hovered
 		borderEnabled,
@@ -138,12 +154,13 @@ public:
 	void hover (bool on);
 
 	CAdventureMapButton(); //c-tor
-	CAdventureMapButton( const std::string &Name, const std::string &HelpBox, const CFunctionList<void()> &Callback, int x, int y, const std::string &defName, int key=0, std::vector<std::string> * add = NULL, bool playerColoredButton = false );//c-tor
-	CAdventureMapButton( const std::pair<std::string, std::string> &help, const CFunctionList<void()> &Callback, int x, int y, const std::string &defName, int key=0, std::vector<std::string> * add = NULL, bool playerColoredButton = false );//c-tor
+	CAdventureMapButton( const std::string &Name, const std::string &HelpBox, const CFunctionList<void()> &Callback, int x, int y, const std::string &animName, int key=0, std::vector<std::string> * add = NULL, bool playerColoredButton = false );//c-tor
+	CAdventureMapButton( const std::pair<std::string, std::string> &help, const CFunctionList<void()> &Callback, int x, int y, const std::string &animName, int key=0, std::vector<std::string> * add = NULL, bool playerColoredButton = false );//c-tor
 	CAdventureMapButton( const std::string &Name, const std::string &HelpBox, const CFunctionList<void()> &Callback, config::ButtonInfo *info, int key=0);//c-tor
 
 	void init(const CFunctionList<void()> &Callback, const std::map<int,std::string> &Name, const std::string &HelpBox, bool playerColoredButton, const std::string &defName, std::vector<std::string> * add, int x, int y, int key );
 
+	void setOffset(int o) {};
 	void setIndex(size_t index, bool playerColoredButton=false);
 	void setImage(Gfx::PAnimation anim, bool playerColoredButton=false, int animFlags=0);
 	void setPlayerColor(PlayerColor player);

+ 3 - 2
client/UIFramework/GL2D.cpp

@@ -23,6 +23,7 @@ static GLXContext glxCtx;
 #endif
 ui32 screenWidth = 0, screenHeight = 0; // Screen/Window size
 
+
 // OpenGL 1.3 functions pointers
 PFNGLACTIVETEXTUREPROC	glActiveTexture;
 // OpenGL 2.0 functions pointers
@@ -276,7 +277,7 @@ void useNoShader()
 }
 
 
-void useColorizeShader(const float cm[4][4])
+void useColorizeShader(const float cm[3][3])
 {
 	if (currentProgram != colorizeProgram) {
 		glUseProgram(currentProgram = colorizeProgram);
@@ -293,7 +294,7 @@ void usePaletteBitmapShader(si32 x, si32 y)
 }
 
 
-void usePaletteBitmapShader(si32 x, si32 y, const float cm[4][4])
+void usePaletteBitmapShader(si32 x, si32 y, const float cm[3][3])
 {
 	if (currentProgram != paletteBitmapProgram) {
 		glUseProgram(currentProgram = paletteBitmapProgram);

+ 2 - 2
client/UIFramework/GL2D.h

@@ -11,7 +11,7 @@ namespace GL2D
 
 	void assignTexture(ui32 slot, ui32 type, ui32 handle);
 	void useNoShader();
-	void useColorizeShader(const float cm[4][4]);
+	void useColorizeShader(const float cm[3][3]);
 	void usePaletteBitmapShader(si32 x, si32 y);
-	void usePaletteBitmapShader(si32 x, si32 y, const float cm[4][4]);
+	void usePaletteBitmapShader(si32 x, si32 y, const float cm[3][3]);
 }

+ 4 - 5
client/VCMI_client.vcxproj

@@ -73,11 +73,9 @@
     <_ProjectFileVersion>10.0.30128.1</_ProjectFileVersion>
     <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(VCMI_Out)</OutDir>
     <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(VCMI_Out)</OutDir>
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(Configuration)\</IntDir>
     <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(Configuration)\</IntDir>
     <OutDir Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">$(VCMI_Out)</OutDir>
     <OutDir Condition="'$(Configuration)|$(Platform)'=='RD|x64'">$(VCMI_Out)</OutDir>
-    <IntDir Condition="'$(Configuration)|$(Platform)'=='RD|Win32'">$(Configuration)\</IntDir>
     <IntDir Condition="'$(Configuration)|$(Platform)'=='RD|x64'">$(Configuration)\</IntDir>
     <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
     <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">AllRules.ruleset</CodeAnalysisRuleSet>
@@ -123,7 +121,7 @@
       <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
     </ClCompile>
     <Link>
-      <AdditionalDependencies>SDL.lib;zlib.lib;SDL_image.lib;SDL_ttf.lib;SDL_mixer.lib;VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>SDL.lib;zlib.lib;opengl32.lib;SDL_image.lib;SDL_ttf.lib;SDL_mixer.lib;VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <ShowProgress>LinkVerbose</ShowProgress>
       <OptimizeReferences>false</OptimizeReferences>
       <Profile>true</Profile>
@@ -138,7 +136,7 @@
       <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
     </ClCompile>
     <Link>
-      <AdditionalDependencies>SDL.lib;zlib.lib;SDL_image.lib;SDL_ttf.lib;SDL_mixer.lib;VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>SDL.lib;zlib.lib;opengl32.lib;SDL_image.lib;SDL_ttf.lib;SDL_mixer.lib;VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <Driver>NotSet</Driver>
       <LinkTimeCodeGeneration>
       </LinkTimeCodeGeneration>
@@ -152,7 +150,7 @@
       <PrecompiledHeaderFile>StdInc.h</PrecompiledHeaderFile>
     </ClCompile>
     <Link>
-      <AdditionalDependencies>SDL.lib;zlib.lib;SDL_image.lib;SDL_ttf.lib;SDL_mixer.lib;VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>SDL.lib;zlib.lib;opengl32.lib;SDL_image.lib;SDL_ttf.lib;SDL_mixer.lib;VCMI_lib.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <Driver>NotSet</Driver>
       <LinkTimeCodeGeneration>
       </LinkTimeCodeGeneration>
@@ -238,6 +236,7 @@
     <ClInclude Include="FontBase.h" />
     <ClInclude Include="FunctionList.h" />
     <ClInclude Include="Gfx\Animations.h" />
+    <ClInclude Include="Gfx\Basic.h" />
     <ClInclude Include="Gfx\CPaletteRGBA.h" />
     <ClInclude Include="Gfx\Images.h" />
     <ClInclude Include="Gfx\FilesHeaders.h" />

+ 6 - 1
client/VCMI_client.vcxproj.filters

@@ -94,7 +94,6 @@
     <ClInclude Include="resource.h" />
     <ClInclude Include="StdInc.h" />
     <ClInclude Include="UIFramework\CCursorHandler.h" />
-    <ClInclude Include="UIFramework\CIntObjectClasses.h" />
     <ClInclude Include="UIFramework\Geometries.h" />
     <ClInclude Include="UIFramework\SDL_Extensions.h" />
     <ClInclude Include="UIFramework\SDL_Pixels.h" />
@@ -128,6 +127,12 @@
     <ClInclude Include="UIFramework\CGuiHandler.h">
       <Filter>UIFramework</Filter>
     </ClInclude>
+    <ClInclude Include="Gfx\Basic.h">
+      <Filter>Gfx</Filter>
+    </ClInclude>
+    <ClInclude Include="UIFramework\CIntObjectClasses.h">
+      <Filter>UIFramework</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="VCMI_client.rc" />

+ 3 - 3
config/creatures/neutral.json

@@ -68,7 +68,7 @@
 	{
 		"special" : true,
 		"id": 133,
-		"level": 9,
+		"level": 10,
 		"faction": "neutral",
 		"abilities": [ [ "DRAGON_NATURE", 0, 0, 0 ] ],			//crystal dragon is a dragon
 		"ability_remove": [ "FLYING" ],							//Crystal Dragons do not fly
@@ -92,7 +92,7 @@
 		"level": 8,
 		"faction": "neutral",
 		"abilities": [ [ "DRAGON_NATURE", 0, 0, 0 ],			//faerie dragon is a dragon
-						[ "MAGIC_MIRROR", 30, 0, 0 ]
+						[ "MAGIC_MIRROR", 30, 0, 0 ],
 						[ "CASTS", 5, 0, 0 ],
 						[ "CREATURE_SPELL_POWER", 500, 0, 0], 	//5 spell power per dragon
 						[ "SPELLCASTER", 2, "spell.magicArrow", 10 ],			
@@ -121,7 +121,7 @@
 	{
 		"special" : true,
 		"id": 135,
-		"level": 9,
+		"level": 10,
 		"faction": "neutral",
 		"abilities": [ [ "SPELL_AFTER_ATTACK", 100, 80, 0 ],			//always reduce defense
 						 [ "ACID_BREATH", 25, 0, 20 ],			//20% chance to do 25 damage

+ 3 - 3
lib/BattleState.cpp

@@ -257,7 +257,7 @@ namespace CGH
 			std::vector<int> pom;
 			BOOST_FOREACH(const JsonNode &value, level.Vector())
 			{
-				pom.push_back(value.Float());
+				pom.push_back(value.asInteger());
 			}
 
 			dest.push_back(pom);
@@ -500,11 +500,11 @@ BattleInfo * BattleInfo::setupBattle( int3 tile, ETerrainType terrain, BFieldTyp
 
 	BOOST_FOREACH (auto position, config["commanderPositions"]["field"].Vector())
 	{
-		commanderField.push_back (position.Float());
+		commanderField.push_back (position.asInteger());
 	}
 	BOOST_FOREACH (auto position, config["commanderPositions"]["creBank"].Vector())
 	{
-		commanderBank.push_back (position.Float());
+		commanderBank.push_back (position.asInteger());
 	}
 
 

+ 3 - 3
lib/CArtHandler.cpp

@@ -245,7 +245,7 @@ void CArtHandler::load(bool onlyTxt)
 
 	BOOST_FOREACH(auto & node, config["artifacts"].Struct())
 	{
-		int numeric = node.second["id"].Float();
+		int numeric = node.second["id"].asInteger();
 		CArtifact * art = artifacts[numeric];
 
 		loadArtifactJson(art, node.second);
@@ -274,7 +274,7 @@ CArtifact * CArtHandler::loadArtifact(const JsonNode & node)
 	art->eventText   = text["event"].String();
 
 	const JsonNode & graphics = node["graphics"];
-	art->iconIndex = graphics["iconIndex"].Float();
+	art->iconIndex = graphics["iconIndex"].asInteger();
 	art->image = graphics["image"].String();
 
 	if (!graphics["large"].loadTo(art->large))
@@ -282,7 +282,7 @@ CArtifact * CArtHandler::loadArtifact(const JsonNode & node)
 
 	art->advMapDef = graphics["map"].String();
 
-	art->price = node["value"].Float();
+	art->price = node["value"].asInteger();
 	{
 		auto it = artifactClassMap.find (node["class"].String());
 		if (it != artifactClassMap.end())

+ 2 - 2
lib/CBattleCallback.cpp

@@ -656,7 +656,7 @@ void CBattleInfoCallback::battleGetStackCountOutsideHexes(bool *ac) const
 	RETURN_IF_NOT_BATTLE();
 	auto accessibility = getAccesibility();
 
-	for(int i = 0; i < accessibility.size(); i++)
+	for(size_t i = 0; i < accessibility.size(); ++i)
 		ac[i] = (accessibility[i] == EAccessibility::ACCESSIBLE);
 }
 
@@ -819,7 +819,7 @@ TDmgRange CBattleInfoCallback::calculateDmgRange(const BattleAttackInfo &info) c
 		std::vector<int> affectedIds;
 		int spLevel = slayerEffect->val;
 
-		for(int g = 0; g < VLC->creh->creatures.size(); ++g)
+		for(size_t g = 0; g < VLC->creh->creatures.size(); ++g)
 		{
 			BOOST_FOREACH(const Bonus *b, VLC->creh->creatures[g]->getBonusList())
 			{

+ 10 - 2
lib/CModHandler.cpp

@@ -84,9 +84,17 @@ void CIdentifierStorage::finalize() const
 {
 	// print list of missing objects and crash
 	// in future should try to do some cleanup (like returning all id's as 0)
-	BOOST_FOREACH(auto object, missingObjects)
+	if (!missingObjects.empty())
 	{
-		tlog1 << "Error: object " << object.first << " was not found!\n";
+		BOOST_FOREACH(auto object, missingObjects)
+		{
+			tlog1 << "Error: object " << object.first << " was not found!\n";
+		}
+		BOOST_FOREACH(auto object, registeredObjects)
+		{
+			tlog5 << object.first << " -> " << object.second << "\n";
+		}
+		tlog1 << "All known identifiers were dumped into log file\n";
 	}
 	assert(missingObjects.empty());
 }

+ 2 - 2
lib/CObjectHandler.cpp

@@ -6951,12 +6951,12 @@ bool IMarket::getOffer(int id1, int id2, int &val1, int &val2, EMarketMode::EMar
 
 			if(r>g) //if given resource is more expensive than wanted
 			{
-				val2 = ceil(r / g);
+				val2 = (int) ceil(r / g);
 				val1 = 1;
 			}
 			else //if wanted resource is more expensive
 			{
-				val1 = (g / r) + 0.5;
+				val1 = (int) ((g / r) + 0.5);
 				val2 = 1;
 			}
 		}

+ 37 - 40
lib/JsonNode.cpp

@@ -32,33 +32,21 @@ JsonNode::JsonNode(JsonType Type):
 JsonNode::JsonNode(const char *data, size_t datasize):
 	type(DATA_NULL)
 {
-	JsonParser parser(data, datasize, *this);
+	JsonParser parser(data, datasize);
+	*this = parser.parse("<unknown>");
+
 	JsonValidator validator(*this);
 }
 
 JsonNode::JsonNode(ResourceID && fileURI):
 	type(DATA_NULL)
 {
-	std::string filename = CResourceHandler::get()->getResourceName(fileURI);
-	FILE * file = fopen(filename.c_str(), "rb");
-	if (!file)
-	{
-		tlog1 << "Failed to open file " << filename << "\n";
-		perror("Last system error was ");
-		return;
-	}
-
-	fseek(file, 0, SEEK_END);
-	size_t datasize = ftell(file);
-	fseek(file, 0, SEEK_SET);
+	auto file = CResourceHandler::get()->loadData(fileURI);
 
-	char *input = new char[datasize];
-	datasize = fread((void*)input, 1, datasize, file);
-	fclose(file);
+	JsonParser parser(reinterpret_cast<char*>(file.first.get()), file.second);
+	*this = parser.parse(fileURI.getName());
 
-	JsonParser parser(input, datasize, *this);
 	JsonValidator validator(*this);
-	delete [] input;
 }
 
 JsonNode::JsonNode(const JsonNode &copy):
@@ -151,9 +139,12 @@ void JsonNode::setType(JsonType Type)
 	}
 }
 
-bool JsonNode::isNull() const
+
+int JsonNode::asInteger() const
 {
-	return type == DATA_NULL;
+	if (type == DATA_NULL) return 0;
+	assert(type == DATA_FLOAT);
+	return (int) data.Float;
 }
 
 bool & JsonNode::Bool()
@@ -186,20 +177,16 @@ JsonMap & JsonNode::Struct()
 	return *data.Struct;
 }
 
-const bool boolDefault = false;
-const bool & JsonNode::Bool() const
+bool JsonNode::Bool() const
 {
-	if (type == DATA_NULL)
-		return boolDefault;
+	if (type == DATA_NULL) return false;
 	assert(type == DATA_BOOL);
 	return data.Bool;
 }
 
-const double floatDefault = 0;
-const double & JsonNode::Float() const
+double JsonNode::Float() const
 {
-	if (type == DATA_NULL)
-		return floatDefault;
+	if (type == DATA_NULL) return 0;
 	assert(type == DATA_FLOAT);
 	return data.Float;
 }
@@ -344,12 +331,18 @@ std::ostream & operator<<(std::ostream &out, const JsonNode &node)
 
 ////////////////////////////////////////////////////////////////////////////////
 
-JsonParser::JsonParser(const char * inputString, size_t stringSize, JsonNode &root):
+JsonParser::JsonParser(const char * inputString, size_t stringSize):
 	input(inputString, stringSize),
 	lineCount(1),
 	lineStart(0),
 	pos(0)
 {
+}
+
+JsonNode JsonParser::parse(std::string fileName)
+{
+	JsonNode root;
+
 	extractValue(root);
 	extractWhitespace(false);
 
@@ -357,8 +350,12 @@ JsonParser::JsonParser(const char * inputString, size_t stringSize, JsonNode &ro
 	if (pos < input.size())
 		error("Not all file was parsed!", true);
 
-	//TODO: better way to show errors (like printing file name as well)
-	tlog3<<errors;
+	if (!errors.empty())
+	{
+		tlog3<<"File " << fileName << " is not a valid JSON file!\n";
+		tlog3<<errors;
+	}
+	return root;
 }
 
 bool JsonParser::extractSeparator()
@@ -889,9 +886,9 @@ JsonValidator::JsonValidator(JsonNode &root, const JsonNode &schema, bool Minimi
 
 void JsonUtils::parseTypedBonusShort(const JsonVector& source, Bonus *dest)
 {
-	dest->val = source[1].Float();
+	dest->val = source[1].asInteger();
 	resolveIdentifier(source[2],dest->subtype);
-	dest->additionalInfo = source[3].Float();
+	dest->additionalInfo = source[3].asInteger();
 	dest->duration = Bonus::PERMANENT; //TODO: handle flags (as integer)
 	dest->turnsRemain = 0;	
 }
@@ -943,10 +940,10 @@ void JsonUtils::resolveIdentifier (si32 &var, const JsonNode &node, std::string
 		switch (value->getType())
 		{
 			case JsonNode::DATA_FLOAT:
-				var = value->Float();
+				var = value->asInteger();
 				break;
 			case JsonNode::DATA_STRING:
-				VLC->modh->identifiers.requestIdentifier (value->String(), [&](si32 identifier)
+				VLC->modh->identifiers.requestIdentifier(value->String(), [&](si32 identifier)
 				{
 					var = identifier;
 				});
@@ -962,10 +959,10 @@ void JsonUtils::resolveIdentifier (const JsonNode &node, si32 &var)
 	switch (node.getType())
 	{
 		case JsonNode::DATA_FLOAT:
-			var = node.Float();
+			var = node.asInteger();
 			break;
 		case JsonNode::DATA_STRING:
-			VLC->modh->identifiers.requestIdentifier (node.String(), [&](si32 identifier)
+			VLC->modh->identifiers.requestIdentifier(node.String(), [&](si32 identifier)
 			{
 				var = identifier;
 			});
@@ -994,7 +991,7 @@ Bonus * JsonUtils::parseBonus (const JsonNode &ability)
 
 	value = &ability["val"];
 	if (!value->isNull())
-		b->val = value->Float();
+		b->val = value->asInteger();
 
 	value = &ability["valueType"];
 	if (!value->isNull())
@@ -1004,11 +1001,11 @@ Bonus * JsonUtils::parseBonus (const JsonNode &ability)
 
 	value = &ability["turns"];
 	if (!value->isNull())
-		b->turnsRemain = value->Float();
+		b->turnsRemain = value->asInteger();
 
 	value = &ability["sourceID"];
 	if (!value->isNull())
-		b->sid = value->Float();
+		b->sid = value->asInteger();
 
 	value = &ability["description"];
 	if (!value->isNull())

+ 11 - 4
lib/JsonNode.h

@@ -67,7 +67,10 @@ public:
 	void setType(JsonType Type);
 	JsonType getType() const;
 
-	bool isNull() const;
+	bool isNull() const { return type == DATA_NULL; };
+
+	// returns int number if type == DATA_FLOAT
+	int asInteger() const;
 
 	//non-const accessors, node will change type on type mismatch
 	bool & Bool();
@@ -77,8 +80,8 @@ public:
 	JsonMap & Struct();
 
 	//const accessors, will cause assertion failure on type mismatch
-	const bool & Bool() const;
-	const double & Float() const;
+	bool Bool() const;
+	double Float() const;
 	const std::string & String() const;
 	const JsonVector & Vector() const;
 	const JsonMap & Struct() const;
@@ -118,6 +121,7 @@ public:
 	}
 };
 
+
 namespace JsonUtils
 {
 	/**
@@ -339,7 +343,10 @@ namespace JsonDetail
 		bool error(const std::string &message, bool warning=false);
 
 	public:
-		JsonParser(const char * inputString, size_t stringSize, JsonNode &root);
+		JsonParser(const char * inputString, size_t stringSize);
+
+		/// do actual parsing. filename is name of file that will printed to console if any errors were found
+		JsonNode parse(std::string fileName);
 	};
 
 	//Internal class for Json validation, used automaticaly in JsonNode constructor. Behaviour:

+ 3 - 3
lib/ResourceSet.cpp

@@ -22,12 +22,12 @@ Res::ResourceSet::ResourceSet(const JsonNode & node)
 {
 	reserve(GameConstants::RESOURCE_QUANTITY);
 	BOOST_FOREACH(std::string name, GameConstants::RESOURCE_NAMES)
-		push_back(node[name].Float());
+		push_back(node[name].asInteger());
 }
 
 bool Res::ResourceSet::nonZero() const
 {
-	for(int i = 0; i < size(); i++)
+	for(size_t i = 0; i < size(); ++i)
 		if(at(i))
 			return true;
 
@@ -36,7 +36,7 @@ bool Res::ResourceSet::nonZero() const
 
 void Res::ResourceSet::amax(const TResourceCap &val)
 {
-	for(int i = 0; i < size(); i++)
+	for(size_t i = 0; i < size(); ++i)
 		::vstd::amax(at(i), val);
 }
 

+ 2 - 1
lib/ResourceSet.h

@@ -124,7 +124,8 @@ namespace Res
 		{
 			struct ResEntry
 			{
-				TResourceCap resType, resVal;
+				TResource resType;
+				TResourceCap resVal;
 			} cur;
 			const ResourceSet &rs;
 			void advance();