From 1e300455416281a492e09ae175f7eee456524c81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20W=2E=20Urba=C5=84czyk?= Date: Thu, 8 Jul 2010 23:03:27 +0000 Subject: [PATCH] Support for Tavern on adv map. --- CCallback.cpp | 15 +++- CCallback.h | 10 ++- CGameInterface.h | 1 + client/CCastleInterface.cpp | 4 +- client/CPlayerInterface.cpp | 6 ++ client/CPlayerInterface.h | 1 + client/GUIClasses.cpp | 152 +++++++++++++++--------------------- client/GUIClasses.h | 21 ++--- client/NetPacksClient.cpp | 8 +- hch/CObjectHandler.cpp | 15 ++++ lib/CGameState.cpp | 7 +- lib/IGameCallback.cpp | 6 ++ lib/IGameCallback.h | 2 + lib/NetPacks.h | 8 +- lib/NetPacksLib.cpp | 8 +- server/CGameHandler.cpp | 51 +++++++----- server/CGameHandler.h | 2 +- server/NetPacksServer.cpp | 9 ++- 18 files changed, 185 insertions(+), 141 deletions(-) diff --git a/CCallback.cpp b/CCallback.cpp index 210d1d391..965415db4 100644 --- a/CCallback.cpp +++ b/CCallback.cpp @@ -137,7 +137,7 @@ void CCallback::getThievesGuildInfo(SThievesGuildInfo & thi, const CGObjectInsta if(obj == NULL) return; - if(obj->ID == TOWNI_TYPE) //it is a town + if(obj->ID == TOWNI_TYPE || obj->ID == 95) //it is a town or adv map tavern { gs->obtainPlayersStats(thi, gs->players[player].towns.size()); } @@ -793,21 +793,22 @@ void CCallback::setSelection(const CArmedInstance * obj) } } -void CCallback::recruitHero(const CGTownInstance *town, const CGHeroInstance *hero) +void CCallback::recruitHero(const CGObjectInstance *townOrTavern, const CGHeroInstance *hero) { ui8 i=0; for(; iplayers[player].availableHeroes.size(); i++) { if(gs->players[player].availableHeroes[i] == hero) { - HireHero pack(i,town->id); + HireHero pack(i,townOrTavern->id); + pack.player = player; sendRequest(&pack); return; } } } -std::vector CCallback::getAvailableHeroes(const CGTownInstance * town) const +std::vector CCallback::getAvailableHeroes(const CGObjectInstance * townOrTavern) const { std::vector ret(gs->players[player].availableHeroes.size()); std::copy(gs->players[player].availableHeroes.begin(),gs->players[player].availableHeroes.end(),ret.begin()); @@ -980,6 +981,12 @@ int CCallback::getPlayerStatus(int player) const return -1; return ps->status; } + +std::string CCallback::getTavernGossip(const CGObjectInstance * townOrTavern) const +{ + return "GOSSIP TEST"; +} + InfoAboutTown::InfoAboutTown() { tType = NULL; diff --git a/CCallback.h b/CCallback.h index 6e88781b3..f38bbbb95 100644 --- a/CCallback.h +++ b/CCallback.h @@ -78,7 +78,7 @@ public: virtual bool dismissHero(const CGHeroInstance * hero)=0; //dismisses given hero; true - successfuly, false - not successfuly //town - virtual void recruitHero(const CGTownInstance *town, const CGHeroInstance *hero)=0; + virtual void recruitHero(const CGObjectInstance *townOrTavern, const CGHeroInstance *hero)=0; virtual bool buildBuilding(const CGTownInstance *town, si32 buildingID)=0; virtual void recruitCreatures(const CGObjectInstance *obj, ui32 ID, ui32 amount)=0; virtual bool upgradeCreature(const CArmedInstance *obj, int stackPos, int newID=-1)=0; //if newID==-1 then best possible upgrade will be made @@ -143,7 +143,8 @@ public: virtual int howManyTowns()const =0; virtual const CGTownInstance * getTownInfo(int val, bool mode)const =0; //mode = 0 -> val = player town serial; mode = 1 -> val = object id (serial) virtual std::vector < const CGTownInstance *> getTownsInfo(bool onlyOur=true) const=0; - virtual std::vector getAvailableHeroes(const CGTownInstance * town) const =0; //heroes that can be recruited + virtual std::vector getAvailableHeroes(const CGObjectInstance * townOrTavern) const =0; //heroes that can be recruited + virtual std::string getTavernGossip(const CGObjectInstance * townOrTavern) const =0; virtual int canBuildStructure(const CGTownInstance *t, int ID) =0;//// 0 - no more than one capitol, 1 - lack of water, 2 - forbidden, 3 - Add another level to Mage Guild, 4 - already built, 5 - cannot build, 6 - cannot afford, 7 - build, 8 - lack of requirements virtual std::set getBuildingRequiments(const CGTownInstance *t, int ID) =0; virtual bool getTownInfo(const CGObjectInstance *town, InfoAboutTown &dest) const = 0; @@ -229,7 +230,7 @@ public: void trade(const CGObjectInstance *market, int mode, int id1, int id2, int val1, const CGHeroInstance *hero = NULL); void setFormation(const CGHeroInstance * hero, bool tight); void setSelection(const CArmedInstance * obj); - void recruitHero(const CGTownInstance *town, const CGHeroInstance *hero); + void recruitHero(const CGObjectInstance *townOrTavern, const CGHeroInstance *hero); void save(const std::string &fname); void sendMessage(const std::string &mess); void buildBoat(const IShipyard *obj); @@ -267,7 +268,8 @@ public: std::vector < const CGObjectInstance * > getVisitableObjs(int3 pos) const; std::vector < const CGObjectInstance * > getFlaggableObjects(int3 pos) const; int3 getMapSize() const; //returns size of map - z is 1 for one - level map and 2 for two level map - std::vector getAvailableHeroes(const CGTownInstance * town) const; //heroes that can be recruited + std::vector getAvailableHeroes(const CGObjectInstance * townOrTavern) const; //heroes that can be recruited + std::string getTavernGossip(const CGObjectInstance * townOrTavern) const; const TerrainTile * getTileInfo(int3 tile) const; int canBuildStructure(const CGTownInstance *t, int ID);//// 0 - no more than one capitol, 1 - lack of water, 2 - forbidden, 3 - Add another level to Mage Guild, 4 - already built, 5 - cannot build, 6 - cannot afford, 7 - build, 8 - lack of requirements std::set getBuildingRequiments(const CGTownInstance *t, int ID); diff --git a/CGameInterface.h b/CGameInterface.h index 927870370..24282f2c3 100644 --- a/CGameInterface.h +++ b/CGameInterface.h @@ -84,6 +84,7 @@ public: 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 virtual void showPuzzleMap(){}; virtual void showMarketWindow(const IMarket *market, const CGHeroInstance *visitor){}; + virtual void showTavernWindow(const CGObjectInstance *townOrTavern){}; virtual void advmapSpellCast(const CGHeroInstance * caster, int spellID){}; //called when a hero casts a spell virtual void tileHidden(const std::set &pos){}; virtual void tileRevealed(const std::set &pos){}; diff --git a/client/CCastleInterface.cpp b/client/CCastleInterface.cpp index dee6fb83a..49fe0012d 100644 --- a/client/CCastleInterface.cpp +++ b/client/CCastleInterface.cpp @@ -1389,9 +1389,7 @@ void CCastleInterface::enterMageGuild() void CCastleInterface::enterTavern() { - std::vector h = LOCPLINT->cb->getAvailableHeroes(town); - CTavernWindow *tv = new CTavernWindow(h[0],h[1],"GOSSIP TEST"); - GH.pushInt(tv); + LOCPLINT->showTavernWindow(town); } void CCastleInterface::keyPressed( const SDL_KeyboardEvent & key ) diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index 995afa6a9..712062262 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -1995,4 +1995,10 @@ void CPlayerInterface::availableArtifactsChanged(const CGBlackMarket *bm /*= NUL { if(CMarketplaceWindow *cmw = dynamic_cast(GH.topInt())) cmw->artifactsChanged(false); +} + +void CPlayerInterface::showTavernWindow(const CGObjectInstance *townOrTavern) +{ + CTavernWindow *tv = new CTavernWindow(townOrTavern); + GH.pushInt(tv); } \ No newline at end of file diff --git a/client/CPlayerInterface.h b/client/CPlayerInterface.h index 5b96513eb..e6eda6da9 100644 --- a/client/CPlayerInterface.h +++ b/client/CPlayerInterface.h @@ -163,6 +163,7 @@ public: void showArtifactAssemblyDialog(ui32 artifactID, ui32 assembleTo, bool assemble, CFunctionList onYes, CFunctionList onNo); void showPuzzleMap(); void showMarketWindow(const IMarket *market, const CGHeroInstance *visitor); + void showTavernWindow(const CGObjectInstance *townOrTavern); void advmapSpellCast(const CGHeroInstance * caster, int spellID); //called when a hero casts a spell void tileHidden(const std::set &pos); //called when given tiles become hidden under fog of war void tileRevealed(const std::set &pos); //called when fog of war disappears from given tiles diff --git a/client/GUIClasses.cpp b/client/GUIClasses.cpp index da1450d93..cbb030c37 100644 --- a/client/GUIClasses.cpp +++ b/client/GUIClasses.cpp @@ -3403,38 +3403,36 @@ void CSystemOptionsWindow::show(SDL_Surface *to) effectsVolume->show(to); } -CTavernWindow::CTavernWindow(const CGHeroInstance *H1, const CGHeroInstance *H2, const std::string &gossip) -:h1(selected,0,72,299,H1),h2(selected,1,162,299,H2) +CTavernWindow::CTavernWindow(const CGObjectInstance *TavernObj) + : tavernObj(TavernObj) { - if(H1) + OBJ_CONSTRUCTION_CAPTURING_ALL; + std::vector h = LOCPLINT->cb->getAvailableHeroes(TavernObj); + assert(h.size() == 2); + + h1 = new HeroPortrait(selected,0,72,299,h[0]); + h2 = new HeroPortrait(selected,1,162,299,h[1]); + if(h[0]) selected = 0; else selected = -1; oldSelected = -1; - SDL_Surface *hhlp = BitmapHandler::loadBitmap("TPTAVERN.bmp"); - graphics->blueToPlayersAdv(hhlp,LOCPLINT->playerID); - bg = SDL_ConvertSurface(hhlp,screen->format,0); - SDL_SetColorKey(bg,SDL_SRCCOLORKEY,SDL_MapRGB(bg->format,0,255,255)); - SDL_FreeSurface(hhlp); + bg = new CPicture("TPTAVERN.bmp"); + bg->colorizeAndConvert(LOCPLINT->playerID); + pos = center(bg->pos); - printAtMiddle(CGI->generaltexth->jktexts[37],200,35,FONT_BIG,tytulowy,bg); - printAtMiddle("2500",320,328,FONT_SMALL,zwykly,bg); + + printAtMiddle(CGI->generaltexth->jktexts[37],200,35,FONT_BIG,tytulowy,*bg); + printAtMiddle("2500",320,328,FONT_SMALL,zwykly,*bg); // printAtMiddle(CGI->generaltexth->jktexts[38],146,283,FONT_BIG,tytulowy,bg); //what is this??? - printAtMiddleWB(gossip,200,220,FONT_SMALL,50,zwykly,bg); - pos.w = bg->w; - pos.h = bg->h; - pos.x = (screen->w-bg->w)/2; - pos.y = (screen->h-bg->h)/2; - bar = new CStatusBar(pos.x+8, pos.y+478, "APHLFTRT.bmp", 380); - h1.pos.x += pos.x; - h2.pos.x += pos.x; - h1.pos.y += pos.y; - h2.pos.y += pos.y; + printAtMiddleWB(LOCPLINT->cb->getTavernGossip(tavernObj), 200, 220, FONT_SMALL, 50, zwykly, *bg); - cancel = new AdventureMapButton(CGI->generaltexth->tavernInfo[7],"", boost::bind(&CTavernWindow::close, this), pos.x+310,pos.y+428, "ICANCEL.DEF", SDLK_ESCAPE); - recruit = new AdventureMapButton("", "", boost::bind(&CTavernWindow::recruitb, this), pos.x+272, pos.y+355, "TPTAV01.DEF", SDLK_RETURN); - thiefGuild = new AdventureMapButton(CGI->generaltexth->tavernInfo[5],"", boost::bind(&CTavernWindow::thievesguildb, this), pos.x+22, pos.y+428, "TPTAV02.DEF", SDLK_t); + + bar = new CGStatusBar(8, 478, "APHLFTRT.bmp", 380); + cancel = new AdventureMapButton(CGI->generaltexth->tavernInfo[7],"", boost::bind(&CTavernWindow::close, this), 310, 428, "ICANCEL.DEF", SDLK_ESCAPE); + recruit = new AdventureMapButton("", "", boost::bind(&CTavernWindow::recruitb, this), 272, 355, "TPTAV01.DEF", SDLK_RETURN); + thiefGuild = new AdventureMapButton(CGI->generaltexth->tavernInfo[5],"", boost::bind(&CTavernWindow::thievesguildb, this), 22, 428, "TPTAV02.DEF", SDLK_t); if(LOCPLINT->cb->getResourceAmount(6) < 2500) //not enough gold { @@ -3454,7 +3452,7 @@ CTavernWindow::CTavernWindow(const CGHeroInstance *H1, const CGHeroInstance *H2, } else { - if(!H1) + if(!h[0]) recruit->block(1); } @@ -3467,47 +3465,20 @@ CTavernWindow::CTavernWindow(const CGHeroInstance *H1, const CGHeroInstance *H2, void CTavernWindow::recruitb() { - const CGHeroInstance *toBuy = (selected ? h2 : h1).h; + const CGHeroInstance *toBuy = (selected ? h2 : h1)->h; + const CGObjectInstance *obj = tavernObj; close(); - LOCPLINT->cb->recruitHero(LOCPLINT->castleInt->town,toBuy); + LOCPLINT->cb->recruitHero(obj, toBuy); } void CTavernWindow::thievesguildb() { - GH.pushInt( new CThievesGuildWindow(LOCPLINT->castleInt->town) ); + GH.pushInt( new CThievesGuildWindow(tavernObj) ); } CTavernWindow::~CTavernWindow() { CGI->videoh->close(); - SDL_FreeSurface(bg); - delete cancel; - delete thiefGuild; - delete recruit; - delete bar; -} - -void CTavernWindow::activate() -{ - thiefGuild->activate(); - cancel->activate(); - if(h1.h) - h1.activate(); - if(h2.h) - h2.activate(); - recruit->activate(); - GH.statusbar = bar; -} - -void CTavernWindow::deactivate() -{ - thiefGuild->deactivate(); - cancel->deactivate(); - if(h1.h) - h1.deactivate(); - if(h2.h) - h2.deactivate(); - recruit->deactivate(); } void CTavernWindow::close() @@ -3517,20 +3488,12 @@ void CTavernWindow::close() void CTavernWindow::show(SDL_Surface * to) { - blitAt(bg,pos.x,pos.y,to); - CGI->videoh->update(pos.x+70, pos.y+56, to, true, false); - if(h1.h) - h1.show(to); - if(h2.h) - h2.show(to); - thiefGuild->show(to); - cancel->show(to); - recruit->show(to); - bar->show(to); + CIntObject::show(to); + CGI->videoh->update(pos.x+70, pos.y+56, to, true, false); if(selected >= 0) { - HeroPortrait *sel = selected ? &h2 : &h1; + HeroPortrait *sel = selected ? h2 : h1; if (selected != oldSelected && !recruit->blocked) { @@ -3549,28 +3512,14 @@ void CTavernWindow::show(SDL_Surface * to) void CTavernWindow::HeroPortrait::clickLeft(tribool down, bool previousState) { - if(previousState && !down) + if(previousState && !down && h) as(); //ClickableL::clickLeft(down); } -void CTavernWindow::HeroPortrait::activate() -{ - activateLClick(); - activateRClick(); - activateHover(); -} - -void CTavernWindow::HeroPortrait::deactivate() -{ - deactivateLClick(); - deactivateRClick(); - deactivateHover(); -} - void CTavernWindow::HeroPortrait::clickRight(tribool down, bool previousState) { - if(down) + if(down && h) { adventureInt->heroWindow->setHero(h); GH.pushInt(new CRClickPopupInt(adventureInt->heroWindow,false)); @@ -3578,13 +3527,15 @@ void CTavernWindow::HeroPortrait::clickRight(tribool down, bool previousState) } CTavernWindow::HeroPortrait::HeroPortrait(int &sel, int id, int x, int y, const CGHeroInstance *H) -:as(sel,id) +:as(sel,id), h(H) { + used = LCLICK | RCLICK | HOVER; h = H; pos.x = x; pos.y = y; pos.w = 58; pos.h = 64; + if(H) { hoverName = CGI->generaltexth->tavernInfo[4]; @@ -5370,7 +5321,7 @@ CThievesGuildWindow::CThievesGuildWindow(const CGObjectInstance * _owner) SDL_FreeSurface(bg); exitb = new AdventureMapButton (std::string(), std::string(), boost::bind(&CThievesGuildWindow::bexitf,this), 748, 556, "HSBTNS.def", SDLK_RETURN); - statusBar = new CStatusBar(3, 555, "TStatBar.bmp", 742); + statusBar = new CGStatusBar(3, 555, "TStatBar.bmp", 742); resdatabar = new CMinorResDataBar(); resdatabar->pos.x += pos.x - 3; @@ -5709,16 +5660,22 @@ CGStatusBar::CGStatusBar(CPicture *BG, EFonts Font /*= FONT_SMALL*/, EAlignment bg = BG; moveChild(bg, bg->parent, this); pos = bg->pos; + calcOffset(); +} - switch(Align) +CGStatusBar::CGStatusBar(int x, int y, std::string name/*="ADROLLVR.bmp"*/, int maxw/*=-1*/) + : CLabel(x, y, FONT_SMALL, CENTER) +{ + OBJ_CONSTRUCTION_CAPTURING_ALL; + init(); + bg = new CPicture(name); + pos = bg->pos; + if(maxw < pos.w) { - case CENTER: - textOffset = Point(pos.w/2, pos.h/2); - break; - case BOTTOMRIGHT: - textOffset = Point(pos.w, pos.h); - break; + amin(pos.w, maxw); + bg->srcRect = new Rect(0, 0, maxw, pos.h); } + calcOffset(); } CGStatusBar::~CGStatusBar() @@ -5737,6 +5694,19 @@ void CGStatusBar::init() GH.statusbar = this; } +void CGStatusBar::calcOffset() +{ + switch(alignment) + { + case CENTER: + textOffset = Point(pos.w/2, pos.h/2); + break; + case BOTTOMRIGHT: + textOffset = Point(pos.w, pos.h); + break; + } +} + CTextInput::CTextInput( const Rect &Pos, const Point &bgOffset, const std::string &bgName, const CFunctionList &CB ) :cb(CB) { diff --git a/client/GUIClasses.h b/client/GUIClasses.h index 64c65a67b..04f275e58 100644 --- a/client/GUIClasses.h +++ b/client/GUIClasses.h @@ -329,8 +329,10 @@ public: CGStatusBar(int x, int y, EFonts Font = FONT_SMALL, EAlignment Align = CENTER, const SDL_Color &Color = zwykly, const std::string &Text = ""); CGStatusBar(CPicture *BG, EFonts Font = FONT_SMALL, EAlignment Align = CENTER, const SDL_Color &Color = zwykly); //given CPicture will be captured by created sbar and it's pos will be used as pos for sbar + CGStatusBar(int x, int y, std::string name, int maxw=-1); ~CGStatusBar(); + void calcOffset(); }; class CFocusable @@ -657,31 +659,30 @@ public: std::string hoverName; vstd::assigner as; const CGHeroInstance *h; - void activate(); - void deactivate(); + char descr[100]; // "XXX is a level Y ZZZ with N artifacts" + void clickLeft(tribool down, bool previousState); void clickRight(tribool down, bool previousState); void hover (bool on); HeroPortrait(int &sel, int id, int x, int y, const CGHeroInstance *H); void show(SDL_Surface * to); - char descr[100]; // "XXX is a level Y ZZZ with N artifacts" - } h1, h2; //recruitable heroes - SDL_Surface *bg; //background - CStatusBar *bar; //tavern's internal status bar + } *h1, *h2; //recruitable heroes + + CPicture *bg; //background + CGStatusBar *bar; //tavern's internal status bar int selected;//0 (left) or 1 (right) int oldSelected;//0 (left) or 1 (right) AdventureMapButton *thiefGuild, *cancel, *recruit; + const CGObjectInstance *tavernObj; - CTavernWindow(const CGHeroInstance *H1, const CGHeroInstance *H2, const std::string &gossip); //c-tor + CTavernWindow(const CGObjectInstance *TavernObj); //c-tor ~CTavernWindow(); //d-tor void recruitb(); void close(); void thievesguildb(); - void activate(); - void deactivate(); void show(SDL_Surface * to); }; @@ -1049,7 +1050,7 @@ class CThievesGuildWindow : public CIntObject { const CGObjectInstance * owner; - CStatusBar * statusBar; + CGStatusBar * statusBar; AdventureMapButton * exitb; SDL_Surface * background; CMinorResDataBar * resdatabar; diff --git a/client/NetPacksClient.cpp b/client/NetPacksClient.cpp index 3625d81d5..adc54687e 100644 --- a/client/NetPacksClient.cpp +++ b/client/NetPacksClient.cpp @@ -343,10 +343,12 @@ void HeroRecruited::applyCl( CClient *cl ) CGI->mh->initHeroDef(h); CGI->mh->printObject(h); + if(vstd::contains(cl->playerint,h->tempOwner)) { cl->playerint[h->tempOwner]->heroCreated(h); - cl->playerint[h->tempOwner]->heroInGarrisonChange(GS(cl)->getTown(tid)); + if(const CGTownInstance *t = GS(cl)->getTown(tid)) + cl->playerint[h->tempOwner]->heroInGarrisonChange(t); } } @@ -733,6 +735,10 @@ void OpenWindow::applyCl(CClient *cl) { INTERFACE_CALL_IF_PRESENT(id1, showPuzzleMap); } + case TAVERN_WINDOW: + const CGObjectInstance *obj1 = cl->getObj(id1), + *obj2 = cl->getObj(id2); + INTERFACE_CALL_IF_PRESENT(obj1->tempOwner, showTavernWindow, obj2); break; } diff --git a/hch/CObjectHandler.cpp b/hch/CObjectHandler.cpp index 20051c350..e4ce5ef3f 100644 --- a/hch/CObjectHandler.cpp +++ b/hch/CObjectHandler.cpp @@ -383,6 +383,12 @@ bool CGObjectInstance::operator<(const CGObjectInstance & cmp) const //screen p void CGObjectInstance::initObj() { + switch(ID) + { + case 95: + blockVisit = true; + break; + } } void CGObjectInstance::setProperty( ui8 what, ui32 val ) @@ -474,6 +480,15 @@ void CGObjectInstance::giveDummyBonus(int heroID, ui8 duration) const void CGObjectInstance::onHeroVisit( const CGHeroInstance * h ) const { + switch(ID) + { + case 95: + OpenWindow ow; + ow.window = OpenWindow::TAVERN_WINDOW; + ow.id1 = h->id; + ow.id2 = id; + cb->sendAndApply(&ow); + } } ui8 CGObjectInstance::getPassableness() const diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index 347b2f311..897fa01fe 100644 --- a/lib/CGameState.cpp +++ b/lib/CGameState.cpp @@ -893,7 +893,12 @@ CGTownInstance *CGameState::getTown(int objid) { if(objid<0 || objid>=map->objects.size()) return NULL; - return static_cast(map->objects[objid]); + CGObjectInstance *obj = map->objects[objid]; + + if(obj->ID != TOWNI_TYPE) + return NULL; + + return static_cast(obj); } const CGTownInstance * CGameState::getTown( int objid ) const diff --git a/lib/IGameCallback.cpp b/lib/IGameCallback.cpp index 996b02fe9..5f4246188 100644 --- a/lib/IGameCallback.cpp +++ b/lib/IGameCallback.cpp @@ -8,6 +8,7 @@ #include "../hch/CSpellHandler.h" #include "../lib/VCMI_Lib.h" #include +#include "../hch/CTownHandler.h" /* * IGameCallback.cpp, part of VCMI engine @@ -233,3 +234,8 @@ const PlayerState * IGameCallback::getPlayerState( int color ) { return gs->getPlayer(color, false); } + +const CTown * IGameCallback::getNativeTown(int color) +{ + return &VLC->townh->towns[gs->scenarioOps->getIthPlayersSettings(color).castle]; +} \ No newline at end of file diff --git a/lib/IGameCallback.h b/lib/IGameCallback.h index 05aed0615..44b7aacbb 100644 --- a/lib/IGameCallback.h +++ b/lib/IGameCallback.h @@ -36,6 +36,7 @@ class CArtifact; class CArmedInstance; struct TerrainTile; struct PlayerState; +class CTown; class DLL_EXPORT IGameCallback { @@ -67,6 +68,7 @@ public: virtual int3 getMapSize(); //returns size of the map virtual TerrainTile * getTile(int3 pos); virtual const PlayerState * getPlayerState(int color); + virtual const CTown *getNativeTown(int color); //do sth virtual void changeSpells(int hid, bool give, const std::set &spells)=0; diff --git a/lib/NetPacks.h b/lib/NetPacks.h index b37de2420..65f2eca98 100644 --- a/lib/NetPacks.h +++ b/lib/NetPacks.h @@ -627,7 +627,8 @@ struct OpenWindow : public CPackForClient //517 OpenWindow(){type = 517;}; void applyCl(CClient *cl); - enum EWindow {EXCHANGE_WINDOW, RECRUITMENT_FIRST, RECRUITMENT_ALL, SHIPYARD_WINDOW, THIEVES_GUILD, PUZZLE_MAP, MARKET_WINDOW}; + enum EWindow {EXCHANGE_WINDOW, RECRUITMENT_FIRST, RECRUITMENT_ALL, SHIPYARD_WINDOW, THIEVES_GUILD, PUZZLE_MAP, + MARKET_WINDOW, TAVERN_WINDOW}; ui8 window; ui32 id1, id2; @@ -1434,12 +1435,13 @@ struct HireHero : public CPackForServer { HireHero(){}; HireHero(si32 HID, si32 TID):hid(HID),tid(TID){}; - si32 hid, tid; //available hero serial and town id + si32 hid, tid; //available hero serial and town (tavern) id + ui8 player; bool applyGh(CGameHandler *gh); template void serialize(Handler &h, const int version) { - h & hid & tid; + h & hid & tid & player; } }; diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp index 6a4536362..7639f700e 100644 --- a/lib/NetPacksLib.cpp +++ b/lib/NetPacksLib.cpp @@ -551,8 +551,12 @@ DLL_EXPORT void HeroRecruited::applyGs( CGameState *gs ) gs->getPlayer(h->getOwner())->heroes.push_back(h); h->initObj(); gs->map->addBlockVisTiles(h); - t->visitingHero = h; - h->visitedTown = t; + + if(t) + { + t->visitingHero = h; + h->visitedTown = t; + } h->inTownGarrison = false; } diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 70d56dfcf..b7ecc454b 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -952,8 +952,6 @@ void CGameHandler::newTurn() if(gs->getDate(1)==7) //first day of week - new heroes in tavern { - const CTown *nativeTownType = &VLC->townh->towns[gs->scenarioOps->getIthPlayersSettings(i->first).castle]; - SetAvailableHeroes sah; sah.player = i->first; @@ -961,7 +959,7 @@ void CGameHandler::newTurn() CHeroClass *banned = NULL; for (int j = 0; j < AVAILABLE_HEROES_PER_PLAYER; j++) { - if(CGHeroInstance *h = gs->hpool.pickHeroFor(j == 0, i->first, nativeTownType, pool, banned)) //first hero - native if possible, second hero -> any other class + if(CGHeroInstance *h = gs->hpool.pickHeroFor(j == 0, i->first, getNativeTown(i->first), pool, banned)) //first hero - native if possible, second hero -> any other class { sah.hid[j] = h->subID; h->initArmy(sah.army[j] = new CCreatureSet()); @@ -3279,35 +3277,47 @@ bool CGameHandler::setFormation( si32 hid, ui8 formation ) return true; } -bool CGameHandler::hireHero( ui32 tid, ui8 hid ) +bool CGameHandler::hireHero(const CGObjectInstance *obj, ui8 hid, ui8 player) { - const CGTownInstance *t = gs->getTown(tid); - const PlayerState *p = gs->getPlayer(t->tempOwner); + const PlayerState *p = gs->getPlayer(player); + const CGTownInstance *t = gs->getTown(obj->id); - if(!vstd::contains(t->builtBuildings,5) && complain("No tavern!") - || p->resources[6]<2500 && complain("Not enough gold for buying hero!") - || t->visitingHero && complain("There is visiting hero - no place!") - || getHeroCount(t->tempOwner,false) >= 8 && complain("Cannot hire hero, only 8 wandering heroes are allowed!") - ) + //common prconditions + if( p->resources[6]<2500 && complain("Not enough gold for buying hero!") + || getHeroCount(player, false) >= 8 && complain("Cannot hire hero, only 8 wandering heroes are allowed!")) return false; + + if(t) //tavern in town + { + if(!vstd::contains(t->builtBuildings,5) && complain("No tavern!") + || t->visitingHero && complain("There is visiting hero - no place!")) + return false; + } + else if(obj->ID == 95) //Tavern on adv map + { + if(getTile(obj->visitablePos())->visitableObjects.back() != obj && complain("Tavern entry must be unoccupied!")) + return false; + } + + CGHeroInstance *nh = p->availableHeroes[hid]; assert(nh); HeroRecruited hr; - hr.tid = tid; + hr.tid = obj->id; hr.hid = nh->subID; - hr.player = t->tempOwner; - hr.tile = t->pos - int3(1,0,0); + hr.player = player; + hr.tile = obj->visitablePos() + nh->getVisitableOffset(); sendAndApply(&hr); std::map pool = gs->unusedHeroesFromPool(); const CGHeroInstance *theOtherHero = p->availableHeroes[!hid]; - const CGHeroInstance *newHero = gs->hpool.pickHeroFor(false, t->tempOwner,t->town, pool, theOtherHero->type->heroClass); + const CGHeroInstance *newHero = gs->hpool.pickHeroFor(false, player, getNativeTown(player), pool, theOtherHero->type->heroClass); SetAvailableHeroes sah; - sah.player = t->tempOwner; + sah.player = player; if(newHero) { @@ -3322,13 +3332,16 @@ bool CGameHandler::hireHero( ui32 tid, ui8 hid ) sendAndApply(&sah); SetResource sr; - sr.player = t->tempOwner; + sr.player = player; sr.resid = 6; sr.val = p->resources[6] - 2500; sendAndApply(&sr); - vistiCastleObjects (t, nh); - giveSpells (t,nh); + if(t) + { + vistiCastleObjects (t, nh); + giveSpells (t,nh); + } return true; } diff --git a/server/CGameHandler.h b/server/CGameHandler.h index f26a92720..ec7d7b03d 100644 --- a/server/CGameHandler.h +++ b/server/CGameHandler.h @@ -166,7 +166,7 @@ public: void handleSpellCasting(int spellID, int spellLvl, int destination, ui8 casterSide, ui8 casterColor, const CGHeroInstance * caster, const CGHeroInstance * secHero, int usedSpellPower); bool makeCustomAction(BattleAction &ba); bool queryReply( ui32 qid, ui32 answer ); - bool hireHero( ui32 tid, ui8 hid ); + bool hireHero( const CGObjectInstance *obj, ui8 hid, ui8 player ); bool buildBoat( ui32 objid ); bool setFormation( si32 hid, ui8 formation ); bool tradeResources(const IMarket *market, ui32 val, ui8 player, ui32 id1, ui32 id2); diff --git a/server/NetPacksServer.cpp b/server/NetPacksServer.cpp index 8d6e70d3b..e9060ef1e 100644 --- a/server/NetPacksServer.cpp +++ b/server/NetPacksServer.cpp @@ -171,8 +171,13 @@ bool SetFormation::applyGh( CGameHandler *gh ) bool HireHero::applyGh( CGameHandler *gh ) { - ERROR_IF_NOT_OWNS(tid); - return gh->hireHero(tid,hid); + const CGObjectInstance *obj = gh->getObj(tid); + + if(obj->ID == TOWNI_TYPE) + ERROR_IF_NOT_OWNS(tid); + //TODO check for visiting hero + + return gh->hireHero(obj, hid,player); } bool BuildBoat::applyGh( CGameHandler *gh )