Explorar el Código

* compiles under MSVC (haven't I broken anything on gcc?)
* half-done support for battles

Michał W. Urbańczyk hace 17 años
padre
commit
a15ffb06e6

+ 3 - 0
CAdvmapInterface.cpp

@@ -22,6 +22,7 @@
 #include "CHeroWindow.h"
 #include "client/Graphics.h"
 #include "hch/CObjectHandler.h"
+#include <boost/thread.hpp>
 #include "map.h"
 #pragma warning (disable : 4355) 
 extern TTF_Font * TNRB16, *TNR, *GEOR13, *GEORXX; //fonts
@@ -283,7 +284,9 @@ void CTerrainRect::clickLeft(tribool down)
 		if ( (currentPath->endPos()) == mp)
 		{ //move
 			CPath sended(*currentPath); //temporary path - engine will operate on it
+			LOCPLINT->pim->unlock();
 			mres = LOCPLINT->cb->moveHero( ((const CGHeroInstance*)LOCPLINT->adventureInt->selection.selected)->type->ID,&sended,1,0);
+			LOCPLINT->pim->lock();
 			if(!mres)
 			{
 				delete currentPath;

+ 19 - 24
CBattleInterface.cpp

@@ -14,7 +14,7 @@
 #include "client/Graphics.h"
 #include <queue>
 #include <sstream>
-
+#include "lib/CondSh.h"
 #ifndef __GNUC__
 const double M_PI = 3.14159265358979323846;
 #else
@@ -30,6 +30,7 @@ SDL_Surface * CBattleInterface::cellBorder, * CBattleInterface::cellShade;
 CBattleInterface::CBattleInterface(CCreatureSet * army1, CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2)
 : printCellBorders(true), attackingHeroInstance(hero1), defendingHeroInstance(hero2), animCount(0), activeStack(-1), givenCommand(NULL), attackingInfo(NULL), myTurn(false)
 {
+	givenCommand = new CondSh<BattleAction *>(NULL);
 	//initializing armies
 	this->army1 = army1;
 	this->army2 = army2;
@@ -169,6 +170,7 @@ CBattleInterface::~CBattleInterface()
 	delete bConsoleUp;
 	delete bConsoleDown;
 	delete console;
+	delete givenCommand;
 
 	delete attackingHero;
 	delete defendingHero;
@@ -391,9 +393,7 @@ void CBattleInterface::bSurrenderf()
 
 void CBattleInterface::bFleef()
 {
-	BattleAction * ba = new BattleAction;
-	ba->actionType = 4;
-	givenCommand = ba;
+	giveCommand(4,0,0);
 }
 
 void CBattleInterface::bAutofightf()
@@ -410,10 +410,7 @@ void CBattleInterface::bWaitf()
 
 void CBattleInterface::bDefencef()
 {
-	BattleAction * ba = new BattleAction;
-	ba->actionType = 3;
-	ba->stackNumber = activeStack;
-	givenCommand = ba;
+	giveCommand(3,0,activeStack);
 }
 
 void CBattleInterface::bConsoleUpf()
@@ -482,7 +479,7 @@ void CBattleInterface::stackKilled(int ID, int dmg, int killed, int IDby, bool b
 
 void CBattleInterface::stackActivated(int number)
 {
-	givenCommand = NULL;
+	//givenCommand = NULL;
 	activeStack = number;
 	shadedHexes = LOCPLINT->cb->battleGetAvailableHexes(number);
 	myTurn = true;
@@ -791,6 +788,16 @@ void CBattleInterface::newRound(int number)
 	console->addText(CGI->generaltexth->allTexts[412]);
 }
 
+void CBattleInterface::giveCommand(ui8 action, ui16 tile, ui32 stack)
+{
+	BattleAction * ba = new BattleAction(); //to be deleted by engine
+	ba->actionType = action;
+	ba->destinationTile = tile;
+	ba->stackNumber = stack;
+	givenCommand->setn(ba);
+	myTurn = false;
+}
+
 void CBattleInterface::hexLclicked(int whichOne)
 {
 	if((whichOne%17)!=0 && (whichOne%17)!=16) //if player is trying to attack enemey unit or move creature stack
@@ -802,28 +809,16 @@ void CBattleInterface::hexLclicked(int whichOne)
 		//LOCPLINT->cb->battleGetCreature();
 		if(atCre==-1) //normal move action
 		{
-			BattleAction * ba = new BattleAction(); //to be deleted by engine
-			ba->actionType = 2;
-			ba->destinationTile = whichOne;
-			ba->stackNumber = activeStack;
-			givenCommand = ba;
+			giveCommand(2,whichOne,activeStack);
 		}
 		else if(LOCPLINT->cb->battleGetStackByID(atCre)->owner != attackingHeroInstance->tempOwner
 			&& LOCPLINT->cb->battleCanShoot(activeStack, whichOne)) //shooting
 		{
-			BattleAction * ba = new BattleAction(); //to be deleted by engine
-			ba->actionType = 7;
-			ba->destinationTile = whichOne;
-			ba->stackNumber = activeStack;
-			givenCommand = ba;
+			giveCommand(7,whichOne,activeStack);
 		}
 		else if(LOCPLINT->cb->battleGetStackByID(atCre)->owner != attackingHeroInstance->tempOwner) //attacking
 		{
-			BattleAction * ba = new BattleAction(); //to be deleted by engine
-			ba->actionType = 6;
-			ba->destinationTile = whichOne;
-			ba->stackNumber = activeStack;
-			givenCommand = ba;
+			giveCommand(6,whichOne,activeStack);
 		}
 	}
 }

+ 3 - 2
CBattleInterface.h

@@ -9,6 +9,7 @@ class CDefHandler;
 class CStack;
 class CCallback;
 class AdventureMapButton;
+template <typename T> struct CondSh;
 
 class CBattleHero : public IShowable, public CIntObject
 {
@@ -112,7 +113,7 @@ private:
 	};
 	std::list<SProjectileInfo> projectiles;
 	void projectileShowHelper(SDL_Surface * to=NULL); //prints projectiles present on the battlefield
-	
+	void giveCommand(ui8 action, ui16 tile, ui32 stack);
 public:
 	CBattleInterface(CCreatureSet * army1, CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2); //c-tor
 	~CBattleInterface(); //d-tor
@@ -122,7 +123,7 @@ public:
 	CBattleHex bfield[187]; //11 lines, 17 hexes on each
 	std::vector< CBattleObstacle * > obstacles; //vector of obstacles on the battlefield
 	static SDL_Surface * cellBorder, * cellShade;
-	BattleAction * givenCommand; //true if we have i.e. moved current unit
+	CondSh<BattleAction *> *givenCommand; //data != NULL if we have i.e. moved current unit
 	bool myTurn; //if true, interface is active (commands can be ordered
 
 	//button handle funcs:

+ 6 - 0
CCallback.cpp

@@ -18,6 +18,12 @@
 #include <boost/thread.hpp>
 #include <boost/foreach.hpp>
 #include "lib/NetPacks.h"
+#ifdef min
+#undef min
+#endif
+#ifdef max
+#undef max
+#endif
 extern CSharedCond<std::set<IPack*> > mess;
 
 HeroMoveDetails::HeroMoveDetails(int3 Src, int3 Dst, CGHeroInstance*Ho)

+ 4 - 11
CGameInterface.h

@@ -3,6 +3,7 @@
 #include "global.h"
 #include <set>
 #include <vector>
+#include "lib/BattleAction.h"
 BOOST_TRIBOOL_THIRD_STATE(outOfRange)
 
 using namespace boost::logic;
@@ -18,21 +19,13 @@ class CGTownInstance;
 class CGObjectInstance;
 class CCreatureSet;
 class CArmedInstance;
-
+struct BattleResult;
 class CObstacle
 {
 	int ID;
 	int position;
 	//TODO: add some kind of the blockmap
 };
-struct BattleAction
-{
-	bool side; //who made this action: false - left, true - right player
-	int stackNumber;//stack ID, -1 left hero, -2 right hero,
-	int actionType; //    0 = Cancel BattleAction   1 = Hero cast a spell   2 = Walk   3 = Defend   4 = Retreat from the battle   5 = Surrender   6 = Walk and Attack   7 = Shoot    8 = Wait   9 = Catapult 10 = Monster casts a spell (i.e. Faerie Dragons)
-	int destinationTile;
-	int additionalInfo; // e.g. spell number if type is 1 || 10
-};
 
 struct StackState
 {
@@ -65,13 +58,13 @@ public:
 	virtual void garrisonChanged(const CGObjectInstance * obj){};
 	virtual void buildChanged(const CGTownInstance *town, int buildingID, int what){}; //what: 1 - built, 2 - demolished
 	//battle call-ins
-	virtual void battleStart(CCreatureSet * army1, CCreatureSet * army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side){}; //called by engine when battle starts; side=0 - left, side=1 - right
+	virtual void battleStart(CCreatureSet *army1, CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side){}; //called by engine when battle starts; side=0 - left, side=1 - right
 	virtual void battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles){}; //called when battlefield is prepared, prior the battle beginning
 	virtual void battleNewRound(int round){}; //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
 	virtual void actionStarted(BattleAction action){};//occurs BEFORE every action taken by any stack or by the hero
 	virtual void actionFinished(BattleAction action){};//occurs AFTER every action taken by any stack or by the hero
 	virtual BattleAction activeStack(int stackID)=0; //called when it's turn of that stack
-	virtual void battleEnd(CCreatureSet * army1, CCreatureSet * army2, CArmedInstance *hero1, CArmedInstance *hero2, std::vector<int> capturedArtifacts, int expForWinner, bool winner){};
+	virtual void battleEnd(BattleResult *br){};
 	virtual void battleStackMoved(int ID, int dest, bool startMoving, bool endMoving)=0;
 	virtual void battleStackAttacking(int ID, int dest)=0;
 	virtual void battleStackIsAttacked(int ID, int dmg, int killed, int IDby, bool byShooting)=0;

+ 56 - 9
CGameState.cpp

@@ -18,14 +18,6 @@
 #include <boost/thread.hpp>
 #include <boost/thread/shared_mutex.hpp>
 boost::rand48 ran;
-class CMP_stack
-{
-public:
-	bool operator ()(const CStack* a, const CStack* b)
-	{
-		return (a->creature->speed)>(b->creature->speed);
-	}
-} cmpst ;
 
 CGObjectInstance * createObject(int id, int subid, int3 pos, int owner)
 {
@@ -135,6 +127,26 @@ void CGameState::apply(IPack * pack)
 				players[sr->player].resources[i] = sr->res[i];
 			break;
 		}
+	case 105:
+		{
+			SetPrimSkill *sr = static_cast<SetPrimSkill*>(pack);
+			CGHeroInstance *hero = getHero(sr->id);
+			if(sr->which <4)
+			{
+				if(sr->abs)
+					hero->primSkills[sr->which] = sr->val;
+				else
+					hero->primSkills[sr->which] += sr->val;
+			}
+			else if(sr->which == 4) //XP
+			{
+				if(sr->abs)
+					hero->exp = sr->val;
+				else
+					hero->exp += sr->val;
+			}
+			break;
+		}
 	case 500:
 		{
 			RemoveHero *rh = static_cast<RemoveHero*>(pack);
@@ -198,6 +210,35 @@ void CGameState::apply(IPack * pack)
 			map->objects[p->id]->*point = p->val;
 			break;
 		}
+	case 3000:
+		{
+			BattleStart * bs = static_cast<BattleStart*>(pack);
+			curB = bs->info;
+			break;
+		}
+	case 3001:
+		{
+			BattleNextRound *ns = static_cast<BattleNextRound*>(pack);
+			curB->round = ns->round;
+			break;
+		}
+	case 3002:
+		{
+			BattleSetActiveStack *ns = static_cast<BattleSetActiveStack*>(pack);
+			curB->activeStack = ns->stack;
+			break;
+		}
+	case 3003:
+		{
+			BattleResult *br = static_cast<BattleResult*>(pack);
+
+			//TODO: give exp, artifacts to winner, decrease armies (casualties)
+
+			for(unsigned i=0;i<curB->stacks.size();i++)
+				delete curB->stacks[i];
+			delete curB;
+			curB = NULL;
+		}
 	//case 1002://set hover name
 	//	{
 	//		SetHoverName * shn = static_cast<SetHoverName*>(pack);
@@ -228,6 +269,12 @@ int CGameState::pickHero(int owner)
 	}
 	return h;
 }
+CGHeroInstance *CGameState::getHero(int objid)
+{
+	if(objid<0 || objid>=map->objects.size())
+		return NULL;
+	return static_cast<CGHeroInstance *>(map->objects[objid]);
+}
 std::pair<int,int> CGameState::pickObject(CGObjectInstance *obj)
 {
 	switch(obj->ID)
@@ -460,7 +507,7 @@ void CGameState::init(StartInfo * si, Mapa * map, int Seed)
 {
 	day = 0;
 	seed = Seed;
-	ran.seed((int32_t)seed);
+	ran.seed((boost::int32_t)seed);
 	scenarioOps = si;
 	this->map = map;
 

+ 39 - 13
CGameState.h

@@ -47,29 +47,53 @@ public:
 
 struct DLL_EXPORT BattleInfo
 {
-	int side1, side2;
-	int round, activeStack;
-	int siege; //    = 0 ordinary battle    = 1 a siege with a Fort    = 2 a siege with a Citadel    = 3 a siege with a Castle
+	ui8 side1, side2;
+	si32 round, activeStack;
+	ui8 siege; //    = 0 ordinary battle    = 1 a siege with a Fort    = 2 a siege with a Citadel    = 3 a siege with a Castle
 	int3 tile; //for background and bonuses
-	CGHeroInstance *hero1, *hero2;
-	CCreatureSet * army1, * army2;
+	si32 hero1, hero2;
+	CCreatureSet army1, army2;
 	std::vector<CStack*> stacks;
-	bool stackActionPerformed; //true if current stack has been moved
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & side1 & side2 & round & activeStack & siege & tile & stacks & army1 & army2 & hero1 & hero2;
+	}
 };
 
 class DLL_EXPORT CStack
 {
 public:
-	int ID; //unique ID of stack
+	ui32 ID; //unique ID of stack
 	CCreature * creature;
-	int amount;
-	int firstHPleft; //HP of first creature in stack
-	int owner;
-	bool attackerOwned; //if true, this stack is owned by attakcer (this one from left hand side of battle)
-	int position; //position on battlefield
-	bool alive; //true if it is alive
+	ui32 amount;
+	ui32 firstHPleft; //HP of first creature in stack
+	ui8 owner;
+	ui8 attackerOwned; //if true, this stack is owned by attakcer (this one from left hand side of battle)
+	ui16 position; //position on battlefield
+	ui8 alive; //true if it is alive
+
 	CStack(CCreature * C, int A, int O, int I, bool AO);
 	CStack() : creature(NULL),amount(-1),owner(255), alive(true), position(-1), ID(-1), attackerOwned(true), firstHPleft(-1){};
+
+	template <typename Handler> void save(Handler &h, const int version)
+	{
+		h & creature->idNumber;
+	}
+	template <typename Handler> void load(Handler &h, const int version)
+	{
+		ui32 id;
+		h & id;
+		creature = &VLC->creh->creatures[id];
+	}
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & ID & amount & firstHPleft & owner & attackerOwned & position & alive;
+		if(h.saving)
+			save(h,version);
+		else
+			load(h,version);
+	}
 };
 
 class DLL_EXPORT CGameState
@@ -94,6 +118,8 @@ private:
 	std::pair<int,int> pickObject(CGObjectInstance *obj);
 	int pickHero(int owner);
 
+	CGHeroInstance *getHero(int objid);
+
 	void battle(CCreatureSet * army1, CCreatureSet * army2, int3 tile, CArmedInstance *hero1, CArmedInstance *hero2);
 	bool battleMoveCreatureStack(int ID, int dest);
 	bool battleAttackCreatureStack(int ID, int dest);

+ 57 - 114
CLua.cpp

@@ -77,10 +77,6 @@ void CLua::open(std::string initpath)
 	//	temp += initpath;
 	//	throw std::exception(temp.c_str());
 	//}
-
-
-
-
 }
 void CLua::registerCLuaCallback()
 {
@@ -113,10 +109,6 @@ void CLua::findFS(std::string fname)
 	//	lua_settop(is, 0);
 	//	throw new std::exception((fname + ": function not defined").c_str()); // the call is not defined
 	//}
-
-
-
-
 }
 #undef LST
 
@@ -153,10 +145,6 @@ void CLuaObjectScript::newObject(int objid)
 	//	throw new  std::exception(("Failed to call "+genFN("newObject",os->ID)+" function in lua script.").c_str());
 	//}
 	//lua_settop(is, 0);
-
-
-
-
 	return;
 }
 void CLuaObjectScript::onHeroVisit(int objid, int heroID)
@@ -170,10 +158,6 @@ void CLuaObjectScript::onHeroVisit(int objid, int heroID)
 	//	throw new  std::exception(("Failed to call "+genFN("heroVisit",os->ID)+" function in lua script.").c_str());
 	//}
 	//lua_settop(is, 0);
-
-
-
-
 }
 //std::string CLuaObjectScript::hoverText(int objid)
 //{
@@ -295,30 +279,33 @@ void CVisitableOPH::onNAHeroVisit(int objid, int heroID, bool alreadyVisited)
 		case 61:
 		case 32:
 			{
-				//cb->changePrimSkill(heroID,w,vvv);
-				//std::vector<SComponent*> weko;
-				//weko.push_back(new SComponent(SComponent::primskill,w,vvv)); 
-				//cb->showInfoDialog(cb->getHeroOwner(heroID),VLC->objh->advobtxt[ot],&weko); 
-				//break;
-
-
+				cb->changePrimSkill(heroID,w,vvv);
+				InfoWindow iw;
+				iw.components.push_back(Component(0,w,vvv,0));
+				iw.text << std::pair<ui8,ui32>(11,ot);
+				iw.player = cb->getHeroOwner(heroID);
+				cb->showInfoDialog(&iw);
+				break;
 			}
-		case 100:
+		case 100: //give 1000 exp
 			{
-				//cb->changePrimSkill(heroID,w,vvv);
-				//std::vector<SComponent*> weko;
-				//weko.push_back(new SComponent(SComponent::experience,0,vvv)); 
-				//cb->showInfoDialog(cb->getHeroOwner(heroID),VLC->objh->advobtxt[ot],&weko); 
-				//break;
-
-
+				cb->changePrimSkill(heroID,w,vvv);
+				InfoWindow iw;
+				iw.components.push_back(Component(0,4,vvv,0));
+				iw.player = cb->getHeroOwner(heroID);
+				iw.text << std::pair<ui8,ui32>(11,ot);
+				cb->showInfoDialog(&iw);
+				break;
 			}
 		}
 	}
 	else
 	{
 		ot++;
-		//cb->showInfoDialog(cb->getHeroOwner(heroID),VLC->objh->advobtxt[ot],&std::vector<SComponent*>());
+		InfoWindow iw;
+		iw.player = cb->getHeroOwner(heroID);
+		iw.text << std::pair<ui8,ui32>(11,ot);
+		cb->showInfoDialog(&iw);
 	}
 }
 
@@ -336,46 +323,6 @@ std::vector<int> CVisitableOPH::yourObjects()
 void CVisitableOPW::onNAHeroVisit(int objid, int heroID, bool alreadyVisited)
 {
 	DEFOS;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
 	int mid;
 	switch (os->ID)
 	{
@@ -518,15 +465,6 @@ void CMines::onHeroVisit(int objid, int heroID)
 	iw.player = h->tempOwner;
 	iw.components.push_back(Component(2,os->subID,vv,-1));
 	cb->showInfoDialog(&iw);
-
-
-
-
-
-
-
-
-
 }
 std::vector<int> CMines::yourObjects()
 {
@@ -585,33 +523,42 @@ void CPickable::onHeroVisit(int objid, int heroID)
 		}
 	case 79:
 		{
-			////TODO: handle guards (when battles are finished)
-			//CResourceObjInfo * t2 = static_cast<CResourceObjInfo *>(os->info);
-			//int val;
-			//if(t2->amount)
-			//	val = t2->amount;
-			//else
-			//{
-			//	switch(os->subID)
-			//	{
-			//	case 6:
-			//		val = 500 + (rand()%6)*100;
-			//		break;
-			//	case 0: case 2:
-			//		val = 6 + (rand()%5);
-			//		break;
-			//	default:
-			//		val = 3 + (rand()%3);
-			//		break;
-			//	}
-			//}
-			//if(t2->message.length())
-			//	cb->showInfoDialog(cb->getHeroOwner(heroID),t2->message,&std::vector<SComponent*>());
-			//SComponent ccc(SComponent::resource,os->subID,val);
-			//ccc.description = VLC->objh->advobtxt[113];
-			//boost::algorithm::replace_first(ccc.description,"%s",VLC->objh->restypes[os->subID]);
-			//cb->giveResource(cb->getHeroOwner(heroID),os->subID,val);
-			//cb->showCompInfo(cb->getHeroOwner(heroID),&ccc);
+			//TODO: handle guards (when battles are finished)
+			CResourceObjInfo * t2 = static_cast<CResourceObjInfo *>(os->info);
+			int val;
+			if(t2->amount)
+				val = t2->amount;
+			else
+			{
+				switch(os->subID)
+				{
+				case 6:
+					val = 500 + (rand()%6)*100;
+					break;
+				case 0: case 2:
+					val = 6 + (rand()%5);
+					break;
+				default:
+					val = 3 + (rand()%3);
+					break;
+				}
+			}
+			if(t2->message.length())
+			{
+				InfoWindow iw;
+				iw.player = cb->getHero(heroID)->tempOwner;
+				iw.text << t2->message;
+				cb->showInfoDialog(&iw);
+			}
+
+			cb->giveResource(cb->getHeroOwner(heroID),os->subID,val);
+
+			ShowInInfobox sii;
+			sii.player = cb->getHeroOwner(heroID);
+			sii.c = Component(2,os->subID,val,0);
+			sii.text << std::pair<ui8,ui32>(11,113);
+			sii.text.replacements.push_back(VLC->objh->restypes[os->subID]);
+			cb->showCompInfo(&sii);
 			break;
 		}
 	case 101:
@@ -672,10 +619,6 @@ void CPickable::chosen(int which)
 	//for (int i=0;i<tempStore.size();i++)
 	//	delete tempStore[i];
 	//tempStore.clear();
-
-
-
-
 }
 
 std::vector<int> CPickable::yourObjects() //returns IDs of objects which are handled by script
@@ -797,8 +740,8 @@ void CMonsterS::onHeroVisit(int objid, int heroID)
 	DEFOS;
 	CCreatureSet set;
 	//TODO: zrobic secik w sposob wyrafinowany
-	set.slots[0] = std::pair<ui32,si32>(os->subID,((CCreatureObjInfo*)os->info)->number);
-	cb->startBattle(heroID,&set,os->pos);
+	set.slots[0] = std::pair<ui32,si32>(os->subID,amounts[objid]);
+	cb->startBattle(heroID,set,os->pos);
 }
 std::vector<int> CMonsterS::yourObjects() //returns IDs of objects which are handled by script
 {

+ 33 - 33
CMT.cpp

@@ -1,6 +1,6 @@
 // CMT.cpp : Defines the entry point for the console application.
 //
-#include "stdafx.h"
+#include "stdafx.h"
 #include <cmath>
 #include <string>
 #include <vector>
@@ -10,11 +10,11 @@
 #include "SDL_ttf.h"
 #include "SDL_mixer.h"
 #include "SDL_Extensions.h"
-#include "SDL_framerate.h"
-#include "CGameInfo.h"
+#include "SDL_framerate.h"
+#include "CGameInfo.h"
 #include "mapHandler.h"
 #include "global.h"
-#include "CPreGame.h"
+#include "CPreGame.h"
 #include "CConsoleHandler.h"
 #include "CCursorHandler.h"
 #include "CPathfinder.h"
@@ -42,15 +42,15 @@
 std::string NAME = NAME_VER + std::string(" (client)");
 DLL_EXPORT void initDLL(CLodHandler *b);
 SDL_Surface * screen, * screen2;
-extern SDL_Surface * CSDL_Ext::std32bppSurface;
+extern SDL_Surface * CSDL_Ext::std32bppSurface;
 std::queue<SDL_Event> events;
-boost::mutex eventsM;
-TTF_Font * TNRB16, *TNR, *GEOR13, *GEORXX, *GEORM, *GEOR16;
+boost::mutex eventsM;
+TTF_Font * TNRB16, *TNR, *GEOR13, *GEORXX, *GEORM, *GEOR16;
 #ifndef __GNUC__
 int _tmain(int argc, _TCHAR* argv[])
-#else
+#else
 int main(int argc, _TCHAR* argv[])
-#endif
+#endif
 { 
 	std::cout.flags(ios::unitbuf);
 	std::cout << NAME << std::endl;
@@ -59,7 +59,7 @@ int main(int argc, _TCHAR* argv[])
 	atexit(SDL_Quit);
 	CGameInfo * cgi = CGI = new CGameInfo; //contains all global informations about game (texts, lodHandlers, map handler itp.)
 	//CLuaHandler luatest;
-	//luatest.test(); 
+	//luatest.test(); 
 		//CBIKHandler cb;
 		//cb.open("CSECRET.BIK");
 	std::cout << "Starting... " << std::endl;
@@ -73,7 +73,7 @@ int main(int argc, _TCHAR* argv[])
 			int rmask = 0xff000000;int gmask = 0x00ff0000;int bmask = 0x0000ff00;int amask = 0x000000ff;
 		#else
 			int rmask = 0x000000ff;	int gmask = 0x0000ff00;	int bmask = 0x00ff0000;	int amask = 0xff000000;
-		#endif
+		#endif
 		CSDL_Ext::std32bppSurface = SDL_CreateRGBSurface(SDL_SWSURFACE, 1, 1, 32, rmask, gmask, bmask, amask);
 		THC std::cout<<"\tInitializing minors: "<<pomtime.getDif()<<std::endl;
 		TTF_Init();
@@ -81,30 +81,30 @@ int main(int argc, _TCHAR* argv[])
 		GEOR13 = TTF_OpenFont("Fonts\\georgia.ttf",13);
 		GEOR16 = TTF_OpenFont("Fonts\\georgia.ttf",16);
 		GEORXX = TTF_OpenFont("Fonts\\tnrb.ttf",22);
-		GEORM = TTF_OpenFont("Fonts\\georgia.ttf",10);
+		GEORM = TTF_OpenFont("Fonts\\georgia.ttf",10);
 		atexit(TTF_Quit);
 		THC std::cout<<"\tInitializing fonts: "<<pomtime.getDif()<<std::endl;
 		CMusicHandler * mush = new CMusicHandler;  //initializing audio
 		mush->initMusics();
-		//audio initialized 
+		//audio initialized 
 		cgi->consoleh = new CConsoleHandler;
 		cgi->mush = mush;
-		THC std::cout<<"\tInitializing sound: "<<pomtime.getDif()<<std::endl;
+		THC std::cout<<"\tInitializing sound: "<<pomtime.getDif()<<std::endl;
 		THC std::cout<<"Initializing screen, fonts and sound handling: "<<tmh.getDif()<<std::endl;
 		CDefHandler::Spriteh = cgi->spriteh = new CLodHandler();
 		cgi->spriteh->init("Data\\H3sprite.lod","Sprites");
 		BitmapHandler::bitmaph = cgi->bitmaph = new CLodHandler;
 		cgi->bitmaph->init("Data\\H3bitmap.lod","Data");
 		THC std::cout<<"Loading .lod files: "<<tmh.getDif()<<std::endl;
-		initDLL(cgi->bitmaph);
+		initDLL(cgi->bitmaph);
 		CGI->arth = VLC->arth;
 		CGI->creh = VLC->creh;
 		CGI->townh = VLC->townh;
 		CGI->heroh = VLC->heroh;
 		CGI->objh = VLC->objh;
 		CGI->dobjinfo = VLC->dobjinfo;
-		CGI->buildh = VLC->buildh;
-		THC std::cout<<"Initializing VCMI_Lib: "<<tmh.getDif()<<std::endl;
+		CGI->buildh = VLC->buildh;
+		THC std::cout<<"Initializing VCMI_Lib: "<<tmh.getDif()<<std::endl;
 		//cgi->curh->initCursor();
 		//cgi->curh->showGraphicCursor();
 		pomtime.getDif();
@@ -112,11 +112,11 @@ int main(int argc, _TCHAR* argv[])
 		cgi->curh->initCursor();
 		//cgi->screenh = new CScreenHandler;
 		//cgi->screenh->initScreen();
-		THC std::cout<<"\tScreen handler: "<<pomtime.getDif()<<std::endl;
+		THC std::cout<<"\tScreen handler: "<<pomtime.getDif()<<std::endl;
 		CAbilityHandler * abilh = new CAbilityHandler;
 		abilh->loadAbilities();
 		cgi->abilh = abilh;
-		THC std::cout<<"\tAbility handler: "<<pomtime.getDif()<<std::endl;
+		THC std::cout<<"\tAbility handler: "<<pomtime.getDif()<<std::endl;
 		THC std::cout<<"Preparing first handlers: "<<tmh.getDif()<<std::endl;
 		pomtime.getDif();
 		graphics = new Graphics();
@@ -130,35 +130,35 @@ int main(int argc, _TCHAR* argv[])
 		CMessage::init();
 		cgi->generaltexth = new CGeneralTextHandler;
 		cgi->generaltexth->load();
-		THC std::cout<<"Preparing more handlers: "<<tmh.getDif()<<std::endl;
+		THC std::cout<<"Preparing more handlers: "<<tmh.getDif()<<std::endl;
 		CPreGame * cpg = new CPreGame(); //main menu and submenus
 		THC std::cout<<"Initialization CPreGame (together): "<<tmh.getDif()<<std::endl;
 		THC std::cout<<"Initialization of VCMI (togeter): "<<total.getDif()<<std::endl;
 		cpg->mush = mush;
 		StartInfo *options = new StartInfo(cpg->runLoop());
-///////////////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////////////
 		boost::thread servthr(boost::bind(system,"VCMI_server.exe > server_log.txt")); //runs server executable; 
 												//TODO: will it work on non-windows platforms?
-		THC tmh.getDif();pomtime.getDif();//reset timers
+		THC tmh.getDif();pomtime.getDif();//reset timers
 		CSpellHandler * spellh = new CSpellHandler;
 		spellh->loadSpells();
 		cgi->spellh = spellh;		
-		THC std::cout<<"\tSpell handler: "<<pomtime.getDif()<<std::endl;
+		THC std::cout<<"\tSpell handler: "<<pomtime.getDif()<<std::endl;
 		cgi->pathf = new CPathfinder();
 		THC std::cout<<"\tPathfinder: "<<pomtime.getDif()<<std::endl;
 		cgi->consoleh->runConsole();
 		THC std::cout<<"\tCallback and console: "<<pomtime.getDif()<<std::endl;
-		THC std::cout<<"Handlers initialization (together): "<<tmh.getDif()<<std::endl;
+		THC std::cout<<"Handlers initialization (together): "<<tmh.getDif()<<std::endl;
 		std::ofstream lll("client_log.txt");
 		CConnection *c = new CConnection("localhost","3030",NAME,lll);
-		THC std::cout<<"\tConnecting to the server: "<<tmh.getDif()<<std::endl;
+		THC std::cout<<"\tConnecting to the server: "<<tmh.getDif()<<std::endl;
 		CClient cl(c,options);
-		boost::thread t(boost::bind(&CClient::run,&cl));
+		boost::thread t(boost::bind(&CClient::run,&cl));
 		SDL_Event ev;
 		while(1) //main SDL events loop
 		{
 			SDL_WaitEvent(&ev);
-			if(ev.type==SDL_QUIT) 
+			if(ev.type==SDL_QUIT) 
 			{
 				t.interrupt();
 				exit(0);
@@ -166,24 +166,24 @@ int main(int argc, _TCHAR* argv[])
 			eventsM.lock();
 			events.push(ev);
 			eventsM.unlock();
-		}
+		}
 		///claculating FoWs for minimap
 		/****************************Minimaps' FoW******************************************/
 		//for(int g=0; g<cgi->playerint.size(); ++g)
 		//{
 		//	if(!cgi->playerint[g]->human)
 		//		continue;
-		//	CMinimap & mm = ((CPlayerInterface*)cgi->playerint[g])->adventureInt->minimap;
+		//	CMinimap & mm = ((CPlayerInterface*)cgi->playerint[g])->adventureInt->minimap;
 		//	int mw = mm.map[0]->w, mh = mm.map[0]->h,
-		//		wo = mw/CGI->mh->sizes.x, ho = mh/CGI->mh->sizes.y;
+		//		wo = mw/CGI->mh->sizes.x, ho = mh/CGI->mh->sizes.y;
 		//	for(int d=0; d<cgi->mh->map->twoLevel+1; ++d)
 		//	{
-		//		SDL_Surface * pt = CSDL_Ext::newSurface(mm.pos.w, mm.pos.h, CSDL_Ext::std32bppSurface);
+		//		SDL_Surface * pt = CSDL_Ext::newSurface(mm.pos.w, mm.pos.h, CSDL_Ext::std32bppSurface);
 		//		for (int i=0; i<mw; i++)
 		//		{
 		//			for (int j=0; j<mh; j++)
 		//			{
-		//				int3 pp( ((i*CGI->mh->sizes.x)/mw), ((j*CGI->mh->sizes.y)/mh), d );
+		//				int3 pp( ((i*CGI->mh->sizes.x)/mw), ((j*CGI->mh->sizes.y)/mh), d );
 		//				if ( !((CPlayerInterface*)cgi->playerint[g])->cb->isVisible(pp) )
 		//				{
 		//					CSDL_Ext::SDL_PutPixelWithoutRefresh(pt,i,j,0,0,0);
@@ -192,7 +192,7 @@ int main(int argc, _TCHAR* argv[])
 		//		}
 		//		CSDL_Ext::update(pt);
 		//		mm.FoW.push_back(pt);
-		//	}
+		//	}
 		//}
 	}
 	else

+ 24 - 35
CPlayerInterface.cpp

@@ -33,6 +33,7 @@
 #include "client/Graphics.h"
 #include "map.h"
 #include "lib/NetPacks.h"
+#include "lib/CondSh.h"
 using namespace CSDL_Ext;
 
 extern TTF_Font * GEOR16;
@@ -564,7 +565,10 @@ SComponent::SComponent(Etype Type, int Subtype, int Val)
 
 SComponent::SComponent(const Component &c)
 {
-	init((Etype)c.id,c.subtype,c.val);
+	if(c.id==0 && c.subtype==4)
+		init(experience,0,c.val);
+	else
+		init((Etype)c.id,c.subtype,c.val);
 	switch(c.id)
 	{
 	case resource:
@@ -1142,6 +1146,7 @@ int getDir(int3 src, int3 dst)
 }
 void CPlayerInterface::heroMoved(const HeroMoveDetails & details)
 {
+	boost::unique_lock<boost::mutex> un(*pim);
 	//initializing objects and performing first step of move
 	CGHeroInstance * ho = details.ho; //object representing this hero
 	int3 hp = details.src;
@@ -1487,7 +1492,7 @@ void CPlayerInterface::heroMoved(const HeroMoveDetails & details)
 		//CGI->screenh->updateScreen();
 
 		++LOCPLINT->adventureInt->animValHitCount; //for animations
-		if(LOCPLINT->adventureInt->animValHitCount == 4)
+		if(LOCPLINT->adventureInt->animValHitCount == 8)
 		{
 			LOCPLINT->adventureInt->animValHitCount = 0;
 			++LOCPLINT->adventureInt->anim;
@@ -1946,8 +1951,9 @@ void CPlayerInterface::buildChanged(const CGTownInstance *town, int buildingID,
 	}
 }
 
-void CPlayerInterface::battleStart(CCreatureSet * army1, CCreatureSet * army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, tribool side) //called by engine when battle starts; side=0 - left, side=1 - right
+void CPlayerInterface::battleStart(CCreatureSet *army1, CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side) //called by engine when battle starts; side=0 - left, side=1 - right
 {
+	boost::unique_lock<boost::mutex> un(*pim);
 	curint->deactivate();
 	curint = new CBattleInterface(army1,army2,hero1,hero2);
 	curint->activate();
@@ -1974,45 +1980,27 @@ void CPlayerInterface::actionFinished(BattleAction action)//occurs AFTER every a
 
 BattleAction CPlayerInterface::activeStack(int stackID) //called when it's turn of that stack
 {
-	unsigned char showCount = 0;
-	dynamic_cast<CBattleInterface*>(curint)->stackActivated(stackID);
-	while(!dynamic_cast<CBattleInterface*>(curint)->givenCommand) //while current unit can perform an action
+	CBattleInterface *b = dynamic_cast<CBattleInterface*>(curint);
 	{
-		++showCount;
-		SDL_Event sEvent;
-		while (SDL_PollEvent(&sEvent))  //wait for event...
-		{
-			LOCPLINT->handleEvent(&sEvent);
-		}
-		if(showCount%2==0)
-			for(int i=0;i<objsToBlit.size();i++)
-				objsToBlit[i]->show();
-		//SDL_Flip(screen);
-		CSDL_Ext::update(screen);
+		boost::unique_lock<boost::mutex> un(*pim);
+		b->stackActivated(stackID);
+	}
+	//wait till BattleInterface sets its command
+	boost::unique_lock<boost::mutex> lock(b->givenCommand->mx);
+	while(!b->givenCommand->data)
+		b->givenCommand->cond.wait(lock);
 
-		/*timeHandler th;
-		th.getDif();
-		int tv = th.getDif();
-		for (int i=0;i<((CBattleInterface*)this->curint)->timeinterested.size();i++)
-		{
-			if (timeinterested[i]->toNextTick>=0)
-				timeinterested[i]->toNextTick-=tv;
-			if (timeinterested[i]->toNextTick<0)
-				timeinterested[i]->tick();
-		}*/
+	//tidy up
+	BattleAction ret = *(b->givenCommand->data);
+	delete b->givenCommand->data;
 
-		SDL_Delay(1); //give time for other apps
-		SDL_framerateDelay(mainFPSmng);
-	}
-	BattleAction ret = *(dynamic_cast<CBattleInterface*>(curint)->givenCommand);
-	delete dynamic_cast<CBattleInterface*>(curint)->givenCommand;
-	dynamic_cast<CBattleInterface*>(curint)->givenCommand = NULL;
-	dynamic_cast<CBattleInterface*>(curint)->myTurn = false;
+	//return command
 	return ret;
 }
 
-void CPlayerInterface::battleEnd(CCreatureSet * army1, CCreatureSet * army2, CArmedInstance *hero1, CArmedInstance *hero2, std::vector<int> capturedArtifacts, int expForWinner, bool winner)
+void CPlayerInterface::battleEnd(BattleResult *br)
 {
+	boost::unique_lock<boost::mutex> un(*pim);
 	dynamic_cast<CBattleInterface*>(curint)->deactivate();
 	LOCPLINT->objsToBlit.erase(std::find(LOCPLINT->objsToBlit.begin(),LOCPLINT->objsToBlit.end(),dynamic_cast<IShowable*>(curint)));
 	delete dynamic_cast<CBattleInterface*>(curint);
@@ -2047,6 +2035,7 @@ void CPlayerInterface::battleStackIsShooting(int ID, int dest)
 
 void CPlayerInterface::showComp(SComponent comp)
 {
+	boost::unique_lock<boost::mutex> un(*pim);
 	adventureInt->infoBar.showComp(&comp,4000);
 }
 

+ 2 - 2
CPlayerInterface.h

@@ -333,13 +333,13 @@ public:
 	void garrisonChanged(const CGObjectInstance * obj);
 	void buildChanged(const CGTownInstance *town, int buildingID, int what); //what: 1 - built, 2 - demolished
 	//for battles
-	void battleStart(CCreatureSet * army1, CCreatureSet * army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, boost::logic::tribool side); //called by engine when battle starts; side=0 - left, side=1 - right
+	void battleStart(CCreatureSet *army1, CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side); //called by engine when battle starts; side=0 - left, side=1 - right
 	void battlefieldPrepared(int battlefieldType, std::vector<CObstacle*> obstacles); //called when battlefield is prepared, prior the battle beginning
 	void battleNewRound(int round); //called at the beggining of each turn, round=-1 is the tactic phase, round=0 is the first "normal" turn
 	void actionStarted(BattleAction action);//occurs BEFORE every action taken by any stack or by the hero
 	void actionFinished(BattleAction action);//occurs AFTER every action taken by any stack or by the hero
 	BattleAction activeStack(int stackID); //called when it's turn of that stack
-	void battleEnd(CCreatureSet * army1, CCreatureSet * army2, CArmedInstance *hero1, CArmedInstance *hero2, std::vector<int> capturedArtifacts, int expForWinner, bool winner);
+	void battleEnd(BattleResult *br);
 	void battleStackMoved(int ID, int dest, bool startMoving, bool endMoving);
 	void battleStackAttacking(int ID, int dest);
 	void battleStackIsAttacked(int ID, int dmg, int killed, int IDby, bool byShooting);

+ 6 - 1
CPreGame.cpp

@@ -22,7 +22,12 @@
 extern SDL_Surface * screen;
 extern SDL_Color tytulowy, tlo, zwykly ;
 extern TTF_Font * TNRB16, *TNR, *GEOR13, *GEORXX, *GEORM;
-
+#ifdef min
+#undef min
+#endif
+#ifdef max
+#undef max
+#endif
 SDL_Rect genRect(int hh, int ww, int xx, int yy);
 SDL_Color genRGB(int r, int g, int b, int a=0);
 //void printAt(std::string text, int x, int y, TTF_Font * font, SDL_Color kolor=tytulowy, SDL_Surface * dst=screen);

+ 78 - 0
client/Client.cpp

@@ -16,6 +16,7 @@
 #include "../hch/CGeneralTextHandler.h"
 #include "../hch/CArtHandler.h"
 #include <boost/thread/shared_mutex.hpp>
+#include "../lib/VCMI_Lib.h"
 CSharedCond<std::set<IPack*> > mess(new std::set<IPack*>);
 
 std::string toString(MetaString &ms)
@@ -208,6 +209,25 @@ void CClient::process(int what)
 			playerint[sr.player]->receivedResource(-1,-1);
 			break;
 		}
+	case 105:
+		{
+			SetPrimSkill sps;
+			*serv >> sps;
+			std::cout << "Changing hero primary skill"<<std::endl;
+			gs->apply(&sps);
+			playerint[gs->getHero(sps.id)->tempOwner]->heroPrimarySkillChanged(gs->getHero(sps.id),sps.which,sps.val);
+			break;
+		}
+	case 107:
+		{
+			ShowInInfobox sii;
+			*serv >> sii;
+			SComponent sc(sii.c);
+			sc.description = toString(sii.text);
+			if(playerint[sii.player]->human)
+				static_cast<CPlayerInterface*>(playerint[sii.player])->showComp(sc);
+			break;
+		}
 	case 500:
 		{
 			RemoveHero rh;
@@ -297,6 +317,59 @@ void CClient::process(int what)
 			gs->mx->lock();
 			gs->map->objects[shn.id]->hoverName = toString(shn.name);
 			gs->mx->unlock();
+			break;
+		}
+	case 3000:
+		{
+			BattleStart bs;
+			*serv >> bs; //uses new to allocate memory for battleInfo - must be deleted when battle is over
+			std::cout << "Starting battle!" <<std::endl;
+			gs->apply(&bs);
+
+			if(playerint.find(gs->curB->side1) != playerint.end())
+				playerint[gs->curB->side1]->battleStart(&gs->curB->army1, &gs->curB->army2, gs->curB->tile, gs->getHero(gs->curB->hero1), gs->getHero(gs->curB->hero2), 0);
+			if(playerint.find(gs->curB->side2) != playerint.end())
+				playerint[gs->curB->side2]->battleStart(&gs->curB->army1, &gs->curB->army2, gs->curB->tile, gs->getHero(gs->curB->hero1), gs->getHero(gs->curB->hero2), 1);
+			
+			break;
+		}
+	case 3001:
+		{
+			BattleNextRound bnr;
+			*serv >> bnr;
+			std::cout << "Round nr " << bnr.round <<std::endl;
+			gs->apply(&bnr);
+
+			//tell players about next round
+			if(playerint.find(gs->curB->side1) != playerint.end())
+				playerint[gs->curB->side1]->battleNewRound(bnr.round);
+			if(playerint.find(gs->curB->side2) != playerint.end())
+				playerint[gs->curB->side2]->battleNewRound(bnr.round);
+			break;
+		}
+	case 3002:
+		{
+			BattleSetActiveStack sas;
+			*serv >> sas;
+			std::cout << "Active stack: " << sas.stack <<std::endl;
+			gs->apply(&sas);
+			boost::thread(boost::bind(&CClient::waitForMoveAndSend,this,gs->curB->stacks[sas.stack]->owner));
+			break;
+		}
+	case 3003:
+		{
+			BattleResult br;
+			*serv >> br;
+			std::cout << "Battle ends. Winner: " << (unsigned)br.winner<< ". Type of end: "<< (unsigned)br.result <<std::endl;
+
+			if(playerint.find(gs->curB->side1) != playerint.end())
+				playerint[gs->curB->side1]->battleEnd(&br);
+			if(playerint.find(gs->curB->side2) != playerint.end())
+				playerint[gs->curB->side2]->battleEnd(&br);
+
+			gs->apply(&br);
+
+
 			break;
 		}
 	case 9999:
@@ -310,6 +383,11 @@ void CClient::process(int what)
 		break;
 	}
 }
+void CClient::waitForMoveAndSend(int color)
+{
+	BattleAction ba = playerint[color]->activeStack(gs->curB->activeStack);
+	*serv << ui16(3002) << ba;
+}
 void CClient::run()
 {
 	try

+ 2 - 0
client/Client.h

@@ -38,6 +38,8 @@ class CClient
 	CGameState *gs;
 	std::map<ui8,CGameInterface *> playerint;
 	CConnection *serv;
+
+	void waitForMoveAndSend(int color);
 public:
 	CClient(void);
 	CClient(CConnection *con, StartInfo *si);

+ 6 - 0
client/Graphics.cpp

@@ -15,6 +15,12 @@
 #include "../hch/CLodHandler.h"
 using namespace boost::assign;
 using namespace CSDL_Ext;
+#ifdef min
+#undef min
+#endif
+#ifdef max
+#undef max
+#endif
 Graphics * graphics = NULL;
 SDL_Surface * Graphics::drawPrimarySkill(const CGHeroInstance *curh, SDL_Surface *ret, int from, int to)
 {

+ 1 - 1
hch/CCreatureHandler.h

@@ -21,7 +21,7 @@ public:
 	std::string abilityText; //description of abilities
 	std::string abilityRefs; //references to abilities, in textformat
 	std::string animDefName;
-	int idNumber;
+	ui32 idNumber;
 	int faction; //-1 = neutral
 
 	///animation info

+ 26 - 0
hch/CHeroHandler.cpp

@@ -6,6 +6,32 @@
 #include "../lib/VCMI_Lib.h"
 extern CLodHandler * bitmaph;
 void loadToIt(std::string &dest, std::string &src, int &iter, int mode);
+
+CHeroClass::CHeroClass()
+{
+	skillLimit = 8;
+}
+CHeroClass::~CHeroClass()
+{
+}
+int CHeroClass::chooseSecSkill(std::set<int> possibles) //picks secondary skill out from given possibilities
+{
+	if(possibles.size()==1)
+		return *possibles.begin();
+	int totalProb = 0;
+	for(std::set<int>::iterator i=possibles.begin(); i!=possibles.end(); i++)
+	{
+		totalProb += proSec[*i];
+	}
+	int ran = rand()%totalProb;
+	for(std::set<int>::iterator i=possibles.begin(); i!=possibles.end(); i++)
+	{
+		ran -= proSec[*i];
+		if(ran<0)
+			return *i;
+	}
+}
+
 CHeroHandler::~CHeroHandler()
 {}
 void CHeroHandler::loadPortraits()

+ 5 - 1
hch/CHeroHandler.h

@@ -3,7 +3,7 @@
 #include "../global.h"
 #include <string>
 #include <vector>
-
+#include <set>
 class CHeroClass;
 class CDefHandler;
 class CGameInfo;
@@ -26,6 +26,7 @@ public:
 class DLL_EXPORT CHeroClass
 {
 public:
+	ui32 skillLimit; //how many secondary skills can hero learn
 	std::string name;
 	float aggression;
 	int initialAttack, initialDefence, initialPower, initialKnowledge;
@@ -34,6 +35,9 @@ public:
 	int selectionProbability[9]; //probability of selection in towns
 	std::vector<int> terrCosts; //default costs of going through terrains: dirt, sand, grass, snow, swamp, rough, subterrain, lava, water, rock; -1 means terrain is imapassable
 	CDefHandler * moveAnim; //added group 10: up - left, 11 - left and 12 - left down // 13 - up-left standing; 14 - left standing; 15 - left down standing
+	int chooseSecSkill(std::set<int> possibles); //picks secondary skill out from given possibilities
+	CHeroClass();
+	~CHeroClass();
 };
 
 class DLL_EXPORT CHeroHandler

+ 1 - 1
hch/CObjectHandler.h

@@ -84,7 +84,7 @@ public:
 					//		765
 	bool isStanding;
 	CHero * type;
-	int exp; //experience point
+	ui32 exp; //experience point
 	int level; //current level of hero
 	std::string name; //may be custom
 	std::string biography; //may be custom

+ 13 - 0
lib/BattleAction.h

@@ -0,0 +1,13 @@
+#pragma once
+struct BattleAction
+{
+	ui8 side; //who made this action: false - left, true - right player
+	ui32 stackNumber;//stack ID, -1 left hero, -2 right hero,
+	ui8 actionType; //    0 = Cancel BattleAction   1 = Hero cast a spell   2 = Walk   3 = Defend   4 = Retreat from the battle   5 = Surrender   6 = Walk and Attack   7 = Shoot    8 = Wait   9 = Catapult 10 = Monster casts a spell (i.e. Faerie Dragons)
+	ui16 destinationTile;
+	ui16 additionalInfo; // e.g. spell number if type is 1 || 10
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & side & stackNumber & actionType & destinationTile & additionalInfo;
+	}
+};

+ 13 - 0
lib/CondSh.h

@@ -0,0 +1,13 @@
+#pragma once
+#include <boost/thread.hpp>
+template <typename T> struct CondSh
+{
+	T data;
+	boost::condition_variable cond;
+	boost::mutex mx;
+	CondSh(){};
+	CondSh(T t){data = t;};
+	void set(T t){mx.lock();data=t;mx.unlock();}; //set data
+	void setn(T t){mx.lock();data=t;mx.unlock();cond.notify_all();}; //set data and notify
+	T get(){boost::unique_lock<boost::mutex> lock(mx); return data;};
+};

+ 51 - 7
lib/Connection.h

@@ -6,14 +6,14 @@
 
 #include <boost/type_traits/is_fundamental.hpp>
 #include <boost/type_traits/is_enum.hpp>
+#include <boost/type_traits/is_pointer.hpp> 
+#include  <boost/type_traits/remove_pointer.hpp>
 
 #include <boost/mpl/eval_if.hpp>
 #include <boost/mpl/equal_to.hpp>
 #include <boost/mpl/int.hpp>
 #include <boost/mpl/identity.hpp>
 
-#include <boost/thread.hpp>
-
 const int version = 63;
 class CConnection;
 
@@ -44,6 +44,7 @@ enum SerializationLvl
 {
 	Wrong=0,
 	Primitive,
+	Pointer,
 	Serializable
 };
 
@@ -64,6 +65,10 @@ struct SerializationLevel
 			boost::is_array<T>,
 			mpl::int_<Primitive>,
 		//else
+		typename mpl::eval_if<
+			boost::is_pointer<T>,
+			mpl::int_<Pointer>,
+		//else
 		typename mpl::eval_if<
 			boost::is_enum<T>,
 			mpl::int_<Primitive>,
@@ -72,6 +77,7 @@ struct SerializationLevel
 		>
 		>
 		>
+		>
 		>::type type;
 	static const int value = SerializationLevel::type::value;
 };
@@ -79,7 +85,8 @@ struct SerializationLevel
 template <typename Serializer> class DLL_EXPORT COSer
 {
 public:
-	COSer(){};
+	bool saving;
+	COSer(){saving=true;};
     Serializer * This()
 	{
 		return static_cast<Serializer*>(this);
@@ -100,7 +107,8 @@ public:
 template <typename Serializer> class DLL_EXPORT CISer
 {
 public:
-	CISer(){};
+	bool saving;
+	CISer(){saving = false;};
     Serializer * This()
 	{
 		return static_cast<Serializer*>(this);
@@ -144,6 +152,22 @@ struct LoadPrimitive
 	}
 };
 template<typename Ser,typename T>
+struct SavePointer
+{
+	static void invoke(Ser &s, const T &data)
+	{
+		s.savePointer(data);
+	}
+};
+template<typename Ser,typename T>
+struct LoadPointer
+{
+	static void invoke(Ser &s, T &data)
+	{
+		s.loadPointer(data);
+	}
+};
+template<typename Ser,typename T>
 struct LoadSerializable
 {
 	static void invoke(Ser &s, T &data)
@@ -203,8 +227,20 @@ public:
 	void loadSerializable(T &data)
 	{
 		data.serialize(*static_cast<CISer<CConnection>*>(this),version);
+	}	
+	template <typename T>
+	void savePointer(const T &data)
+	{
+		*this << *data;
+	}
+	template <typename T>
+	void loadPointer(T &data)
+	{
+		std::cout<<"Allocating memory for pointer!"<<std::endl;
+		typedef boost::remove_pointer<T>::type npT;
+		data = new npT;
+		*this >> *data;
 	}
-	
 	template <typename T>
 	void saveSerializable(const std::vector<T> &data)
 	{
@@ -283,11 +319,15 @@ public:
 			typename mpl::eval_if< mpl::equal_to<SerializationLevel<T>,mpl::int_<Primitive> >,
 				mpl::identity<SavePrimitive<CConnection,T> >,
 			//else if
+			typename mpl::eval_if<mpl::equal_to<SerializationLevel<T>,mpl::int_<Pointer> >,
+				mpl::identity<SavePointer<CConnection,T> >,
+			//else if
 			typename mpl::eval_if<mpl::equal_to<SerializationLevel<T>,mpl::int_<Serializable> >,
 				mpl::identity<SaveSerializable<CConnection,T> >,
 			//else
 				mpl::identity<SaveWrong<CConnection,T> >
 			>
+			>
 			>::type typex;
 		typex::invoke(*this, data);
 	}
@@ -300,11 +340,15 @@ public:
 			typename mpl::eval_if< mpl::equal_to<SerializationLevel<T>,mpl::int_<Primitive> >,
 				mpl::identity<LoadPrimitive<CConnection,T> >,
 			//else if
+			typename mpl::eval_if<mpl::equal_to<SerializationLevel<T>,mpl::int_<Pointer> >,
+				mpl::identity<LoadPointer<CConnection,T> >,
+			//else if
 			typename mpl::eval_if<mpl::equal_to<SerializationLevel<T>,mpl::int_<Serializable> >,
 				mpl::identity<LoadSerializable<CConnection,T> >,
 			//else
 				mpl::identity<LoadWrong<CConnection,T> >
 			>
+			>
 			>::type typex;
 		typex::invoke(*this, data);
 	}
@@ -330,9 +374,9 @@ public:
 	~CConnection(void);
 };
 
-template<> 
+template<> DLL_EXPORT 
 void CConnection::saveSerializable<std::string>(const std::string &data);
-template <>
+template <>DLL_EXPORT 
 void CConnection::loadSerializable<std::string>(std::string &data);
 
 

+ 88 - 1
lib/NetPacks.h

@@ -82,6 +82,18 @@ struct SetResources : public CPack<SetResources> //104
 		h & player & res;
 	}
 }; 
+struct SetPrimSkill : public CPack<SetPrimSkill> //105
+{
+	SetPrimSkill(){type = 105;};
+	ui8 abs; //0 - changes by value; 1 - sets to value
+	si32 id;
+	ui16 which, val;
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & abs & id & which & val;
+	}
+}; 
 struct RemoveHero : public CPack<RemoveHero> //500
 {
 	RemoveHero(){type = 500;};
@@ -225,4 +237,79 @@ struct SetHoverName : public CPack<SetHoverName>//1002
 	{
 		h & id & name;
 	}
-};
+};
+struct HeroLevelUp : public CPack<HeroLevelUp>//2000
+{
+	si32 id;
+	ui8 primskill, level;
+	std::set<ui16> skills;
+
+	HeroLevelUp(){type = 2000;};
+	
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & id & primskill & level & skills;
+	}
+};
+struct BattleInfo;
+struct BattleStart : public CPack<BattleStart>//3000
+{
+	BattleInfo * info;
+
+	BattleStart(){type = 3000;};
+	
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & info;
+	}
+};
+struct BattleNextRound : public CPack<BattleNextRound>//3001
+{
+	si32 round;
+
+	BattleNextRound(){type = 3001;};
+	
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & round;
+	}
+};
+struct BattleSetActiveStack : public CPack<BattleSetActiveStack>//3002
+{
+	ui32 stack;
+
+	BattleSetActiveStack(){type = 3002;};
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & stack;
+	}
+};
+struct BattleResult : public CPack<BattleResult>//3003
+{
+	ui8 result; //0 - normal victory; 1 - escape; 2 - surrender
+	ui8 winner; //0 - attacker, 1 - defender, [2 - draw (should be possible?)]
+	std::set<std::pair<ui32,si32> > s1, s2; //first => casualties of attackers - set of pairs crid<>number
+	ui32 exp[2]; //exp for attacker and defender
+	std::set<ui32> artifacts; //artifacts taken from loser to winner
+
+
+
+	BattleResult(){type = 3003;};
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & result & winner & s1 & s2 & exp & artifacts;
+	}
+};
+
+struct ShowInInfobox : public CPack<ShowInInfobox> //107
+{
+	ShowInInfobox(){type = 107;};
+	ui8 player;
+	Component c;
+	MetaString text;
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & player & c & text;
+	}
+}; 

+ 8 - 0
lib/VCMI_lib.vcproj

@@ -319,6 +319,10 @@
 			Filter="h;hpp;hxx;hm;inl;inc;xsd"
 			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
 			>
+			<File
+				RelativePath=".\BattleAction.h"
+				>
+			</File>
 			<File
 				RelativePath="..\hch\CAmbarCendamo.h"
 				>
@@ -355,6 +359,10 @@
 				RelativePath="..\hch\CObjectHandler.h"
 				>
 			</File>
+			<File
+				RelativePath=".\CondSh.h"
+				>
+			</File>
 			<File
 				RelativePath=".\Connection.h"
 				>

+ 330 - 6
server/CGameHandler.cpp

@@ -17,14 +17,36 @@
 #include "../hch/CHeroHandler.h"
 #include "boost/date_time/posix_time/posix_time_types.hpp" //no i/o just types
 #include "../lib/VCMI_Lib.h"
-#include <boost/thread.hpp>
+#include "../lib/CondSh.h"
 #include <boost/thread/xtime.hpp>
 extern bool end2;
-bool makingTurn;
+#include "../lib/BattleAction.h"
+#ifdef min
+#undef min
+#endif
+#ifdef max
+#undef max
+#endif
+#define NEW_ROUND 		BattleNextRound bnr;\
+		bnr.round = gs->curB->round + 1;\
+		sendAndApply(&bnr);
 boost::condition_variable cTurn;
 boost::mutex mTurn;
 boost::shared_mutex gsm;
 
+
+CondSh<bool> battleMadeAction;
+CondSh<BattleResult *> battleResult(NULL);
+
+class CMP_stack
+{
+public:
+	bool operator ()(const CStack* a, const CStack* b)
+	{
+		return (a->creature->speed)>(b->creature->speed);
+	}
+} cmpst ;
+
 double distance(int3 a, int3 b)
 {
 	return std::sqrt( (double)(a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) );
@@ -51,6 +73,268 @@ void CGameHandler::handleCPPObjS(std::map<int,CCPPObjectScript*> * mapa, CCPPObj
 	cppscripts.insert(script);
 }
 
+void CGameHandler::changePrimSkill(int ID, int which, int val, bool abs)
+{
+	SetPrimSkill sps;
+	sps.id = ID;
+	sps.which = which;
+	sps.abs = abs;
+	sps.val = val;
+	sendAndApply(&sps);
+	if(which==4)
+	{
+		CGHeroInstance *hero = static_cast<CGHeroInstance *>(gs->map->objects[ID]);
+		if(hero->exp >= VLC->heroh->reqExp(hero->level+1)) //new level
+		{
+			//hero->level++;
+
+			//give prim skill
+			std::cout << hero->name <<" got level "<<hero->level<<std::endl;
+			int r = rand()%100, pom=0, x=0;
+			int std::pair<int,int>::*g  =  (hero->level>9) ? (&std::pair<int,int>::second) : (&std::pair<int,int>::first);
+			for(;x<PRIMARY_SKILLS;x++)
+			{
+				pom += hero->type->heroClass->primChance[x].*g;
+				if(r<pom)
+					break;
+			}
+			std::cout << "Bohater dostaje umiejetnosc pierwszorzedna " << x << " (wynik losowania "<<r<<")"<<std::endl; 
+			SetPrimSkill sps;
+			sps.id = ID;
+			sps.which = x;
+			sps.abs = false;
+			sps.val = 1;
+			sendAndApply(&sps);
+			hero->primSkills[x]++;
+
+			std::set<ui16> choice;
+
+			std::set<int> basicAndAdv, expert, none;
+			for(int i=0;i<SKILL_QUANTITY;i++) none.insert(i);
+			for(unsigned i=0;i<hero->secSkills.size();i++)
+			{
+				if(hero->secSkills[i].second < 2)
+					basicAndAdv.insert(hero->secSkills[i].first);
+				else
+					expert.insert(hero->secSkills[i].first);
+				none.erase(hero->secSkills[i].first);
+			}
+			if(hero->secSkills.size() < hero->type->heroClass->skillLimit) //free skill slot
+			{
+				choice.insert(hero->type->heroClass->chooseSecSkill(none)); //new skill
+			}
+			else
+			{
+				int s = hero->type->heroClass->chooseSecSkill(basicAndAdv);
+				choice.insert(s);
+				basicAndAdv.erase(s);
+			}
+			if(basicAndAdv.size())
+			{
+				choice.insert(hero->type->heroClass->chooseSecSkill(basicAndAdv)); //new skill
+			}
+			else if(hero->secSkills.size() < hero->type->heroClass->skillLimit)
+			{
+				choice.insert(hero->type->heroClass->chooseSecSkill(none)); //new skill
+			}
+
+		}
+		//TODO - powiadomic interfejsy, sprawdzic czy nie ma awansu itp
+	}
+}
+
+void CGameHandler::startBattle(CCreatureSet army1, CCreatureSet army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2)
+{
+
+	BattleInfo *curB = new BattleInfo;
+	//battle start
+	{
+		battleResult.set(NULL);
+		std::vector<CStack*> & stacks = (curB->stacks);
+
+		curB->army1=army1;
+		curB->army2=army2;
+		curB->hero1=(hero1)?(hero1->id):(-1);
+		curB->hero2=(hero1)?(hero1->id):(-1);
+		curB->side1=(hero1)?(hero1->tempOwner):(-1);
+		curB->side2=(hero2)?(hero2->tempOwner):(-1);
+		curB->round = -2;
+		curB->activeStack = -1;
+		for(std::map<si32,std::pair<ui32,si32> >::iterator i = army1.slots.begin(); i!=army1.slots.end(); i++)
+		{
+			stacks.push_back(new CStack(&VLC->creh->creatures[i->second.first],i->second.second,hero1->tempOwner, stacks.size(), true));
+			stacks[stacks.size()-1]->ID = stacks.size()-1;
+		}
+		//initialization of positions
+		switch(army1.slots.size()) //for attacker
+		{
+		case 0:
+			break;
+		case 1:
+			stacks[0]->position = 86; //6
+			break;
+		case 2:
+			stacks[0]->position = 35; //3
+			stacks[1]->position = 137; //9
+			break;
+		case 3:
+			stacks[0]->position = 35; //3
+			stacks[1]->position = 86; //6
+			stacks[2]->position = 137; //9
+			break;
+		case 4:
+			stacks[0]->position = 1; //1
+			stacks[1]->position = 69; //5
+			stacks[2]->position = 103; //7
+			stacks[3]->position = 171; //11
+			break;
+		case 5:
+			stacks[0]->position = 1; //1
+			stacks[1]->position = 35; //3
+			stacks[2]->position = 86; //6
+			stacks[3]->position = 137; //9
+			stacks[4]->position = 171; //11
+			break;
+		case 6:
+			stacks[0]->position = 1; //1
+			stacks[1]->position = 35; //3
+			stacks[2]->position = 69; //5
+			stacks[3]->position = 103; //7
+			stacks[4]->position = 137; //9
+			stacks[5]->position = 171; //11
+			break;
+		case 7:
+			stacks[0]->position = 1; //1
+			stacks[1]->position = 35; //3
+			stacks[2]->position = 69; //5
+			stacks[3]->position = 86; //6
+			stacks[4]->position = 103; //7
+			stacks[5]->position = 137; //9
+			stacks[6]->position = 171; //11
+			break;
+		default: //fault
+			break;
+		}
+		for(std::map<si32,std::pair<ui32,si32> >::iterator i = army2.slots.begin(); i!=army2.slots.end(); i++)
+			stacks.push_back(new CStack(&VLC->creh->creatures[i->second.first],i->second.second,hero2 ? hero2->tempOwner : 255, stacks.size(), false));
+		switch(army2.slots.size()) //for defender
+		{
+		case 0:
+			break;
+		case 1:
+			stacks[0+army1.slots.size()]->position = 100; //6
+			break;
+		case 2:
+			stacks[0+army1.slots.size()]->position = 49; //3
+			stacks[1+army1.slots.size()]->position = 151; //9
+			break;
+		case 3:
+			stacks[0+army1.slots.size()]->position = 49; //3
+			stacks[1+army1.slots.size()]->position = 100; //6
+			stacks[2+army1.slots.size()]->position = 151; //9
+			break;
+		case 4:
+			stacks[0+army1.slots.size()]->position = 15; //1
+			stacks[1+army1.slots.size()]->position = 83; //5
+			stacks[2+army1.slots.size()]->position = 117; //7
+			stacks[3+army1.slots.size()]->position = 185; //11
+			break;
+		case 5:
+			stacks[0+army1.slots.size()]->position = 15; //1
+			stacks[1+army1.slots.size()]->position = 49; //3
+			stacks[2+army1.slots.size()]->position = 100; //6
+			stacks[3+army1.slots.size()]->position = 151; //9
+			stacks[4+army1.slots.size()]->position = 185; //11
+			break;
+		case 6:
+			stacks[0+army1.slots.size()]->position = 15; //1
+			stacks[1+army1.slots.size()]->position = 49; //3
+			stacks[2+army1.slots.size()]->position = 83; //5
+			stacks[3+army1.slots.size()]->position = 117; //7
+			stacks[4+army1.slots.size()]->position = 151; //9
+			stacks[5+army1.slots.size()]->position = 185; //11
+			break;
+		case 7:
+			stacks[0+army1.slots.size()]->position = 15; //1
+			stacks[1+army1.slots.size()]->position = 49; //3
+			stacks[2+army1.slots.size()]->position = 83; //5
+			stacks[3+army1.slots.size()]->position = 100; //6
+			stacks[4+army1.slots.size()]->position = 117; //7
+			stacks[5+army1.slots.size()]->position = 151; //9
+			stacks[6+army1.slots.size()]->position = 185; //11
+			break;
+		default: //fault
+			break;
+		}
+		for(unsigned g=0; g<stacks.size(); ++g) //shifting positions of two-hex creatures
+		{
+			if((stacks[g]->position%17)==1 && stacks[g]->creature->isDoubleWide())
+			{
+				stacks[g]->position += 1;
+			}
+			else if((stacks[g]->position%17)==15 && stacks[g]->creature->isDoubleWide())
+			{
+				stacks[g]->position -= 1;
+			}
+		}
+		std::stable_sort(stacks.begin(),stacks.end(),cmpst);
+
+		//block engaged players
+		if(hero1->tempOwner<PLAYER_LIMIT)
+			states[hero1->tempOwner] += 10;
+		if(hero2 && hero2->tempOwner<PLAYER_LIMIT)
+			states[hero2->tempOwner] += 10;
+
+		//send info about battles
+		BattleStart bs;
+		bs.info = curB;
+		sendAndApply(&bs);
+
+		NEW_ROUND;
+	}
+
+	//tactic round
+	{
+		NEW_ROUND;
+		if( (hero1 && hero1->getSecSkillLevel(19)>=0) || 
+			( hero2 && hero2->getSecSkillLevel(19)>=0)  )//someone has tactics
+		{
+			//TODO: tactic round (round -1)
+		}
+	}
+
+	//main loop
+	while(!battleResult.get()) //till the end of the battle ;]
+	{
+		NEW_ROUND;
+		std::vector<CStack*> & stacks = (gs->curB->stacks);
+		const BattleInfo & curB = *gs->curB;
+
+		//stack loop
+		for(unsigned i=0;i<stacks.size() && !battleResult.get();i++)
+		{
+			if(!stacks[i]->alive) continue;//indicates imposiibility of making action for this dead unit
+			BattleSetActiveStack sas;
+			sas.stack = i;
+			sendAndApply(&sas);
+
+			//wait for response about battle action
+
+			boost::unique_lock<boost::mutex> lock(battleMadeAction.mx);
+			while(!battleMadeAction.data)
+				battleMadeAction.cond.wait(lock);
+		}
+	}
+
+	//end battle, remove all info, free memory
+	sendAndApply(battleResult.data);
+	delete battleResult.data;
+	//for(int i=0;i<stacks.size();i++)
+	//	delete stacks[i];
+	//delete curB;
+	//curB = NULL;
+}
+
 void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
 {
 	try
@@ -65,7 +349,7 @@ void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
 			case 100: //my interface ended its turn
 				{
 					mTurn.lock();
-					makingTurn = false;
+					states[gs->currentPlayer] = 0;
 					mTurn.unlock();
 					cTurn.notify_all();
 					break;
@@ -290,6 +574,47 @@ void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
 						sr.res[i]-=b->resources[i];
 					sendAndApply(&sr);
 
+					break;
+				}
+			case 3002:
+				{			
+					BattleAction ba;
+					c >> ba;
+					switch(ba.actionType)
+					{
+					case 2: //walk
+						{
+							//battleMoveCreatureStack(ba.stackNumber, ba.destinationTile);
+							break;
+						}
+					case 3: //defend
+						{
+							break;
+						}
+					case 4: //retreat/flee
+						{
+							//TODO: check if fleeing is possible (e.g. enemy may have Shackles of War)
+							//TODO: calculate casualties
+							//TODO: remove retreating hero from map and place it in recrutation list
+							BattleResult *br = new BattleResult;
+							br->result = 1;
+							battleResult.set(br);
+							break;
+						}
+					case 6: //walk or attack
+						{
+							//battleMoveCreatureStack(ba.stackNumber, ba.destinationTile);
+							//battleAttackCreatureStack(ba.stackNumber, ba.destinationTile);
+							break;
+						}
+					case 7: //shoot
+						{
+							//battleShootCreatureStack(ba.stackNumber, ba.destinationTile);
+							break;
+						}
+					}
+					battleMadeAction.setn(true);
+					//sprawdzic czy po tej akcji ktoras strona nie wygrala bitwy
 					break;
 				}
 			default:
@@ -490,12 +815,12 @@ void CGameHandler::run()
 		for(std::map<ui8,PlayerState>::iterator i = gs->players.begin(); i != gs->players.end(); i++)
 		{
 			if((i->second.towns.size()==0 && i->second.heroes.size()==0)  || i->second.color<0 || i->first>=PLAYER_LIMIT  ) continue; //players has not towns/castle - loser
-			makingTurn = true;
+			states[i->first] = 1;
 			gs->currentPlayer = i->first;
 			*connections[i->first] << ui16(100) << i->first;    
 			//wait till turn is done
 			boost::unique_lock<boost::mutex> lock(mTurn);
-			while(makingTurn && !end2)
+			while(states[i->first] && !end2)
 			{
 				boost::posix_time::time_duration p;
 				p= boost::posix_time::seconds(1);
@@ -503,7 +828,6 @@ void CGameHandler::run()
 				time.sec = static_cast<boost::xtime::xtime_sec_t>(p.total_seconds());
 				cTurn.timed_wait(lock,time);
 			}
-
 		}
 	}
 }

+ 8 - 4
server/CGameHandler.h

@@ -10,7 +10,7 @@ struct StartInfo;
 class CCPPObjectScript;
 class CScriptCallback;
 template <typename T> struct CPack;
-
+class CGHeroInstance;
 class CGameHandler
 {
 
@@ -19,10 +19,14 @@ class CGameHandler
 	//std::map<int, std::map<std::string, CObjectScript*> > objscr; //non-C++ scripts 
 
 	CVCMIServer *s;
-	std::map<int,CConnection*> connections;
+	std::map<int,CConnection*> connections; //player color -> connection to clinet with interface of that player
+	std::map<int,int> states; //player color -> player state
 	std::set<CConnection*> conns;
 
 	void handleCPPObjS(std::map<int,CCPPObjectScript*> * mapa, CCPPObjectScript * script);
+	void changePrimSkill(int ID, int which, int val, bool abs=false);
+	void startBattle(CCreatureSet army1, CCreatureSet army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2); //use hero=NULL for no hero
+
 
 public:
 	CGameHandler(void);
@@ -33,9 +37,9 @@ public:
 	{
 		for(std::set<CConnection*>::iterator i=conns.begin(); i!=conns.end();i++)
 		{
-			(*i)->rmx->lock();
+			(*i)->wmx->lock();
 			**i << info->getType() << *info->This();
-			(*i)->rmx->unlock();
+			(*i)->wmx->unlock();
 		}
 	}
 	template <typename T>void sendAndApply(CPack<T> * info)

+ 12 - 39
server/CScriptCallback.cpp

@@ -8,6 +8,8 @@
 #include "../hch/CTownHandler.h"
 #include "../hch/CHeroHandler.h"
 #include "../lib/NetPacks.h"
+#include "../lib/VCMI_Lib.h"
+#include <boost/bind.hpp>
 #include <boost/foreach.hpp>
 #include <boost/thread.hpp>
 CScriptCallback::CScriptCallback(void)
@@ -48,37 +50,9 @@ int3 CScriptCallback::getPos(CGObjectInstance * ob)
 {
 	return ob->pos;
 }
-void CScriptCallback::changePrimSkill(int ID, int which, int val)
-{	
-	//CGHeroInstance * hero = gh->gs->map->getHero(ID,0);
-	//if (which<PRIMARY_SKILLS)
-	//{
-	//	hero->primSkills[which]+=val;
-	//	sv->playerint[hero->getOwner()]->heroPrimarySkillChanged(hero, which, val);
-	//}
-	//else if (which==4)
-	//{
-	//	hero->exp+=val;
-	//	if(hero->exp >= CGI->heroh->reqExp(hero->level+1)) //new level
-	//	{
-	//		hero->level++;
-	//		std::cout << hero->name <<" got level "<<hero->level<<std::endl;
-	//		int r = rand()%100, pom=0, x=0;
-	//		int std::pair<int,int>::*g  =  (hero->level>9) ? (&std::pair<int,int>::second) : (&std::pair<int,int>::first);
-	//		for(;x<PRIMARY_SKILLS;x++)
-	//		{
-	//			pom += hero->type->heroClass->primChance[x].*g;
-	//			if(r<pom)
-	//				break;
-	//		}
-	//		std::cout << "Bohater dostaje umiejetnosc pierwszorzedna " << x << " (wynik losowania "<<r<<")"<<std::endl; 
-	//		hero->primSkills[x]++;
-
-	//		//TODO: dac dwie umiejetnosci 2-rzedne to wyboru
-
-	//	}
-	//	//TODO - powiadomic interfejsy, sprawdzic czy nie ma awansu itp
-	//}
+void CScriptCallback::changePrimSkill(int ID, int which, int val, bool abs)
+{
+	gh->changePrimSkill(ID, which, val, abs);
 }
 
 int CScriptCallback::getHeroOwner(int heroID)
@@ -116,7 +90,7 @@ void CScriptCallback::showSelDialog(int player, std::string text, std::vector<CS
 }
 int CScriptCallback::getSelectedHero()
 {	
-	int ret;
+	//int ret;
 	//if (LOCPLINT->adventureInt->selection.type == HEROI_TYPE)
 	//	ret = ((CGHeroInstance*)(LOCPLINT->adventureInt->selection.selected))->subID;
 	//else 
@@ -135,11 +109,9 @@ void CScriptCallback::giveResource(int player, int which, int val)
 	sr.val = (gh->gs->players[player].resources[which]+val);
 	gh->sendAndApply(&sr);
 }
-void CScriptCallback::showCompInfo(int player, SComponent * comp)
+void CScriptCallback::showCompInfo(ShowInInfobox * comp)
 {
-	//CPlayerInterface * i = dynamic_cast<CPlayerInterface*>(sv->playerint[player]);
-	//if(i)
-	//	i->showComp(*comp);
+	gh->sendToAllClients(comp);
 }
 void CScriptCallback::heroVisitCastle(int obj, int heroID)
 {
@@ -195,11 +167,12 @@ void CScriptCallback::giveHeroArtifact(int artid, int hid, int position) //pos==
 
 void CScriptCallback::startBattle(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2) //use hero=NULL for no hero
 {
-	//gh->gs->battle(army1,army2,tile,hero1,hero2);
+	boost::thread(boost::bind(&CGameHandler::startBattle,gh,*(CCreatureSet *)army1,*(CCreatureSet *)army2,tile,(CGHeroInstance *)hero1,(CGHeroInstance *)hero2));
 }
-void CScriptCallback::startBattle(int heroID, CCreatureSet * army, int3 tile) //for hero<=>neutral army
+void CScriptCallback::startBattle(int heroID, CCreatureSet army, int3 tile) //for hero<=>neutral army
 {
-	//CGHeroInstance* h = gh->gs->map->getHero(heroID,0);
+	CGHeroInstance* h = const_cast<CGHeroInstance*>(getHero(heroID));
+	startBattle(&h->army,&army,tile,h,NULL);
 	//gh->gs->battle(&h->army,army,tile,h,NULL);
 }
 void CLuaCallback::registerFuncs(lua_State * L)

+ 4 - 3
server/CScriptCallback.h

@@ -15,6 +15,7 @@ class CGameState;
 struct lua_State;
 struct MetaString;
 struct InfoWindow;
+struct ShowInInfobox;
 class CScriptCallback
 {
 	CScriptCallback(void);
@@ -35,16 +36,16 @@ public:
 	void setBlockVis(int objid, bool bv);
 	void setOwner(int objid, ui8 owner);
 	void setHoverName(int objid, MetaString * name);
-	void changePrimSkill(int ID, int which, int val);
+	void changePrimSkill(int ID, int which, int val, bool abs=false);
 	void showInfoDialog(InfoWindow *iw);
 	void showSelDialog(int player, std::string text, std::vector<CSelectableComponent*>*components, IChosen * asker);
 	void giveResource(int player, int which, int val);
-	void showCompInfo(int player, SComponent * comp);
+	void showCompInfo(ShowInInfobox * comp);
 	void heroVisitCastle(int obj, int heroID);
 	void stopHeroVisitCastle(int obj, int heroID);
 	void giveHeroArtifact(int artid, int hid, int position); //pos==-1 - first free slot in backpack
 	void startBattle(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2); //use hero=NULL for no hero
-	void startBattle(int heroID, CCreatureSet * army, int3 tile); //for hero<=>neutral army
+	void startBattle(int heroID, CCreatureSet army, int3 tile); //for hero<=>neutral army
 
 	//friends
 	friend class CGameHandler;