diff --git a/AI/GeniusAI/BattleLogic.cpp b/AI/GeniusAI/BattleLogic.cpp index b661aca61..8ca4baca6 100644 --- a/AI/GeniusAI/BattleLogic.cpp +++ b/AI/GeniusAI/BattleLogic.cpp @@ -39,7 +39,7 @@ ui8 side; //who made this action: false - left, true - right player */ CBattleLogic::CBattleLogic(ICallback *cb, CCreatureSet *army1, CCreatureSet *army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, bool side) : m_iCurrentTurn(-2), - m_bIsAttacker(false), + m_bIsAttacker(!side), m_cb(cb), m_army1(army1), m_army2(army2), @@ -261,7 +261,7 @@ BattleAction CBattleLogic::MakeDecision(int stackID) MakeStatistics(stackID); list creatures; - int additionalInfo; + int additionalInfo = 0; //? if (m_bEnemyDominates) { diff --git a/client/CAdvmapInterface.cpp b/client/CAdvmapInterface.cpp index c6f83765e..759161e61 100644 --- a/client/CAdvmapInterface.cpp +++ b/client/CAdvmapInterface.cpp @@ -710,138 +710,140 @@ void CTerrainRect::mouseMoved (const SDL_MouseMotionEvent & sEvent) int turns = pnode->turns; amin(turns, 3); - if(LOCPLINT->adventureInt->selection->ID == TOWNI_TYPE) + if(LOCPLINT->adventureInt->selection) { - if(obj) + if(LOCPLINT->adventureInt->selection->ID == TOWNI_TYPE) { - if(obj->ID == TOWNI_TYPE) + if(obj) { - CGI->curh->changeGraphic(0, 3); + if(obj->ID == TOWNI_TYPE) + { + CGI->curh->changeGraphic(0, 3); + } + else if(obj->ID == HEROI_TYPE) + { + CGI->curh->changeGraphic(0, 2); + } } - else if(obj->ID == HEROI_TYPE) + else { - CGI->curh->changeGraphic(0, 2); + CGI->curh->changeGraphic(0, 0); } } - else + else if(LOCPLINT->adventureInt->selection->ID == HEROI_TYPE) { - CGI->curh->changeGraphic(0, 0); - } - } - else if(LOCPLINT->adventureInt->selection->ID == HEROI_TYPE) - { - const CGHeroInstance *h = static_cast(LOCPLINT->adventureInt->selection); - if(obj) - { - if(obj->ID == HEROI_TYPE) + const CGHeroInstance *h = static_cast(LOCPLINT->adventureInt->selection); + if(obj) { - if(obj->tempOwner != LOCPLINT->playerID) //enemy hero TODO: allies + if(obj->ID == HEROI_TYPE) + { + if(obj->tempOwner != LOCPLINT->playerID) //enemy hero TODO: allies + { + if(accessible) + CGI->curh->changeGraphic(0, 5 + turns*6); + else + CGI->curh->changeGraphic(0, 0); + } + else //our hero + { + if(LOCPLINT->adventureInt->selection == obj) + CGI->curh->changeGraphic(0, 2); + else if(accessible) + CGI->curh->changeGraphic(0, 8 + turns*6); + else + CGI->curh->changeGraphic(0, 2); + } + } + else if(obj->ID == TOWNI_TYPE) + { + if(obj->tempOwner != LOCPLINT->playerID) //enemy town TODO: allies + { + if(accessible) { + const CGTownInstance* townObj = dynamic_cast(obj); + + // Show movement cursor for unguarded enemy towns, otherwise attack cursor. + if (townObj && townObj->army.slots.empty()) + CGI->curh->changeGraphic(0, 9 + turns*6); + else + CGI->curh->changeGraphic(0, 5 + turns*6); + + } else { + CGI->curh->changeGraphic(0, 0); + } + } + else //our town + { + if(accessible) + CGI->curh->changeGraphic(0, 9 + turns*6); + else + CGI->curh->changeGraphic(0, 3); + } + } + else if(obj->ID == 54) //monster { if(accessible) CGI->curh->changeGraphic(0, 5 + turns*6); else CGI->curh->changeGraphic(0, 0); } - else //our hero + else if(obj->ID == 8) //boat { - if(LOCPLINT->adventureInt->selection == obj) - CGI->curh->changeGraphic(0, 2); - else if(accessible) - CGI->curh->changeGraphic(0, 8 + turns*6); + if(accessible) + CGI->curh->changeGraphic(0, 6 + turns*6); else - CGI->curh->changeGraphic(0, 2); + CGI->curh->changeGraphic(0, 0); } - } - else if(obj->ID == TOWNI_TYPE) - { - if(obj->tempOwner != LOCPLINT->playerID) //enemy town TODO: allies + else if (obj->ID == 33 || obj->ID == 219) // Garrison { - if(accessible) { - const CGTownInstance* townObj = dynamic_cast(obj); + if (accessible) { + const CGGarrison* garrObj = dynamic_cast(obj); - // Show movement cursor for unguarded enemy towns, otherwise attack cursor. - if (townObj && townObj->army.slots.empty()) - CGI->curh->changeGraphic(0, 9 + turns*6); - else + // Show battle cursor for guarded enemy garrisons, otherwise movement cursor. + if (garrObj && garrObj->tempOwner != LOCPLINT->playerID + && !garrObj->army.slots.empty()) + { CGI->curh->changeGraphic(0, 5 + turns*6); - + } + else + { + CGI->curh->changeGraphic(0, 9 + turns*6); + } } else { CGI->curh->changeGraphic(0, 0); } } - else //our town + else { if(accessible) - CGI->curh->changeGraphic(0, 9 + turns*6); - else - CGI->curh->changeGraphic(0, 3); - } - } - else if(obj->ID == 54) //monster - { - if(accessible) - CGI->curh->changeGraphic(0, 5 + turns*6); - else - CGI->curh->changeGraphic(0, 0); - } - else if(obj->ID == 8) //boat - { - if(accessible) - CGI->curh->changeGraphic(0, 6 + turns*6); - else - CGI->curh->changeGraphic(0, 0); - } - else if (obj->ID == 33 || obj->ID == 219) // Garrison - { - if (accessible) { - const CGGarrison* garrObj = dynamic_cast(obj); - - // Show battle cursor for guarded enemy garrisons, otherwise movement cursor. - if (garrObj && garrObj->tempOwner != LOCPLINT->playerID - && !garrObj->army.slots.empty()) { - CGI->curh->changeGraphic(0, 5 + turns*6); + if(pnode->land) + CGI->curh->changeGraphic(0, 9 + turns*6); + else + CGI->curh->changeGraphic(0, 28 + turns); } else - { - CGI->curh->changeGraphic(0, 9 + turns*6); - } - } else { - CGI->curh->changeGraphic(0, 0); + CGI->curh->changeGraphic(0, 0); } - } - else + } + else //no objs { if(accessible) { if(pnode->land) - CGI->curh->changeGraphic(0, 9 + turns*6); + { + if(LOCPLINT->cb->getTileInfo(h->getPosition(false))->tertype != TerrainTile::water) + CGI->curh->changeGraphic(0, 4 + turns*6); + else + CGI->curh->changeGraphic(0, 7 + turns*6); //anchor + } else - CGI->curh->changeGraphic(0, 28 + turns); + CGI->curh->changeGraphic(0, 6 + turns*6); } else CGI->curh->changeGraphic(0, 0); } - } - else //no objs - { - if(accessible) - { - if(pnode->land) - { - if(LOCPLINT->cb->getTileInfo(h->getPosition(false))->tertype != TerrainTile::water) - CGI->curh->changeGraphic(0, 4 + turns*6); - else - CGI->curh->changeGraphic(0, 7 + turns*6); //anchor - } - else - CGI->curh->changeGraphic(0, 6 + turns*6); - } - else - CGI->curh->changeGraphic(0, 0); } } - //tlog1 << "Tile " << pom << ": Turns=" << (int)pnode->turns <<" Move:=" << pnode->moveRemains <w; pos.h = screen->h; - active = 0; selection = NULL; townList.fun = boost::bind(&CAdvMapInt::selectionChanged,this); LOCPLINT->adventureInt=this; @@ -1631,14 +1632,14 @@ void CAdvMapInt::fnextHero() void CAdvMapInt::fendTurn() { LOCPLINT->makingTurn = false; + LOCPLINT->cb->endTurn(); } void CAdvMapInt::activate() { - if(active++) + if(isActive()) { tlog1 << "Error: advmapint already active...\n"; - active--; return; } screenBuf = screen; @@ -1689,12 +1690,6 @@ void CAdvMapInt::deactivate() infoBar.mode=-1; LOCPLINT->cingconsole->deactivate(); - - if(--active) - { - tlog1 << "Error: advmapint still active...\n"; - deactivate(); - } } void CAdvMapInt::showAll(SDL_Surface *to) { @@ -1807,16 +1802,16 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key) switch(k) { case SDLK_i: - if(active) + if(isActive()) CAdventureOptions::showScenarioInfo(); return; case SDLK_s: - if(active) + if(isActive()) GH.pushInt(new CSelectionScreen(saveGame)); return; case SDLK_SPACE: //space - try to revisit current object with selected hero { - if(!active) + if(!isActive()) return; const CGHeroInstance *h = dynamic_cast(selection); if(h && key.state == SDL_PRESSED) @@ -1829,7 +1824,7 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key) return; case SDLK_RETURN: { - if(!active || !selection || key.state != SDL_PRESSED) + if(!isActive() || !selection || key.state != SDL_PRESSED) return; if(selection->ID == HEROI_TYPE) LOCPLINT->openHeroWindow(static_cast(selection)); @@ -1883,7 +1878,7 @@ void CAdvMapInt::keyPressed(const SDL_KeyboardEvent & key) k = arrowToNum(SDLKey(k)); } - if(!active || LOCPLINT->ctrlPressed())//ctrl makes arrow move screen, not hero + if(!isActive() || LOCPLINT->ctrlPressed())//ctrl makes arrow move screen, not hero break; k -= SDLK_KP0 + 1; @@ -2003,7 +1998,7 @@ void CAdvMapInt::select(const CArmedInstance *sel ) void CAdvMapInt::mouseMoved( const SDL_MouseMotionEvent & sEvent ) { //adventure map scrolling with mouse - if(!SDL_GetKeyState(NULL)[SDLK_LCTRL] && active) + if(!SDL_GetKeyState(NULL)[SDLK_LCTRL] && isActive()) { if(sEvent.x<15) { @@ -2040,6 +2035,11 @@ void CAdvMapInt::mouseMoved( const SDL_MouseMotionEvent & sEvent ) } } +bool CAdvMapInt::isActive() +{ + return active & ~CIntObject.KEYBOARD; +} + CAdventureOptions::CAdventureOptions() { OBJ_CONSTRUCTION_CAPTURING_ALL; diff --git a/client/CAdvmapInterface.h b/client/CAdvmapInterface.h index bcb20e7c1..8d392ce74 100644 --- a/client/CAdvmapInterface.h +++ b/client/CAdvmapInterface.h @@ -138,7 +138,7 @@ public: ~CAdvMapInt(); int3 position; //top left corner of visible map part - int player, active; + int player; enum{LEFT=1, RIGHT=2, UP=4, DOWN=8}; @@ -202,5 +202,6 @@ public: void handleRightClick(std::string text, tribool down, CIntObject * client); void keyPressed(const SDL_KeyboardEvent & key); void mouseMoved (const SDL_MouseMotionEvent & sEvent); + bool isActive(); }; #endif // __CADVMAPINTERFACE_H__ diff --git a/client/CBattleInterface.cpp b/client/CBattleInterface.cpp index e6a6e5227..a443da1d6 100644 --- a/client/CBattleInterface.cpp +++ b/client/CBattleInterface.cpp @@ -2327,13 +2327,13 @@ void CBattleInterface::hexLclicked(int whichOne) giveCommand(9,whichOne,activeStack); } } - else if(dest->owner != attackingHeroInstance->tempOwner + else if(dest->owner != actSt->owner && LOCPLINT->cb->battleCanShoot(activeStack, whichOne) ) //shooting { CGI->curh->changeGraphic(1, 6); //cursor should be changed giveCommand(7,whichOne,activeStack); } - else if(dest->owner != attackingHeroInstance->tempOwner) //attacking + else if(dest->owner != actSt->owner) //attacking { const CStack * actStack = LOCPLINT->cb->battleGetStackByID(activeStack); int attackFromHex = -1; //hex from which we will attack chosen stack diff --git a/client/CMT.cpp b/client/CMT.cpp index 15c9a0fdb..a3d640715 100644 --- a/client/CMT.cpp +++ b/client/CMT.cpp @@ -69,7 +69,7 @@ static CClient *client; SDL_Surface *screen = NULL, //main screen surface *screen2 = NULL,//and hlp surface (used to store not-active interfaces layer) *screenBuf = screen; //points to screen (if only advmapint is present) or screen2 (else) - should be used when updating controls which are not regularly redrawed -static boost::thread *hhh; +static boost::thread *mainGUIThread; SystemOptions GDefaultOptions; VCMIDirs GVCMIDirs; @@ -214,8 +214,8 @@ int main(int argc, char** argv) CGI->musich->playMusic(musicBase::mainMenu, -1); - new CGPreGame; //will set CGP pointer to itself - hhh = new boost::thread(&CGPreGame::run, CGP); + GH.curInt = new CGPreGame; //will set CGP pointer to itself + mainGUIThread = new boost::thread(&CGuiHandler::run, boost::ref(GH)); listenForEvents(); return 0; @@ -472,18 +472,18 @@ static void listenForEvents() { if (client) client->stop(); - if (hhh) { - CGP->terminate = true; - hhh->join(); - delete hhh; - hhh = NULL; + if (mainGUIThread) + { + GH.terminate = true; + mainGUIThread->join(); + delete mainGUIThread; + mainGUIThread = NULL; } delete console; console = NULL; SDL_Delay(750); SDL_Quit(); tlog0 << "Ending...\n"; - break; } else if(LOCPLINT && ev->type == SDL_KEYDOWN && ev->key.keysym.sym==SDLK_F4) @@ -501,9 +501,12 @@ static void listenForEvents() delete ev; continue; } - else if (ev->type == SDL_USEREVENT && ev->user.code == 2) { + else if (ev->type == SDL_USEREVENT && ev->user.code == 2) + { client->stop(); delete ev; + + GH.curInt = CGP; continue; } @@ -517,6 +520,7 @@ static void listenForEvents() void startGame(StartInfo * options) { + GH.curInt =NULL; if(gOnlyAI) { for (size_t i =0; i < options->playerInfos.size(); i++) @@ -534,22 +538,18 @@ void startGame(StartInfo * options) SDL_PushEvent(&ev); } - CClient cl; + client = new CClient; if(options->mode == 0) //new game { - cl.newGame(NULL, options); + client->newGame(NULL, options); } else //load game { std::string fname = options->mapname; boost::algorithm::erase_last(fname,".vlgm1"); - cl.loadGame(fname); + client->loadGame(fname); } - client = &cl; CGI->musich->stopMusic(); - client->run(); - LOCPLINT->terminate_cond.waitUntil(true); - client->endGame(); - client = NULL; + client->connectionHandler = new boost::thread(&CClient::run, client); } diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index d40cb23fe..a2a4f1557 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -40,6 +40,8 @@ #include #include #include +#include + #ifdef min #undef min #endif @@ -102,12 +104,16 @@ CPlayerInterface::CPlayerInterface(int Player, int serial) cingconsole = new CInGameConsole; terminate = false; terminate_cond.set(false); + firstCall = 1; //if loading will be overwritten in serialize + autosaveCount = 0; } CPlayerInterface::~CPlayerInterface() { delete pim; delete showingDialog; delete mainFPSmng; + if(adventureInt->active & CIntObject::KEYBOARD) + adventureInt->deactivateKeys(); delete adventureInt; delete cingconsole; @@ -135,90 +141,58 @@ void CPlayerInterface::init(ICallback * CB) } void CPlayerInterface::yourTurn() { - try + LOCPLINT = this; + makingTurn = true; + + if(firstCall) { - LOCPLINT = this; - makingTurn = true; - - static bool firstCall = true; - static int autosaveCount = 0; - - if(firstCall) - firstCall = false; - else - LOCPLINT->cb->save("Autosave_" + boost::lexical_cast(autosaveCount++ + 1)); - - autosaveCount %= 5; - - for(std::map::iterator i=graphics->heroWins.begin(); i!=graphics->heroWins.end();i++) //redraw hero infoboxes - SDL_FreeSurface(i->second); - graphics->heroWins.clear(); - std::vector hh = cb->getHeroesInfo(false); - for(int i=0;iheroWins.insert(std::pair(hh[i]->subID,pom)); - } - - /* TODO: This isn't quite right. First day in game should play - * NEWDAY. And we don't play NEWMONTH. */ - int day = cb->getDate(1); - if (day != 1) - CGI->soundh->playSound(soundBase::newDay); - else - CGI->soundh->playSound(soundBase::newWeek); - - adventureInt->infoBar.newDay(day); - - //select first hero if available. - //TODO: check if hero is slept - if(wanderingHeroes.size()) - adventureInt->select(wanderingHeroes[0]); - else - adventureInt->select(adventureInt->townList.items[0]); - - adventureInt->showAll(screen); + autosaveCount = getLastIndex("Autosave_"); GH.pushInt(adventureInt); adventureInt->activateKeys(); - - while(makingTurn) // main loop + if(firstCall > 0) //new game, not laoded { - if (terminate) - break; - - pim->lock(); - - //if there are any waiting dialogs, show them - if(dialogs.size() && !showingDialog->get()) - { - showingDialog->set(true); - GH.pushInt(dialogs.front()); - dialogs.pop_front(); - } - - GH.updateTime(); - GH.handleEvents(); - - if(!adventureInt->active && adventureInt->scrollingDir) //player forces map scrolling though interface is disabled - GH.totalRedraw(); - else - GH.simpleRedraw(); - - CGI->curh->draw1(); - CSDL_Ext::update(screen); - CGI->curh->draw2(); - pim->unlock(); - SDL_framerateDelay(mainFPSmng); + int index = getLastIndex("Newgame_Autosave_"); + index %= SAVES_COUNT; + cb->save("Newgame_Autosave_" + boost::lexical_cast(index + 1)); } + firstCall = 0; + } + else + { + LOCPLINT->cb->save("Autosave_" + boost::lexical_cast(autosaveCount++ + 1)); + autosaveCount %= 5; + } - adventureInt->deactivateKeys(); - GH.popInt(adventureInt); + for(std::map::iterator i=graphics->heroWins.begin(); i!=graphics->heroWins.end();i++) //redraw hero infoboxes + SDL_FreeSurface(i->second); + graphics->heroWins.clear(); + std::vector hh = cb->getHeroesInfo(false); + for(int i=0;iheroWins.insert(std::pair(hh[i]->subID,pom)); + } - cb->endTurn(); - } HANDLE_EXCEPTION; + /* TODO: This isn't quite right. First day in game should play + * NEWDAY. And we don't play NEWMONTH. */ + int day = cb->getDate(1); + if (day != 1) + CGI->soundh->playSound(soundBase::newDay); + else + CGI->soundh->playSound(soundBase::newWeek); - if (terminate) - terminate_cond.set(true); + adventureInt->infoBar.newDay(day); + + //select first hero if available. + //TODO: check if hero is slept + if(wanderingHeroes.size()) + adventureInt->select(wanderingHeroes[0]); + else + adventureInt->select(adventureInt->townList.items[0]); + + adventureInt->showAll(screen); + + GH.curInt = this; } inline void subRect(const int & x, const int & y, const int & z, const SDL_Rect & r, const int & hid) @@ -1338,6 +1312,7 @@ void CPlayerInterface::serialize( CISer &h, const int version ) { serializeTempl(h,version); sysOpts.apply(); + firstCall = -1; } void CPlayerInterface::redrawHeroWin(const CGHeroInstance * hero) @@ -1526,7 +1501,7 @@ void CPlayerInterface::centerView (int3 pos, int focusTime) LOCPLINT->adventureInt->centerOn (pos); if(focusTime) { - bool activeAdv = (GH.topInt() == adventureInt && adventureInt->active); + bool activeAdv = (GH.topInt() == adventureInt && adventureInt->isActive()); if(activeAdv) adventureInt->deactivate(); @@ -1551,6 +1526,64 @@ bool CPlayerInterface::ctrlPressed() const return SDL_GetKeyState(NULL)[SDLK_LCTRL] || SDL_GetKeyState(NULL)[SDLK_RCTRL]; } +void CPlayerInterface::update() +{ + pim->lock(); + + //if there are any waiting dialogs, show them + if(dialogs.size() && !showingDialog->get()) + { + showingDialog->set(true); + GH.pushInt(dialogs.front()); + dialogs.pop_front(); + } + + GH.updateTime(); + GH.handleEvents(); + + if(!adventureInt->isActive() && adventureInt->scrollingDir) //player forces map scrolling though interface is disabled + GH.totalRedraw(); + else + GH.simpleRedraw(); + + CGI->curh->draw1(); + CSDL_Ext::update(screen); + CGI->curh->draw2(); + + pim->unlock(); + + SDL_framerateDelay(mainFPSmng); +} + +int CPlayerInterface::getLastIndex( std::string namePrefix) +{ + using namespace boost::filesystem; + using namespace boost::algorithm; + + std::map dates; //save number => datestamp + + directory_iterator enddir; + for (directory_iterator dir(DATA_DIR "/Games"); dir!=enddir; dir++) + { + if(is_regular(dir->status())) + { + std::string name = dir->path().leaf(); + if(starts_with(name, namePrefix) && ends_with(name, ".vlgm1")) + { + char nr = name[namePrefix.size()]; + if(std::isdigit(nr)) + { + dates[last_write_time(dir->path())] = boost::lexical_cast(nr); + } + } + } + } + + if(dates.size()) + return (--dates.end())->second; //return latest file number + return 0; +} + void SystemOptions::setMusicVolume( int newVolume ) { musicVolume = newVolume; diff --git a/client/CPlayerInterface.h b/client/CPlayerInterface.h index f424a6d47..cb2a08d42 100644 --- a/client/CPlayerInterface.h +++ b/client/CPlayerInterface.h @@ -7,6 +7,7 @@ #include #include #include +#include "GUIBase.h" #ifdef __GNUC__ #define sprintf_s snprintf @@ -106,7 +107,7 @@ struct SystemOptions extern SystemOptions GDefaultOptions; //defined and inited in CMT.cpp, stores default settings loaded with application -class CPlayerInterface : public CGameInterface +class CPlayerInterface : public CGameInterface, public IUpdateable { public: //minor interfaces @@ -114,6 +115,9 @@ public: boost::recursive_mutex *pim; bool makingTurn; //if player is already making his turn + int firstCall; // -1 - just loaded game; 1 - just started game; 0 otherwise + int autosaveCount; + static const int SAVES_COUNT = 5; SystemOptions sysOpts; @@ -131,8 +135,11 @@ public: std::vector wanderingHeroes; //our heroes on the adventure map (not the garrisoned ones) + + void update(); void recreateWanderingHeroes(); const CGHeroInstance *getWHero(int pos); //returns NULL if position is not valid + int getLastIndex(std::string namePrefix); //overloaded funcs from CGameInterface void buildChanged(const CGTownInstance *town, int buildingID, int what); //what: 1 - built, 2 - demolished diff --git a/client/CPreGame.cpp b/client/CPreGame.cpp index 07081c660..4289128c9 100644 --- a/client/CPreGame.cpp +++ b/client/CPreGame.cpp @@ -122,38 +122,11 @@ void CMenuScreen::moveTo( CMenuScreen *next ) GH.pushInt(next); } -void CGPreGame::run() -{ - GH.handleEvents(); - - while(!terminate) - { - if (GH.listInt.size() == 0) - { - #ifdef _WIN32 - CGI->videoh->open("ACREDIT.SMK"); - #else - CGI->videoh->open("ACREDIT.SMK", true, false); - #endif - GH.pushInt(scrs[mainMenu]); - } - - CGI->curh->draw1(); - SDL_Flip(screen); - CGI->curh->draw2(); - SDL_Delay(20); //give time for other apps - GH.topInt()->show(screen); - GH.updateTime(); - GH.handleEvents(); - } -} - CGPreGame::CGPreGame() { GH.defActionsDef = 63; CGP = this; mainbg = BitmapHandler::loadBitmap("ZPIC1005.bmp"); - terminate = false; for(int i = 0; i < ARRAY_COUNT(scrs); i++) scrs[i] = new CMenuScreen((EState)i); @@ -193,6 +166,26 @@ void CGPreGame::disposeGraphics() SDL_FreeSurface(nTown); } +void CGPreGame::update() +{ + if (GH.listInt.size() == 0) + { + #ifdef _WIN32 + CGI->videoh->open("ACREDIT.SMK"); + #else + CGI->videoh->open("ACREDIT.SMK", true, false); + #endif + GH.pushInt(scrs[mainMenu]); + } + + CGI->curh->draw1(); + SDL_Flip(screen); + CGI->curh->draw2(); + GH.topInt()->show(screen); + GH.updateTime(); + GH.handleEvents(); +} + CSelectionScreen::CSelectionScreen( EState Type ) { OBJ_CONSTRUCTION_CAPTURING_ALL; diff --git a/client/CPreGame.h b/client/CPreGame.h index 0b4e90117..4a634df90 100644 --- a/client/CPreGame.h +++ b/client/CPreGame.h @@ -212,7 +212,7 @@ public: ~CScenarioInfo(); }; -class CGPreGame : public CIntObject +class CGPreGame : public CIntObject, public IUpdateable { public: SDL_Surface *mainbg; @@ -222,10 +222,9 @@ public: CDefHandler *bonuses; CDefHandler *victory, *loss; - bool terminate; - CGPreGame(); ~CGPreGame(); + void update(); void run(); void openSel(EState type); void loadGraphics(); diff --git a/client/Client.cpp b/client/Client.cpp index 99ebcc86e..35f754fe6 100644 --- a/client/Client.cpp +++ b/client/Client.cpp @@ -83,6 +83,7 @@ public: void CClient::init() { + connectionHandler = NULL; pathInfo = NULL; applier = new CCLApplier; IObjectInterface::cb = this; @@ -124,17 +125,14 @@ void CClient::waitForMoveAndSend(int color) }HANDLE_EXCEPTION tlog1 << "We should not be here!" << std::endl; } + void CClient::run() { try { CPack *pack; - while(1) + while(!terminate) { - if (terminate) { - break; - } - //get the package from the server { boost::unique_lock lock(*serv->rmx); @@ -143,7 +141,8 @@ void CClient::run() tlog5 << "\treceived server message of type " << typeid(*pack).name() << std::endl; } - if (terminate) { + if (terminate) + { delete pack; break; } @@ -174,6 +173,7 @@ void CClient::stop() // Tell the network thread and interface thread to reach a stable state terminate = true; LOCPLINT->terminate = true; + endGame(); } void CClient::save(const std::string & fname) @@ -190,6 +190,10 @@ void CClient::save(const std::string & fname) void CClient::endGame() { tlog0 << "\n\nEnding current game!" << std::endl; + GH.curInt = NULL; + GH.topInt()->deactivate(); + GH.listInt.clear(); + GH.objsToBlit.clear(); delete CGI->mh; CGI->mh = NULL; @@ -197,6 +201,7 @@ void CClient::endGame() delete CGI->state; CGI->state = NULL; + LOCPLINT = NULL; while (!playerint.empty()) { delete playerint.begin()->second; @@ -208,7 +213,8 @@ void CClient::endGame() delete cb; } - if (serv) { + if (serv) + { tlog3 << "Connection has been requested to be closed.\n"; boost::unique_lock(*serv->wmx); *serv << &CloseServer(); @@ -219,6 +225,10 @@ void CClient::endGame() serv = NULL; tlog3 << "Our socket has been closed." << std::endl; } + + connectionHandler->join(); + delete connectionHandler; + connectionHandler = NULL; } void CClient::loadGame( const std::string & fname ) diff --git a/client/Client.h b/client/Client.h index 276363bcb..ec0cb046e 100644 --- a/client/Client.h +++ b/client/Client.h @@ -81,7 +81,8 @@ public: void run(); void stop(); - bool terminate; // tell to terminate + bool terminate; // tell to terminate + boost::thread *connectionHandler; //thread running run() method ////////////////////////////////////////////////////////////////////////// //from IGameCallback diff --git a/client/GUIBase.cpp b/client/GUIBase.cpp index 71c6a77fd..3a844b129 100644 --- a/client/GUIBase.cpp +++ b/client/GUIBase.cpp @@ -331,6 +331,32 @@ void CGuiHandler::fakeMouseMove() handleMoveInterested(sme); } +void CGuiHandler::run() +{ + try + { + while(!terminate) + { + if(curInt) + curInt->update(); + SDL_Delay(20); //give time for other apps + } + } HANDLE_EXCEPTION +} + +CGuiHandler::CGuiHandler() +:lastClick(-500, -500) +{ + curInt = NULL; + current = NULL; + terminate = false; +} + +CGuiHandler::~CGuiHandler() +{ + +} + void CIntObject::activateLClick() { GH.lclickable.push_front(this); @@ -462,6 +488,8 @@ CIntObject::CIntObject() pos.y = parent->pos.y; } } + else + parent = NULL; } void CIntObject::show( SDL_Surface * to ) diff --git a/client/GUIBase.h b/client/GUIBase.h index 1e8bcad8a..c9c5e319c 100644 --- a/client/GUIBase.h +++ b/client/GUIBase.h @@ -287,6 +287,13 @@ public: virtual ~IShowActivable(){}; //d-tor }; +class IUpdateable +{ +public: + virtual void update()=0; + virtual ~IUpdateable(){}; //d-tor +}; + class CIntObject : public IShowActivable //interface object { public: @@ -440,10 +447,15 @@ public: std::vector objsToBlit; SDL_Event * current; //current event + IUpdateable *curInt; Point lastClick; unsigned lastClickTime; + bool terminate; + CGuiHandler(); + ~CGuiHandler(); + void run(); void totalRedraw(); //forces total redraw (using showAll) void simpleRedraw(); //update only top interface and draw background from buffer void popInt(IShowActivable *top); //removes given interface from the top and activates next diff --git a/client/NetPacksClient.cpp b/client/NetPacksClient.cpp index 034ea67ed..23c97c8bf 100644 --- a/client/NetPacksClient.cpp +++ b/client/NetPacksClient.cpp @@ -150,7 +150,18 @@ void RemoveObject::applyCl( CClient *cl ) void TryMoveHero::applyFirstCl( CClient *cl ) { CGHeroInstance *h = GS(cl)->getHero(id); - if(result == TELEPORTATION || result == EMBARK || result == DISEMBARK) + + //check if playerint will have the knowledge about movement - if not, directly update maphandler + for(std::map::iterator i=cl->playerint.begin();i!=cl->playerint.end();i++) + { + if(i->first >= PLAYER_LIMIT) + continue; + PlayerState &p = GS(cl)->players[i->first]; + if((p.fogOfWarMap[start.x-1][start.y][start.z] || p.fogOfWarMap[end.x-1][end.y][end.z]) && p.human) + humanKnows = true; + } + + if(result == TELEPORTATION || result == EMBARK || result == DISEMBARK || !humanKnows) CGI->mh->removeObject(h); @@ -179,11 +190,17 @@ void TryMoveHero::applyCl( CClient *cl ) for(std::map::iterator i=cl->playerint.begin();i!=cl->playerint.end();i++) { if(i->first >= PLAYER_LIMIT) continue; - if(GS(cl)->players[i->first].fogOfWarMap[start.x-1][start.y][start.z] || GS(cl)->players[i->first].fogOfWarMap[end.x-1][end.y][end.z]) + PlayerState &p = GS(cl)->players[i->first]; + if(p.fogOfWarMap[start.x-1][start.y][start.z] || p.fogOfWarMap[end.x-1][end.y][end.z]) { i->second->heroMoved(*this); } } + + if(!humanKnows) //maphandler didn't get update from playerint, do it now + { //TODO: restructure nicely + CGI->mh->printObject(h); + } } void SetGarrisons::applyCl( CClient *cl ) @@ -538,7 +555,7 @@ void PlayerBlocked::applyCl( CClient *cl ) void YourTurn::applyCl( CClient *cl ) { - boost::thread(boost::bind(&CGameInterface::yourTurn,cl->playerint[player])); + INTERFACE_CALL_IF_PRESENT(player,yourTurn); } void SaveGame::applyCl(CClient *cl) diff --git a/hch/CLodHandler.cpp b/hch/CLodHandler.cpp index ab423f190..0f505b1cc 100644 --- a/hch/CLodHandler.cpp +++ b/hch/CLodHandler.cpp @@ -187,7 +187,8 @@ void CLodHandler::init(std::string lodFile, std::string dirName) LOD.open(lodFile.c_str(), std::ios::in | std::ios::binary); - if (!LOD.is_open()) { + if (!LOD.is_open()) + { tlog1 << "Cannot open " << lodFile << std::endl; return; } diff --git a/lib/NetPacks.h b/lib/NetPacks.h index a7592095f..afb1c239c 100644 --- a/lib/NetPacks.h +++ b/lib/NetPacks.h @@ -405,7 +405,7 @@ struct RemoveObject : public CPackForClient //500 }; struct TryMoveHero : public CPackForClient //501 { - TryMoveHero(){type = 501;}; + TryMoveHero(){type = 501;humanKnows=false;}; void applyFirstCl(CClient *cl); void applyCl(CClient *cl); void applyGs(CGameState *gs); @@ -420,6 +420,8 @@ struct TryMoveHero : public CPackForClient //501 int3 start, end; std::set fowRevealed; //revealed tiles + bool humanKnows; //used locally during applying to client + template void serialize(Handler &h, const int version) { h & id & result & start & end & movePoints & fowRevealed;