浏览代码

* CGameInterface.h/.cpp moved from client project to lib (and, appropriately, to lib subfolder).
* New files in lib: ResourceSet.h/.cpp -> containing new structure for managing resources logic
* Minor changes and fixes

Michał W. Urbańczyk 14 年之前
父节点
当前提交
b3234e8bfa

+ 10 - 10
AI/GeniusAI/CGeniusAI.cpp

@@ -325,8 +325,8 @@ float CGeniusAI::TownObjective::getValue() const
 
 			newID = ui.newID.back();
 			int upgrade_serial = ui.newID.size() - 1;
-			for (std::set< std::pair<int,int> >::iterator j = ui.cost[upgrade_serial].begin(); j != ui.cost[upgrade_serial].end(); j++)
-				resourceCosts[j->first] = j->second*howMany;
+// 			for (std::set< std::pair<int,int> >::iterator j = ui.cost[upgrade_serial].begin(); j != ui.cost[upgrade_serial].end(); j++)
+// 				resourceCosts[j->first] = j->second*howMany;
 		break;
 	}
 
@@ -762,9 +762,9 @@ void CGeniusAI::HeroObjective::fulfill(CGeniusAI& cg, HypotheticalGameState& hgs
 				std::set<std::pair<int,int> >::iterator j;
 				for (int ii = 0; ii < ui.cost.size(); ii++) // Can afford the upgrade?
 				{
-					for (j = ui.cost[ii].begin(); j != ui.cost[ii].end(); j++)
-						if (hgs.resourceAmounts[j->first] < j->second * i->second->count)
-							canUpgrade = false;
+// 					for (j = ui.cost[ii].begin(); j != ui.cost[ii].end(); j++)
+// 						if (hgs.resourceAmounts[j->first] < j->second * i->second->count)
+// 							canUpgrade = false;
 				}
 			}
 			if (canUpgrade)
@@ -889,11 +889,11 @@ void CGeniusAI::addTownObjectives (HypotheticalGameState::TownModel& t, Hypothet
 			bool canAfford = true;
 			
 			int upgrade_serial = ui.newID.size() - 1;
-			for (std::set< std::pair<int, int> >::iterator j = ui.cost[upgrade_serial].begin(); j != ui.cost[upgrade_serial].end(); j++)
-			{
-				if (hgs.resourceAmounts[j->first] < j->second * i->second->count)
-					canAfford = false;
-			}
+// 			for (std::set< std::pair<int, int> >::iterator j = ui.cost[upgrade_serial].begin(); j != ui.cost[upgrade_serial].end(); j++)
+// 			{
+// 				if (hgs.resourceAmounts[j->first] < j->second * i->second->count)
+// 					canAfford = false;
+// 			}
 			if (canAfford)
 			{
 				TownObjective to(hgs,AIObjective::upgradeCreatures,&t,i->first,this);

+ 1 - 1
AI_Base.h

@@ -3,7 +3,7 @@
 
 #include <vector>
 #include <iostream>
-#include "CGameInterface.h"
+#include "lib/CGameInterface.h"
 
 /*
  * AI_Base.h, part of VCMI engine

+ 8 - 5
CCallback.cpp

@@ -157,14 +157,17 @@ bool CCallback::assembleArtifacts (const CGHeroInstance * hero, ui16 artifactSlo
 
 bool CCallback::buildBuilding(const CGTownInstance *town, si32 buildingID)
 {
-	CGTownInstance * t = const_cast<CGTownInstance *>(town);
+	//CGTownInstance * t = const_cast<CGTownInstance *>(town);
 
 	if(town->tempOwner!=player)
 		return false;
-	const CBuilding *b = CGI->buildh->buildings[t->subID][buildingID];
-	for(int i=0;i<b->resources.size();i++)
-		if(b->resources[i] > gs->players[player].resources[i])
-			return false; //lack of resources
+
+	if(!canBuildStructure(town, buildingID))
+		return false;
+// 	const CBuilding *b = CGI->buildh->buildings[t->subID][buildingID];
+// 	for(int i=0;i<b->resources.size();i++)
+// 		if(b->resources[i] > gs->players[player].resources[i])
+// 			return false; //lack of resources
 
 	BuildStructure pack(town->id,buildingID);
 	sendRequest(&pack);

+ 4 - 6
client/CCreatureWindow.cpp

@@ -82,16 +82,14 @@ CCreatureWindow::CCreatureWindow(const CStackInstance &st, int Type, boost::func
 	{
 		if(Upg && ui)
 		{
-			bool enough = true;
-			for(std::set<std::pair<int,int> >::iterator i=ui->cost[0].begin(); i!=ui->cost[0].end(); i++) //calculate upgrade cost
+			TResources upgradeCost = ui->cost[0] * st.count;
+			for(TResources::nziterator i(upgradeCost); i.valid(); i++)
 			{
 				BLOCK_CAPTURING;
-				if(LOCPLINT->cb->getResourceAmount(i->first) < i->second*st.count)
-					enough = false;
-				upgResCost.push_back(new SComponent(SComponent::resource,i->first,i->second*st.count)); 
+				upgResCost.push_back(new SComponent(SComponent::resource, i->resType, i->resVal)); 
 			}
 
-			if(enough)
+			if(LOCPLINT->cb->getResourceAmount().canAfford(upgradeCost))
 			{
 				CFunctionList<void()> fs;
 				fs += Upg;

+ 2 - 1
client/CPlayerInterface.h

@@ -1,12 +1,13 @@
 #ifndef __CPLAYERINTERFACE_H__
 #define __CPLAYERINTERFACE_H__
 #include "../global.h"
-#include "../CGameInterface.h"
+#include "../lib/CGameInterface.h"
 #include "../lib/CondSh.h"
 #include <map>
 #include <list>
 #include <algorithm>
 #include "GUIBase.h"
+#include "FunctionList.h"
 
 #ifdef __GNUC__
 #define sprintf_s snprintf 

+ 5 - 0
client/GUIBase.cpp

@@ -820,6 +820,11 @@ void CIntObject::changeUsedEvents(ui16 what, bool enable, bool adjust /*= true*/
 	}
 }
 
+void CIntObject::drawBorderLoc(SDL_Surface * sur, const Rect &r, const int3 &color)
+{
+	CSDL_Ext::drawBorder(sur, r + pos, color);
+}
+
 CPicture::CPicture( SDL_Surface *BG, int x, int y, bool Free )
 {
 	init();

+ 1 - 0
client/GUIBase.h

@@ -416,6 +416,7 @@ public:
 	void show(SDL_Surface * to);
 	void showAll(SDL_Surface * to);
 
+	void drawBorderLoc(SDL_Surface * sur, const Rect &r, const int3 &color);
 	void printAtLoc(const std::string & text, int x, int y, EFonts font, SDL_Color kolor, SDL_Surface * dst);
 	void printToLoc(const std::string & text, int x, int y, EFonts font, SDL_Color kolor, SDL_Surface * dst);
 	void printAtMiddleLoc(const std::string & text, int x, int y, EFonts font, SDL_Color kolor, SDL_Surface * dst);

+ 25 - 26
client/GUIClasses.cpp

@@ -1741,7 +1741,7 @@ void CRecruitmentWindow::clickLeft(tribool down, bool previousState)
 {
 	for(int i=0;i<creatures.size();i++)
 	{
-		Rect creaPos = pos + creatures[i].pos;
+		Rect creaPos = Rect(creatures[i].pos) + pos;
 		if(isItIn(&creaPos, GH.current->motion.x, GH.current->motion.y))
 		{
 			which = i;
@@ -1804,9 +1804,9 @@ void CRecruitmentWindow::showAll( SDL_Surface * to )
 	for(int j=0;j<creatures.size();j++)
 	{
 		if(which==j)
-			drawBorder(*bitmap,creatures[j].pos,int3(255,0,0));
+			drawBorderLoc(to,creatures[j].pos,int3(255,0,0));
 		else
-			drawBorder(*bitmap,creatures[j].pos,int3(239,215,123));
+			drawBorderLoc(to,creatures[j].pos,int3(239,215,123));
 	}
 }
 
@@ -2076,22 +2076,20 @@ CCreInfoWindow::CCreInfoWindow(const CStackInstance &st, int Type, boost::functi
 	{
 		if(Upg && ui)
 		{
-			bool enough = true;
-			for(std::set<std::pair<int,int> >::iterator i=ui->cost[0].begin(); i!=ui->cost[0].end(); i++) //calculate upgrade cost
+			TResources upgradeCost = ui->cost[0] * st.count;
+			for(TResources::nziterator i(upgradeCost); i.valid(); i++)
 			{
 				BLOCK_CAPTURING;
-				if(LOCPLINT->cb->getResourceAmount(i->first) < i->second*st.count)
-					enough = false;
-				upgResCost.push_back(new SComponent(SComponent::resource,i->first,i->second*st.count)); 
+				upgResCost.push_back(new SComponent(SComponent::resource, i->resType, i->resVal)); 
 			}
 
-			if(enough)
+			if(LOCPLINT->cb->getResourceAmount().canAfford(upgradeCost))
 			{
 				CFunctionList<void()> fs;
 				fs += Upg;
 				fs += boost::bind(&CCreInfoWindow::close,this);
 				CFunctionList<void()> cfl;
-				cfl = boost::bind(&CPlayerInterface::showYesNoDialog, LOCPLINT, CGI->generaltexth->allTexts[207], boost::ref(upgResCost), fs, 0, false);
+				cfl = boost::bind(&CPlayerInterface::showYesNoDialog, LOCPLINT, CGI->generaltexth->allTexts[207], boost::ref(upgResCost), fs, 0, true);
 				upgrade = new AdventureMapButton("",CGI->generaltexth->zelp[446].second,cfl,76,237,"IVIEWCR.DEF",SDLK_u);
 			}
 			else
@@ -2109,7 +2107,7 @@ CCreInfoWindow::CCreInfoWindow(const CStackInstance &st, int Type, boost::functi
 			fs[0] += Dsm; //dismiss
 			fs[0] += boost::bind(&CCreInfoWindow::close,this);//close this window
 			CFunctionList<void()> cfl;
-			cfl = boost::bind(&CPlayerInterface::showYesNoDialog,LOCPLINT,CGI->generaltexth->allTexts[12],std::vector<SComponent*>(),fs[0],fs[1],false);
+			cfl = boost::bind(&CPlayerInterface::showYesNoDialog,LOCPLINT,CGI->generaltexth->allTexts[12],std::vector<SComponent*>(),fs[0],fs[1],true);
 			dismiss = new AdventureMapButton("",CGI->generaltexth->zelp[445].second,cfl,21,237,"IVIEWCR2.DEF",SDLK_d);
 		}
 		ok = new AdventureMapButton("",CGI->generaltexth->zelp[445].second,boost::bind(&CCreInfoWindow::close,this),216,237,"IOKAY.DEF",SDLK_RETURN);
@@ -6417,12 +6415,10 @@ void CHillFortWindow::updateGarrisons()
 			UpgradeInfo info;
 			LOCPLINT->cb->getUpgradeInfo(hero, i, info);
 			if (info.newID.size())//we have upgrades here - update costs
-				for(std::set<std::pair<int,int> >::iterator it=info.cost[0].begin(); it!=info.cost[0].end(); it++)
-				{
-					std::pair<int, int> pair = std::make_pair(it->first, it->second * hero->getStackCount(i) );
-					costs[i].insert(pair);
-					totalSumm[pair.first] += pair.second;
-				}
+			{
+				costs[i] = info.cost[0] * hero->getStackCount(i);
+				totalSumm += costs[i];
+			}
 		}
 		
 		currState[i] = newState;
@@ -6474,10 +6470,13 @@ void CHillFortWindow::showAll (SDL_Surface *to)
 			if ( costs[i].size() )//we have several elements
 			{
 				int curY = 128;//reverse iterator is used to display gold as first element
-				for( std::map<int,int>::reverse_iterator rit=costs[i].rbegin(); rit!=costs[i].rend(); rit++)
+				for(int j = costs[i].size()-1; j >= 0; j--)
 				{
-					blitAtLoc(resources->ourImages[rit->first].bitmap, 104+76*i, curY, to);
-					printToLoc(boost::lexical_cast<std::string>(rit->second), 168+76*i, curY+16, FONT_SMALL, zwykly, to);
+					int val = costs[i][j];
+					if(!val) continue;
+
+					blitAtLoc(resources->ourImages[j].bitmap, 104+76*i, curY, to);
+					printToLoc(boost::lexical_cast<std::string>(val), 168+76*i, curY+16, FONT_SMALL, zwykly, to);
 					curY += 20;
 				}
 			}
@@ -6515,6 +6514,7 @@ std::string CHillFortWindow::getTextForSlot(int slot)
 
 int CHillFortWindow::getState(int slot)
 {
+	TResources myRes = LOCPLINT->cb->getResourceAmount();
 	if ( slot == slotsCount )//"Upgrade all" slot
 	{
 		bool allUpgraded = true;//All creatures are upgraded?
@@ -6524,10 +6524,9 @@ int CHillFortWindow::getState(int slot)
 		if (allUpgraded)
 			return 1;
 
-		for ( int i=0; i<RESOURCE_QUANTITY; i++)//if we need more resources
-			if(LOCPLINT->cb->getResourceAmount(i) < totalSumm[i])
-				return 0;
-				
+		if(!totalSumm.canBeAfforded(myRes))
+			return 0;
+
 		return 2;
 	}
 
@@ -6539,9 +6538,9 @@ int CHillFortWindow::getState(int slot)
 	if (!info.newID.size())//already upgraded
 		return 1;
 
-	for(std::set<std::pair<int,int> >::iterator it=info.cost[0].begin(); it!=info.cost[0].end(); it++)
-		if(LOCPLINT->cb->getResourceAmount(it->first) < it->second * hero->getStackCount(slot))
+	if(!(info.cost[0] * hero->getStackCount(slot)).canBeAfforded(myRes))
 			return 0;
+
 	return 2;//can upgrade
 }
 

+ 3 - 2
client/GUIClasses.h

@@ -7,6 +7,7 @@
 #include <set>
 #include <list>
 #include <boost/thread/mutex.hpp>
+#include "../lib/ResourceSet.h"
 
 #ifdef max
 #undef max
@@ -1246,8 +1247,8 @@ public:
 	const CGObjectInstance * fort;
 	const CGHeroInstance * hero;
 	std::vector<int> currState;//current state of slot - to avoid calls to getState or updating buttons
-	std::vector<std::map<int,int> > costs;// costs [slot ID] [resource ID] = resource count for upgrade
-	std::vector<int> totalSumm; // totalSum[resource ID] = value
+	std::vector<TResources> costs;// costs [slot ID] [resource ID] = resource count for upgrade
+	TResources totalSumm; // totalSum[resource ID] = value
 
 	CHillFortWindow(const CGHeroInstance *visitor, const CGObjectInstance *object); //c-tor
 	~CHillFortWindow(); //d-tor

+ 0 - 2
client/VCMI_client.vcxproj

@@ -183,7 +183,6 @@
     <ClCompile Include="CCursorHandler.cpp" />
     <ClCompile Include="CDefHandler.cpp" />
     <ClCompile Include="CGameInfo.cpp" />
-    <ClCompile Include="..\CGameInterface.cpp" />
     <ClCompile Include="CHeroWindow.cpp" />
     <ClCompile Include="CKingdomInterface.cpp" />
     <ClCompile Include="Client.cpp" />
@@ -218,7 +217,6 @@
     <ClInclude Include="CCursorHandler.h" />
     <ClInclude Include="CDefHandler.h" />
     <ClInclude Include="CGameInfo.h" />
-    <ClInclude Include="..\CGameInterface.h" />
     <ClInclude Include="CHeroWindow.h" />
     <ClInclude Include="CKingdomInterface.h" />
     <ClInclude Include="Client.h" />

+ 0 - 8
global.h

@@ -349,14 +349,6 @@ namespace Buildings
 	};
 }
 
-namespace Res
-{
-	enum ERes 
-	{
-		WOOD = 0, MERCURY, ORE, SULFUR, CRYSTAL, GEMS, GOLD, MITHRIL
-	};
-}
-
 namespace Arts
 {
 	enum EPos

+ 0 - 1
lib/CBuildingHandler.cpp

@@ -38,7 +38,6 @@ static unsigned int readNr(std::string &in, int &it)
 static CBuilding * readBg(std::string &buf, int& it)
 {
 	CBuilding * nb = new CBuilding();
-	nb->resources.resize(RESOURCE_QUANTITY);
 	for(int res=0;res<7;res++)
 		nb->resources[res] = readNr(buf,it);
 	/*nb->refName = */readTo(buf,it,'\n');

+ 2 - 1
lib/CBuildingHandler.h

@@ -6,6 +6,7 @@
 #include <set>
 
 #include "../lib/ConstTransitivePtr.h"
+#include "ResourceSet.h"
 
 /*
  * CBuildingHandler.h, part of VCMI engine
@@ -22,7 +23,7 @@ class DLL_EXPORT CBuilding //a typical building encountered in every castle ;]
 {
 public:
 	si32 tid, bid; //town ID and structure ID
-	std::vector<si32> resources;
+	TResources resources;
 	std::string name;
 	std::string description;
 

+ 2 - 1
lib/CCreatureHandler.h

@@ -8,6 +8,7 @@
 
 #include "../lib/HeroBonus.h"
 #include "../lib/ConstTransitivePtr.h"
+#include "ResourceSet.h"
 
 /*
  * CCreatureHandler.h, part of VCMI engine
@@ -28,7 +29,7 @@ class DLL_EXPORT CCreature : public CBonusSystemNode
 {
 public:
 	std::string namePl, nameSing, nameRef; //name in singular and plural form; and reference name
-	std::vector<ui32> cost; //cost[res_id] - amount of that resource
+	TResources cost; //cost[res_id] - amount of that resource
 	std::set<ui32> upgrades; // IDs of creatures to which this creature can be upgraded
 	ui32 hitPoints, speed, attack, defence;
 	ui32 fightValue, AIValue, growth, hordeGrowth, shots, spells;

+ 90 - 2
CGameInterface.cpp → lib/CGameInterface.cpp

@@ -1,6 +1,6 @@
-#include "stdafx.h"
+#define VCMI_DLL
 #include "CGameInterface.h"
-#include "lib/BattleState.h"
+#include "BattleState.h"
 
 #ifdef _WIN32
 	#define WIN32_LEAN_AND_MEAN //excludes rarely used stuff from windows headers - delete this line if something is missing
@@ -102,3 +102,91 @@ BattleAction CGlobalAI::activeStack( const CStack * stack )
 	ba.stackNumber = stack->ID;
 	return ba;
 }
+
+CGlobalAI::CGlobalAI()
+{
+	human = false;
+}
+
+void CAdventureAI::battleNewRound(int round)
+{
+	battleAI->battleNewRound(round);
+}
+
+void CAdventureAI::battleCatapultAttacked(const CatapultAttack & ca)
+{
+	battleAI->battleCatapultAttacked(ca);
+}
+
+void CAdventureAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side)
+{
+	assert(!battleAI);
+	battleAI = CDynLibHandler::getNewBattleAI(battleAIName);
+	battleAI->battleStart(army1, army2, tile, hero1, hero2, side);
+}
+
+void CAdventureAI::battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa)
+{
+	battleAI->battleStacksAttacked(bsa);
+}
+
+void CAdventureAI::actionStarted(const BattleAction *action)
+{
+	battleAI->actionStarted(action);
+}
+
+void CAdventureAI::battleNewRoundFirst(int round)
+{
+	battleAI->battleNewRoundFirst(round);
+}
+
+void CAdventureAI::actionFinished(const BattleAction *action)
+{
+	battleAI->actionFinished(action);
+}
+
+void CAdventureAI::battleStacksEffectsSet(const SetStackEffect & sse)
+{
+	battleAI->battleStacksEffectsSet(sse);
+}
+
+void CAdventureAI::battleStacksRemoved(const BattleStacksRemoved & bsr)
+{
+	battleAI->battleStacksRemoved(bsr);
+}
+
+void CAdventureAI::battleObstaclesRemoved(const std::set<si32> & removedObstacles)
+{
+	battleAI->battleObstaclesRemoved(removedObstacles);
+}
+
+void CAdventureAI::battleNewStackAppeared(const CStack * stack)
+{
+	battleAI->battleNewStackAppeared(stack);
+}
+
+void CAdventureAI::battleStackMoved(const CStack * stack, THex dest, int distance, bool end)
+{
+	battleAI->battleStackMoved(stack, dest, distance, end);
+}
+
+void CAdventureAI::battleAttack(const BattleAttack *ba)
+{
+	battleAI->battleAttack(ba);
+}
+
+void CAdventureAI::battleSpellCast(const BattleSpellCast *sc)
+{
+	battleAI->battleSpellCast(sc);
+}
+
+void CAdventureAI::battleEnd(const BattleResult *br)
+{
+	battleAI->battleEnd(br);
+	delNull(battleAI);
+}
+
+void CAdventureAI::battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, bool tentHeal, si32 lifeDrainFrom)
+{
+	battleAI->battleStacksHealedRes(healedStacks, lifeDrain, tentHeal, lifeDrainFrom);
+}

+ 36 - 7
CGameInterface.h → lib/CGameInterface.h

@@ -1,11 +1,10 @@
 #ifndef __CGAMEINTERFACE_H__
 #define __CGAMEINTERFACE_H__
-#include "global.h"
+#include "../global.h"
 #include <set>
 #include <vector>
-#include "lib/BattleAction.h"
-#include "client/FunctionList.h"
-#include "lib/IGameEventsReceiver.h"
+#include "BattleAction.h"
+#include "IGameEventsReceiver.h"
 
 /*
  * CGameInterface.h, part of VCMI engine
@@ -83,7 +82,7 @@ public:
 	virtual void serialize(CISer<CLoadFile> &h, const int version){}; //loading
 };
 
-class CDynLibHandler
+class DLL_EXPORT CDynLibHandler
 {
 public:
 	static CGlobalAI * getNewAI(std::string dllname);
@@ -91,10 +90,10 @@ public:
 	static CScriptingModule * getNewScriptingModule(std::string dllname);
 };
 
-class CGlobalAI : public CGameInterface // AI class (to derivate)
+class DLL_EXPORT CGlobalAI : public CGameInterface // AI class (to derivate)
 {
 public:
-	//CGlobalAI();
+	CGlobalAI();
 	virtual void yourTurn() OVERRIDE{};
 	virtual void heroKilled(const CGHeroInstance*){};
 	virtual void heroCreated(const CGHeroInstance*) OVERRIDE{};
@@ -104,4 +103,34 @@ public:
 	virtual BattleAction activeStack(const CStack * stack) OVERRIDE;
 };
 
+//class to  be inherited by adventure-only AIs, it cedes battle actions to given battle-AI
+class DLL_EXPORT CAdventureAI : public CGlobalAI
+{
+public:
+	CAdventureAI() : battleAI(NULL) {};
+	CAdventureAI(const std::string &BattleAIName) : battleAIName(BattleAIName), battleAI(NULL) {};
+
+	std::string battleAIName;
+	CBattleGameInterface *battleAI;
+
+	//battle interface
+	virtual void battleNewRound(int round);
+	virtual void battleCatapultAttacked(const CatapultAttack & ca);
+	virtual void battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side);
+	virtual void battleStacksAttacked(const std::vector<BattleStackAttacked> & bsa);
+	virtual void actionStarted(const BattleAction *action);
+	virtual void battleNewRoundFirst(int round);
+	virtual void actionFinished(const BattleAction *action);
+	virtual void battleStacksEffectsSet(const SetStackEffect & sse);
+	virtual void battleStacksRemoved(const BattleStacksRemoved & bsr);
+	virtual void battleObstaclesRemoved(const std::set<si32> & removedObstacles);
+	virtual void battleNewStackAppeared(const CStack * stack);
+	virtual void battleStackMoved(const CStack * stack, THex dest, int distance, bool end);
+	virtual void battleAttack(const BattleAttack *ba);
+	virtual void battleSpellCast(const BattleSpellCast *sc);
+	virtual void battleEnd(const BattleResult *br);
+	virtual void battleStacksHealedRes(const std::vector<std::pair<ui32, ui32> > & healedStacks, bool lifeDrain, bool tentHeal, si32 lifeDrainFrom);
+};
+
+
 #endif // __CGAMEINTERFACE_H__

+ 25 - 35
lib/CGameState.cpp

@@ -1184,7 +1184,7 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed )
 	}
 
 	/******************RESOURCES****************************************************/
-	std::vector<int> startresAI, startresHuman;
+	TResources startresAI, startresHuman;
 	std::ifstream tis(DATA_DIR "/config/startres.txt");
 	int k;
 	for (int j=0; j<scenarioOps->difficulty * 2; j++)
@@ -1195,32 +1195,22 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed )
 	}
 	tis >> k;
 	for (int i=0; i<RESOURCE_QUANTITY; i++)
-	{
-		tis >> k;
-		startresHuman.push_back(k);
-	}
+		tis >> startresHuman[i];
+
 	tis >> k;
 	for (int i=0; i<RESOURCE_QUANTITY; i++)
-	{
-		tis >> k;
-		startresAI.push_back(k);
-	}
+		tis >> startresAI[i];
+
 	tis.close();
 	tis.clear();
 	for (std::map<ui8,PlayerState>::iterator i = players.begin(); i!=players.end(); i++)
 	{
-		(*i).second.resources.resize(RESOURCE_QUANTITY);
-		for (int x=0;x<RESOURCE_QUANTITY;x++)
-		{
-			if (i->second.human)
-			{
-				(*i).second.resources[x] = startresHuman[x];
-			}
-			else
-			{
-				(*i).second.resources[x] = startresAI[x];
-			}
-		}
+		PlayerState &p = i->second;
+
+		if (p.human)
+			p.resources = startresHuman;
+		else
+			p.resources = startresAI;
 	}
 
 	//give start resource bonus in case of campaign
@@ -1231,7 +1221,7 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed )
 		if(chosenBonus.type == 7) //resource
 		{
 			std::vector<const PlayerSettings *> people = HLP::getHumanPlayerInfo(scenarioOps); //players we will give resource bonus
-			for (int b=0; b<people.size(); ++b)
+			BOOST_FOREACH(const PlayerSettings *ps, people)
 			{
 				std::vector<int> res; //resources we will give
 				switch (chosenBonus.info1)
@@ -1240,10 +1230,10 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed )
 					res.push_back(chosenBonus.info1);
 					break;
 				case 0xFD: //wood+ore
-					res.push_back(0); res.push_back(2);
+					res.push_back(Res::WOOD); res.push_back(Res::ORE);
 					break;
 				case 0xFE:  //rare
-					res.push_back(1); res.push_back(3); res.push_back(4); res.push_back(5);
+					res.push_back(Res::MERCURY); res.push_back(Res::SULFUR); res.push_back(Res::CRYSTAL); res.push_back(Res::GEMS);
 					break;
 				default:
 					assert(0);
@@ -1252,7 +1242,7 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed )
 				//increasing resource quantity
 				for (int n=0; n<res.size(); ++n)
 				{
-					players[people[b]->color].resources[res[n]] += chosenBonus.info2;
+					players[ps->color].resources[res[n]] += chosenBonus.info2;
 				}
 			}
 		}
@@ -1393,15 +1383,15 @@ void CGameState::init( StartInfo * si, ui32 checksum, int Seed )
 		switch(scenarioOps->playerInfos[k->first].bonus)
 		{
 		case PlayerSettings::bgold:
-			k->second.resources[6] += 500 + (ran()%6)*100;
+			k->second.resources[Res::GOLD] += 500 + (ran()%6)*100;
 			break;
 		case PlayerSettings::bresource:
 			{
 				int res = VLC->townh->towns[scenarioOps->playerInfos[k->first].castle].primaryRes;
 				if(res == 127)
 				{
-					k->second.resources[0] += 5 + ran()%6;
-					k->second.resources[2] += 5 + ran()%6;
+					k->second.resources[Res::WOOD] += 5 + ran()%6;
+					k->second.resources[Res::ORE] += 5 + ran()%6;
 				}
 				else
 				{
@@ -1682,10 +1672,10 @@ UpgradeInfo CGameState::getUpgradeInfo(const CStackInstance &stack)
 		BOOST_FOREACH(const Bonus *it, *lista)
 		{
 			ui16 nid = it->additionalInfo;
-			if (nid != base->idNumber) //in very specific case the upgrade is avaliable by default (?)
+			if (nid != base->idNumber) //in very specific case the upgrade is available by default (?)
 			{
 				ret.newID.push_back(nid);
-				ret.cost.push_back(costDiff(VLC->creh->creatures[nid]->cost, base->cost));
+				ret.cost.push_back(VLC->creh->creatures[nid]->cost - base->cost);
 			}
 		}
 		t = h->visitedTown;
@@ -1700,7 +1690,7 @@ UpgradeInfo CGameState::getUpgradeInfo(const CStackInstance &stack)
 				if(vstd::contains(base->upgrades, nid)) //possible upgrade
 				{
 					ret.newID.push_back(nid);
-					ret.cost.push_back(costDiff(VLC->creh->creatures[nid]->cost, base->cost));
+					ret.cost.push_back(VLC->creh->creatures[nid]->cost - base->cost);
 				}
 			}
 		}
@@ -1715,7 +1705,7 @@ UpgradeInfo CGameState::getUpgradeInfo(const CStackInstance &stack)
 		BOOST_FOREACH(si32 nid, base->upgrades)
 		{
 			ret.newID.push_back(nid);
-			ret.cost.push_back(costDiff(VLC->creh->creatures[nid]->cost, base->cost, costModifier));
+			ret.cost.push_back((VLC->creh->creatures[nid]->cost - base->cost) * costModifier / 100);
 		}
 	}
 
@@ -2619,15 +2609,15 @@ void CGameState::obtainPlayersStats(SThievesGuildInfo & tgi, int level)
 	}
 	if(level >= 2) //gold
 	{
-		FILL_FIELD(gold, g->second.resources[6])
+		FILL_FIELD(gold, g->second.resources[Res::GOLD])
 	}
 	if(level >= 2) //wood & ore
 	{
-		FILL_FIELD(woodOre, g->second.resources[0] + g->second.resources[1])
+		FILL_FIELD(woodOre, g->second.resources[Res::WOOD] + g->second.resources[Res::ORE])
 	}
 	if(level >= 3) //mercury, sulfur, crystal, gems
 	{
-		FILL_FIELD(mercSulfCrystGems, g->second.resources[2] + g->second.resources[3] + g->second.resources[4] + g->second.resources[5])
+		FILL_FIELD(mercSulfCrystGems, g->second.resources[Res::MERCURY] + g->second.resources[Res::SULFUR] + g->second.resources[Res::CRYSTAL] + g->second.resources[Res::GEMS])
 	}
 	if(level >= 4) //obelisks found
 	{

+ 3 - 2
lib/CGameState.h

@@ -23,6 +23,7 @@
 
 #include "ConstTransitivePtr.h"
 #include "IGameCallback.h"
+#include "ResourceSet.h"
 
 
 /*
@@ -161,7 +162,7 @@ public:
 	ui8 human; //true if human controlled player, false for AI
 	ui32 currentSelection; //id of hero/town, 0xffffffff if none
 	ui8 team;
-	std::vector<si32> resources;
+	TResources resources;
 	std::vector<ConstTransitivePtr<CGHeroInstance> > heroes;
 	std::vector<ConstTransitivePtr<CGTownInstance> > towns;
 	std::vector<ConstTransitivePtr<CGHeroInstance> > availableHeroes; //heroes available in taverns
@@ -209,7 +210,7 @@ struct UpgradeInfo
 {
 	int oldID; //creature to be upgraded
 	std::vector<int> newID; //possible upgrades
-	std::vector<std::set<std::pair<int,int> > > cost; // cost[upgrade_serial] -> set of pairs<resource_ID,resource_amount>
+	std::vector<TResources> cost; // cost[upgrade_serial] -> set of pairs<resource_ID,resource_amount>; cost is for single unit (not entire stack)
 	UpgradeInfo(){oldID = -1;};
 };
 

+ 5 - 8
lib/IGameCallback.cpp

@@ -848,11 +848,8 @@ int CGameInfoCallback::canBuildStructure( const CGTownInstance *t, int ID )
 		return Buildings::ERROR;
 
 	//checking resources
-	for(int res=0; res<RESOURCE_QUANTITY; res++)
-	{
-		if(pom->resources[res] > getResource(t->tempOwner, res))
-			ret = Buildings::NO_RESOURCES; //lack of res
-	}
+	if(pom->resources.canBeAfforded(getPlayer(t->tempOwner)->resources))
+		ret = Buildings::NO_RESOURCES; //lack of res
 
 	//checking for requirements
 	std::set<int> reqs = getBuildingRequiments(t, ID);//getting all requirements
@@ -1122,10 +1119,10 @@ int CPlayerSpecificInfoCallback::getResourceAmount(int type) const
 	return getResource(player, type);
 }
 
-std::vector<si32> CPlayerSpecificInfoCallback::getResourceAmount() const
+TResources CPlayerSpecificInfoCallback::getResourceAmount() const
 {
 	//boost::shared_lock<boost::shared_mutex> lock(*gs->mx);
-	ERROR_RET_VAL_IF(player == -1, "Applicable only for player callbacks", std::vector<si32>());
+	ERROR_RET_VAL_IF(player == -1, "Applicable only for player callbacks", TResources());
 	return gs->players[player].resources;
 }
 
@@ -1214,7 +1211,7 @@ const CGObjectInstance * IGameCallback::putNewObject(int ID, int subID, int3 pos
 	no.subID= subID;
 	no.pos = pos;
 	commitPackage(&no);
-	return getObj(no.id); //id field will be filled during applaying on gs
+	return getObj(no.id); //id field will be filled during applying on gs
 }
 
 const CGCreature * IGameCallback::putNewMonster(int creID, int count, int3 pos)

+ 2 - 1
lib/IGameCallback.h

@@ -6,6 +6,7 @@
 #include <set>
 #include "../client/FunctionList.h"
 #include "CObstacleInstance.h"
+#include "ResourceSet.h"
 
 /*
  * IGameCallback.h, part of VCMI engine
@@ -213,7 +214,7 @@ public:
 	std::vector <const CGObjectInstance * > getMyObjects() const; //returns all objects flagged by belonging player
 
 	int getResourceAmount(int type)const;
-	std::vector<si32> getResourceAmount() const;
+	TResources getResourceAmount() const;
 	const std::vector< std::vector< std::vector<unsigned char> > > & getVisibilityMap()const; //returns visibility map 
 	const PlayerSettings * getPlayerSettings(int color) const;
 };

+ 4 - 3
lib/NetPacks.h

@@ -10,6 +10,7 @@
 #include "../StartInfo.h"
 #include "ConstTransitivePtr.h"
 #include "../int3.h"
+#include "ResourceSet.h"
 
 /*
  * NetPacks.h, part of VCMI engine
@@ -238,12 +239,12 @@ struct SetResource : public CPackForClient //102
 }; 
  struct SetResources : public CPackForClient //104
  {
- 	SetResources(){res.resize(RESOURCE_QUANTITY);type = 104;};
+ 	SetResources(){type = 104;};
  	void applyCl(CClient *cl);
  	DLL_EXPORT void applyGs(CGameState *gs);
  
  	ui8 player;
- 	std::vector<si32> res; //res[resid] => res amount
+ 	TResources res; //res[resid] => res amount
  
  	template <typename Handler> void serialize(Handler &h, const int version)
  	{
@@ -965,7 +966,7 @@ struct NewTurn : public CPackForClient //101
 
 	std::set<Hero> heroes; //updates movement and mana points
 	//std::vector<SetResources> res;//resource list
-	std::map<ui8, std::vector<si32> > res; //player ID => resource value[res_id]
+	std::map<ui8, TResources> res; //player ID => resource value[res_id]
 	std::vector<SetAvailableCreatures> cres;//creatures to be placed in towns
 	ui32 day;
 	bool resetBuilded;

+ 7 - 10
lib/NetPacksLib.cpp

@@ -45,12 +45,11 @@ DLL_EXPORT void SetResource::applyGs( CGameState *gs )
 	gs->getPlayer(player)->resources[resid] = val;
 }
 
- DLL_EXPORT void SetResources::applyGs( CGameState *gs )
- {
- 	assert(player < PLAYER_LIMIT);
- 	for(int i=0;i<res.size();i++)
- 		gs->getPlayer(player)->resources[i] = res[i];
- }
+DLL_EXPORT void SetResources::applyGs( CGameState *gs )
+{
+	assert(player < PLAYER_LIMIT);
+	gs->getPlayer(player)->resources = res;
+}
 
 DLL_EXPORT void SetPrimSkill::applyGs( CGameState *gs )
 {
@@ -751,12 +750,10 @@ DLL_EXPORT void NewTurn::applyGs( CGameState *gs )
 		hero->mana = h.mana;
 	}
 
-	for(std::map<ui8, std::vector<si32> >::iterator i = res.begin(); i != res.end(); i++)
+	for(std::map<ui8, TResources>::iterator i = res.begin(); i != res.end(); i++)
 	{
 		assert(i->first < PLAYER_LIMIT);
-		std::vector<si32> &playerRes = gs->getPlayer(i->first)->resources;
-		for(int j = 0;  j < i->second.size();  j++)
-			playerRes[j] = i->second[j];
+		gs->getPlayer(i->first)->resources = i->second;
 	}
 
 	BOOST_FOREACH(SetAvailableCreatures h, cres) //set available creatures in towns

+ 91 - 0
lib/ResourceSet.cpp

@@ -0,0 +1,91 @@
+#define VCMI_DLL
+#include "ResourceSet.h"
+
+Res::ResourceSet::ResourceSet()
+{
+	resize(RESOURCE_QUANTITY, 0);
+}
+
+bool Res::ResourceSet::nonZero() const
+{
+	for(int i = 0; i < size(); i++)
+		if(at(i))
+			return true;
+
+	return false;
+}
+
+void Res::ResourceSet::amax(const TResource &val)
+{
+	for(int i = 0; i < size(); i++)
+		::amax(at(i), val);
+}
+
+bool Res::ResourceSet::canBeAfforded(const ResourceSet &res) const
+{
+	return Res::canAfford(res, *this);
+}
+
+bool Res::ResourceSet::canAfford(const ResourceSet &price) const
+{
+	return Res::canAfford(*this, price);
+}
+
+bool Res::canAfford(const ResourceSet &res, const ResourceSet &price)
+{
+	assert(res.size() == price.size() && price.size() == RESOURCE_QUANTITY);
+	for(int i = 0; i < RESOURCE_QUANTITY; i++)
+		if(price[i] > res[i])
+			return false;
+
+	return true;
+}
+
+bool Res::ResourceSet::nziterator::valid()
+{
+	return cur.resType < RESOURCE_QUANTITY && cur.resVal;
+}
+
+Res::ResourceSet::nziterator Res::ResourceSet::nziterator::operator++()
+{
+	advance();
+	return *this;
+}
+
+Res::ResourceSet::nziterator Res::ResourceSet::nziterator::operator++(int)
+{
+	nziterator ret = *this;
+	advance();
+	return ret;
+}
+
+const Res::ResourceSet::nziterator::ResEntry& Res::ResourceSet::nziterator::operator*() const
+{
+	return cur;
+}
+
+const Res::ResourceSet::nziterator::ResEntry * Res::ResourceSet::nziterator::operator->() const
+{
+	return &cur;
+}
+
+void Res::ResourceSet::nziterator::advance()
+{
+	do
+	{
+		cur.resType++;
+	} while(cur.resType < RESOURCE_QUANTITY && !(cur.resVal=rs[cur.resType]));
+
+	if(cur.resType >= RESOURCE_QUANTITY)
+		cur.resVal = -1;
+}
+
+Res::ResourceSet::nziterator::nziterator(const ResourceSet &RS)
+	: rs(RS)
+{
+	cur.resType = 0;
+	cur.resVal = rs[0];
+
+	if(!valid())
+		advance();
+}

+ 123 - 0
lib/ResourceSet.h

@@ -0,0 +1,123 @@
+#pragma once
+
+#include"../global.h"
+
+typedef si32 TResource;
+
+namespace Res
+{
+	class ResourceSet;
+	bool canAfford(const ResourceSet &res, const ResourceSet &price); //can a be used to pay price b
+
+	enum ERes 
+	{
+		WOOD = 0, MERCURY, ORE, SULFUR, CRYSTAL, GEMS, GOLD, MITHRIL
+	};
+
+	//class to be representing a vector of resource
+	class ResourceSet : public std::vector<int>
+	{
+	public:
+		DLL_EXPORT ResourceSet();
+
+
+#define scalarOperator(OPSIGN)									\
+		DLL_EXPORT ResourceSet operator OPSIGN(const TResource &rhs) const	\
+		{														\
+			ResourceSet ret = *this;							\
+			for(int i = 0; i < size(); i++)						\
+				ret[i] = at(i) OPSIGN rhs;						\
+																\
+			return ret;											\
+		}
+
+
+
+#define vectorOperator(OPSIGN)										\
+		DLL_EXPORT ResourceSet operator OPSIGN(const ResourceSet &rhs) const	\
+		{															\
+			ResourceSet ret = *this;								\
+			for(int i = 0; i < size(); i++)							\
+				ret[i] = at(i) OPSIGN rhs[i];						\
+																	\
+			return ret;												\
+		}
+
+
+#define opEqOperator(OPSIGN, RHS_TYPE)							\
+		DLL_EXPORT ResourceSet& operator OPSIGN ## =(const RHS_TYPE &rhs)	\
+		{														\
+			return *this = *this OPSIGN rhs;					\
+		}
+
+		scalarOperator(+)
+		scalarOperator(-)
+		scalarOperator(*)
+		scalarOperator(/)
+		opEqOperator(+, TResource)
+		opEqOperator(-, TResource)
+		opEqOperator(*, TResource)
+		vectorOperator(+)
+		vectorOperator(-)
+		opEqOperator(+, ResourceSet)
+		opEqOperator(-, ResourceSet)
+
+#undef scalarOperator
+#undef vectorOperator
+#undef opEqOperator
+
+		//to be used for calculations of type "how many units of sth can I afford?"
+		DLL_EXPORT int operator/(const ResourceSet &rhs)
+		{
+			int ret = INT_MAX;
+			for(int i = 0; i < size(); i++)
+				amin(ret, at(i) / rhs[i]);
+
+			return ret;
+		}
+
+	// WARNING: comparison operators are used for "can afford" relation: a <= b means that foreach i a[i] <= b[i] 
+	// that doesn't work the other way: a > b doesn't mean that a cannot be afforded with b, it's still b can afford a
+// 		bool operator<(const ResourceSet &rhs)
+// 		{
+// 			for(int i = 0; i < size(); i++)
+// 				if(at(i) >= rhs[i])
+// 					return false;
+// 
+// 			return true;
+// 		}
+
+		template <typename Handler> void serialize(Handler &h, const int version)
+		{
+			h & static_cast<std::vector<int>&>(*this);
+		}
+
+		DLL_EXPORT void amax(const TResource &val); //performs amax on each element
+		DLL_EXPORT bool nonZero() const; //returns true if at least one value is non-zero;
+		DLL_EXPORT bool canAfford(const ResourceSet &price) const;
+		DLL_EXPORT bool canBeAfforded(const ResourceSet &res) const;
+
+		//special iterator of iterating over non-zero resources in set
+		class DLL_EXPORT nziterator
+		{
+			struct ResEntry
+			{
+				TResource resType, resVal;
+			} cur;
+			const ResourceSet &rs;
+			void advance();
+		
+		public:
+			nziterator(const ResourceSet &RS);
+			bool valid();
+			nziterator operator++();
+			nziterator operator++(int);
+			const ResEntry& operator*() const;
+			const ResEntry* operator->() const;
+		
+		};
+	};
+}
+
+typedef Res::ResourceSet TResources;
+

+ 4 - 0
lib/VCMI_lib.vcxproj

@@ -173,6 +173,7 @@
     <ClCompile Include="CCreatureSet.cpp" />
     <ClCompile Include="CDefObjInfoHandler.cpp" />
     <ClCompile Include="CFileUtility.cpp" />
+    <ClCompile Include="CGameInterface.cpp" />
     <ClCompile Include="CGameState.cpp" />
     <ClCompile Include="CGeneralTextHandler.cpp" />
     <ClCompile Include="CHeroHandler.cpp" />
@@ -188,6 +189,7 @@
     <ClCompile Include="NetPacksLib.cpp" />
     <ClCompile Include="RegisterTypes.cpp" />
     <ClCompile Include="..\stdafx.cpp" />
+    <ClCompile Include="ResourceSet.cpp" />
     <ClCompile Include="VCMI_Lib.cpp" />
   </ItemGroup>
   <ItemGroup>
@@ -203,6 +205,7 @@
     <ClInclude Include="CCreatureSet.h" />
     <ClInclude Include="CDefObjInfoHandler.h" />
     <ClInclude Include="CFileUtility.h" />
+    <ClInclude Include="CGameInterface.h" />
     <ClInclude Include="CGameState.h" />
     <ClInclude Include="CGeneralTextHandler.h" />
     <ClInclude Include="CHeroHandler.h" />
@@ -223,6 +226,7 @@
     <ClInclude Include="map.h" />
     <ClInclude Include="NetPacks.h" />
     <ClInclude Include="RegisterTypes.h" />
+    <ClInclude Include="ResourceSet.h" />
     <ClInclude Include="VCMI_Lib.h" />
     <ClInclude Include="VCMIDirs.h" />
   </ItemGroup>

+ 0 - 2
lib/map.cpp

@@ -724,7 +724,6 @@ void Mapa::loadTown( CGObjectInstance * &nobj, const unsigned char * bufor, int
 		nce->town = nt;
 		nce->name = readString(bufor,i);
 		nce->message = readString(bufor,i);
-		nce->resources.resize(RESOURCE_QUANTITY);
 		for(int x=0; x < 7; x++)
 		{
 			nce->resources[x] = readNormalNr(bufor,i); 
@@ -1885,7 +1884,6 @@ void Mapa::readEvents( const unsigned char * bufor, int &i )
 		{
 			ne->message +=bufor[i]; ++i;
 		}
-		ne->resources.resize(RESOURCE_QUANTITY);
 		for(int k=0; k < 7; k++)
 		{
 			ne->resources[k] = readNormalNr(bufor,i); i+=4;

+ 2 - 1
lib/map.h

@@ -15,6 +15,7 @@
 #endif
 
 #include "ConstTransitivePtr.h"
+#include "ResourceSet.h"
 
 /*
  * map.h, part of VCMI engine
@@ -211,7 +212,7 @@ class DLL_EXPORT CMapEvent
 {
 public:
 	std::string name, message;
-	std::vector<si32> resources; //gained / taken resources
+	TResources resources; //gained / taken resources
 	ui8 players; //affected players
 	ui8 humanAffected;
 	ui8 computerAffected;

+ 35 - 56
server/CGameHandler.cpp

@@ -924,11 +924,7 @@ void CGameHandler::newTurn()
 		}
 
 		n.res[i->first] = i->second.resources;
-// 		SetResources r;
-// 		r.player = i->first;
-// 		for(int j=0;j<RESOURCE_QUANTITY;j++)
-// 			r.res[j] = i->second.resources[j];
-		
+
 		BOOST_FOREACH(CGHeroInstance *h, (*i).second.heroes)
 		{
 			if(h->visitedTown)
@@ -955,7 +951,6 @@ void CGameHandler::newTurn()
 				}
 			}
 		}
-		//n.res.push_back(r);
 	}
 	//      townID,    creatureID, amount
 	std::map<si32, std::map<si32, si32> > newCreas;//creatures that needs to be added by town events
@@ -987,7 +982,7 @@ void CGameHandler::newTurn()
 					n.res[player][(**j).town->primaryRes] ++;;
 				}
 			}
-			n.res[player][6] += (**j).dailyIncome();
+			n.res[player][Res::GOLD] += (**j).dailyIncome();
 		}
 		handleTownEvents(*j, n, newCreas);
 		if (vstd::contains((**j).builtBuildings, 26)) 
@@ -2211,9 +2206,7 @@ bool CGameHandler::buildStructure( si32 tid, si32 bid, bool force /*=false*/ )
 	{
 		SetResources sr;
 		sr.player = t->tempOwner;
-		sr.res = gs->getPlayer(t->tempOwner)->resources;
-		for(int i=0;i<b->resources.size();i++)
-			sr.res[i]-=b->resources[i];
+		sr.res = gs->getPlayer(t->tempOwner)->resources - b->resources;
 		sendAndApply(&sr);
 	}
 
@@ -2315,8 +2308,7 @@ bool CGameHandler::recruitCreatures( si32 objid, ui32 crid, ui32 cram, si32 from
 	//recruit
 	SetResources sr;
 	sr.player = dst->tempOwner;
-	for(int i=0;i<RESOURCE_QUANTITY;i++)
-		sr.res[i]  =  gs->getPlayer(dst->tempOwner)->resources[i] - (c->cost[i] * cram);
+	sr.res = gs->getPlayer(dst->tempOwner)->resources - (c->cost * cram);
 
 	SetAvailableCreatures sac;
 	sac.tid = objid;
@@ -2361,8 +2353,10 @@ bool CGameHandler::upgradeCreature( ui32 objid, ui8 pos, ui32 upgID )
 	assert(obj->hasStackAtSlot(pos));
 	UpgradeInfo ui = gs->getUpgradeInfo(obj->getStack(pos));
 	int player = obj->tempOwner;
+	const PlayerState *p = getPlayer(player);
 	int crQuantity = obj->stacks[pos]->count;
 	int newIDpos= vstd::findPos(ui.newID, upgID);//get position of new id in UpgradeInfo
+	TResources totalCost = ui.cost[newIDpos] * crQuantity;
 
 	//check if upgrade is possible
 	if( (ui.oldID<0 || newIDpos == -1 ) && complain("That upgrade is not possible!")) 
@@ -2372,24 +2366,14 @@ bool CGameHandler::upgradeCreature( ui32 objid, ui8 pos, ui32 upgID )
 	
 
 	//check if player has enough resources
-	for (std::set<std::pair<int,int> >::iterator j=ui.cost[newIDpos].begin(); j!=ui.cost[newIDpos].end(); j++)
-	{
-		if(gs->getPlayer(player)->resources[j->first] < j->second*crQuantity)
-		{
-			complain("Cannot upgrade, not enough resources!");
-			return false;
-		}
-	}
+	if(!p->resources.canAfford(totalCost))
+		COMPLAIN_RET("Cannot upgrade, not enough resources!");
 	
 	//take resources
-	for (std::set<std::pair<int,int> >::iterator j=ui.cost[newIDpos].begin(); j!=ui.cost[newIDpos].end(); j++)
-	{
-		SetResource sr;
-		sr.player = player;
-		sr.resid = j->first;
-		sr.val = gs->getPlayer(player)->resources[j->first] - j->second*crQuantity;
-		sendAndApply(&sr);
-	}
+	SetResources sr;
+	sr.player = player;
+	sr.res = p->resources - totalCost;
+	sendAndApply(&sr);
 	
 	//upgrade creature
 	changeStackType(StackLocation(obj, pos), VLC->creh->creatures[upgID]);
@@ -2854,8 +2838,8 @@ bool CGameHandler::hireHero(const CGObjectInstance *obj, ui8 hid, ui8 player)
 	const PlayerState *p = gs->getPlayer(player);
 	const CGTownInstance *t = gs->getTown(obj->id);
 
-	//common prconditions
-	if( p->resources[6]<2500  && complain("Not enough gold for buying hero!")
+	//common preconditions
+	if( p->resources[Res::GOLD]<2500  && complain("Not enough gold for buying hero!")
 		|| getHeroCount(player, false) >= 8 && complain("Cannot hire hero, only 8 wandering heroes are allowed!"))
 		return false;
 
@@ -2905,8 +2889,8 @@ bool CGameHandler::hireHero(const CGObjectInstance *obj, ui8 hid, ui8 player)
 
 	SetResource sr;
 	sr.player = player;
-	sr.resid = 6;
-	sr.val = p->resources[6] - 2500;
+	sr.resid = Res::GOLD;
+	sr.val = p->resources[Res::GOLD] - 2500;
 	sendAndApply(&sr);
 
 	if(t)
@@ -3775,30 +3759,22 @@ void CGameHandler::handleTimeEvents()
 				//give resources
 				SetResources sr;
 				sr.player = player;
-				sr.res = pinfo->resources;
+				sr.res = pinfo->resources + ev->resources;
 
 				//prepare dialog
 				InfoWindow iw;
 				iw.player = player;
 				iw.text << ev->message;
+
 				for (int i=0; i<ev->resources.size(); i++)
 				{
 					if(ev->resources[i]) //if resource is changed, we add it to the dialog
-					{
-						// If removing too much resources, adjust the
-						// amount so the total doesn't become negative.
-						if (sr.res[i] + ev->resources[i] < 0)
-							ev->resources[i] = -sr.res[i];
-
-						if(ev->resources[i]) //if non-zero res change
-						{
-							iw.components.push_back(Component(Component::RESOURCE,i,ev->resources[i],0));
-							sr.res[i] += ev->resources[i];
-						}
-					}
+						iw.components.push_back(Component(Component::RESOURCE,i,ev->resources[i],0));
 				}
+
 				if (iw.components.size())
 				{
+					sr.res.amax(0); // If removing too much resources, adjust the amount so the total doesn't become negative.
 					sendAndApply(&sr); //update player resources if changed
 				}
 
@@ -3839,21 +3815,24 @@ void CGameHandler::handleTownEvents(CGTownInstance * town, NewTurn &n, std::map<
 				|| (ev->humanAffected && pinfo->human) ) )
 		{
 
+
 			// dialog
 			InfoWindow iw;
 			iw.player = player;
 			iw.text << ev->message;
 
-			for (int i=0; i<ev->resources.size(); i++)
-				if(ev->resources[i]) //if resource had changed, we add it to the dialog
-				{
-					int was = n.res[player][i];
-					n.res[player][i] += ev->resources[i];
-					n.res[player][i] = std::max<si32>(n.res[player][i], 0);
+			if(ev->resources.nonZero())
+			{
+				TResources was = n.res[player];
+				n.res[player] += ev->resources;
+				n.res[player].amax(0);
+
+				for (int i=0; i<ev->resources.size(); i++)
+					if(ev->resources[i] && pinfo->resources[i] != n.res[player][i]) //if resource had changed, we add it to the dialog
+						iw.components.push_back(Component(Component::RESOURCE,i,n.res[player][i]-was[i],0));
+
+			}
 
-					if(pinfo->resources[i] != n.res[player][i]) //if non-zero res change
-						iw.components.push_back(Component(Component::RESOURCE,i,n.res[player][i]-was,0));
-				}
 			for(std::set<si32>::iterator i = ev->buildings.begin(); i!=ev->buildings.end();i++)
 				if ( !vstd::contains(town->builtBuildings, *i))
 				{
@@ -4018,8 +3997,8 @@ bool CGameHandler::buildBoat( ui32 objid )
 	SetResources sr;
 	sr.player = obj->o->tempOwner;
 	sr.res = gs->getPlayer(obj->o->tempOwner)->resources;
-	sr.res[0] -= 10;
-	sr.res[6] -= 1000;
+	sr.res[Res::WOOD] -= 10;
+	sr.res[Res::GOLD] -= 1000;
 	sendAndApply(&sr);
 
 	//create boat