diff --git a/CCallback.cpp b/CCallback.cpp index a63897533..e6a595a25 100644 --- a/CCallback.cpp +++ b/CCallback.cpp @@ -58,6 +58,7 @@ bool CCallback::moveHero(const CGHeroInstance *h, int3 dst) void CCallback::selectionMade(int selection, int asker) { QueryReply pack(asker,selection); + boost::unique_lock lock(*cl->serv->wmx); *cl->serv << &pack; } void CCallback::recruitCreatures(const CGObjectInstance *obj, ui32 ID, ui32 amount, si32 level/*=-1*/) @@ -188,9 +189,12 @@ void CBattleCallback::sendRequest(const T* request) //TODO? should be part of CClient but it would have to be very tricky cause template/serialization issues if(waitTillRealize) - cl->waitingRequest.set(true); + cl->waitingRequest.set(typeList.getTypeID()); - *cl->serv << request; + { + boost::unique_lock lock(*cl->serv->wmx); + *cl->serv << request; + } if(waitTillRealize) { diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index 3a420cf61..c166e2681 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -238,6 +238,13 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details) const CGHeroInstance * ho = cb->getHero(details.id); //object representing this hero int3 hp = details.start; + if(!ho) + { + //AI hero left the visible area (we can't obtain info) + //TODO - probably needs some handling + return; + } + adventureInt->centerOn(ho); //actualizing screen pos adventureInt->minimap.draw(screen2); adventureInt->heroList.draw(screen2); diff --git a/client/Client.cpp b/client/Client.cpp index 58c1780c1..0d299ddd6 100644 --- a/client/Client.cpp +++ b/client/Client.cpp @@ -100,13 +100,13 @@ void CClient::init() } CClient::CClient(void) -:waitingRequest(false) +:waitingRequest(0) { init(); } CClient::CClient(CConnection *con, StartInfo *si) -:waitingRequest(false) +:waitingRequest(0) { init(); newGame(con,si); @@ -431,19 +431,19 @@ void CClient::newGame( CConnection *con, StartInfo *si ) serv->addStdVecItems(const_cast(CGI)->state); hotSeat = (humanPlayers > 1); - std::vector scriptModules; - CFileUtility::getFilesWithExt(scriptModules, LIB_DIR "/Scripting", "." LIB_EXT); - BOOST_FOREACH(FileInfo &m, scriptModules) - { - CScriptingModule * nm = CDynLibHandler::getNewScriptingModule(m.name); - privilagedGameEventReceivers.push_back(nm); - privilagedBattleEventReceivers.push_back(nm); - nm->giveActionCB(this); - nm->giveInfoCB(this); - nm->init(); - - erm = nm; //something tells me that there'll at most one module and it'll be ERM - } +// std::vector scriptModules; +// CFileUtility::getFilesWithExt(scriptModules, LIB_DIR "/Scripting", "." LIB_EXT); +// BOOST_FOREACH(FileInfo &m, scriptModules) +// { +// CScriptingModule * nm = CDynLibHandler::getNewScriptingModule(m.name); +// privilagedGameEventReceivers.push_back(nm); +// privilagedBattleEventReceivers.push_back(nm); +// nm->giveActionCB(this); +// nm->giveInfoCB(this); +// nm->init(); +// +// erm = nm; //something tells me that there'll at most one module and it'll be ERM +// } } template @@ -585,8 +585,8 @@ void CClient::battleStarted(const BattleInfo * info) else def = NULL; - - new CBattleInterface(info->belligerents[0], info->belligerents[1], info->heroes[0], info->heroes[1], Rect((conf.cc.resx - 800)/2, (conf.cc.resy - 600)/2, 800, 600), att, def); + if(att || def || gs->scenarioOps->mode == StartInfo::DUEL) + new CBattleInterface(info->belligerents[0], info->belligerents[1], info->heroes[0], info->heroes[1], Rect((conf.cc.resx - 800)/2, (conf.cc.resy - 600)/2, 800, 600), att, def); if(vstd::contains(battleints,info->sides[0])) battleints[info->sides[0]]->battleStart(info->belligerents[0], info->belligerents[1], info->tile, info->heroes[0], info->heroes[1], 0); diff --git a/client/Client.h b/client/Client.h index 30519cdd2..5f1a57f0d 100644 --- a/client/Client.h +++ b/client/Client.h @@ -78,7 +78,7 @@ public: CScriptingModule *erm; - CondSh waitingRequest; + CondSh waitingRequest; std::queue packs; boost::mutex packsM; diff --git a/client/NetPacksClient.cpp b/client/NetPacksClient.cpp index 3affd4f04..11ec3778b 100644 --- a/client/NetPacksClient.cpp +++ b/client/NetPacksClient.cpp @@ -709,7 +709,7 @@ void PackageApplied::applyCl( CClient *cl ) { ui8 player = GS(cl)->currentPlayer; INTERFACE_CALL_IF_PRESENT(player, requestRealized, this); - if(cl->waitingRequest.get()) + if(cl->waitingRequest.get() == packType) cl->waitingRequest.setn(false); } @@ -730,6 +730,7 @@ void PlayerBlocked::applyCl( CClient *cl ) void YourTurn::applyCl( CClient *cl ) { + CALL_IN_ALL_INTERFACES(playerStartsTurn, player); CALL_ONLY_THAT_INTERFACE(player,yourTurn); } diff --git a/lib/CGameInterface.h b/lib/CGameInterface.h index c68e51e53..887a7eef0 100644 --- a/lib/CGameInterface.h +++ b/lib/CGameInterface.h @@ -74,7 +74,7 @@ class CGameInterface : public CBattleGameInterface, public IGameEventsReceiver { public: virtual void init(CCallback * CB){}; - virtual void yourTurn(){}; + virtual void yourTurn(){}; //called AFTER playerStartsTurn(player) virtual void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector &skills, boost::function &callback)=0; //pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id virtual void showBlockingDialog(const std::string &text, const std::vector &components, ui32 askID, const int soundID, bool selection, bool cancel) = 0; //Show a dialog, player must take decision. If selection then he has to choose between one of given components, if cancel he is allowed to not choose. After making choice, CCallback::selectionMade should be called with number of selected component (1 - n) or 0 for cancel (if allowed) and askID. virtual void showGarrisonDialog(const CArmedInstance *up, const CGHeroInstance *down, bool removableUnits, boost::function &onEnd) = 0; //all stacks operations between these objects become allowed, interface has to call onEnd when done diff --git a/lib/Connection.h b/lib/Connection.h index 66ce3c640..8e94ff238 100644 --- a/lib/Connection.h +++ b/lib/Connection.h @@ -99,7 +99,7 @@ public: } ui16 getTypeID(const std::type_info *type); - template ui16 getTypeID(const T * t) + template ui16 getTypeID(const T * t = NULL) { return getTypeID(getTypeInfo(t)); } diff --git a/lib/IGameEventsReceiver.h b/lib/IGameEventsReceiver.h index e182d2939..f99b4a1be 100644 --- a/lib/IGameEventsReceiver.h +++ b/lib/IGameEventsReceiver.h @@ -110,4 +110,5 @@ public: virtual void objectRemoved(const CGObjectInstance *obj){}; //eg. collected resource, picked artifact, beaten hero virtual void playerBlocked(int reason){}; //reason: 0 - upcoming battle virtual void gameOver(ui8 player, bool victory){}; //player lost or won the game + virtual void playerStartsTurn(ui8 player){}; }; \ No newline at end of file diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index a129a4344..7155b8732 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -646,15 +646,12 @@ void CGameHandler::handleConnection(std::set players, CConnection &c) tlog5 << "Message successfully applied (result=" << result << ")!\n"; //send confirmation that we've applied the package - if(pack->type != 6000) //WORKAROUND - not confirm query replies TODO: reconsider + PackageApplied applied; + applied.result = result; + applied.packType = packType; { - PackageApplied applied; - applied.result = result; - applied.packType = packType; - { - boost::unique_lock lock(*c.wmx); - c << &applied; - } + boost::unique_lock lock(*c.wmx); + c << &applied; } } else @@ -1757,6 +1754,7 @@ void CGameHandler::sendMessageTo( CConnection &c, const std::string &message ) { SystemMessage sm; sm.text = message; + boost::unique_lock lock(*c.wmx); c << &sm; } @@ -1925,9 +1923,8 @@ void CGameHandler::sendToAllClients( CPackForClient * info ) tlog5 << "Sending to all clients a package of type " << typeid(*info).name() << std::endl; for(std::set::iterator i=conns.begin(); i!=conns.end();i++) { - (*i)->wmx->lock(); + boost::unique_lock lock(*(*i)->wmx); **i << info; - (*i)->wmx->unlock(); } } diff --git a/server/NetPacksServer.cpp b/server/NetPacksServer.cpp index ca6e5de89..74af058da 100644 --- a/server/NetPacksServer.cpp +++ b/server/NetPacksServer.cpp @@ -65,7 +65,11 @@ bool CloseServer::applyGh( CGameHandler *gh ) bool EndTurn::applyGh( CGameHandler *gh ) { - ERROR_IF_NOT(GS(gh)->currentPlayer); + int player = GS(gh)->currentPlayer; + ERROR_IF_NOT(player); + if(gh->states.checkFlag(player, &PlayerStatus::engagedIntoBattle)) + COMPLAIN_AND_RETURN("Cannot end turn when in battle!"); + gh->states.setFlag(GS(gh)->currentPlayer,&PlayerStatus::makingTurn,false); return true; }