diff --git a/client/CBattleInterface.cpp b/client/CBattleInterface.cpp index 6a4e4b2f3..edf04e8c1 100644 --- a/client/CBattleInterface.cpp +++ b/client/CBattleInterface.cpp @@ -1985,6 +1985,9 @@ void CBattleInterface::clickRight(tribool down, bool previousState) void CBattleInterface::bOptionsf() { + if(activeStack < 0) //workaround to prevent crashing calls in the middle of movement (action) + return; //TODO: disable options button during action (other buttons should be disabled as well) + if(spellDestSelectMode) //we are casting a spell return; diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index 594a2b571..419017086 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -263,7 +263,7 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details) adventureInt->paths.erase(ho); adventureInt->terrain.currentPath = NULL; } - else if(adventureInt->terrain.currentPath) //&& hero is moving + else if(adventureInt->terrain.currentPath && details.result == TryMoveHero::SUCCESS) //&& hero is moving { //remove one node from the path (the one we went) adventureInt->terrain.currentPath->nodes.erase(adventureInt->terrain.currentPath->nodes.end()-1); @@ -1204,17 +1204,7 @@ void CPlayerInterface::showYesNoDialog(const std::string &text, const std::vecto { boost::unique_lock<boost::recursive_mutex> un(*pim); LOCPLINT->showingDialog->setn(true); - std::vector<std::pair<std::string,CFunctionList<void()> > > pom; - pom.push_back(std::pair<std::string,CFunctionList<void()> >("IOKAY.DEF",0)); - pom.push_back(std::pair<std::string,CFunctionList<void()> >("ICANCEL.DEF",0)); - CInfoWindow * temp = new CInfoWindow(text,playerID,0,components,pom,DelComps); - temp->delComps = DelComps; - for(int i=0;i<onYes.funcs.size();i++) - temp->buttons[0]->callback += onYes.funcs[i]; - for(int i=0;i<onNo.funcs.size();i++) - temp->buttons[1]->callback += onNo.funcs[i]; - - GH.pushInt(temp); + CInfoWindow::showYesNoDialog(text, &components, onYes, onNo, DelComps, playerID); } void CPlayerInterface::showBlockingDialog( const std::string &text, const std::vector<Component> &components, ui32 askID, int soundID, bool selection, bool cancel ) @@ -1378,8 +1368,8 @@ bool CPlayerInterface::moveHero( const CGHeroInstance *h, CGPath path ) for(int i=path.nodes.size()-1; i>0 && stillMoveHero.data == CONTINUE_MOVE; i--) { - //stop sending move requests if hero exhausted all his move points - if(!h->movement) + //stop sending move requests if the next node can't be reached at the current turn (hero exhausted his move points) + if(path.nodes[i-1].turns) { stillMoveHero.data = STOP_MOVE; break; diff --git a/client/CPreGame.cpp b/client/CPreGame.cpp index 0b7ae2eaa..56b16a979 100644 --- a/client/CPreGame.cpp +++ b/client/CPreGame.cpp @@ -70,6 +70,7 @@ CMenuScreen::CMenuScreen( EState which ) buttons[1] = new AdventureMapButton("", CGI->generaltexth->zelp[4].second, bind(&CMenuScreen::moveTo, this, ref(CGP->scrs[loadGame])), 532, 132, "ZMENULG.DEF", SDLK_l); buttons[2] = new AdventureMapButton("", CGI->generaltexth->zelp[5].second, 0 /*cb*/, 524, 251, "ZMENUHS.DEF", SDLK_h); buttons[3] = new AdventureMapButton("", CGI->generaltexth->zelp[6].second, 0 /*cb*/, 557, 359, "ZMENUCR.DEF", SDLK_c); + //boost::function<void()> confWindow = bind(CInfoWindow::showYesNoDialog, ) buttons[4] = new AdventureMapButton("", CGI->generaltexth->zelp[7].second, do_quit, 586, 468, "ZMENUQT.DEF", SDLK_ESCAPE); } break; diff --git a/client/GUIClasses.cpp b/client/GUIClasses.cpp index de6697cc7..ed4d48b2c 100644 --- a/client/GUIClasses.cpp +++ b/client/GUIClasses.cpp @@ -699,6 +699,22 @@ void CInfoWindow::showAll( SDL_Surface * to ) show(to); } +void CInfoWindow::showYesNoDialog(const std::string & text, const std::vector<SComponent*> *components, const CFunctionList<void( ) > &onYes, const CFunctionList<void()> &onNo, bool DelComps, int player) +{ + assert(!LOCPLINT || LOCPLINT->showingDialog->get()); + std::vector<std::pair<std::string,CFunctionList<void()> > > pom; + pom.push_back(std::pair<std::string,CFunctionList<void()> >("IOKAY.DEF",0)); + pom.push_back(std::pair<std::string,CFunctionList<void()> >("ICANCEL.DEF",0)); + CInfoWindow * temp = new CInfoWindow(text, player, 0, *components, pom, DelComps); + temp->delComps = DelComps; + for(int i=0;i<onYes.funcs.size();i++) + temp->buttons[0]->callback += onYes.funcs[i]; + for(int i=0;i<onNo.funcs.size();i++) + temp->buttons[1]->callback += onNo.funcs[i]; + + GH.pushInt(temp); +} + void CRClickPopup::clickRight(tribool down, bool previousState) { if(down) diff --git a/client/GUIClasses.h b/client/GUIClasses.h index 23dee6f3f..3e453aa61 100644 --- a/client/GUIClasses.h +++ b/client/GUIClasses.h @@ -79,6 +79,8 @@ public: CInfoWindow(std::string text, int player, int charperline, const std::vector<SComponent*> &comps, std::vector<std::pair<std::string,CFunctionList<void()> > > &Buttons, bool delComps); //c-tor CInfoWindow(); //c-tor ~CInfoWindow(); //d-tor + + static void showYesNoDialog( const std::string & text, const std::vector<SComponent*> *components, const CFunctionList<void( ) > &onYes, const CFunctionList<void()> &onNo, bool DelComps, int player); //use only before the game starts! (showYesNoDialog in LOCPLINT must be used then) }; class CSelWindow : public CInfoWindow //component selection window { //warning - this window deletes its components by closing! diff --git a/hch/CCreatureHandler.h b/hch/CCreatureHandler.h index f5d6367c1..385cfca87 100644 --- a/hch/CCreatureHandler.h +++ b/hch/CCreatureHandler.h @@ -75,6 +75,12 @@ public: & timeBetweenFidgets & walkAnimationTime & attackAnimationTime & flightAnimationDistance & upperRightMissleOffsetX & rightMissleOffsetX & lowerRightMissleOffsetX & upperRightMissleOffsetY & rightMissleOffsetY & lowerRightMissleOffsetY & missleFrameAngles & troopCountLocationOffset & attackClimaxFrame; + + if(version == 710) //temporary, for 0.74 savegames compatibility + { + char snd[40]; + h & snd; + } } }; diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index b2609a102..a0fe53d7b 100644 --- a/lib/CGameState.cpp +++ b/lib/CGameState.cpp @@ -2150,6 +2150,9 @@ void CGameState::calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int getNeighbours(ct, cp->coord, neighbours, boost::logic::indeterminate); for(unsigned int i=0; i < neighbours.size(); i++) { + int moveAtNextTile = movement; + int turnAtNextTile = turn; + const int3 &n = neighbours[i]; //current neighbor CGPathNode & dp = graph[n.x][n.y][n.z]; if( !checkForVisitableDir(cp->coord, dp.coord) @@ -2165,19 +2168,19 @@ void CGameState::calculatePaths(const CGHeroInstance *hero, CPathsInfo &out, int if(remains < 0) { //occurs rarely, when hero with low movepoints tries to go leave the road - turn++; - movement = hero->maxMovePoints(ct.tertype != TerrainTile::water); - cost = getMovementCost(hero, cp->coord, dp.coord, movement); //cost must be updated, movement points changed :( - remains = movement - cost; + turnAtNextTile++; + moveAtNextTile = hero->maxMovePoints(ct.tertype != TerrainTile::water); + cost = getMovementCost(hero, cp->coord, dp.coord, moveAtNextTile); //cost must be updated, movement points changed :( + remains = moveAtNextTile - cost; } if(dp.turns==0xff //we haven't been here before - || dp.turns > turn - || (dp.turns >= turn && dp.moveRemains < remains)) //this route is faster + || dp.turns > turnAtNextTile + || (dp.turns >= turnAtNextTile && dp.moveRemains < remains)) //this route is faster { assert(&dp != cp->theNodeBefore); //two tiles can't point to each other dp.moveRemains = remains; - dp.turns = turn; + dp.turns = turnAtNextTile; dp.theNodeBefore = cp; if(dp.accessible == CGPathNode::ACCESSIBLE) { diff --git a/lib/Connection.cpp b/lib/Connection.cpp index beaadf1be..fecad0482 100644 --- a/lib/Connection.cpp +++ b/lib/Connection.cpp @@ -253,7 +253,7 @@ CLoadFile::CLoadFile( const std::string &fname ) } *this >> myVersion; - if(myVersion != version) + if(myVersion > version || myVersion < 110) { tlog1 << "Wrong save format! (file " << fname << " )\n"; delete sfile; diff --git a/lib/Connection.h b/lib/Connection.h index 9a0f3adaa..77c7429f7 100644 --- a/lib/Connection.h +++ b/lib/Connection.h @@ -20,7 +20,7 @@ #include <boost/mpl/identity.hpp> #include <boost/type_traits/is_array.hpp> -const ui32 version = 710; +const ui32 version = 711; class CConnection; class CGObjectInstance; class CGameState; diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp index 2d80336a1..d16f05156 100644 --- a/lib/NetPacksLib.cpp +++ b/lib/NetPacksLib.cpp @@ -37,12 +37,14 @@ DLL_EXPORT void SetResource::applyGs( CGameState *gs ) { + assert(player < PLAYER_LIMIT); amax(val, 0); //new value must be >= 0 gs->getPlayer(player)->resources[resid] = val; } DLL_EXPORT void SetResources::applyGs( CGameState *gs ) { + assert(player < PLAYER_LIMIT); for(int i=0;i<res.size();i++) gs->getPlayer(player)->resources[i] = res[i]; } diff --git a/lib/RegisterTypes.cpp b/lib/RegisterTypes.cpp index a38b68a3f..7f3828504 100644 --- a/lib/RegisterTypes.cpp +++ b/lib/RegisterTypes.cpp @@ -23,7 +23,6 @@ void registerTypes1(Serializer &s) s.template registerType<CGHeroInstance>(); s.template registerType<CGTownInstance>(); s.template registerType<CTownBonus>(); - s.template registerType<COPWBonus>(); s.template registerType<CGPandoraBox>(); s.template registerType<CGEvent>(); s.template registerType<CGDwelling>(); @@ -58,6 +57,7 @@ void registerTypes1(Serializer &s) s.template registerType<CGShipyard>(); s.template registerType<CCartographer>(); s.template registerType<CGObjectInstance>(); + s.template registerType<COPWBonus>(); } template<typename Serializer> DLL_EXPORT diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 8406972db..471b7a25e 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -782,6 +782,8 @@ void CGameHandler::newTurn() for ( std::map<ui8, PlayerState>::iterator i=gs->players.begin() ; i!=gs->players.end();i++) { if(i->first == 255) continue; + else if(i->first > PLAYER_LIMIT) assert(0); //illegal player number! + if(gs->getDate(1)==7) //first day of week - new heroes in tavern { SetAvailableHeroes sah; @@ -843,42 +845,43 @@ void CGameHandler::newTurn() n.res.push_back(r); } for(std::vector<CGTownInstance *>::iterator j = gs->map->towns.begin(); j!=gs->map->towns.end(); j++)//handle towns + { + if(gs->getDate(1)==7) //first day of week { - if(gs->getDate(1)==7) //first day of week + SetAvailableCreatures sac; + sac.tid = (**j).id; + sac.creatures = (**j).creatures; + for(int k=0;k<CREATURES_PER_TOWN;k++) //creature growths { - SetAvailableCreatures sac; - sac.tid = (**j).id; - sac.creatures = (**j).creatures; - for(int k=0;k<CREATURES_PER_TOWN;k++) //creature growths + if((**j).creatureDwelling(k))//there is dwelling (k-level) { - if((**j).creatureDwelling(k))//there is dwelling (k-level) - { - sac.creatures[k].first += (**j).creatureGrowth(k); - if(!gs->getDate(0)) //first day of game: use only basic growths - amin(sac.creatures[k].first, VLC->creh->creatures[(*j)->town->basicCreatures[k]].growth); - } + sac.creatures[k].first += (**j).creatureGrowth(k); + if(!gs->getDate(0)) //first day of game: use only basic growths + amin(sac.creatures[k].first, VLC->creh->creatures[(*j)->town->basicCreatures[k]].growth); } - n.cres.push_back(sac); } - if(gs->day && (*j)->tempOwner < PLAYER_LIMIT)//not the first day and town not neutral - { - SetResources r; - if(vstd::contains((**j).builtBuildings,15)) //there is resource silo - { - if((**j).town->primaryRes == 127) //we'll give wood and ore - { - r.res[0] += 1; - r.res[2] += 1; - } - else - { - r.res[(**j).town->primaryRes] += 1; - } - } - r.res[6] += (**j).dailyIncome(); - n.res.push_back(r); - } + n.cres.push_back(sac); } + if(gs->day && (*j)->tempOwner < PLAYER_LIMIT)//not the first day and town not neutral + { + SetResources r; + r.player = (**j).tempOwner; + if(vstd::contains((**j).builtBuildings,15)) //there is resource silo + { + if((**j).town->primaryRes == 127) //we'll give wood and ore + { + r.res[0] += 1; + r.res[2] += 1; + } + else + { + r.res[(**j).town->primaryRes] += 1; + } + } + r.res[6] += (**j).dailyIncome(); + n.res.push_back(r); + } + } sendAndApply(&n); tlog5 << "Info about turn " << n.day << "has been sent!" << std::endl; @@ -1862,7 +1865,7 @@ void CGameHandler::save( const std::string &fname ) CSaveFile save(GVCMIDirs.UserPath + "/Games/" + fname + ".vsgm1"); save << *this; } - tlog0 << "Game has been succesfully saved!\n"; + tlog0 << "Game has been successfully saved!\n"; } void CGameHandler::close()