浏览代码

Bugfixes and support for timed events.

Michał W. Urbańczyk 16 年之前
父节点
当前提交
a7680d3957
共有 11 个文件被更改,包括 139 次插入54 次删除
  1. 1 0
      CGameState.cpp
  2. 2 1
      CGameState.h
  3. 31 7
      CPlayerInterface.cpp
  4. 2 0
      CPlayerInterface.h
  5. 4 3
      client/Client.cpp
  6. 3 2
      lib/NetPacks.h
  7. 15 13
      map.cpp
  8. 5 18
      map.h
  9. 72 7
      server/CGameHandler.cpp
  10. 1 0
      server/CGameHandler.h
  11. 3 3
      server/NetPacksServer.cpp

+ 1 - 0
CGameState.cpp

@@ -907,6 +907,7 @@ void CGameState::init(StartInfo * si, Mapa * map, int Seed)
 		std::pair<int,PlayerState> ins(scenarioOps->playerInfos[i].color,PlayerState());
 		ins.second.color=ins.first;
 		ins.second.serial=i;
+		ins.second.human = scenarioOps->playerInfos[i].human;
 		players.insert(ins);
 	}
 	/******************RESOURCES****************************************************/

+ 2 - 1
CGameState.h

@@ -50,6 +50,7 @@ struct DLL_EXPORT PlayerState
 {
 public:
 	ui8 color, serial;
+	ui8 human; //true if human controlled player, false for AI
 	ui32 currentSelection; //id of hero/town, 0xffffffff if none
 	std::vector<std::vector<std::vector<ui8> > >  fogOfWarMap; //true - visible, false - hidden
 	std::vector<si32> resources;
@@ -59,7 +60,7 @@ public:
 	PlayerState():color(-1),currentSelection(0xffffffff){};
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & color & serial & currentSelection & fogOfWarMap & resources;
+		h & color & serial & human & currentSelection & fogOfWarMap & resources;
 
 		ui32 size;
 		if(h.saving) //write subids of available heroes

+ 31 - 7
CPlayerInterface.cpp

@@ -1049,9 +1049,11 @@ void TimeInterested::deactivate()
 CPlayerInterface::CPlayerInterface(int Player, int serial)
 {
 	LOCPLINT = this;
+	curint = NULL;
 	playerID=Player;
 	serialID=serial;
 	human=true;
+	castleInt = NULL;
 	adventureInt = NULL;
 	pim = new boost::recursive_mutex;
 	showingDialog = new CondSh<bool>(false);
@@ -1079,7 +1081,6 @@ void CPlayerInterface::init(ICallback * CB)
 {
 	cb = dynamic_cast<CCallback*>(CB);
 	adventureInt = new CAdvMapInt(playerID);
-	castleInt = NULL;
 	std::vector<const CGTownInstance*> tt = cb->getTownsInfo(false);
 	for(int i=0;i<tt.size();i++)
 	{
@@ -1112,12 +1113,27 @@ void CPlayerInterface::yourTurn()
 		adventureInt->select(adventureInt->townList.items[0]);
 	adventureInt->activate();
 
+
 	timeHandler th;
 	th.getDif();
 	for(;makingTurn;) // main loop
 	{
+
 		updateWater();
 		pim->lock();
+
+
+		//if there are any waiting dialogs, show them
+		if(dialogs.size())
+		{
+			dialogs.front()->buttons[0]->callback += boost::bind(&IActivable::activate,LOCPLINT->curint);
+			showingDialog->set(true);
+			curint->deactivate(); //dezaktywacja starego interfejsu
+			dialogs.front()->activate();
+			LOCPLINT->objsToBlit.push_back(dialogs.front());
+			dialogs.pop_front();
+		}
+
 		int tv = th.getDif();
 		std::list<TimeInterested*> hlp = timeinterested;
 		for (std::list<TimeInterested*>::iterator i=hlp.begin(); i != hlp.end();i++)
@@ -2279,19 +2295,27 @@ void CPlayerInterface::showInfoDialog(std::string &text, const std::vector<Compo
 		intComps.push_back(new SComponent(*components[i]));
 	showInfoDialog(text,intComps);
 }
+
 void CPlayerInterface::showInfoDialog(std::string &text, const std::vector<SComponent*> & components)
 {
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
-	showingDialog->set(true);
-	curint->deactivate(); //dezaktywacja starego interfejsu
 
 	std::vector<std::pair<std::string,CFunctionList<void()> > > pom;
 	pom.push_back(std::pair<std::string,CFunctionList<void()> >("IOKAY.DEF",0));
-	
 	CInfoWindow * temp = new CInfoWindow(text,playerID,32,components,pom);
-	temp->buttons[0]->callback += boost::bind(&IActivable::activate,LOCPLINT->curint);
-	temp->activate();
-	LOCPLINT->objsToBlit.push_back(temp);
+
+	if(makingTurn && curint)
+	{
+		temp->buttons[0]->callback += boost::bind(&IActivable::activate,LOCPLINT->curint);
+		showingDialog->set(true);
+		curint->deactivate(); //dezaktywacja starego interfejsu
+		temp->activate();
+		LOCPLINT->objsToBlit.push_back(temp);
+	}
+	else
+	{
+		dialogs.push_back(temp);
+	}
 }
 void CPlayerInterface::showYesNoDialog(std::string &text, const std::vector<SComponent*> & components, CFunctionList<void()> onYes, CFunctionList<void()> onNo, bool deactivateCur, bool DelComps)
 {

+ 2 - 0
CPlayerInterface.h

@@ -451,6 +451,8 @@ public:
 	CCallback * cb;
 	const BattleAction *curAction;
 
+	std::list<CInfoWindow *> dialogs;
+
 	//GUI elements
 	std::list<ClickableL*> lclickable;
 	std::list<ClickableR*> rclickable;

+ 4 - 3
client/Client.cpp

@@ -102,7 +102,7 @@ void CClient::waitForMoveAndSend(int color)
 	try
 	{
 		BattleAction ba = playerint[color]->activeStack(gs->curB->activeStack);
-		*serv << ui16(3002) << ba;
+		*serv << &MakeAction(ba);
 		return;
 	}HANDLE_EXCEPTION
 	tlog1 << "We should not be here!" << std::endl;
@@ -113,17 +113,18 @@ void CClient::run()
 	while(1)
 	{
 		*serv >> pack;
+		tlog5 << "Received server message of type " << typeid(*pack).name() << std::endl;
 		CBaseForCLApply *apply = applier->apps[typeList.getTypeID(pack)];
 		if(apply)
 		{
 			apply->applyOnClBefore(this,pack);
 			gs->apply(pack);
 			apply->applyOnClAfter(this,pack);
-			tlog5 << "Applied server message of type " << typeid(*pack).name() << std::endl;
+			tlog5 << "Message successfully applied!\n";
 		}
 		else
 		{
-			tlog1 << "Unknown server message. Type: " << pack->type << ". Typeinfo: " << typeid(*pack).name() << std::endl;
+			tlog5 << "Message cannot be applied, cannot find applier!\n";
 		}
 		delete pack;
 		pack = NULL;

+ 3 - 2
lib/NetPacks.h

@@ -472,7 +472,8 @@ struct NewTurn : public CPackForClient //101
 
 struct Component : public CPack //2002 helper for object scrips informations
 {
-	ui16 id, subtype; //ids: 0 - primskill; 1 - secskill; 2 - resource; 3 - creature; 4 - artifact; 5 - experience (sub==0 exp points; sub==1 levels)
+	enum {PRIM_SKILL,SEC_SKILL,RESOURCE,CREATURE,ARTIFACT,EXPERIENCE};
+	ui16 id, subtype; //id uses ^^^ enums, when id==EXPPERIENCE subtype==0 means exp points and subtype==1 levels)
 	si32 val; // + give; - take
 	si16 when; // 0 - now; +x - within x days; -x - per x days
 
@@ -1008,7 +1009,7 @@ struct QueryReply : public CPackForServer
 struct MakeAction : public CPackForServer
 {
 	MakeAction(){};
-	MakeAction(const BattleAction &BA):ba(ba){};
+	MakeAction(const BattleAction &BA):ba(BA){};
 	BattleAction ba;
 
 	void applyGh(CGameHandler *gh);

+ 15 - 13
map.cpp

@@ -567,6 +567,8 @@ Mapa::~Mapa()
 		}
 		delete [] terrain;
 	}
+	for(std::list<CMapEvent*>::iterator i = events.begin(); i != events.end(); i++)
+		delete *i;
 }
 
 CGHeroInstance * Mapa::getHero(int ID, int mode)
@@ -1833,34 +1835,34 @@ void Mapa::readEvents( unsigned char * bufor, int &i )
 	int numberOfEvents = readNormalNr(bufor,i); i+=4;
 	for(int yyoo=0; yyoo<numberOfEvents; ++yyoo)
 	{
-		CMapEvent ne;
-		ne.name = std::string();
-		ne.message = std::string();
+		CMapEvent *ne = new CMapEvent();
+		ne->name = std::string();
+		ne->message = std::string();
 		int nameLen = readNormalNr(bufor,i); i+=4;
 		for(int qq=0; qq<nameLen; ++qq)
 		{
-			ne.name += bufor[i]; ++i;
+			ne->name += bufor[i]; ++i;
 		}
 		int messLen = readNormalNr(bufor,i); i+=4;
 		for(int qq=0; qq<messLen; ++qq)
 		{
-			ne.message +=bufor[i]; ++i;
+			ne->message +=bufor[i]; ++i;
 		}
-		ne.resources.resize(RESOURCE_QUANTITY);
+		ne->resources.resize(RESOURCE_QUANTITY);
 		for(int k=0; k < 7; k++)
 		{
-			ne.resources[k] = readNormalNr(bufor,i); i+=4;
+			ne->resources[k] = readNormalNr(bufor,i); i+=4;
 		}
-		ne.players = bufor[i]; ++i;
+		ne->players = bufor[i]; ++i;
 		if(version>AB)
 		{
-			ne.humanAffected = bufor[i]; ++i;
+			ne->humanAffected = bufor[i]; ++i;
 		}
 		else
-			ne.humanAffected = true;
-		ne.computerAffected = bufor[i]; ++i;
-		ne.firstOccurence = bufor[i]; ++i;
-		ne.nextOccurence = bufor[i]; ++i;
+			ne->humanAffected = true;
+		ne->computerAffected = bufor[i]; ++i;
+		ne->firstOccurence = bufor[i]; ++i;
+		ne->nextOccurence = bufor[i]; ++i;
 		i+=18;
 		events.push_back(ne);
 	}

+ 5 - 18
map.h

@@ -53,23 +53,6 @@ public:
 	unsigned char player; //owner
 	unsigned char minLevel, maxLevel; //minimal and maximal level of creature in dwelling: <0, 6>
 };
-
-struct DLL_EXPORT Sresource
-{
-	std::string resName; //name of this resource
-	int amount; //it can be greater and lesser than 0
-};
-struct DLL_EXPORT TimeEvent
-{
-	std::string eventName;
-	std::string message;
-	std::vector<Sresource> decIncRes; //decreases / increases of resources
-	unsigned int whichPlayers; //which players are affected by this event (+1 - first, +2 - second, +4 - third, +8 - fourth etc.)
-	bool areHumansAffected;
-	bool areCompsAffected;
-	int firstAfterNDays; //how many days after appears this event
-	int nextAfterNDays; //how many days after the epperance before appaers this event
-};
 struct DLL_EXPORT TerrainTile
 {
 	EterrainType tertype; // type of terrain
@@ -197,6 +180,10 @@ public:
 		h & name & message & resources
 			& players & humanAffected & computerAffected & firstOccurence & nextOccurence;
 	}
+	bool operator<(const CMapEvent &b) const
+	{
+		return firstOccurence < b.firstOccurence;
+	}
 };
 class DLL_EXPORT CMapHeader
 {
@@ -297,7 +284,7 @@ struct DLL_EXPORT Mapa : public CMapHeader
 	std::vector<ui8> allowedArtifact; //allowedArtifact[artifact_ID] - if the artifact is allowed
 	std::vector<ui8> allowedAbilities; //allowedAbilities[ability_ID] - if the ability is allowed
 	std::vector<ui8> allowedHeroes; //allowedHeroes[hero_ID] - if the hero is allowed
-	std::list<CMapEvent> events;
+	std::list<CMapEvent*> events;
 
 	int3 grailPos;
 	int grailRadious;

+ 72 - 7
server/CGameHandler.cpp

@@ -52,14 +52,15 @@ std::map<ui32, CFunctionList<void(ui32)> > callbacks; //question id => callback
 class CBaseForGHApply
 {
 public:
-	virtual void applyOnGH(CGameHandler *gh, void *pack) const =0; 
+	virtual void applyOnGH(CGameHandler *gh, CConnection *c, void *pack) const =0; 
 };
 template <typename T> class CApplyOnGH : public CBaseForGHApply
 {
 public:
-	void applyOnGH(CGameHandler *gh, void *pack) const
+	void applyOnGH(CGameHandler *gh, CConnection *c, void *pack) const
 	{
 		T *ptr = static_cast<T*>(pack);
+		ptr->c = c;
 		ptr->applyGh(gh);
 	}
 };
@@ -495,22 +496,22 @@ void CGameHandler::prepareAttack(BattleAttack &bat, CStack *att, CStack *def)
 }
 void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
 {
-	CPackForServer *pack = NULL;
+	CPack *pack = NULL;
 	try
 	{
 		while(!end2)
 		{
 			c >> pack;
+			tlog5 << "Received client message of type " << typeid(*pack).name() << std::endl;
 			CBaseForGHApply *apply = applier->apps[typeList.getTypeID(pack)];
 			if(apply)
 			{
-				pack->c = &c;
-				apply->applyOnGH(this,pack);
-				tlog5 << "Applied client message of type " << typeid(*pack).name() << std::endl;
+				apply->applyOnGH(this,&c,pack);
+				tlog5 << "Message successfully applied!\n";
 			}
 			else
 			{
-				tlog1 << "Unknown client message. Type: " << pack->type << ". Typeinfo: " << typeid(*pack).name() << std::endl;
+				tlog5 << "Message cannot be applied, cannot find applier!\n";
 			}
 			delete pack;
 			pack = NULL;
@@ -638,6 +639,11 @@ void CGameHandler::init(StartInfo *si, int Seed)
 		states.addPlayer(i->first);
 }
 
+bool evntCmp(const CMapEvent *a, const CMapEvent *b)
+{
+	return *a < *b;
+}
+
 void CGameHandler::newTurn()
 {
 	tlog5 << "Turn " << gs->day+1 << std::endl;
@@ -724,6 +730,10 @@ void CGameHandler::newTurn()
 	}	
 	sendAndApply(&n);
 	tlog5 << "Info about turn " << n.day << "has been sent!" << std::endl;
+
+	handleTimeEvents();
+
+	//call objects
 	for(size_t i = 0; i<gs->map->objects.size(); i++)
 		if(gs->map->objects[i])
 			gs->map->objects[i]->newTurn();
@@ -2382,4 +2392,59 @@ if(getSchoolLevel(h,s) < 3)  /*not expert */ \
 			sendAndApply(&EndAction());
 		}
 	}
+}
+
+void CGameHandler::handleTimeEvents()
+{
+	while(gs->map->events.size() && gs->map->events.front()->firstOccurence+1 == gs->day)
+	{
+		CMapEvent *ev = gs->map->events.front();
+		for(int player = 0; player < PLAYER_LIMIT; player++)
+		{
+			PlayerState *pinfo = gs->getPlayer(player);
+
+			if( pinfo  //player exists
+				&& (ev->players & 1<<player) //event is enabled to this player
+				&& ((ev->computerAffected && !pinfo->human) 
+				|| (ev->humanAffected && pinfo->human)
+				)
+				)
+			{
+				//give resources
+				SetResources sr;
+				sr.player = player;
+				sr.res = pinfo->resources;
+
+				//prepare dialog
+				InfoWindow iw;
+				iw.player = player;
+				iw.text << ev->message;
+				for (int i=0; i<ev->resources.size(); i++)
+				{
+					if(ev->resources[i]) //if resource is changed, we add it to the dialog
+					{
+						iw.components.push_back(Component(Component::RESOURCE,i,ev->resources[i],0));
+						sr.res[i] += ev->resources[i];
+					}
+				}
+				if (iw.components.size())
+				{
+					sendAndApply(&sr); //update player resources if changed
+				}
+
+				sendAndApply(&iw); //show dialog
+			}
+		} //PLAYERS LOOP
+
+		if(ev->nextOccurence)
+		{
+			ev->firstOccurence += ev->nextOccurence;
+			gs->map->events.sort(evntCmp);
+		}
+		else
+		{
+			delete ev;
+			gs->map->events.pop_front();
+		}
+	}
 }

+ 1 - 0
server/CGameHandler.h

@@ -132,6 +132,7 @@ public:
 	void arrangeStacks( si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, si32 val );
 	void save(const std::string &fname);
 	void close();
+	void handleTimeEvents();
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{

+ 3 - 3
server/NetPacksServer.cpp

@@ -3,7 +3,7 @@
 
 
 #define PLAYER_OWNS(id) (gh->getPlayerAt(c)==gh->getOwner(id))
-#define ERROR_AND_RETURN	{if(c) *c << &SystemMessage("You don't own this object!");	\
+#define ERROR_AND_RETURN	{if(c) *c << &SystemMessage("You are not allowed to perform this action!");	\
 							tlog1<<"Player is not allowed to perform this action!\n";	\
 							return;}
 #define ERROR_IF_NOT_OWNS(id)	if(!PLAYER_OWNS(id)) ERROR_AND_RETURN
@@ -117,13 +117,13 @@ void QueryReply::applyGh( CGameHandler *gh )
 
 void MakeAction::applyGh( CGameHandler *gh )
 {
-	if(gh->getPlayerAt(c) != GS(gh)->curB->getStack(GS(gh)->curB->activeStack)->owner) ERROR_AND_RETURN;
+	if(gh->connections[GS(gh)->curB->getStack(GS(gh)->curB->activeStack)->owner] != c) ERROR_AND_RETURN;
 	gh->makeBattleAction(ba);
 }
 
 void MakeCustomAction::applyGh( CGameHandler *gh )
 {
-	if(gh->getPlayerAt(c) != GS(gh)->curB->getStack(GS(gh)->curB->activeStack)->owner) ERROR_AND_RETURN;
+	if(gh->connections[GS(gh)->curB->getStack(GS(gh)->curB->activeStack)->owner] != c) ERROR_AND_RETURN;
 	gh->makeCustomAction(ba);
 }