Browse Source

Battles: attacking, shooting, killing.

Michał W. Urbańczyk 17 năm trước cách đây
mục cha
commit
15ff21e84c
13 tập tin đã thay đổi với 268 bổ sung232 xóa
  1. 38 11
      CBattleInterface.cpp
  2. 1 1
      CBattleInterface.h
  3. 4 4
      CGameInterface.h
  4. 21 108
      CGameState.cpp
  5. 1 2
      CGameState.h
  6. 16 1
      CMT.cpp
  7. 28 21
      CPlayerInterface.cpp
  8. 3 4
      CPlayerInterface.h
  9. 8 0
      client/Client.cpp
  10. 16 0
      global.h
  11. 42 1
      lib/NetPacks.h
  12. 89 79
      server/CGameHandler.cpp
  13. 1 0
      server/CGameHandler.h

+ 38 - 11
CBattleInterface.cpp

@@ -461,6 +461,8 @@ void CBattleInterface::stackKilled(int ID, int dmg, int killed, int IDby, bool b
 		show();
 		CSDL_Ext::update();
 		SDL_framerateDelay(LOCPLINT->mainFPSmng);
+		if((animCount+1)%4)
+			creAnims[ID]->incrementFrame();
 	}
 
 	printConsoleAttacked(ID, dmg, killed, IDby);
@@ -614,6 +616,8 @@ void CBattleInterface::stackIsAttacked(int ID, int dmg, int killed, int IDby, bo
 		show();
 		CSDL_Ext::update();
 		SDL_framerateDelay(LOCPLINT->mainFPSmng);
+		if((animCount+1)%4)
+			creAnims[ID]->incrementFrame();
 	}
 	creAnims[ID]->setType(2);
 
@@ -680,22 +684,22 @@ void CBattleInterface::stackAttacking(int ID, int dest)
 	switch(BattleInfo::mutualPosition(aStack.position, dest)) //attack direction
 	{
 		case 0:
-			attackingInfo->maxframe = creAnims[ID]->framesInGroup(10);
+			attackingInfo->maxframe = creAnims[ID]->framesInGroup(11);
 			break;
 		case 1:
-			attackingInfo->maxframe = creAnims[ID]->framesInGroup(10);
+			attackingInfo->maxframe = creAnims[ID]->framesInGroup(11);
 			break;
 		case 2:
-			attackingInfo->maxframe = creAnims[ID]->framesInGroup(11);
+			attackingInfo->maxframe = creAnims[ID]->framesInGroup(12);
 			break;
 		case 3:
-			attackingInfo->maxframe = creAnims[ID]->framesInGroup(12);
+			attackingInfo->maxframe = creAnims[ID]->framesInGroup(13);
 			break;
 		case 4:
-			attackingInfo->maxframe = creAnims[ID]->framesInGroup(12);
+			attackingInfo->maxframe = creAnims[ID]->framesInGroup(13);
 			break;
 		case 5:
-			attackingInfo->maxframe = creAnims[ID]->framesInGroup(11);
+			attackingInfo->maxframe = creAnims[ID]->framesInGroup(12);
 			break;
 	}
 }
@@ -705,12 +709,13 @@ void CBattleInterface::newRound(int number)
 	console->addText(CGI->generaltexth->allTexts[412]);
 }
 
-void CBattleInterface::giveCommand(ui8 action, ui16 tile, ui32 stack)
+void CBattleInterface::giveCommand(ui8 action, ui16 tile, ui32 stack, si32 additional)
 {
-	BattleAction * ba = new BattleAction(); //to be deleted by engine
+	BattleAction * ba = new BattleAction(); //is deleted in CPlayerInterface::activeStack()
 	ba->actionType = action;
 	ba->destinationTile = tile;
 	ba->stackNumber = stack;
+	ba->additionalInfo = additional;
 	givenCommand->setn(ba);
 	myTurn = false;
 	activeStack = -1;
@@ -737,7 +742,16 @@ void CBattleInterface::hexLclicked(int whichOne)
 		}
 		else if(LOCPLINT->cb->battleGetStackByID(atCre)->owner != attackingHeroInstance->tempOwner) //attacking
 		{
-			giveCommand(6,whichOne,activeStack);
+			std::vector<int> n = BattleInfo::neighbouringTiles(whichOne);
+			for(int i=0;i<n.size();i++)
+			{
+				//TODO: now we are using first available tile, but in the future we should add possibility of choosing from which tile we want to attack
+				if(vstd::contains(shadedHexes,n[i]))
+				{
+					giveCommand(6,n[i],activeStack,whichOne);
+					return;
+				}
+			}
 		}
 	}
 }
@@ -1151,9 +1165,20 @@ void CBattleHex::mouseMoved(SDL_MouseMotionEvent &sEvent)
 			{
 				if(std::find(myInterface->shadedHexes.begin(),myInterface->shadedHexes.end(),myNumber) == myInterface->shadedHexes.end())
 				{
-					CGI->curh->changeGraphic(1,0);
+					CStack *shere = LOCPLINT->cb->battleGetStackByPos(myNumber);
+					if(shere)
+					{
+						if(shere->owner == LOCPLINT->playerID) //our stack
+							CGI->curh->changeGraphic(1,5);
+						else if(LOCPLINT->cb->battleGetStackByID(myInterface->activeStack)->creature->isShooting()) //we can shoot enemy
+							CGI->curh->changeGraphic(1,3);
+						else //unavailable enemy
+							CGI->curh->changeGraphic(1,0);
+					}
+					else //empty unavailable tile
+						CGI->curh->changeGraphic(1,0);
 				}
-				else
+				else //available tile
 				{
 					if(LOCPLINT->cb->battleGetStackByID(myInterface->activeStack)->creature->isFlying())
 						CGI->curh->changeGraphic(1,2);
@@ -1199,6 +1224,7 @@ void CBattleHex::clickRight(boost::logic::tribool down)
 	if(hovered && strictHovered && stID!=-1)
 	{
 		CStack myst = *LOCPLINT->cb->battleGetStackByID(stID); //stack info
+		if(!myst.alive) return;
 		StackState *pom = NULL;
 		if(down)
 		{
@@ -1210,6 +1236,7 @@ void CBattleHex::clickRight(boost::logic::tribool down)
 				pom->defenseBonus = h->primSkills[1];
 				pom->luck = h->getCurrentLuck();
 				pom->morale = h->getCurrentMorale();
+				pom->currentHealth = myst.firstHPleft;
 			}
 			(new CCreInfoWindow(myst.creature->idNumber,0,pom,boost::function<void()>(),boost::function<void()>()))
 					->activate();

+ 1 - 1
CBattleInterface.h

@@ -112,7 +112,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);
+	void giveCommand(ui8 action, ui16 tile, ui32 stack, si32 additional=-1);
 public:
 	CBattleInterface(CCreatureSet * army1, CCreatureSet * army2, CGHeroInstance *hero1, CGHeroInstance *hero2); //c-tor
 	~CBattleInterface(); //d-tor

+ 4 - 4
CGameInterface.h

@@ -20,6 +20,7 @@ class CGObjectInstance;
 class CCreatureSet;
 class CArmedInstance;
 struct BattleResult;
+struct BattleAttack;
 class CObstacle
 {
 	int ID;
@@ -61,13 +62,12 @@ public:
 	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 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(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;
+	virtual void battleAttack(BattleAttack *ba){};
 	virtual void battleStackKilled(int ID, int dmg, int killed, int IDby, bool byShooting)=0;
 	//
 

+ 21 - 108
CGameState.cpp

@@ -405,6 +405,23 @@ void CGameState::apply(IPack * pack)
 			curB->getStack(br->stack)->position = br->tile;
 			break;
 		}
+	case 3005:
+		{
+			BattleStackAttacked *br = static_cast<BattleStackAttacked*>(pack);
+			CStack * at = curB->getStack(br->stackAttacked);
+			at->amount = br->newAmount;
+			at->firstHPleft = br->newHP;
+			at->alive = !br->killed();
+			break;
+		}
+	case 3006:
+		{
+			BattleAttack *br = static_cast<BattleAttack*>(pack);
+			mx->unlock();
+			apply(&br->bsa);
+			mx->lock();
+			break;
+		}
 	//case 1002://set hover name
 	//	{
 	//		SetHoverName * shn = static_cast<SetHoverName*>(pack);
@@ -921,65 +938,7 @@ void CGameState::init(StartInfo * si, Mapa * map, int Seed)
 }
 
 bool CGameState::battleShootCreatureStack(int ID, int dest)
-{/*
-	CStack * curStack = NULL;
-	for(int y=0; y<curB->stacks.size(); ++y)
-	{
-		if(curB->stacks[y]->ID == ID)
-		{
-			curStack = curB->stacks[y];
-			break;
-		}
-	}
-	if(!curStack)
-		return false;
-	int IDOfStackAtEnd = battleGetStack(dest);
-	int numberOfStackAtEnd = -1;
-	for(int v=0; v<curB->stacks.size(); ++v)
-	{
-		if(curB->stacks[v]->ID == IDOfStackAtEnd)
-		{
-			numberOfStackAtEnd = v;
-			break;
-		}
-	}
-
-	if(IDOfStackAtEnd == -1 || curB->stacks[numberOfStackAtEnd]->owner == curStack->owner || !curB->stacks[numberOfStackAtEnd]->alive)
-		return false;
-
-	LOCPLINT->battleStackIsShooting(ID, dest);
-
-	//counting dealt damage
-	int finalDmg = calculateDmg(curStack, curB->stacks[numberOfStackAtEnd]);
-
-	//applying damages
-	int cresKilled = finalDmg / curB->stacks[ID]->creature->hitPoints;
-	int damageFirst = finalDmg % curB->stacks[ID]->creature->hitPoints;
-
-	if( curB->stacks[numberOfStackAtEnd]->firstHPleft <= damageFirst )
-	{
-		curB->stacks[numberOfStackAtEnd]->amount -= 1;
-		curB->stacks[numberOfStackAtEnd]->firstHPleft += curB->stacks[numberOfStackAtEnd]->creature->hitPoints - damageFirst;
-	}
-	else
-	{
-		curB->stacks[numberOfStackAtEnd]->firstHPleft -= damageFirst;
-	}
-
-	int cresInstackBefore = curB->stacks[numberOfStackAtEnd]->amount; 
-	curB->stacks[numberOfStackAtEnd]->amount -= cresKilled;
-	if(curB->stacks[numberOfStackAtEnd]->amount<=0) //stack killed
-	{
-		curB->stacks[numberOfStackAtEnd]->amount = 0;
-		LOCPLINT->battleStackKilled(curB->stacks[numberOfStackAtEnd]->ID, finalDmg, std::min(cresKilled, cresInstackBefore), ID, true);
-		curB->stacks[numberOfStackAtEnd]->alive = false;
-	}
-	else
-	{
-		LOCPLINT->battleStackIsAttacked(curB->stacks[numberOfStackAtEnd]->ID, finalDmg, std::min(cresKilled, cresInstackBefore), ID, true);
-	}
-
-	//damage applied*/
+{
 	return true;
 }
 
@@ -990,7 +949,7 @@ int CGameState::battleGetStack(int pos)
 		if(curB->stacks[g]->position == pos ||
 				( curB->stacks[g]->creature->isDoubleWide() &&
 					( (curB->stacks[g]->attackerOwned && curB->stacks[g]->position-1 == pos) ||
-						(!curB->stacks[g]->attackerOwned && curB->stacks[g]->position+1 == pos)
+						(!curB->stacks[g]->attackerOwned && curB->stacks[g]->position-1 == pos)
 					)
 				)
 			)
@@ -999,7 +958,7 @@ int CGameState::battleGetStack(int pos)
 	return -1;
 }
 
-int CGameState::calculateDmg(const CStack* attacker, const CStack* defender)
+int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender)
 {
 	int attackDefenseBonus = attacker->creature->attack - defender->creature->defence;
 	int damageBase = 0;
@@ -1037,50 +996,4 @@ int CGameState::calculateDmg(const CStack* attacker, const CStack* defender)
 	}
 
 	return (float)damageBase * (float)attacker->amount * dmgBonusMultiplier;
-}
-
-std::vector<int> CGameState::battleGetRange(int ID)
-{/*
-	std::vector<int> additionals;
-
-	//adding enemies' positions
-	for(int c=0; c<curB->stacks.size(); ++c)
-	{
-		if(curB->stacks[c]->alive && curB->stacks[c]->owner != owner)
-		{
-			for(int g=0; g<ret.size(); ++g)
-			{
-				if(CBattleHex::mutualPosition(ret[g], curB->stacks[c]->position) != -1)
-				{
-					additionals.push_back(curB->stacks[c]->position);
-				}
-				if(curB->stacks[c]->creature->isDoubleWide() && curB->stacks[c]->attackerOwned && CBattleHex::mutualPosition(ret[g], curB->stacks[c]->position-1) != -1)
-				{
-					additionals.push_back(curB->stacks[c]->position-1);
-				}
-				if(curB->stacks[c]->creature->isDoubleWide() && !curB->stacks[c]->attackerOwned && CBattleHex::mutualPosition(ret[g], curB->stacks[c]->position+1) != -1)
-				{
-					additionals.push_back(curB->stacks[c]->position+1);
-				}
-			}
-		}
-	}
-	for(int g=0; g<additionals.size(); ++g)
-	{
-		ret.push_back(additionals[g]);
-	}
-
-	std::sort(ret.begin(), ret.end());
-	std::vector<int>::iterator nend = std::unique(ret.begin(), ret.end());
-
-	std::vector<int> ret2;
-
-	for(std::vector<int>::iterator it = ret.begin(); it != nend; ++it)
-	{
-		ret2.push_back(*it);
-	}
-
-	return ret2;*/
-	return std::vector<int>();
-}
-
+}

+ 1 - 2
CGameState.h

@@ -73,6 +73,7 @@ struct DLL_EXPORT BattleInfo
 
 	static signed char mutualPosition(int hex1, int hex2); //returns info about mutual position of given hexes (-1 - they're distant, 0 - left top, 1 - right top, 2 - right, 3 - right bottom, 4 - left bottom, 5 - left)
 	static std::vector<int> neighbouringTiles(int hex);
+	static int calculateDmg(const CStack* attacker, const CStack* defender); //TODO: add additional conditions and require necessary data
 };
 
 class DLL_EXPORT CStack
@@ -138,8 +139,6 @@ private:
 	bool battleAttackCreatureStack(int ID, int dest);
 	bool battleShootCreatureStack(int ID, int dest);
 	int battleGetStack(int pos); //returns ID of stack at given tile
-	static int calculateDmg(const CStack* attacker, const CStack* defender); //TODO: add additional conditions and require necessary data
-	std::vector<int> battleGetRange(int ID); //called by std::vector<int> CCallback::battleGetAvailableHexes(int ID);
 public:
 	int getDate(int mode=0) const; //mode=0 - total days in game, mode=1 - day of week, mode=2 - current week, mode=3 - current month
 	

+ 16 - 1
CMT.cpp

@@ -150,7 +150,22 @@ int main(int argc, _TCHAR* argv[])
 		THC std::cout<<"\tCallback and console: "<<pomtime.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);
+
+		CConnection *c=NULL;
+		while(!c)
+		{
+			try
+			{
+				std::cout << "Establishing connection...\t";
+				c = new CConnection("localhost","3030",NAME,lll);
+				std::cout << "done!" <<std::endl;
+			}
+			catch(...)
+			{
+				std::cout << "\nCannot establish connection! Retrying within 3 seconds" <<std::endl;
+				SDL_Delay(3000);
+			}
+		}
 		THC std::cout<<"\tConnecting to the server: "<<tmh.getDif()<<std::endl;
 		CClient cl(c,options);
 		boost::thread t(boost::bind(&CClient::run,&cl));

+ 28 - 21
CPlayerInterface.cpp

@@ -1076,10 +1076,10 @@ void CPlayerInterface::yourTurn()
 		}
 		for(int i=0;i<objsToBlit.size();i++)
 			objsToBlit[i]->show();
-		pim->unlock();
 		CGI->curh->draw1();
 		CSDL_Ext::update(screen);
 		CGI->curh->draw2();
+		pim->unlock();
 		SDL_framerateDelay(mainFPSmng);
 	}
 	adventureInt->hide();
@@ -1969,14 +1969,14 @@ void CPlayerInterface::battleNewRound(int round) //called at the beggining of ea
 	dynamic_cast<CBattleInterface*>(curint)->newRound(round);
 }
 
-void CPlayerInterface::actionStarted(BattleAction action)//occurs BEFORE every action taken by any stack or by the hero
-{
-}
-
-void CPlayerInterface::actionFinished(BattleAction action)//occurs AFTER every action taken by any stack or by the hero
-{
-	//dynamic_cast<CBattleInterface*>(curint)->givenCommand = -1;
-}
+//void CPlayerInterface::actionStarted(BattleAction action)//occurs BEFORE every action taken by any stack or by the hero
+//{
+//}
+//
+//void CPlayerInterface::actionFinished(BattleAction action)//occurs AFTER every action taken by any stack or by the hero
+//{
+//	//dynamic_cast<CBattleInterface*>(curint)->givenCommand = -1;
+//}
 
 BattleAction CPlayerInterface::activeStack(int stackID) //called when it's turn of that stack
 {
@@ -2014,17 +2014,18 @@ void CPlayerInterface::battleStackMoved(int ID, int dest, bool startMoving, bool
 	boost::unique_lock<boost::mutex> un(*pim);
 	dynamic_cast<CBattleInterface*>(curint)->stackMoved(ID, dest, startMoving, endMoving);
 }
-
-void CPlayerInterface::battleStackAttacking(int ID, int dest)
-{
-	dynamic_cast<CBattleInterface*>(curint)->stackAttacking(ID, dest);
-}
-
-void CPlayerInterface::battleStackIsAttacked(int ID, int dmg, int killed, int IDby, bool byShooting)
+void CPlayerInterface::battleAttack(BattleAttack *ba)
 {
-	dynamic_cast<CBattleInterface*>(curint)->stackIsAttacked(ID, dmg, killed, IDby, byShooting);
+	boost::unique_lock<boost::mutex> un(*pim);
+	if(ba->shot())
+		dynamic_cast<CBattleInterface*>(curint)->stackIsShooting(ba->stackAttacking,cb->battleGetPos(ba->bsa.stackAttacked));
+	else
+		dynamic_cast<CBattleInterface*>(curint)->stackAttacking( ba->stackAttacking, cb->battleGetPos(ba->bsa.stackAttacked) );
+	if(ba->killed())
+		dynamic_cast<CBattleInterface*>(curint)->stackKilled(ba->bsa.stackAttacked, ba->bsa.damageAmount, ba->bsa.killedAmount, ba->stackAttacking, ba->shot());
+	else
+		dynamic_cast<CBattleInterface*>(curint)->stackIsAttacked(ba->bsa.stackAttacked, ba->bsa.damageAmount, ba->bsa.killedAmount, ba->stackAttacking, ba->shot());
 }
-
 void CPlayerInterface::battleStackKilled(int ID, int dmg, int killed, int IDby, bool byShooting)
 {
 	dynamic_cast<CBattleInterface*>(curint)->stackKilled(ID, dmg, killed, IDby, byShooting);
@@ -2970,7 +2971,8 @@ CCreInfoWindow::CCreInfoWindow
 		int hlp = log10f(c->defence)+2;
 		pom[hlp-1] = ' '; pom[hlp] = '(';
 		SDL_itoa(c->defence+State->defenseBonus,pom+hlp+1,10);
-		pom[hlp+2+(int)log10f(State->defenseBonus+c->defence)] = ')';
+		hlp += 2+(int)log10f(State->defenseBonus+c->defence);
+		pom[hlp] = ')'; pom[hlp+1] = '\0';
 	}
 	printToWR(pom,276,80,GEOR13,zwykly,bitmap);
 
@@ -2995,8 +2997,13 @@ CCreInfoWindow::CCreInfoWindow
 	SDL_itoa(c->hitPoints,pom,10);
 	printToWR(pom,276,137,GEOR13,zwykly,bitmap);
 
-	//remaining health - TODO: show during the battles
-	//printAt(CGI->preth->zelp[440].first,155,143,GEOR13,zwykly,bitmap);
+	//remaining health
+	if(State)
+	{
+		printAt(CGI->preth->zelp[440].first,155,143,GEOR13,zwykly,bitmap);
+		SDL_itoa(State->currentHealth,pom,10);
+		printToWR(pom,276,156,GEOR13,zwykly,bitmap);
+	}
 
 	//speed
 	printAt(CGI->preth->zelp[441].first,155,162,GEOR13,zwykly,bitmap);

+ 3 - 4
CPlayerInterface.h

@@ -336,13 +336,12 @@ public:
 	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
+	//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(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);
+	void battleAttack(BattleAttack *ba);
 	void battleStackKilled(int ID, int dmg, int killed, int IDby, bool byShooting);
 	void battleStackIsShooting(int ID, int dest); //called when stack with id ID is shooting to hex dest
 

+ 8 - 0
client/Client.cpp

@@ -394,6 +394,14 @@ void CClient::process(int what)
 			gs->apply(&br);
 			break;
 		}
+	case 3006:
+		{
+			BattleAttack ba;
+			*serv >> ba;
+			gs->apply(&ba);
+			LOCPLINT->battleAttack(&ba);
+			break;
+		}
 	case 9999:
 		break;
 	default:

+ 16 - 0
global.h

@@ -89,4 +89,20 @@ const int MAX_BUILDING_PER_TURN = 1;
 		delete e;						\
 	}
 
+
+namespace vstd
+{
+	template <typename Container, typename Item>
+	bool contains(const Container & c, const Item &i)
+	{
+		return std::find(c.begin(),c.end(),i) != c.end();
+	}
+	template <typename Container, typename Item>
+	typename Container::iterator find(const Container & c, const Item &i)
+	{
+		return std::find(c.begin(),c.end(),i);
+	}
+
+}
+
 #endif //GLOBAL_H

+ 42 - 1
lib/NetPacks.h

@@ -304,7 +304,7 @@ struct BattleResult : public CPack<BattleResult>//3003
 struct BattleStackMoved : public CPack<BattleStackMoved>//3004
 {
 	ui32 stack, tile;
-	ui8 flags;
+	ui8 flags; // 1 - start moving, 2 - end moving
 
 
 
@@ -323,6 +323,47 @@ struct BattleStackMoved : public CPack<BattleStackMoved>//3004
 	}
 };
 
+struct BattleStackAttacked : public CPack<BattleStackAttacked>//3005
+{
+	ui32 stackAttacked;
+	ui32 newAmount, newHP, killedAmount, damageAmount;
+	ui8 flags; //1 - is stack killed
+
+
+	BattleStackAttacked(){flags = 0; type = 3005;};
+	bool killed() //if target stack was killed
+	{
+		return flags & 1;
+	}
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & stackAttacked & newAmount & newHP & flags & killedAmount & damageAmount;
+	}
+};
+
+struct BattleAttack : public CPack<BattleAttack>//3006
+{
+	BattleStackAttacked bsa;
+	ui32 stackAttacking;
+	ui8 flags;
+
+
+
+	BattleAttack(){flags = 0; type = 3006;};
+	bool shot()//distance attack - decrease number of shots
+	{
+		return flags & 1;
+	}
+	bool killed() //if target stack was killed
+	{
+		return bsa.killed();
+	}
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & bsa & stackAttacking & flags;
+	}
+};
+
 struct ShowInInfobox : public CPack<ShowInInfobox> //107
 {
 	ShowInInfobox(){type = 107;};

+ 89 - 79
server/CGameHandler.cpp

@@ -18,7 +18,9 @@
 #include "boost/date_time/posix_time/posix_time_types.hpp" //no i/o just types
 #include "../lib/VCMI_Lib.h"
 #include "../lib/CondSh.h"
+#ifndef _MSC_VER
 #include <boost/thread/xtime.hpp>
+#endif
 extern bool end2;
 #include "../lib/BattleAction.h"
 #ifdef min
@@ -335,7 +337,36 @@ void CGameHandler::startBattle(CCreatureSet army1, CCreatureSet army2, int3 tile
 	//delete curB;
 	//curB = NULL;
 }
+void prepareAttack(BattleAttack &bat, CStack *att, CStack *def)
+{
+	bat.stackAttacking = att->ID;
+	bat.bsa.stackAttacked = def->ID;
+	bat.bsa.damageAmount = BattleInfo::calculateDmg(att, def);//counting dealt damage
+
+	//applying damages
+	bat.bsa.killedAmount = bat.bsa.damageAmount / def->creature->hitPoints;
+	unsigned damageFirst = bat.bsa.damageAmount % def->creature->hitPoints;
+
+	if( def->firstHPleft <= damageFirst )
+	{
+		bat.bsa.killedAmount++;
+		bat.bsa.newHP = def->firstHPleft + def->creature->hitPoints - damageFirst;
+	}
+	else
+	{
+		bat.bsa.newHP = def->firstHPleft - damageFirst;
+	}
 
+	if(def->amount <= bat.bsa.killedAmount) //stack killed
+	{
+		bat.bsa.newAmount = 0;
+		bat.bsa.flags |= 1;
+	}
+	else
+	{
+		bat.bsa.newAmount = def->amount - bat.bsa.killedAmount;
+	}
+}
 void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
 {
 	try
@@ -585,80 +616,7 @@ void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
 					{
 					case 2: //walk
 						{
-							CStack *curStack = gs->curB->getStack(ba.stackNumber),
-								*stackAtEnd = gs->curB->getStackT(ba.destinationTile);
-
-							//initing necessary tables
-							bool accessibility[187];
-							if(curStack->creature->isDoubleWide())
-							{
-								gs->curB->getAccessibilityMapForTwoHex(accessibility,curStack->attackerOwned,curStack->ID);
-								//accessibility[curStack->attackerOwned ? curStack->position+1 : curStack->position-1]=true;//OUR second tile is for US accessible
-							}
-							else 
-								gs->curB->getAccessibilityMap(accessibility,curStack->ID);
-							//accessibility[curStack->position] = true; //OUR tile is for US accessible
-
-							//if(!stackAtEnd && !accessibility[dest])
-							//	return false;
-
-							//if(dists[dest] > curStack->creature->speed && !(stackAtEnd && dists[dest] == curStack->creature->speed+1)) //we can attack a stack if we can go to adjacent hex
-							//	return false;
-
-							std::vector<int> path = gs->curB->getPath(curStack->position,ba.destinationTile,accessibility);
-							int tilesToMove = std::max((int)path.size()-curStack->creature->speed, 0);
-							for(int v=path.size()-1; v>=tilesToMove; --v)
-							{
-								if(v!=0 || !stackAtEnd) //it's not the last step or the last tile is free
-								{
-									//inform clients about move
-									BattleStackMoved sm;
-									sm.stack = curStack->ID;
-									sm.tile = path[v];
-									if(v==path.size()-1)//move start - set flag
-										sm.flags |= 1;
-									if(v==0 || (stackAtEnd && v==1)) //move end - set flag
-										sm.flags |= 2;
-									sendAndApply(&sm);
-								}
-								else //if it's last step and we should attack unit at the end
-								{
-									//LOCPLINT->battleStackAttacking(ID, path[v]);
-									////counting dealt damage
-									//int finalDmg = calculateDmg(curStack, curB->stacks[numberOfStackAtEnd]);
-
-									////applying damages
-									//int cresKilled = finalDmg / curB->stacks[numberOfStackAtEnd]->creature->hitPoints;
-									//int damageFirst = finalDmg % curB->stacks[numberOfStackAtEnd]->creature->hitPoints;
-
-									//if( curB->stacks[numberOfStackAtEnd]->firstHPleft <= damageFirst )
-									//{
-									//	curB->stacks[numberOfStackAtEnd]->amount -= 1;
-									//	curB->stacks[numberOfStackAtEnd]->firstHPleft += curB->stacks[numberOfStackAtEnd]->creature->hitPoints - damageFirst;
-									//}
-									//else
-									//{
-									//	curB->stacks[numberOfStackAtEnd]->firstHPleft -= damageFirst;
-									//}
-
-									//int cresInstackBefore = curB->stacks[numberOfStackAtEnd]->amount; 
-									//curB->stacks[numberOfStackAtEnd]->amount -= cresKilled;
-									//if(curB->stacks[numberOfStackAtEnd]->amount<=0) //stack killed
-									//{
-									//	curB->stacks[numberOfStackAtEnd]->amount = 0;
-									//	LOCPLINT->battleStackKilled(curB->stacks[numberOfStackAtEnd]->ID, finalDmg, std::min(cresKilled, cresInstackBefore) , ID, false);
-									//	curB->stacks[numberOfStackAtEnd]->alive = false;
-									//}
-									//else
-									//{
-									//	LOCPLINT->battleStackIsAttacked(curB->stacks[numberOfStackAtEnd]->ID, finalDmg, std::min(cresKilled, cresInstackBefore), ID, false);
-									//}
-
-									//damage applied
-								}
-							}
-							//curB->stackActionPerformed = true;
-							//LOCPLINT->actionFinished(BattleAction());
+							moveStack(ba.stackNumber,ba.destinationTile);
 							break;
 						}
 					case 3: //defend
@@ -677,13 +635,29 @@ void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
 						}
 					case 6: //walk or attack
 						{
-							//battleMoveCreatureStack(ba.stackNumber, ba.destinationTile);
-							//battleAttackCreatureStack(ba.stackNumber, ba.destinationTile);
+							moveStack(ba.stackNumber,ba.destinationTile);
+							CStack *curStack = gs->curB->getStack(ba.stackNumber),
+								*stackAtEnd = gs->curB->getStackT(ba.additionalInfo);
+
+							if((curStack->position != ba.destinationTile) || //we wasn't able to reach destination tile
+								(BattleInfo::mutualPosition(ba.destinationTile,ba.additionalInfo)<0) ) //destination tile is not neighbouring with enemy stack
+								return;
+
+							BattleAttack bat;
+							prepareAttack(bat,curStack,stackAtEnd);
+							sendAndApply(&bat);
 							break;
 						}
 					case 7: //shoot
 						{
-							//battleShootCreatureStack(ba.stackNumber, ba.destinationTile);
+							CStack *curStack = gs->curB->getStack(ba.stackNumber),
+								*destStack= gs->curB->getStackT(ba.destinationTile);
+
+							BattleAttack bat;
+							prepareAttack(bat,curStack,destStack);
+							bat.flags |= 1;
+
+							sendAndApply(&bat);
 							break;
 						}
 					}
@@ -717,6 +691,39 @@ void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
 		end2 = true;
 	}
 }
+void CGameHandler::moveStack(int stack, int dest)
+{							
+	CStack *curStack = gs->curB->getStack(stack),
+		*stackAtEnd = gs->curB->getStackT(dest);
+
+	//initing necessary tables
+	bool accessibility[187];
+	if(curStack->creature->isDoubleWide())
+		gs->curB->getAccessibilityMapForTwoHex(accessibility,curStack->attackerOwned,curStack->ID);
+	else 
+		gs->curB->getAccessibilityMap(accessibility,curStack->ID);
+
+	if((stackAtEnd && stackAtEnd->alive) || !accessibility[dest])
+		return;
+
+	//if(dists[dest] > curStack->creature->speed && !(stackAtEnd && dists[dest] == curStack->creature->speed+1)) //we can attack a stack if we can go to adjacent hex
+	//	return false;
+
+	std::vector<int> path = gs->curB->getPath(curStack->position,dest,accessibility);
+	int tilesToMove = std::max((int)path.size()-curStack->creature->speed, 0);
+	for(int v=path.size()-1; v>=tilesToMove; --v)
+	{
+		//inform clients about move
+		BattleStackMoved sm;
+		sm.stack = curStack->ID;
+		sm.tile = path[v];
+		if(v==path.size()-1) //move start - set flag
+			sm.flags |= 1;
+		if(v==0) //move end - set flag
+			sm.flags |= 2;
+		sendAndApply(&sm);
+	}
+}
 CGameHandler::CGameHandler(void)
 {
 	gs = NULL;
@@ -898,10 +905,13 @@ void CGameHandler::run()
 			{
 				boost::posix_time::time_duration p;
 				p= boost::posix_time::seconds(1);
+#ifdef _MSC_VER
+				cTurn.timed_wait(lock,p); 
+#else
 				boost::xtime time={0,0};
 				time.sec = static_cast<boost::xtime::xtime_sec_t>(p.total_seconds());
-				cTurn.wait(lock);
-				//cTurn.timed_wait(lock,time);
+				cTurn.timed_wait(lock,time);
+#endif
 			}
 		}
 	}

+ 1 - 0
server/CGameHandler.h

@@ -28,6 +28,7 @@ class CGameHandler
 
 	void handleCPPObjS(std::map<int,CCPPObjectScript*> * mapa, CCPPObjectScript * script);
 	void changePrimSkill(int ID, int which, int val, bool abs=false);
+	void moveStack(int stack, int dest);
 	void startBattle(CCreatureSet army1, CCreatureSet army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2); //use hero=NULL for no hero