Browse Source

Rewrote hero moving code. Seems to be working.

Michał W. Urbańczyk 17 years ago
parent
commit
3247a9a4dd
15 changed files with 455 additions and 234 deletions
  1. 144 195
      CCallback.cpp
  2. 5 1
      CCallback.h
  3. 0 2
      CGameInfo.h
  4. 14 0
      CGameState.cpp
  5. 2 5
      CPlayerInterface.cpp
  6. 48 8
      client/Client.cpp
  7. 29 1
      client/Client.h
  8. 2 2
      client/Graphics.cpp
  9. 1 1
      hch/CObjectHandler.h
  10. 12 8
      int3.h
  11. 31 2
      lib/NetPacks.h
  12. 32 0
      map.cpp
  13. 5 0
      map.h
  14. 2 2
      mapHandler.cpp
  15. 128 7
      server/CGameHandler.cpp

+ 144 - 195
CCallback.cpp

@@ -17,8 +17,16 @@
 #include "lib/Connection.h"
 #include "client/Client.h"
 #include <boost/thread.hpp>
+#include <boost/foreach.hpp>
+#include "lib/NetPacks.h"
 //LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);
+extern CSharedCond<std::set<IPack*> > mess;
 
+HeroMoveDetails::HeroMoveDetails(int3 Src, int3 Dst, CGHeroInstance*Ho)
+	:src(Src),dst(Dst),ho(Ho)
+{
+	owner = ho->getOwner();
+};
 bool CCallback::moveHero(int ID, CPath * path, int idtype, int pathType)
 {
 	CGHeroInstance * hero = NULL;
@@ -69,120 +77,123 @@ bool CCallback::moveHero(int ID, CPath * path, int idtype, int pathType)
 		return false;
 	for(int i=ourPath->nodes.size()-1; i>0; i--)
 	{
-		int3 stpos, endpos;
-		stpos = int3(ourPath->nodes[i].coord.x, ourPath->nodes[i].coord.y, hero->pos.z);
-		endpos = int3(ourPath->nodes[i-1].coord.x, ourPath->nodes[i-1].coord.y, hero->pos.z);
-		HeroMoveDetails curd;
-		curd.src = stpos;
-		curd.dst = endpos;
-		curd.ho = hero;
-		curd.owner = hero->getOwner();
-		/*if(player!=-1)
-		{
-			hero->pos = endpos;
-		}*/
-		if(hero->movement >= (ourPath->nodes.size()>=2 ?  (*(ourPath->nodes.end()-2)).dist : 0) - ourPath->nodes[i].dist  || player==-1)
-		{ //performing move
-			hero->movement -= (ourPath->nodes.size()>=2 ?  (*(ourPath->nodes.end()-2)).dist : 0) - ourPath->nodes[i].dist;
-			ourPath->nodes.pop_back();
-			
-			std::vector< CGObjectInstance * > vis = CGI->mh->getVisitableObjs(CGHeroInstance::convertPosition(curd.dst,false));
-			bool blockvis = false;
-			for (int pit = 0; pit<vis.size();pit++)
-				if (vis[pit]->blockVisit)
-					blockvis = true;
-
-			if (!blockvis)
-			{
-				curd.successful = true;
-				hero->pos = curd.dst;
-
-				//inform leaved objects
-				std::vector< CGObjectInstance * > leave = CGI->mh->getVisitableObjs(CGHeroInstance::convertPosition(curd.src,false));
-				for (int iii=0; iii<leave.size(); iii++) //if object is visitable we call onHeroVisit
-				{
-					//TODO: allow to handle this in LUA
-					if(leave[iii]->state) //hard-coded function
-						leave[iii]->state->onHeroLeave(leave[iii],curd.ho->subID);
-				}
-
-
-				//reveal fog of war
-				int heroSight = hero->getSightDistance();
-				int xbeg = stpos.x - heroSight - 2;
-				if(xbeg < 0)
-					xbeg = 0;
-				int xend = stpos.x + heroSight + 2;
-				if(xend >= CGI->mh->map->width)
-					xend = CGI->mh->map->width;
-				int ybeg = stpos.y - heroSight - 2;
-				if(ybeg < 0)
-					ybeg = 0;
-				int yend = stpos.y + heroSight + 2;
-				if(yend >= CGI->mh->map->height)
-					yend = CGI->mh->map->height;
-				for(int xd=xbeg; xd<xend; ++xd) //revealing part of map around heroes
-				{
-					for(int yd=ybeg; yd<yend; ++yd)
-					{
-						int deltaX = (hero->getPosition(false).x-xd)*(hero->getPosition(false).x-xd);
-						int deltaY = (hero->getPosition(false).y-yd)*(hero->getPosition(false).y-yd);
-						if(deltaX+deltaY<hero->getSightDistance()*hero->getSightDistance())
-						{
-							if(gs->players[player].fogOfWarMap[xd][yd][hero->getPosition(false).z] == 0)
-							{
-								CGI->playerint[gs->players[player].serial]->tileRevealed(int3(xd, yd, hero->getPosition(false).z));
-							}
-							gs->players[player].fogOfWarMap[xd][yd][hero->getPosition(false).z] = 1;
-						}
-					}
-				}
-
-
-				//notify interfacesabout move
-				int nn=0; //number of interfece of currently browsed player
-				for(std::map<ui8, PlayerState>::iterator j=CGI->state->players.begin(); j!=CGI->state->players.end(); ++j)//CGI->state->players.size(); ++j) //for testing
-				{
-					if (j->first > PLAYER_LIMIT)
-						break;
-					if(j->second.fogOfWarMap[stpos.x-1][stpos.y][stpos.z] || j->second.fogOfWarMap[endpos.x-1][endpos.y][endpos.z])
-					{ //player should be notified
-						CGI->playerint[j->second.serial]->heroMoved(curd);
-					}
-					++nn;
-				}
-
-
-				//call objects if they arevisited
-				for (int iii=0; iii<vis.size(); iii++) //if object is visitable we call onHeroVisit
-				{
-					if(gs->checkFunc(vis[iii]->ID,"heroVisit")) //script function
-						gs->objscr[vis[iii]->ID]["heroVisit"]->onHeroVisit(vis[iii],curd.ho->subID);
-					if(vis[iii]->state) //hard-coded function
-						vis[iii]->state->onHeroVisit(vis[iii],curd.ho->subID);
-				}
-			}
-			else //interaction with blocking object (like resources)
-			{
-				curd.successful = false;
-				CGI->playerint[gs->players[hero->getOwner()].serial]->heroMoved(curd);
-				for (int iii=0; iii<vis.size(); iii++) //if object is visitable we call onHeroVisit
-				{
-					if (vis[iii]->blockVisit)
-					{
-						if(gs->checkFunc(vis[iii]->ID,"heroVisit")) //script function
-							gs->objscr[vis[iii]->ID]["heroVisit"]->onHeroVisit(vis[iii],curd.ho->subID);
-						if(vis[iii]->state) //hard-coded function
-							vis[iii]->state->onHeroVisit(vis[iii],curd.ho->subID);
-					}
-				}
+		int3 stpos(ourPath->nodes[i].coord.x, ourPath->nodes[i].coord.y, hero->pos.z), 
+			endpos(ourPath->nodes[i-1].coord.x, ourPath->nodes[i-1].coord.y, hero->pos.z);
+		HeroMoveDetails curd(stpos,endpos,hero);
+
+		*cl->serv << ui16(501) << hero->id << stpos << endpos;
+		{//wait till there is server answer
+			boost::unique_lock<boost::mutex> lock(*mess.mx);
+			while(std::find_if(mess.res->begin(),mess.res->end(),IPack::isType<501>) == mess.res->end())
+				mess.cv->wait(lock);
+			std::set<IPack*>::iterator itr = std::find_if(mess.res->begin(),mess.res->end(),IPack::isType<501>);
+			TryMoveHero tmh = *static_cast<TryMoveHero*>(*itr);
+			mess.res->erase(itr);
+			if(!tmh.result)
 				return false;
-			}
-
 		}
-		else
-			return true; //move ended - no more movement points
 	}
+
+	//	if(hero->movement >= (ourPath->nodes.size()>=2 ?  (*(ourPath->nodes.end()-2)).dist : 0) - ourPath->nodes[i].dist  || player==-1)
+	//	{ //performing move
+	//		hero->movement -= (ourPath->nodes.size()>=2 ?  (*(ourPath->nodes.end()-2)).dist : 0) - ourPath->nodes[i].dist;
+	//		ourPath->nodes.pop_back();
+	//		
+	//		std::vector< CGObjectInstance * > vis = CGI->mh->getVisitableObjs(CGHeroInstance::convertPosition(curd.dst,false));
+	//		bool blockvis = false;
+	//		for (int pit = 0; pit<vis.size();pit++)
+	//			if (vis[pit]->blockVisit)
+	//				blockvis = true;
+
+	//		if (!blockvis)
+	//		{
+	//			curd.successful = true;
+	//			hero->pos = curd.dst;
+
+	//			//inform leaved objects
+	//			std::vector< CGObjectInstance * > leave = CGI->mh->getVisitableObjs(CGHeroInstance::convertPosition(curd.src,false));
+	//			for (int iii=0; iii<leave.size(); iii++) //if object is visitable we call onHeroVisit
+	//			{
+	//				//TODO: allow to handle this in LUA
+	//				if(leave[iii]->state) //hard-coded function
+	//					leave[iii]->state->onHeroLeave(leave[iii],curd.ho->subID);
+	//			}
+
+
+	//			//reveal fog of war
+	//			int heroSight = hero->getSightDistance();
+	//			int xbeg = stpos.x - heroSight - 2;
+	//			if(xbeg < 0)
+	//				xbeg = 0;
+	//			int xend = stpos.x + heroSight + 2;
+	//			if(xend >= CGI->mh->map->width)
+	//				xend = CGI->mh->map->width;
+	//			int ybeg = stpos.y - heroSight - 2;
+	//			if(ybeg < 0)
+	//				ybeg = 0;
+	//			int yend = stpos.y + heroSight + 2;
+	//			if(yend >= CGI->mh->map->height)
+	//				yend = CGI->mh->map->height;
+	//			for(int xd=xbeg; xd<xend; ++xd) //revealing part of map around heroes
+	//			{
+	//				for(int yd=ybeg; yd<yend; ++yd)
+	//				{
+	//					int deltaX = (hero->getPosition(false).x-xd)*(hero->getPosition(false).x-xd);
+	//					int deltaY = (hero->getPosition(false).y-yd)*(hero->getPosition(false).y-yd);
+	//					if(deltaX+deltaY<hero->getSightDistance()*hero->getSightDistance())
+	//					{
+	//						if(gs->players[player].fogOfWarMap[xd][yd][hero->getPosition(false).z] == 0)
+	//						{
+	//							cl->playerint[player]->tileRevealed(int3(xd, yd, hero->getPosition(false).z));
+	//						}
+	//						gs->players[player].fogOfWarMap[xd][yd][hero->getPosition(false).z] = 1;
+	//					}
+	//				}
+	//			}
+
+
+	//			//notify interfacesabout move
+	//			int nn=0; //number of interfece of currently browsed player
+	//			for(std::map<ui8, PlayerState>::iterator j=CGI->state->players.begin(); j!=CGI->state->players.end(); ++j)//CGI->state->players.size(); ++j) //for testing
+	//			{
+	//				if (j->first > PLAYER_LIMIT)
+	//					break;
+	//				if(j->second.fogOfWarMap[stpos.x-1][stpos.y][stpos.z] || j->second.fogOfWarMap[endpos.x-1][endpos.y][endpos.z])
+	//				{ //player should be notified
+	//					cl->playerint[j->second.color]->heroMoved(curd);
+	//				}
+	//				++nn;
+	//			}
+
+
+	//			//call objects if they arevisited
+	//			for (int iii=0; iii<vis.size(); iii++) //if object is visitable we call onHeroVisit
+	//			{
+	//				if(gs->checkFunc(vis[iii]->ID,"heroVisit")) //script function
+	//					gs->objscr[vis[iii]->ID]["heroVisit"]->onHeroVisit(vis[iii],curd.ho->subID);
+	//				if(vis[iii]->state) //hard-coded function
+	//					vis[iii]->state->onHeroVisit(vis[iii],curd.ho->subID);
+	//			}
+	//		}
+	//		else //interaction with blocking object (like resources)
+	//		{
+	//			curd.successful = false;
+	//			cl->playerint[gs->players[hero->getOwner()].color]->heroMoved(curd);
+	//			for (int iii=0; iii<vis.size(); iii++) //if object is visitable we call onHeroVisit
+	//			{
+	//				if (vis[iii]->blockVisit)
+	//				{
+	//					if(gs->checkFunc(vis[iii]->ID,"heroVisit")) //script function
+	//						gs->objscr[vis[iii]->ID]["heroVisit"]->onHeroVisit(vis[iii],curd.ho->subID);
+	//					if(vis[iii]->state) //hard-coded function
+	//						vis[iii]->state->onHeroVisit(vis[iii],curd.ho->subID);
+	//				}
+	//			}
+	//			return false;
+	//		}
+
+	//	}
+	//}
 	return true;
 }
 
@@ -254,7 +265,7 @@ void CCallback::recruitCreatures(const CGObjectInstance *obj, int ID, int amount
 			t->army.slots[slot].first = &CGI->creh->creatures[ID];
 			t->army.slots[slot].second = amount;
 		}
-		CGI->playerint[gs->players[player].serial]->garrisonChanged(obj);
+		cl->playerint[player]->garrisonChanged(obj);
 
 	}
 	//TODO: recruit from dwellings on the adventure map
@@ -267,7 +278,7 @@ bool CCallback::dismissCreature(const CArmedInstance *obj, int stackPos)
 		return false;
 	CArmedInstance *ob = const_cast<CArmedInstance*>(obj);
 	ob->army.slots.erase(stackPos);
-	CGI->playerint[gs->players[player].serial]->garrisonChanged(obj);
+	cl->playerint[player]->garrisonChanged(obj);
 	return true;
 }
 bool CCallback::upgradeCreature(const CArmedInstance *obj, int stackPos, int newID)
@@ -515,27 +526,9 @@ int CCallback::swapCreatures(const CGObjectInstance *s1, const CGObjectInstance
 		S2->slots.erase(p2);
 
 	if(s1->tempOwner<PLAYER_LIMIT)
-	{
-		for(int b=0; b<CGI->playerint.size(); ++b)
-		{
-			if(CGI->playerint[b]->playerID == s1->tempOwner)
-			{
-				CGI->playerint[b]->garrisonChanged(s1);
-				break;
-			}
-		}
-	}
+		cl->playerint[s1->tempOwner]->garrisonChanged(s1);
 	if((s2->tempOwner<PLAYER_LIMIT) && (s2 != s1))
-	{
-		for(int b=0; b<CGI->playerint.size(); ++b)
-		{
-			if(CGI->playerint[b]->playerID == s2->tempOwner)
-			{
-				CGI->playerint[b]->garrisonChanged(s2);
-				break;
-			}
-		}
-	}
+		cl->playerint[s2->tempOwner]->garrisonChanged(s2);
 	return 0;
 }
 
@@ -555,27 +548,10 @@ int CCallback::mergeStacks(const CGObjectInstance *s1, const CGObjectInstance *s
 	S1->slots.erase(p1);
 
 	if(s1->tempOwner<PLAYER_LIMIT)
-	{
-		for(int b=0; b<CGI->playerint.size(); ++b)
-		{
-			if(CGI->playerint[b]->playerID == s1->tempOwner)
-			{
-				CGI->playerint[b]->garrisonChanged(s1);
-				break;
-			}
-		}
-	}
+		cl->playerint[s1->tempOwner]->garrisonChanged(s1);
+
 	if((s2->tempOwner<PLAYER_LIMIT) && (s2 != s1))
-	{
-		for(int b=0; b<CGI->playerint.size(); ++b)
-		{
-			if(CGI->playerint[b]->playerID == s2->tempOwner)
-			{
-				CGI->playerint[b]->garrisonChanged(s2);
-				break;
-			}
-		}
-	}
+		cl->playerint[s2->tempOwner]->garrisonChanged(s2);
 	return 0;
 }
 int CCallback::splitStack(const CGObjectInstance *s1, const CGObjectInstance *s2, int p1, int p2, int val)
@@ -597,25 +573,11 @@ int CCallback::splitStack(const CGObjectInstance *s1, const CGObjectInstance *s2
 
 	if(s1->tempOwner<PLAYER_LIMIT)
 	{
-		for(int b=0; b<CGI->playerint.size(); ++b)
-		{
-			if(CGI->playerint[b]->playerID == s1->tempOwner)
-			{
-				CGI->playerint[b]->garrisonChanged(s1);
-				break;
-			}
-		}
+		cl->playerint[s1->tempOwner]->garrisonChanged(s1);
 	}
 	if((s2->tempOwner<PLAYER_LIMIT) && (s2 != s1))
 	{
-		for(int b=0; b<CGI->playerint.size(); ++b)
-		{
-			if(CGI->playerint[b]->playerID == s2->tempOwner)
-			{
-				CGI->playerint[b]->garrisonChanged(s2);
-				break;
-			}
-		}
+		cl->playerint[s2->tempOwner]->garrisonChanged(s2);
 	}
 	return 0;
 }
@@ -686,7 +648,7 @@ bool CCallback::buildBuilding(const CGTownInstance *town, int buildingID)
 	for(int i=0;i<7;i++)
 		gs->players[player].resources[i]-=b->resources[i];
 	t->builded++;
-	CGI->playerint[CGI->state->players[player].serial]->buildChanged(town,buildingID,1);
+	cl->playerint[player]->buildChanged(town,buildingID,1);
 	return true;
 }
 
@@ -782,18 +744,11 @@ int3 CScriptCallback::getPos(CGObjectInstance * ob)
 }
 void CScriptCallback::changePrimSkill(int ID, int which, int val)
 {	
-	CGHeroInstance * hero = CGI->state->map->getHero(ID,0);
+	CGHeroInstance * hero = gs->map->getHero(ID,0);
 	if (which<PRIMARY_SKILLS)
 	{
 		hero->primSkills[which]+=val;
-		for (int i=0; i<CGI->playerint.size(); i++)
-		{
-			if (CGI->playerint[i]->playerID == hero->getOwner())
-			{
-				CGI->playerint[i]->heroPrimarySkillChanged(hero, which, val);
-				break;
-			}
-		}
+		cl->playerint[hero->getOwner()]->heroPrimarySkillChanged(hero, which, val);
 	}
 	else if (which==4)
 	{
@@ -830,24 +785,25 @@ void CScriptCallback::showInfoDialog(int player, std::string text, std::vector<S
 	//TODO: upewniac sie ze mozemy to zrzutowac (przy customowych interfejsach cos moze sie kopnac)
 	if (player>=0)
 	{
-		CGameInterface * temp = CGI->playerint[CGI->state->players[player].serial];
+		CGameInterface * temp = cl->playerint[player];
 		if (temp->human)
 			((CPlayerInterface*)(temp))->showInfoDialog(text,*components);
 		return;
 	}
 	else
 	{
-		for (int i=0; i<CGI->playerint.size();i++)
+		typedef std::pair<const ui8, CGameInterface*> intf;
+		BOOST_FOREACH(intf & i, cl->playerint)
 		{
-			if (CGI->playerint[i]->human)
-				((CPlayerInterface*)(CGI->playerint[i]))->showInfoDialog(text,*components);
+			if (i.second->human)
+				((CPlayerInterface*)(i.second))->showInfoDialog(text,*components);
 		}
 	}
 }
 
 void CScriptCallback::showSelDialog(int player, std::string text, std::vector<CSelectableComponent*>*components, IChosen * asker)
 {
-	CGameInterface * temp = CGI->playerint[CGI->state->players[player].serial];
+	CGameInterface * temp = cl->playerint[player];
 	if (temp->human)
 		((CPlayerInterface*)(temp))->showSelDialog(text,*components,(int)asker);
 	return;
@@ -891,11 +847,11 @@ int CScriptCallback::getDate(int mode)
 void CScriptCallback::giveResource(int player, int which, int val)
 {
 	gs->players[player].resources[which]+=val;
-	CGI->playerint[gs->players[player].serial]->receivedResource(which,val);
+	cl->playerint[player]->receivedResource(which,val);
 }
 void CScriptCallback::showCompInfo(int player, SComponent * comp)
 {
-	CPlayerInterface * i = dynamic_cast<CPlayerInterface*>(CGI->playerint[gs->players[player].serial]);
+	CPlayerInterface * i = dynamic_cast<CPlayerInterface*>(cl->playerint[player]);
 	if(i)
 		i->showComp(*comp);
 }
@@ -905,15 +861,8 @@ void CScriptCallback::heroVisitCastle(CGObjectInstance * ob, int heroID)
 	if(n = dynamic_cast<CGTownInstance*>(ob))
 	{
 		n->visitingHero = CGI->state->map->getHero(heroID,0);
-		CGI->state->map->getHero(heroID,0)->visitedTown = n;
-		for(int b=0; b<CGI->playerint.size(); ++b)
-		{
-			if(CGI->playerint[b]->playerID == getHeroOwner(heroID))
-			{
-				CGI->playerint[b]->heroVisitsTown(CGI->state->map->getHero(heroID,0),n);
-				break;
-			}
-		}
+		gs->map->getHero(heroID,0)->visitedTown = n;
+		cl->playerint[getHeroOwner(heroID)]->heroVisitsTown(CGI->state->map->getHero(heroID,0),n);
 	}
 	else
 		return;

+ 5 - 1
CCallback.h

@@ -78,6 +78,8 @@ public:
 
 struct HeroMoveDetails
 {
+	HeroMoveDetails(){};
+	HeroMoveDetails(int3 Src, int3 Dst, CGHeroInstance*Ho);
 	int3 src, dst; //source and destination points
 	CGHeroInstance * ho; //object instance of this hero
 	int owner;
@@ -152,8 +154,10 @@ public:
 };
 class CScriptCallback
 {
+	CScriptCallback(){};
 public:
 	CGameState * gs;
+	CClient *cl;
 
 	//get info
 	static int3 getPos(CGObjectInstance * ob);
@@ -162,7 +166,7 @@ public:
 	int getDate(int mode=0);
 
 	//do sth
-	static void changePrimSkill(int ID, int which, int val);
+	void changePrimSkill(int ID, int which, int val);
 	void showInfoDialog(int player, std::string text, std::vector<SComponent*> * components); //TODO: obslugiwac nulle
 	void showSelDialog(int player, std::string text, std::vector<CSelectableComponent*>*components, IChosen * asker);
 	void giveResource(int player, int which, int val);

+ 0 - 2
CGameInfo.h

@@ -58,8 +58,6 @@ public:
 	CPathfinder * pathf;
 	CCursorHandler * curh;
 	CScreenHandler * screenh;
-	int localPlayer;
-	std::vector<CGameInterface *> playerint;
 };
 
 #endif //CGAMEINFO_H

+ 14 - 0
CGameState.cpp

@@ -128,6 +128,20 @@ void CGameState::apply(IPack * pack)
 			if(n->resetBuilded) //reset amount of structures set in this turn in towns
 				BOOST_FOREACH(CGTownInstance* t, map->towns)
 					t->builded = 0;
+			break;
+		}
+	case 501://hero try-move
+		{
+			TryMoveHero * n = static_cast<TryMoveHero*>(pack);
+			CGHeroInstance *h = static_cast<CGHeroInstance*>(map->objects[n->id]);
+			h->movement = n->movePoints;
+			if(n->result)
+				h->pos = n->end;
+			else
+				h->pos = n->start;			
+			BOOST_FOREACH(int3 t, n->fowRevealed)
+				players[h->getOwner()].fogOfWarMap[t.x][t.y][t.z] = 1;
+			break;
 		}
 	}
 	mx->unlock();

+ 2 - 5
CPlayerInterface.cpp

@@ -340,7 +340,7 @@ void CGarrisonInt::createSlots()
 	{
 		sup = new std::vector<CGarrisonSlot*>(7,(CGarrisonSlot *)(NULL));
 		for
-			(std::map<int,std::pair<CCreature*,int> >::const_iterator i=set1->slots.begin();
+			(std::map<si32,std::pair<CCreature*,si32> >::const_iterator i=set1->slots.begin();
 			i!=set1->slots.end(); i++)
 		{
 			(*sup)[i->first] = 
@@ -354,7 +354,7 @@ void CGarrisonInt::createSlots()
 	{	
 		sdown = new std::vector<CGarrisonSlot*>(7,(CGarrisonSlot *)(NULL));
 		for
-			(std::map<int,std::pair<CCreature*,int> >::const_iterator i=set2->slots.begin();
+			(std::map<si32,std::pair<CCreature*,si32> >::const_iterator i=set2->slots.begin();
 			i!=set2->slots.end(); i++)
 		{
 			(*sdown)[i->first] = 
@@ -902,13 +902,11 @@ CPlayerInterface::CPlayerInterface(int Player, int serial)
 	LOCPLINT = this;
 	playerID=Player;
 	serialID=serial;
-	CGI->localPlayer = playerID;
 	human=true;
 }
 void CPlayerInterface::init(ICallback * CB)
 {
 	cb = dynamic_cast<CCallback*>(CB);
-	CGI->localPlayer = serialID;
 	adventureInt = new CAdvMapInt(playerID);
 	castleInt = NULL;
 	std::vector <const CGHeroInstance *> hh = cb->getHeroesInfo(false);
@@ -928,7 +926,6 @@ void CPlayerInterface::yourTurn()
 {
 	LOCPLINT = this;
 	makingTurn = true;
-	CGI->localPlayer = serialID;
 	unsigned char & animVal = LOCPLINT->adventureInt->anim; //for animations handling
 	unsigned char & heroAnimVal = LOCPLINT->adventureInt->heroAnim;
 	adventureInt->infoBar.newDay(cb->getDate(1));

+ 48 - 8
client/Client.cpp

@@ -11,6 +11,9 @@
 #include "../lib/NetPacks.h"
 #include <boost/bind.hpp>
 #include <boost/thread.hpp>
+#include "../hch/CObjectHandler.h"
+CSharedCond<std::set<IPack*> > mess(new std::set<IPack*>);
+
 CClient::CClient(void)
 {
 }
@@ -58,17 +61,18 @@ CClient::CClient(CConnection *con, StartInfo *si)
 
 	for (int i=0; i<CGI->state->scenarioOps->playerInfos.size();i++) //initializing interfaces
 	{ 
-		CCallback *cb = new CCallback(CGI->state,CGI->state->scenarioOps->playerInfos[i].color,this);
-		if(!CGI->state->scenarioOps->playerInfos[i].human)
-			CGI->playerint.push_back(static_cast<CGameInterface*>(CAIHandler::getNewAI(cb,"EmptyAI.dll")));
+		ui8 color = gs->scenarioOps->playerInfos[i].color;
+		CCallback *cb = new CCallback(gs,color,this);
+		if(!gs->scenarioOps->playerInfos[i].human)
+			playerint[color] = static_cast<CGameInterface*>(CAIHandler::getNewAI(cb,"EmptyAI.dll"));
 		else 
 		{
-			CGI->state->currentPlayer=CGI->state->scenarioOps->playerInfos[i].color;
-			CGI->playerint.push_back(new CPlayerInterface(CGI->state->scenarioOps->playerInfos[i].color,i));
-			((CPlayerInterface*)(CGI->playerint[i]))->init(cb);
+			gs->currentPlayer = color;
+			playerint[color] = new CPlayerInterface(color,i);
+			playerint[color]->init(cb);
 		}
 	}
-	CGI->consoleh->cb = new CCallback(CGI->state,-1,this);
+	CGI->consoleh->cb = new CCallback(gs,-1,this);
 }
 CClient::~CClient(void)
 {
@@ -82,7 +86,7 @@ void CClient::process(int what)
 			ui8 player;
 			*serv >> player;//who?
 			std::cout << "It's turn of "<<(unsigned)player<<" player."<<std::endl;
-			boost::thread(boost::bind(&CGameInterface::yourTurn,CGI->playerint[gs->players[player].serial]));
+			boost::thread(boost::bind(&CGameInterface::yourTurn,playerint[player]));
 			break;
 		}
 	case 101:
@@ -94,6 +98,42 @@ void CClient::process(int what)
 			std::cout << "done!"<<std::endl;
 			break;
 		}
+	case 501: //hero movement response - we have to notify interfaces and callback
+		{
+			TryMoveHero *th = new TryMoveHero;
+			*serv >> *th;
+			std::cout << "HeroMove: id="<<th->id<<"\tResult: "<<(unsigned)th->result<<"\tPosition "<<th->end<<std::endl;
+
+			gs->apply(th);
+			int player = gs->map->objects[th->id]->getOwner();
+
+			if(playerint[player])
+			{
+				for(std::set<int3>::iterator i=th->fowRevealed.begin(); i != th->fowRevealed.end(); i++)
+					playerint[player]->tileRevealed(*i);
+				//boost::function<void(int3)> tr = boost::bind(&CGameInterface::tileRevealed,playerint[player]);
+				//std::for_each(th->fowRevealed.begin(),th->fowRevealed.end(),tr);
+			}
+
+			//notify interfacesabout move
+			int nn=0; //number of interfece of currently browsed player
+			for(std::map<ui8, CGameInterface*>::iterator i=playerint.begin();i!=playerint.end();i++)
+			{
+				if(gs->players[i->first].fogOfWarMap[th->start.x-1][th->start.y][th->start.z] || gs->players[i->first].fogOfWarMap[th->end.x-1][th->end.y][th->end.z])
+				{
+					HeroMoveDetails hmd(th->start,th->end,static_cast<CGHeroInstance*>(gs->map->objects[th->id]));
+					hmd.successful = th->result;
+					i->second->heroMoved(hmd);
+				}
+			}
+
+			//add info for callback
+			mess.mx->lock();
+			mess.res->insert(th);
+			mess.mx->unlock();
+			mess.cv->notify_all();
+			break;
+		}
 	default:
 		throw std::exception("Not supported server message!");
 		break;

+ 29 - 1
client/Client.h

@@ -5,10 +5,37 @@ class CGameState;
 class CGameInterface;
 class CConnection;
 class CCallback;
+
+namespace boost
+{
+	class mutex;
+	class condition_variable;
+}
+
+template <typename T>
+struct CSharedCond
+{
+	boost::mutex *mx;
+	boost::condition_variable *cv;
+	T *res;
+	CSharedCond(T*R)
+	{
+		res = R;
+		mx = new boost::mutex;
+		cv = new boost::condition_variable;
+	}
+	~CSharedCond()
+	{
+		delete res;
+		delete mx;
+		delete cv;
+	}
+};
+
 class CClient
 {
 	CGameState *gs;
-	std::map<int,CGameInterface *> playerint;
+	std::map<ui8,CGameInterface *> playerint;
 	CConnection *serv;
 public:
 	CClient(void);
@@ -19,4 +46,5 @@ public:
 	void run();
 
 	friend class CCallback;
+	friend class CScriptCallback;
 };

+ 2 - 2
client/Graphics.cpp

@@ -35,7 +35,7 @@ SDL_Surface * Graphics::drawHeroInfoWin(const CGHeroInstance * curh)
 	SDL_SetColorKey(ret,SDL_SRCCOLORKEY,SDL_MapRGB(ret->format,0,255,255));
 	printAt(curh->name,75,15,GEOR13,zwykly,ret);
 	drawPrimarySkill(curh, ret);
-	for (std::map<int,std::pair<CCreature*,int> >::const_iterator i=curh->army.slots.begin(); i!=curh->army.slots.end();i++)
+	for (std::map<si32,std::pair<CCreature*,si32> >::const_iterator i=curh->army.slots.begin(); i!=curh->army.slots.end();i++)
 	{
 		blitAt(graphics->smallImgs[(*i).second.first->idNumber],slotsPos[(*i).first].first+1,slotsPos[(*i).first].second+1,ret);
 		itoa((*i).second.second,buf,10);
@@ -64,7 +64,7 @@ SDL_Surface * Graphics::drawTownInfoWin(const CGTownInstance * curh)
 		blitAt(halls->ourImages[pom].bitmap,77,42,ret);
 	itoa(curh->dailyIncome(),buf,10);
 	printAtMiddle(buf,167,70,GEORM,zwykly,ret);
-	for (std::map<int,std::pair<CCreature*,int> >::const_iterator i=curh->army.slots.begin(); i!=curh->army.slots.end();i++)
+	for (std::map<si32,std::pair<CCreature*,si32> >::const_iterator i=curh->army.slots.begin(); i!=curh->army.slots.end();i++)
 	{
 		if(!i->second.first)
 			continue;

+ 1 - 1
hch/CObjectHandler.h

@@ -53,7 +53,7 @@ class DLL_EXPORT CGObjectInstance
 public:
 	int3 pos; //h3m pos
 	int ID, subID; //normal ID (this one from OH3 maps ;]) - eg. town=98; hero=34
-	int id;//number of object in CObjectHandler's vector		
+	si32 id;//number of object in CObjectHandler's vector		
 	CGDefInfo * defInfo;
 	CCPPObjectScript * state;
 	CSpecObjInfo * info;

+ 12 - 8
int3.h

@@ -5,26 +5,26 @@ class CCreature;
 class CCreatureSet //seven combined creatures
 {
 public:
-	std::map<int,std::pair<CCreature*,int> > slots;
+	std::map<si32,std::pair<CCreature*,si32> > slots;
 	bool formation; //false - wide, true - tight
 };
 
 class int3
 {
 public:
-	int x,y,z;
+	si32 x,y,z;
 	inline int3():x(0),y(0),z(0){}; //c-tor, x/y/z initialized to 0
-	inline int3(const int & X, const int & Y, const int & Z):x(X),y(Y),z(Z){}; //c-tor
+	inline int3(const si32 & X, const si32 & Y, const si32 & Z):x(X),y(Y),z(Z){}; //c-tor
 	inline ~int3(){} // d-tor - does nothing
 	inline int3 operator+(const int3 & i) const
 		{return int3(x+i.x,y+i.y,z+i.z);}
-	inline int3 operator+(const int i) const //increases all components by int
+	inline int3 operator+(const si32 i) const //increases all components by si32
 		{return int3(x+i,y+i,z+i);}
 	inline int3 operator-(const int3 & i) const
 		{return int3(x-i.x,y-i.y,z-i.z);}
-	inline int3 operator-(const int i) const
+	inline int3 operator-(const si32 i) const
 		{return int3(x-i,y-i,z-i);}
-	inline int3 operator-() const //increases all components by int
+	inline int3 operator-() const //increases all components by si32
 		{return int3(-x,-y,-z);}
 	inline void operator+=(const int3 & i)
 	{
@@ -32,7 +32,7 @@ public:
 		y+=i.y;
 		z+=i.z;
 	}	
-	inline void operator+=(const int & i)
+	inline void operator+=(const si32 & i)
 	{
 		x+=i;
 		y+=i;
@@ -44,7 +44,7 @@ public:
 		y-=i.y;
 		z-=i.z;
 	}	
-	inline void operator-=(const int & i)
+	inline void operator-=(const si32 & i)
 	{
 		x+=i;
 		y+=i;
@@ -70,6 +70,10 @@ public:
 			return false;
 		return false;
 	}
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & x & y & z;
+	}
 };
 inline std::istream & operator>>(std::istream & str, int3 & dest)
 {

+ 31 - 2
lib/NetPacks.h

@@ -1,13 +1,28 @@
 #include "../global.h"
 struct IPack
 {
-	virtual ui16 getType()=0;
+	virtual ui16 getType()const = 0 ;
+	//template<ui16 Type>
+	//static bool isType(const IPack * ip)
+	//{
+	//	return Type == ip->getType();
+	//}
+	template<ui16 Type>
+	static bool isType(IPack * ip)
+	{
+		return Type == ip->getType();
+	}
+	//template<ui16 Type>
+	//static bool isType(const IPack & ip)
+	//{
+	//	return Type == ip.getType();
+	//}
 };
 template <typename T> struct CPack
 	:public IPack
 {
 	ui16 type; 
-	ui16 getType(){return type;}
+	ui16 getType() const{return type;}
 	T* This(){return static_cast<T*>(this);};
 };
 struct NewTurn : public CPack<NewTurn> //101
@@ -43,4 +58,18 @@ struct NewTurn : public CPack<NewTurn> //101
 	{
 		h & heroes & res & day & resetBuilded;
 	}
+}; 
+struct TryMoveHero : public CPack<TryMoveHero> //501
+{
+	TryMoveHero(){type = 501;};
+
+	ui32 id, movePoints;
+	ui8 result;
+	int3 start, end;
+	std::set<int3> fowRevealed; //revealed tiles
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & id & result & start & end & movePoints & fowRevealed;
+	}
 }; 

+ 32 - 0
map.cpp

@@ -926,6 +926,8 @@ void Mapa::initFromBytes(unsigned char * bufor)
 			terrain[z][c].malle = (Eroad)bufor[i++];
 			terrain[z][c].roadDir = bufor[i++];
 			terrain[z][c].siodmyTajemniczyBajt = bufor[i++];
+			terrain[z][c].blocked = 0;
+			terrain[z][c].visitable = 0;
 		}
 	}
 	if (twoLevel) // read underground terrain
@@ -941,6 +943,8 @@ void Mapa::initFromBytes(unsigned char * bufor)
 				undergroungTerrain[z][c].malle = (Eroad)bufor[i++];
 				undergroungTerrain[z][c].roadDir = bufor[i++];
 				undergroungTerrain[z][c].siodmyTajemniczyBajt = bufor[i++];
+				undergroungTerrain[z][c].blocked = 0;
+				undergroungTerrain[z][c].visitable = 0;
 			}
 		}
 	}
@@ -2289,6 +2293,34 @@ borderguardend:
 
 	//map readed, bufor no longer needed
 	delete[] bufor; bufor=NULL;
+
+	
+	for(int f=0; f<objects.size(); ++f) //calculationg blocked / visitable positions
+	{
+		if(!objects[f]->defInfo)
+			continue;
+		CDefHandler * curd = objects[f]->defInfo->handler;
+		for(int fx=0; fx<8; ++fx)
+		{
+			for(int fy=0; fy<6; ++fy)
+			{
+				int xVal = objects[f]->pos.x + fx - 7;
+				int yVal = objects[f]->pos.y + fy - 5;
+				int zVal = objects[f]->pos.z;
+				if(xVal>=0 && xVal<width && yVal>=0 && yVal<height)
+				{
+					TerrainTile & curt = (zVal) ? (undergroungTerrain[xVal][yVal]) : (terrain[xVal][yVal]);
+					if(((objects[f]->defInfo->visitMap[fy] >> (7 - fx)) & 1))
+					{
+						curt.visitableObjects.push_back(objects[f]);
+						curt.visitable = true;
+					}
+					if(!((objects[f]->defInfo->blockMap[fy] >> (7 - fx)) & 1))
+						curt.blocked = true;
+				}
+			}
+		}
+	}
 }	
 
 Mapa::Mapa(std::string filename)

+ 5 - 0
map.h

@@ -263,6 +263,11 @@ struct DLL_EXPORT TerrainTile
 	Eroad malle; // type of Eroad (0 if there is no Eriver)
 	unsigned char roadDir; // direction of Eroad
 	unsigned char siodmyTajemniczyBajt; //bitfield, info whether this tile is coastal and how to rotate tile graphics
+
+	bool visitable; //false = not visitable; true = visitable
+	bool blocked; //false = free; true = blocked;
+
+	std::vector <CGObjectInstance*> visitableObjects; //pointers to objects hero can visit while being on this tile
 };
 struct DLL_EXPORT SheroName //name of starting hero
 {

+ 2 - 2
mapHandler.cpp

@@ -1325,7 +1325,7 @@ unsigned char CMapHandler::getHeroFrameNum(const unsigned char &dir, const bool
 		case 8:
 			return 11;
 		default:
-			return -1; //should never happen
+			throw std::exception("Something very wrong1.");
 		}
 	}
 	else //if(isMoving)
@@ -1349,7 +1349,7 @@ unsigned char CMapHandler::getHeroFrameNum(const unsigned char &dir, const bool
 		case 8:
 			return 14;
 		default:
-			return -1; //should never happen
+			throw std::exception("Something very wrong2.");
 		}
 	}
 }

+ 128 - 7
server/CGameHandler.cpp

@@ -3,6 +3,7 @@
 #include <boost/thread/shared_mutex.hpp>
 #include <boost/bind.hpp>
 #include "CGameHandler.h"
+#include "../CLua.h"
 #include "../CGameState.h"
 #include "../StartInfo.h"
 #include "../map.h"
@@ -19,6 +20,11 @@ boost::condition_variable cTurn;
 boost::mutex mTurn;
 boost::shared_mutex gsm;
 
+double neighbours(int3 a, int3 b)
+{
+	return std::sqrt( (double)(a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) );
+}
+
 void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
 {
 	try
@@ -29,12 +35,126 @@ void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
 			c >> pom;
 			switch(pom)
 			{
-			case 100: //my interface end its turn
-				mTurn.lock();
-				makingTurn = false;
-				mTurn.unlock();
-				cTurn.notify_all();
-				break;
+			case 100: //my interface ended its turn
+				{
+					mTurn.lock();
+					makingTurn = false;
+					mTurn.unlock();
+					cTurn.notify_all();
+					break;
+				}
+			case 501://interface wants to move hero
+				{
+					int3 start, end;
+					si32 id;
+					c >> id >> start >> end;
+					int3 hmpos = end + int3(-1,0,0);
+					TerrainTile t = (hmpos.z) ? (gs->map->undergroungTerrain[hmpos.x][hmpos.y]) : (gs->map->terrain[hmpos.x][hmpos.y]);
+					CGHeroInstance *h = static_cast<CGHeroInstance *>(gs->map->objects[id]);
+					int cost = (double)h->getTileCost(t.tertype,t.malle,t.nuine) * neighbours(start,end);
+
+					TryMoveHero tmh;
+					tmh.id = id;
+					tmh.start = tmh.end = start;
+					tmh.end = end;
+					tmh.result = 0;
+					tmh.movePoints = h->movement;
+
+					if((h->getOwner() != gs->currentPlayer) || //not turn of that hero
+						(neighbours(start,end)>=1.5) || //tiles are not neighouring
+						(h->movement < cost) || //lack of movement points
+						(t.tertype == rock) || //rock
+						(!h->canWalkOnSea() && t.tertype == water) ||
+						(t.blocked && !t.visitable) ) //tile is blocked andnot visitable
+						goto fail;
+
+					//we start moving
+					bool blockvis = false;
+					tmh.movePoints = h->movement = (h->movement-cost); //take move points
+					BOOST_FOREACH(CGObjectInstance *obj, t.visitableObjects)
+					{
+						if(obj->blockVisit)
+						{
+							blockvis = true;
+							break;
+						}
+					}
+
+					if(blockvis)//interaction with blocking object (like resources)
+					{
+						gs->apply(&tmh);
+						sendToAllClients(&tmh);
+						BOOST_FOREACH(CGObjectInstance *obj, t.visitableObjects)
+						{
+							if (obj->blockVisit)
+							{
+								if(gs->checkFunc(obj->ID,"heroVisit")) //script function
+									gs->objscr[obj->ID]["heroVisit"]->onHeroVisit(obj,h->subID);
+								if(obj->state) //hard-coded function
+									obj->state->onHeroVisit(obj,h->subID);
+							}
+						}
+						break;
+					}
+					else //normal move
+					{
+						tmh.result = 1;
+
+						BOOST_FOREACH(CGObjectInstance *obj, ((start.z) ? (gs->map->undergroungTerrain[start.x][start.y]) : (gs->map->terrain[start.x][start.y])).visitableObjects)
+						{
+							//TODO: allow to handle this in script-languages
+							if(obj->state) //hard-coded function
+								obj->state->onHeroLeave(obj,h->subID);
+						}
+
+						//reveal fog of war
+						int heroSight = h->getSightDistance();
+						int xbeg = start.x - heroSight - 2;
+						if(xbeg < 0)
+							xbeg = 0;
+						int xend = start.x + heroSight + 2;
+						if(xend >= gs->map->width)
+							xend = gs->map->width;
+						int ybeg = start.y - heroSight - 2;
+						if(ybeg < 0)
+							ybeg = 0;
+						int yend = start.y + heroSight + 2;
+						if(yend >= gs->map->height)
+							yend = gs->map->height;
+						for(int xd=xbeg; xd<xend; ++xd) //revealing part of map around heroes
+						{
+							for(int yd=ybeg; yd<yend; ++yd)
+							{
+								int deltaX = (hmpos.x-xd)*(hmpos.x-xd);
+								int deltaY = (hmpos.y-yd)*(hmpos.y-yd);
+								if(deltaX+deltaY<h->getSightDistance()*h->getSightDistance())
+								{
+									if(gs->players[h->getOwner()].fogOfWarMap[xd][yd][hmpos.z] == 0)
+									{
+										tmh.fowRevealed.insert(int3(xd,yd,hmpos.z));
+									}
+								}
+							}
+						}
+
+						gs->apply(&tmh);
+						sendToAllClients(&tmh);
+
+						//call objects if they arevisited
+						BOOST_FOREACH(CGObjectInstance *obj, t.visitableObjects)
+						{
+							if(gs->checkFunc(obj->ID,"heroVisit")) //script function
+								gs->objscr[obj->ID]["heroVisit"]->onHeroVisit(obj,h->subID);
+							if(obj->state) //hard-coded function
+								obj->state->onHeroVisit(obj,h->subID);
+						}
+					}
+					break;
+				fail:
+					gs->apply(&tmh);
+					sendToAllClients(&tmh);
+					break;
+				}
 			default:
 				throw std::exception("Not supported client message!");
 				break;
@@ -79,7 +199,7 @@ void CGameHandler::init(StartInfo *si, int Seed)
 }
 int lowestSpeed(CGHeroInstance * chi)
 {
-	std::map<int,std::pair<CCreature*,int> >::iterator i = chi->army.slots.begin();
+	std::map<si32,std::pair<CCreature*,si32> >::iterator i = chi->army.slots.begin();
 	int ret = (*i++).second.first->speed;
 	for (;i!=chi->army.slots.end();i++)
 	{
@@ -174,6 +294,7 @@ void CGameHandler::run()
 		{
 			if((i->second.towns.size()==0 && i->second.heroes.size()==0)  || i->second.color<0) continue; //players has not towns/castle - loser
 			makingTurn = true;
+			gs->currentPlayer = i->first;
 			*connections[i->first] << ui16(100) << i->first;    
 			//wait till turn is done
 			boost::unique_lock<boost::mutex> lock(mTurn);