diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index 4543e2ce7..f15d23f51 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -282,7 +282,7 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details) int3 hp = details.start; if (details.result != TryMoveHero::SUCCESS) //hero failed to move { - if(details.result == TryMoveHero::BLOCKING_VISIT) + if(details.result != TryMoveHero::FAILED) { adventureInt->paths.erase(ho); adventureInt->terrain.currentPath = NULL; @@ -290,6 +290,7 @@ void CPlayerInterface::heroMoved(const TryMoveHero & details) ho->isStanding = true; stillMoveHero.setn(STOP_MOVE); + LOCPLINT->totalRedraw(); return; } @@ -1573,6 +1574,12 @@ bool CPlayerInterface::moveHero( const CGHeroInstance *h, CPath 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) + { + stillMoveHero.data = STOP_MOVE; + break; + } // Start a new sound for the hero movement or let the existing one carry on. #if 0 // TODO diff --git a/client/Graphics.cpp b/client/Graphics.cpp index 1ad1afce4..3a76f4bdf 100644 --- a/client/Graphics.cpp +++ b/client/Graphics.cpp @@ -368,19 +368,20 @@ void Graphics::loadHeroFlags(std::pair Graphics::*, rotations += std::make_pair(6,10), std::make_pair(7,11), std::make_pair(8,12); for(int q=0; q<8; ++q) { - for(size_t o=0; o<(this->*pr.first)[q]->ourImages.size(); ++o) + std::vector &curImgs = (this->*pr.first)[q]->ourImages; + for(size_t o=0; o*pr.first)[q]->ourImages[o].groupNumber==rotations[p].first) + if(curImgs[o].groupNumber==rotations[p].first) { for(int e=0; e<8; ++e) { Cimage nci; - nci.bitmap = CSDL_Ext::rotate01((this->*pr.first)[q]->ourImages[o+e].bitmap); + nci.bitmap = CSDL_Ext::rotate01(curImgs[o+e].bitmap); nci.groupNumber = rotations[p].second; nci.imName = std::string(); - (this->*pr.first)[q]->ourImages.push_back(nci); + curImgs.push_back(nci); } o+=8; } @@ -388,50 +389,50 @@ void Graphics::loadHeroFlags(std::pair Graphics::*, } if (mode) { - for(size_t o=0; oourImages.size(); ++o) + for(size_t o=0; oourImages[o].groupNumber==1) + if(curImgs[o].groupNumber==1) { for(int e=0; e<8; ++e) { Cimage nci; - nci.bitmap = CSDL_Ext::rotate01(flags4[q]->ourImages[o+e].bitmap); + nci.bitmap = CSDL_Ext::rotate01(curImgs[o+e].bitmap); nci.groupNumber = 13; nci.imName = std::string(); - flags4[q]->ourImages.push_back(nci); + curImgs.push_back(nci); } o+=8; } - if(flags4[q]->ourImages[o].groupNumber==2) + if(curImgs[o].groupNumber==2) { for(int e=0; e<8; ++e) { Cimage nci; - nci.bitmap = CSDL_Ext::rotate01(flags4[q]->ourImages[o+e].bitmap); + nci.bitmap = CSDL_Ext::rotate01(curImgs[o+e].bitmap); nci.groupNumber = 14; nci.imName = std::string(); - flags4[q]->ourImages.push_back(nci); + curImgs.push_back(nci); } o+=8; } - if(flags4[q]->ourImages[o].groupNumber==3) + if(curImgs[o].groupNumber==3) { for(int e=0; e<8; ++e) { Cimage nci; - nci.bitmap = CSDL_Ext::rotate01(flags4[q]->ourImages[o+e].bitmap); + nci.bitmap = CSDL_Ext::rotate01(curImgs[o+e].bitmap); nci.groupNumber = 15; nci.imName = std::string(); - flags4[q]->ourImages.push_back(nci); + curImgs.push_back(nci); } o+=8; } } } - for(size_t ff=0; ff<(this->*pr.first)[q]->ourImages.size(); ++ff) + for(size_t ff=0; ff*pr.first)[q]->ourImages[ff].bitmap, SDL_SRCCOLORKEY, - SDL_MapRGB((this->*pr.first)[q]->ourImages[ff].bitmap->format, 0, 255, 255) + SDL_SetColorKey(curImgs[ff].bitmap, SDL_SRCCOLORKEY, + SDL_MapRGB(curImgs[ff].bitmap->format, 0, 255, 255) ); } } @@ -456,9 +457,9 @@ void Graphics::loadHeroFlags() ("AF05.DEF"),("AF06.DEF"),("AF07.DEF"); boost::thread_group grupa; grupa.create_thread(boost::bind(&Graphics::loadHeroFlags,this,boost::ref(pr[3]),true)); - grupa.create_thread(boost::bind(&Graphics::loadHeroFlags,this,boost::ref(pr[2]),false)); - grupa.create_thread(boost::bind(&Graphics::loadHeroFlags,this,boost::ref(pr[1]),false)); - grupa.create_thread(boost::bind(&Graphics::loadHeroFlags,this,boost::ref(pr[0]),false)); + grupa.create_thread(boost::bind(&Graphics::loadHeroFlags,this,boost::ref(pr[2]),true)); + grupa.create_thread(boost::bind(&Graphics::loadHeroFlags,this,boost::ref(pr[1]),true)); + grupa.create_thread(boost::bind(&Graphics::loadHeroFlags,this,boost::ref(pr[0]),true)); grupa.join_all(); tlog0 << "Loading and transforming heroes' flags: "<mh->removeObject(GS(cl)->getHero(id)); + CGHeroInstance *h = GS(cl)->getHero(id); + if(result == TELEPORTATION || result == EMBARK || result == DISEMBARK) + CGI->mh->removeObject(h); + + + if(result == DISEMBARK) + CGI->mh->printObject(h->boat); } void TryMoveHero::applyCl( CClient *cl ) { const CGHeroInstance *h = cl->getHero(id); - if(result == TELEPORTATION || result == EMBARK) + if(result == TELEPORTATION || result == EMBARK || result == DISEMBARK) CGI->mh->printObject(h); + + if(result == EMBARK) + CGI->mh->hideObject(h->boat); + int player = h->tempOwner; if(vstd::contains(cl->playerint,player)) diff --git a/hch/CObjectHandler.cpp b/hch/CObjectHandler.cpp index 15959d406..0552323e1 100644 --- a/hch/CObjectHandler.cpp +++ b/hch/CObjectHandler.cpp @@ -2200,6 +2200,60 @@ void CGPickable::initObj() val1 = val2 * 100; type = ran()%6; //given resource break; + case 29: //floatsam + switch(type = ran()%4) + { + case 0: + val1 = val2 = 0; + break; + case 1: + val1 = 5; + val2 = 0; + break; + case 2: + val1 = 5; + val2 = 200; + break; + case 3: + val1 = 10; + val2 = 500; + break; + } + break; + case 82: //sea chest + { + int hlp = ran()%100; + if(hlp < 20) + { + val1 = 0; + type = 0; + } + else if(hlp < 90) + { + val1 = 1500; + type = 2; + } + else + { + val1 = 1000; + val2 = VLC->arth->treasures[ran()%VLC->arth->treasures.size()]->id; + type = 1; + } + } + break; + case 86: //Shipwreck Survivor + { + int hlp = ran()%100; + if(hlp < 55) + val1 = VLC->arth->treasures[ran()%VLC->arth->treasures.size()]->id; + else if(hlp < 75) + val1 = VLC->arth->minors[ran()%VLC->arth->minors.size()]->id; + else if(hlp < 95) + val1 = VLC->arth->majors[ran()%VLC->arth->majors.size()]->id; + else + val1 = VLC->arth->relics[ran()%VLC->arth->relics.size()]->id; + } + break; case 101: //treasure chest { int hlp = ran()%100; @@ -2247,6 +2301,57 @@ void CGPickable::onHeroVisit( const CGHeroInstance * h ) const cb->showInfoDialog(&iw); break; } + case 29: //flotsam + { + cb->giveResource(h->tempOwner,0,val1); //wood + cb->giveResource(h->tempOwner,6,val2);//gold + InfoWindow iw; + iw.soundID = soundBase::GENIE; + iw.player = h->tempOwner; + if(val1) + iw.components.push_back(Component(2,0,val1,0)); + if(val2) + iw.components.push_back(Component(2,6,val2,0)); + + iw.text.addTxt(MetaString::ADVOB_TXT, 51+type); + cb->showInfoDialog(&iw); + break; + } + case 82: //Sea Chest + { + InfoWindow iw; + iw.soundID = soundBase::chest; + iw.player = h->tempOwner; + iw.text.addTxt(MetaString::ADVOB_TXT, 116 + type); + + if(val1) //there is gold + { + iw.components.push_back(Component(2,6,val1,0)); + cb->giveResource(h->tempOwner,6,val1); + } + if(type == 1) //art + { + //TODO: what if no space in backpack? + iw.components.push_back(Component(4, val2, 1, 0)); + iw.text.addReplacement(MetaString::ART_NAMES, val2); + cb->giveHeroArtifact(val2,h->id,-2); + } + cb->showInfoDialog(&iw); + break; + } + case 86: //Shipwreck Survivor + { + //TODO: what if no space in backpack? + InfoWindow iw; + iw.soundID = soundBase::experience; + iw.player = h->tempOwner; + iw.components.push_back(Component(4,val1,1,0)); + iw.text.addTxt(MetaString::ADVOB_TXT, 125); + iw.text.addReplacement(MetaString::ART_NAMES, val1); + cb->giveHeroArtifact(val1,h->id,-2); + cb->showInfoDialog(&iw); + break; + } case 101: //treasure chest { if (subID) //not OH3 treasure chest diff --git a/hch/CObjectHandler.h b/hch/CObjectHandler.h index df2d48241..4f42e274b 100644 --- a/hch/CObjectHandler.h +++ b/hch/CObjectHandler.h @@ -581,7 +581,7 @@ public: } }; -class DLL_EXPORT CGPickable : public CGObjectInstance //campfire, treasure chest +class DLL_EXPORT CGPickable : public CGObjectInstance //campfire, treasure chest, Flotsam, Shipwreck Survivor, Sea Chest { public: ui32 type, val1, val2; diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp index 56f13974c..86653fcbb 100644 --- a/lib/NetPacksLib.cpp +++ b/lib/NetPacksLib.cpp @@ -288,6 +288,9 @@ void TryMoveHero::applyGs( CGameState *gs ) CGHeroInstance *h = gs->getHero(id); h->movement = movePoints; + if(result == SUCCESS || result == BLOCKING_VISIT || result == EMBARK || result == DISEMBARK) + h->moveDir = getDir(start,end); + if(result == EMBARK) //hero enters boat at dest tile { const TerrainTile &tt = gs->map->getTile(CGHeroInstance::convertPosition(end, false)); @@ -298,19 +301,26 @@ void TryMoveHero::applyGs( CGameState *gs ) h->boat = boat; boat->hero = h; } + else if(result == DISEMBARK) //hero leaves boat to dest tile + { + h->boat->direction = h->moveDir; + h->boat->pos = start; + h->boat->hero = NULL; + gs->map->addBlockVisTiles(h->boat); + h->boat = NULL; + } - if(start!=end && (result == SUCCESS || result == TELEPORTATION || result == EMBARK)) + if(start!=end && (result == SUCCESS || result == TELEPORTATION || result == EMBARK || result == DISEMBARK)) { gs->map->removeBlockVisTiles(h); h->pos = end; + if(h->boat) + h->boat->pos = end; gs->map->addBlockVisTiles(h); } BOOST_FOREACH(int3 t, fowRevealed) gs->getPlayer(h->getOwner())->fogOfWarMap[t.x][t.y][t.z] = 1; - - if(result == SUCCESS || result == BLOCKING_VISIT || result == EMBARK) - h->moveDir = getDir(start,end); } DLL_EXPORT void SetGarrisons::applyGs( CGameState *gs ) diff --git a/lib/map.cpp b/lib/map.cpp index b2762ac4c..60fb53aa6 100644 --- a/lib/map.cpp +++ b/lib/map.cpp @@ -1498,7 +1498,10 @@ void Mapa::readObjects( unsigned char * bufor, int &i) break; } case 12: //campfire - case 101: //treasure chest + case 29: //Flotsam + case 82: //Sea Chest + case 86: //Shipwreck Survivor + case 101://treasure chest { nobj = new CGPickable(); break; diff --git a/mapHandler.cpp b/mapHandler.cpp index 77fd17986..f5abb4e6a 100644 --- a/mapHandler.cpp +++ b/mapHandler.cpp @@ -784,10 +784,29 @@ void CMapHandler::terrainRect(int3 top_tile, unsigned char anim, std::vector< st SDL_Surface * tb; if(themp->type==NULL) continue; + + //pick graphics of hero (or boat if hero is sailing) std::vector & iv = (themp->boat) ? graphics->boatAnims[themp->boat->subID]->ourImages : graphics->heroAnims[themp->type->heroType]->ourImages; + //pick appropriate flag set + std::vector Graphics::*flg = NULL; + if(themp->boat) + { + switch (themp->boat->subID) + { + case 0: flg = &Graphics::flags1; break; + case 1: flg = &Graphics::flags2; break; + case 2: flg = &Graphics::flags3; break; + default: tlog1 << "Not supported boat subtype: " << themp->boat->subID << std::endl; + } + } + else + { + flg = &Graphics::flags4; + } + if(!themp->isStanding) //hero is moving { size_t gg; @@ -802,7 +821,7 @@ void CMapHandler::terrainRect(int3 top_tile, unsigned char anim, std::vector< st CSDL_Ext::blit8bppAlphaTo24bpp(tb,&pp,extSurf,&sr); pp.y+=imgVal*2-32; sr.y-=16; - SDL_BlitSurface(graphics->flags4[themp->getOwner()]->ourImages[gg+heroAnim%imgVal+35].bitmap, &pp, extSurf, &sr); + SDL_BlitSurface((graphics->*flg)[themp->getOwner()]->ourImages[gg+heroAnim%imgVal+35].bitmap, &pp, extSurf, &sr); } else //hero stands still { @@ -825,7 +844,7 @@ void CMapHandler::terrainRect(int3 top_tile, unsigned char anim, std::vector< st bufr.h = 64; bufr.w = 96; if(bufr.x-extRect->x>-64) - SDL_BlitSurface(graphics->flags4[themp->getOwner()]->ourImages[ getHeroFrameNum(themp->moveDir, !themp->isStanding) *8+(heroAnim/4)%imgVal].bitmap, NULL, extSurf, &bufr); + SDL_BlitSurface((graphics->*flg)[themp->getOwner()]->ourImages[ getHeroFrameNum(themp->moveDir, !themp->isStanding) *8+(heroAnim/4)%imgVal].bitmap, NULL, extSurf, &bufr); } } } diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 9203d2885..9be0bab1f 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -1167,7 +1167,10 @@ bool CGameHandler::moveHero( si32 hid, int3 dst, ui8 instant, ui8 asker /*= 255* if((t.tertype == TerrainTile::rock || (t.blocked && !t.visitable)) && complain("Cannot move hero, destination tile is blocked!") || (!h->boat && !h->canWalkOnSea() && t.tertype == TerrainTile::water && (t.visitableObjects.size() != 1 || t.visitableObjects.front()->ID != 8)) - && complain("Cannot move hero, destination tile is on water!")) + && complain("Cannot move hero, destination tile is on water!") + || (h->boat && t.tertype != TerrainTile::water && t.blocked) + && complain("Cannot disembark hero, tile is blocked!") + || !h->movement && complain("Hero don't have any movement points left!")) { //send info about movement failure sendAndApply(&tmh); @@ -1185,11 +1188,22 @@ bool CGameHandler::moveHero( si32 hid, int3 dst, ui8 instant, ui8 asker /*= 255* sendAndApply(&tmh); return true; } + //hero leaves the boat + else if(h->boat && t.tertype != TerrainTile::water && !t.blocked) + { + tmh.result = TryMoveHero::DISEMBARK; + tmh.movePoints = 0; //disembarking takes all move points + //TODO: check for bonus that removes that penalty + + getTilesInRange(tmh.fowRevealed,h->getSightCenter()+(tmh.end-tmh.start),h->getSightRadious(),h->tempOwner,1); + sendAndApply(&tmh); + return true; + } //checks for standard movement if(!instant) { - if( (distance(h->pos,dst)>=1.5) //tiles are not neighouring + if( (distance(h->pos,dst)>=1.5) //tiles are not neighbouring || (h->movement < cost && h->movement < 100) //lack of movement points ) { @@ -1308,6 +1322,7 @@ int CGameHandler::getCurrentPlayer() void CGameHandler::giveResource(int player, int which, int val) { + if(!val) return; //don't waste time on empty call SetResource sr; sr.player = player; sr.resid = which;