浏览代码

Rewrote hero moving code. Seems to be working.

Michał W. Urbańczyk 17 年之前
父节点
当前提交
3247a9a4dd
共有 15 个文件被更改,包括 455 次插入234 次删除
  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);