diff --git a/CAdvmapInterface.cpp b/CAdvmapInterface.cpp index c1f8c7563..403fb9dda 100644 --- a/CAdvmapInterface.cpp +++ b/CAdvmapInterface.cpp @@ -402,7 +402,7 @@ endchkpt: { //move CPath sended(*currentPath); //temporary path - engine will operate on it LOCPLINT->pim->unlock(); - mres = LOCPLINT->cb->moveHero( ((const CGHeroInstance*)LOCPLINT->adventureInt->selection)->type->ID,&sended,1,0); + mres = LOCPLINT->moveHero(static_cast(LOCPLINT->adventureInt->selection),&sended); LOCPLINT->pim->lock(); if(mres) { @@ -1249,7 +1249,7 @@ void CAdvMapInt::fmoveHero() return; CPath sended(*(terrain.currentPath)); //temporary path - engine will operate on it LOCPLINT->pim->unlock(); - LOCPLINT->cb->moveHero( ((const CGHeroInstance*)LOCPLINT->adventureInt->selection)->type->ID,&sended,1,0); + LOCPLINT->moveHero(static_cast(LOCPLINT->adventureInt->selection),&sended); LOCPLINT->pim->lock(); } void CAdvMapInt::fshowSpellbok() diff --git a/CCallback.cpp b/CCallback.cpp index a4c7ea9de..c5523a7ba 100644 --- a/CCallback.cpp +++ b/CCallback.cpp @@ -54,79 +54,26 @@ template bool isType(CPack *pack) return pack->getType() == N; } -bool CCallback::moveHero(int ID, CPath * path, int idtype, int pathType) +bool CCallback::moveHero(const CGHeroInstance *h, int3 dst) const { - CGHeroInstance * hero = NULL; + *cl->serv << &MoveHero(dst,h->id); - if (idtype==0) - { - if (player==-1) - hero=gs->players[player+1].heroes[ID]; - else - hero=gs->players[player].heroes[ID]; - } - else if (idtype==1 && player>=0) //looking for it in local area - { - for (size_t i=0; i < gs->players[player].heroes.size(); ++i) + {//wait till there is server answer + boost::unique_lock lock(*mess.mx); + while(std::find_if(mess.res->begin(),mess.res->end(),&isType<501>) == mess.res->end()) + mess.cv->wait(lock); + std::set::iterator itr = std::find_if(mess.res->begin(),mess.res->end(),&isType<501>); + TryMoveHero *tmh = dynamic_cast(*itr); + mess.res->erase(itr); + if(!tmh->result) { - if (gs->players[player].heroes[i]->type->ID == ID) - hero = gs->players[player].heroes[i]; - } - } - else //idtype==1; player<0 - { - - for(std::map::iterator j=gs->players.begin(); j!=gs->players.end(); ++j) - { - for (size_t i=0; i < (*j).second.heroes.size(); ++i) - { - if ((*j).second.heroes[i]->type->ID == ID) - { - hero = (*j).second.heroes[i]; - } - } - } - } - - if (!hero) - return false; //can't find hero - if(!verifyPath(path,!hero->canWalkOnSea()))//TODO: not check sea, if hero has flying or walking on water - return false; //invalid path - - //check path format - if (pathType==0) - CPathfinder::convertPath(path,pathType); - if (pathType>1) - throw std::string("Unknown path format"); - - CPath * ourPath = path; - if(!ourPath) - return false; - for(int i=ourPath->nodes.size()-1; i>0; i--) - { - 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 << &MoveHero(endpos,hero->id); - - {//wait till there is server answer - boost::unique_lock lock(*mess.mx); - while(std::find_if(mess.res->begin(),mess.res->end(),&isType<501>) == mess.res->end()) - mess.cv->wait(lock); - std::set::iterator itr = std::find_if(mess.res->begin(),mess.res->end(),&isType<501>); - TryMoveHero *tmh = dynamic_cast(*itr); - mess.res->erase(itr); - if(!tmh->result) - { - delete tmh; - return false; - } delete tmh; + return false; } + delete tmh; } return true; } - void CCallback::selectionMade(int selection, int asker) { *cl->serv << &QueryReply(asker,selection); @@ -700,7 +647,7 @@ void CCallback::recruitHero(const CGTownInstance *town, const CGHeroInstance *he { if(gs->players[player].availableHeroes[i] == hero) { - *cl->serv << &HireHero(town->id,i); + *cl->serv << &HireHero(i,town->id); return; } } diff --git a/CCallback.h b/CCallback.h index 5155d62f5..199af6c2b 100644 --- a/CCallback.h +++ b/CCallback.h @@ -31,8 +31,7 @@ struct TerrainTile; class ICallback { public: - virtual bool moveHero(int ID, CPath * path, int idtype, int pathType=0)=0;//idtype: 0 - position in vector of heroes (of that player); 1 - ID of hero - //pathType: 0 - nodes are manifestation pos, 1 - nodes are object pos + virtual bool moveHero(const CGHeroInstance *h, int3 dst) const =0; //dst must be free, neighbouring tile (this function can move hero only by one tile) virtual int swapCreatures(const CGObjectInstance *s1, const CGObjectInstance *s2, int p1, int p2)=0;//swaps creatures between two posiibly different garrisons // TODO: AI-unsafe code - fix it! virtual int mergeStacks(const CGObjectInstance *s1, const CGObjectInstance *s2, int p1, int p2)=0;//joins first stack tothe second (creatures must be same type) virtual int splitStack(const CGObjectInstance *s1, const CGObjectInstance *s2, int p1, int p2, int val)=0;//split creatures from the first stack @@ -118,8 +117,7 @@ protected: public: //commands - bool moveHero(int ID, CPath * path, int idtype, int pathType=0);//idtype: 0 - position in vector of heroes (of that player); 1 - ID of hero - //pathType: 0 - nodes are manifestation pos, 1 - nodes are object pos + bool moveHero(const CGHeroInstance *h, int3 dst) const; //dst must be free, neighbouring tile (this function can move hero only by one tile) void selectionMade(int selection, int asker); int swapCreatures(const CGObjectInstance *s1, const CGObjectInstance *s2, int p1, int p2); int mergeStacks(const CGObjectInstance *s1, const CGObjectInstance *s2, int p1, int p2); //first goes to the second diff --git a/CCastleInterface.cpp b/CCastleInterface.cpp index 83c193217..926a886f4 100644 --- a/CCastleInterface.cpp +++ b/CCastleInterface.cpp @@ -1010,38 +1010,50 @@ CHallInterface::CHallInterface(CCastleInterface * owner) boxes.resize(5); for(size_t i=0;i<5;i++) //for each row { - for(size_t j=0; jbuildh->hall[owner->town->subID].second[i].size();j++) //for each box + std::vector< std::vector< std::vector > > &boxList = CGI->buildh->hall[owner->town->subID].second; + + for(size_t j=0; jbuildh->hall[owner->town->subID].second[i][j].size();k++)//we are looking for the first not build structure + for(;ktown->builtBuildings.find(CGI->buildh->hall[owner->town->subID].second[i][j][k])) - == - (owner->town->builtBuildings.end()) ) + int bid = boxList[i][j][k]; + + if(!vstd::contains(owner->town->builtBuildings,bid)) { int x = 34 + 194*j, y = 37 + 104*i, - ID = CGI->buildh->hall[owner->town->subID].second[i][j][k]; - if(CGI->buildh->hall[owner->town->subID].second[i].size() == 2) //only two boxes in this row + ID = bid; + if(boxList[i].size() == 2) //only two boxes in this row x+=194; - else if(CGI->buildh->hall[owner->town->subID].second[i].size() == 3) //only three boxes in this row + else if(boxList[i].size() == 3) //only three boxes in this row x+=97; - boxes[i].push_back(new CBuildingBox(CGI->buildh->hall[owner->town->subID].second[i][j][k],pos.x+x,pos.y+y)); + boxes[i].push_back(new CBuildingBox(bid,pos.x+x,pos.y+y)); + + //if this is horde dwelling for upgraded creatures and we already have one for basic creatures + if((bid == 25 && vstd::contains(owner->town->builtBuildings,24)) + || (bid == 19 && vstd::contains(owner->town->builtBuildings,18)) + ) + { + boxes[i].back()->state = 4; //already built + } + else + { + boxes[i].back()->state = LOCPLINT->cb->canBuildStructure(owner->town,ID); + } - boxes[i].back()->state = LOCPLINT->cb->canBuildStructure(owner->town,ID); break; } } - if(k==CGI->buildh->hall[owner->town->subID].second[i][j].size()) //all buildings built - let's take the last one + if(k == boxList[i][j].size()) //all buildings built - let's take the last one { int x = 34 + 194*j, y = 37 + 104*i; - if(CGI->buildh->hall[owner->town->subID].second[i].size() == 2) + if(boxList[i].size() == 2) x+=194; - else if(CGI->buildh->hall[owner->town->subID].second[i].size() == 3) + else if(boxList[i].size() == 3) x+=97; - boxes[i].push_back(new CBuildingBox(CGI->buildh->hall[owner->town->subID].second[i][j][k-1],pos.x+x,pos.y+y)); + boxes[i].push_back(new CBuildingBox(boxList[i][j][k-1],pos.x+x,pos.y+y)); boxes[i][boxes[i].size()-1]->state = 4; //already exists } } diff --git a/CMT.cpp b/CMT.cpp index d418c733d..5b51fc905 100644 --- a/CMT.cpp +++ b/CMT.cpp @@ -48,7 +48,7 @@ #endif std::string NAME = NAME_VER + std::string(" (client)"); SDL_Surface * screen, * screen2; -std::queue events; +std::queue events; boost::mutex eventsM; TTF_Font * TNRB16, *TNR, *GEOR13, *GEORXX, *GEORM, *GEOR16; void processCommand(const std::string &message, CClient *&client); @@ -191,11 +191,12 @@ int main(int argc, char** argv) boost::thread t(boost::bind(&CClient::run,&cl)); } - SDL_Event ev; + SDL_Event *ev = NULL; while(1) //main SDL events loop { - SDL_WaitEvent(&ev); - if((ev.type==SDL_QUIT) || (ev.type == SDL_KEYDOWN && ev.key.keysym.sym==SDLK_F4 && (ev.key.keysym.mod & KMOD_ALT))) + ev = new SDL_Event(); + SDL_WaitEvent(ev); + if((ev->type==SDL_QUIT) || (ev->type == SDL_KEYDOWN && ev->key.keysym.sym==SDLK_F4 && (ev->key.keysym.mod & KMOD_ALT))) { cl.close(); #ifndef __unix__ @@ -206,7 +207,7 @@ int main(int argc, char** argv) tlog0 << "Ending...\n"; exit(EXIT_SUCCESS); } - else if(ev.type == SDL_KEYDOWN && ev.key.keysym.sym==SDLK_F4) + else if(ev->type == SDL_KEYDOWN && ev->key.keysym.sym==SDLK_F4) { LOCPLINT->pim->lock(); bool full = !(screen->flags&SDL_FULLSCREEN); @@ -329,6 +330,6 @@ void processCommand(const std::string &message, CClient *&client) } else if(client && client->serv && client->serv->connected) //send to server { - *client->serv << &PlayerMessage(255,message); + *client->serv << &PlayerMessage(LOCPLINT->playerID,message); } } \ No newline at end of file diff --git a/CPlayerInterface.cpp b/CPlayerInterface.cpp index a191e394d..7fb5f92d2 100644 --- a/CPlayerInterface.cpp +++ b/CPlayerInterface.cpp @@ -49,7 +49,7 @@ using namespace CSDL_Ext; extern TTF_Font * GEOR16; CPlayerInterface * LOCPLINT; -extern std::queue events; +extern std::queue events; extern boost::mutex eventsM; @@ -1145,13 +1145,26 @@ void CPlayerInterface::yourTurn() (*i)->tick(); } LOCPLINT->adventureInt->updateScreen = false; - eventsM.lock(); - while(!events.empty()) + + while(true) { - handleEvent(&events.front()); - events.pop(); + SDL_Event *ev = NULL; + { + boost::unique_lock lock(eventsM); + if(!events.size()) + { + break; + } + else + { + ev = events.front(); + events.pop(); + } + } + handleEvent(ev); + delete ev; } - eventsM.unlock(); + if (curint == adventureInt) //stuff for advMapInt { adventureInt->update(); @@ -1702,6 +1715,27 @@ void CPlayerInterface::heroMoved(const HeroMoveDetails & details) //move finished adventureInt->minimap.draw(); adventureInt->heroList.updateMove(ho); + + //check if user cancelled movement + { + boost::unique_lock un(eventsM); + while(events.size()) + { + SDL_Event *ev = events.front(); + events.pop(); + switch(ev->type) + { + case SDL_MOUSEBUTTONDOWN: + stillMoveHero = false; + break; + case SDL_KEYDOWN: + if(ev->key.keysym.sym < SDLK_F1) + stillMoveHero = false; + break; + } + delete ev; + } + } } void CPlayerInterface::heroKilled(const CGHeroInstance* hero) { @@ -2445,6 +2479,30 @@ void CPlayerInterface::redrawHeroWin(const CGHeroInstance * hero) adventureInt->infoBar.draw(); } +bool CPlayerInterface::moveHero( const CGHeroInstance *h, CPath * path ) +{ + bool result = false; + + if (!h || !path) + return false; //can't find hero + + CPathfinder::convertPath(path,0); + stillMoveHero = true; + + for(int i=path->nodes.size()-1; i>0; i--) + { + { + boost::unique_lock un(*pim); + if(!stillMoveHero) + return result; + } + int3 endpos(path->nodes[i-1].coord.x, path->nodes[i-1].coord.y, h->pos.z); + result = cb->moveHero(h,endpos); + } + stillMoveHero = false; + return result; +} + CStatusBar::CStatusBar(int x, int y, std::string name, int maxw) { bg=BitmapHandler::loadBitmap(name); diff --git a/CPlayerInterface.h b/CPlayerInterface.h index 337814bec..04493db53 100644 --- a/CPlayerInterface.h +++ b/CPlayerInterface.h @@ -450,6 +450,7 @@ public: //to commucate with engine CCallback * cb; const BattleAction *curAction; + bool stillMoveHero; std::list dialogs; @@ -515,6 +516,7 @@ public: void removeObjToBlit(IShowable* obj); void showInfoDialog(std::string &text, const std::vector & components); void showYesNoDialog(std::string &text, const std::vector & components, CFunctionList onYes, CFunctionList onNo, bool deactivateCur, bool DelComps); //deactivateCur - whether current main interface should be deactivated; delComps - if components will be deleted on window close + bool moveHero(const CGHeroInstance *h, CPath * path); CPlayerInterface(int Player, int serial);//c-tor ~CPlayerInterface();//d-tor diff --git a/ChangeLog b/ChangeLog index 7f67d1012..86042c852 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -0.7 -> 0.71 (as for r751) +0.7 -> 0.71 (as for r754) GENERAL: * fixed scrolling behind window problem (now it's possible to scroll with CTRL + arrows) * morale/luck system and corresponding sec. skills supported @@ -12,6 +12,7 @@ GENERAL: * fixed crashes on loading maps with flag all mines/dwelling victory condition * further fixes for leveling-up (stability and identical offered skills bug) * support for numpad keyboard +* support for timed events ADVENTURE INTERFACE: * added "Next hero" button functionality @@ -22,6 +23,8 @@ ADVENTURE INTERFACE: * orientation of hero can't be change if movement points are exhausted * campfire, borderguard, bordergate, questguard will be accessible from the top * new movement cost calculation algorithm +* fixed sight radious calculation +* it's possible to stop hero movement BATTLES: * partial support for battle obstacles