From efb1049860bef78a5b259f979b0b7e0ecede2f63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20W=2E=20Urba=C5=84czyk?= Date: Sat, 12 Sep 2009 22:17:23 +0000 Subject: [PATCH] * fixed crashes with paths when fastly switching heroes * fixed and improved slider behavior * fixed possible thread access conflicts * support for attacking town with visiting hero * fixed dwellings saving * minor improvements --- CCallback.cpp | 7 +++++++ client/AdventureMapButton.cpp | 17 +++++++---------- client/AdventureMapButton.h | 2 +- client/CAdvmapInterface.cpp | 4 ++++ client/CPlayerInterface.cpp | 2 ++ client/Client.h | 6 +++--- client/GUIClasses.cpp | 25 +++++++++++++++++++++++++ client/GUIClasses.h | 4 ++++ client/NetPacksClient.cpp | 2 +- hch/CObjectHandler.cpp | 26 ++++++++++++++------------ lib/CGameState.cpp | 20 +++++++++++++------- lib/IGameCallback.h | 6 +++--- lib/RegisterTypes.cpp | 1 + server/CGameHandler.cpp | 8 ++++---- server/CGameHandler.h | 7 +++---- 15 files changed, 92 insertions(+), 45 deletions(-) diff --git a/CCallback.cpp b/CCallback.cpp index 24025df26..bfb2e3664 100644 --- a/CCallback.cpp +++ b/CCallback.cpp @@ -738,6 +738,13 @@ void CCallback::setSelection(const CArmedInstance * obj) ss.player = player; ss.id = obj->id; sendRequest(&ss); + + if(obj->ID == HEROI_TYPE) + { + cl->gs->calculatePaths(static_cast(obj), *cl->pathInfo); + //nasty workaround. TODO: nice workaround + cl->gs->getPlayer(player)->currentSelection = obj->id; + } } void CCallback::recruitHero(const CGTownInstance *town, const CGHeroInstance *hero) diff --git a/client/AdventureMapButton.cpp b/client/AdventureMapButton.cpp index 1c6a528d3..1f831f12f 100644 --- a/client/AdventureMapButton.cpp +++ b/client/AdventureMapButton.cpp @@ -91,6 +91,7 @@ AdventureMapButton::AdventureMapButton () ourObj=NULL; state=0; blocked = actOnDown = false; + used = LCLICK | RCLICK | HOVER | KEYBOARD; } //AdventureMapButton::AdventureMapButton( std::string Name, std::string HelpBox, boost::function Callback, int x, int y, std::string defName, bool activ, std::vector * add, bool playerColoredButton) //{ @@ -435,10 +436,9 @@ void CHighlightableButtonsGroup::block( ui8 on ) void CSlider::sliderClicked() { - if(!moving) + if(!(active & MOVE)) { activateMouseMove(); - moving = true; } } @@ -527,26 +527,24 @@ void CSlider::clickLeft(tribool down, bool previousState) float rw = 0; if(horizontal) { - pw = GH.current->motion.x-pos.x-16; + pw = GH.current->motion.x-pos.x-25; rw = pw / ((float)(pos.w-48)); } else { - pw = GH.current->motion.y-pos.y-16; + pw = GH.current->motion.y-pos.y-24; rw = pw / ((float)(pos.h-48)); } - if(pw < 0 || pw > (horizontal ? pos.w : pos.h) - 32) + if(pw < -8 || pw > (horizontal ? pos.w : pos.h) - 40) return; // if (rw>1) return; // if (rw<0) return; + slider->clickLeft(true, slider->pressedL); moveTo(rw * positions + 0.5f); return; } - if(moving) - { + if(active & MOVE) deactivateMouseMove(); - moving = false; - } } CSlider::~CSlider() @@ -561,7 +559,6 @@ CSlider::CSlider(int x, int y, int totalw, boost::function Moved, int setAmount(amount); used = LCLICK; - moving = false; strongInterest = true; diff --git a/client/AdventureMapButton.h b/client/AdventureMapButton.h index 51cd5fdaf..d21a009fe 100644 --- a/client/AdventureMapButton.h +++ b/client/AdventureMapButton.h @@ -120,7 +120,7 @@ public: amount, //how many elements positions, //number of highest position (0 if there is only one) value; //first active element - bool horizontal, moving; + bool horizontal; CDefEssential *imgs ; boost::function moved; diff --git a/client/CAdvmapInterface.cpp b/client/CAdvmapInterface.cpp index cac9f2a18..8fc2ecacd 100644 --- a/client/CAdvmapInterface.cpp +++ b/client/CAdvmapInterface.cpp @@ -1896,13 +1896,17 @@ void CAdvMapInt::select(const CArmedInstance *sel ) { int pos = vstd::findPos(townList.items,sel); townList.selected = pos; + townList.fixPos(); } else //hero selected { const CGHeroInstance *h = static_cast(sel); if(LOCPLINT->getWHero(heroList.selected) != h) + { heroList.selected = heroList.getPosOfHero(h); + heroList.fixPos(); + } if(vstd::contains(paths,h)) //hero has assigned path { diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index a37279bc6..691320a0e 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -1504,12 +1504,14 @@ void CPlayerInterface::requestRealized( PackageApplied *pa ) void CPlayerInterface::heroExchangeStarted(si32 hero1, si32 hero2) { + boost::unique_lock un(*pim); GH.pushInt(new CExchangeWindow(hero2, hero1)); } void CPlayerInterface::objectPropertyChanged(const SetObjectProperty * sop) { //redraw minimap if owner changed + boost::unique_lock un(*pim); if(sop->what == 1) { const CGObjectInstance * obj = cb->getObjectInfo(sop->id); diff --git a/client/Client.h b/client/Client.h index f32cdca53..6dc3c161d 100644 --- a/client/Client.h +++ b/client/Client.h @@ -104,9 +104,9 @@ public: void heroVisitCastle(int obj, int heroID){}; void stopHeroVisitCastle(int obj, int heroID){}; void giveHeroArtifact(int artid, int hid, int position){}; //pos==-1 - first free slot in backpack=0; pos==-2 - default if available or backpack - void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank, boost::function cb = 0, const CGTownInstance *town = NULL){}; //use hero=NULL for no hero - void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, bool creatureBank, boost::function cb = 0){}; //if any of armies is hero, hero will be used - void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, bool creatureBank, boost::function cb = 0){}; //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle + void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, boost::function cb = 0, const CGTownInstance *town = NULL){}; //use hero=NULL for no hero + void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, boost::function cb = 0, bool creatureBank = false){}; //if any of armies is hero, hero will be used + void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, boost::function cb = 0, bool creatureBank = false){}; //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle void setAmount(int objid, ui32 val){}; bool moveHero(si32 hid, int3 dst, ui8 instant, ui8 asker = 255){return false;}; void giveHeroBonus(GiveBonus * bonus){}; diff --git a/client/GUIClasses.cpp b/client/GUIClasses.cpp index 1f75ebcc4..c8d0ac79b 100644 --- a/client/GUIClasses.cpp +++ b/client/GUIClasses.cpp @@ -1126,6 +1126,20 @@ CList::CList(int Size) { } +void CList::fixPos() +{ + int oldFrom = from; + if(selected < 0) //no selection, do nothing + return; + if(selected < from) //scroll up + from = selected; + else if(from + SIZE <= selected) + from = selected - SIZE + 1; + + amin(from, size() - SIZE); + amax(from, 0); +} + CHeroList::CHeroList(int Size) :CList(Size), heroes(LOCPLINT->wanderingHeroes) { @@ -1422,6 +1436,12 @@ void CHeroList::show( SDL_Surface * to ) { } + +int CHeroList::size() +{ + return heroes.size(); +} + CTownList::~CTownList() { delete arrup; @@ -1659,6 +1679,11 @@ void CTownList::show( SDL_Surface * to ) } +int CTownList::size() +{ + return items.size(); +} + CCreaturePic::CCreaturePic(const CCreature *cre, bool Big) :c(cre),big(Big) { diff --git a/client/GUIClasses.h b/client/GUIClasses.h index 2320edbd9..20eaa520a 100644 --- a/client/GUIClasses.h +++ b/client/GUIClasses.h @@ -272,6 +272,8 @@ public: virtual void genList()=0; virtual void select(int which)=0; virtual void draw(SDL_Surface * to)=0; + virtual int size() = 0; //how many elements do we have + void fixPos(); //scrolls list, so the selection will be visible }; class CHeroList : public CList @@ -295,6 +297,7 @@ public: void draw(SDL_Surface * to); void show(SDL_Surface * to); void init(); + int size(); //how many elements do we have }; class CTownList @@ -316,6 +319,7 @@ public: void keyPressed (const SDL_KeyboardEvent & key); //call-in void draw(SDL_Surface * to); void show(SDL_Surface * to); + int size(); //how many elements do we have }; class CCreaturePic //draws picture with creature on background, use nextFrame=true to get animation diff --git a/client/NetPacksClient.cpp b/client/NetPacksClient.cpp index 962839e47..5d311ce1d 100644 --- a/client/NetPacksClient.cpp +++ b/client/NetPacksClient.cpp @@ -547,7 +547,7 @@ void SetSelection::applyCl(CClient *cl) if(!h) return; - CPackForClient::GS(cl)->calculatePaths(h, *cl->pathInfo); + //CPackForClient::GS(cl)->calculatePaths(h, *cl->pathInfo); } void ShowInInfobox::applyCl(CClient *cl) diff --git a/hch/CObjectHandler.cpp b/hch/CObjectHandler.cpp index 039b56494..c8637bf2b 100644 --- a/hch/CObjectHandler.cpp +++ b/hch/CObjectHandler.cpp @@ -777,10 +777,12 @@ void CGHeroInstance::onHeroVisit(const CGHeroInstance * h) const //exchange cb->heroExchange(id, h->id); } - else + else //battle { - //battle - cb->startBattleI(h, this, false); + if(visitedTown) //we're in town + visitedTown->onHeroVisit(h); //town will handle attacking + else + cb->startBattleI(h, this); } } else if(ID == 62) //prison @@ -1350,7 +1352,7 @@ void CGDwelling::heroAcceptsCreatures( const CGHeroInstance *h, ui32 answer ) co void CGDwelling::wantsFight( const CGHeroInstance *h, ui32 answer ) const { if(answer) - cb->startBattleI(h, this, false, boost::bind(&CGDwelling::fightOver, this, h, _1)); + cb->startBattleI(h, this, boost::bind(&CGDwelling::fightOver, this, h, _1)); } void CGDwelling::fightOver(const CGHeroInstance *h, BattleResult *result) const @@ -1503,7 +1505,7 @@ void CGTownInstance::onHeroVisit(const CGHeroInstance * h) const if(getOwner() != h->getOwner()) { //TODO ally check - if(army) + if(army || visitingHero) { const CGHeroInstance *defendingHero = NULL; if(visitingHero) @@ -2226,7 +2228,7 @@ void CGCreature::joinDecision(const CGHeroInstance *h, int cost, ui32 accept) co void CGCreature::fight( const CGHeroInstance *h ) const { - cb->startBattleI(h, this, false, boost::bind(&CGCreature::endBattle,this,_1)); + cb->startBattleI(h, this, boost::bind(&CGCreature::endBattle,this,_1)); } void CGCreature::flee( const CGHeroInstance * h ) const @@ -2362,7 +2364,7 @@ void CGResource::collectRes( int player ) const void CGResource::fightForRes(ui32 agreed, const CGHeroInstance *h) const { if(agreed) - cb->startBattleI(h, this, false, boost::bind(&CGResource::endBattle,this,_1,h)); + cb->startBattleI(h, this, boost::bind(&CGResource::endBattle,this,_1,h)); } void CGResource::endBattle( BattleResult *result, const CGHeroInstance *h ) const @@ -2614,7 +2616,7 @@ void CGArtifact::pick(const CGHeroInstance * h) const void CGArtifact::fightForArt( ui32 agreed, const CGHeroInstance *h ) const { if(agreed) - cb->startBattleI(h, this, false, boost::bind(&CGArtifact::endBattle,this,_1,h)); + cb->startBattleI(h, this, boost::bind(&CGArtifact::endBattle,this,_1,h)); } void CGArtifact::endBattle( BattleResult *result, const CGHeroInstance *h ) const @@ -3118,7 +3120,7 @@ void CGPandoraBox::open( const CGHeroInstance * h, ui32 accept ) const iw.player = h->tempOwner; iw.text.addTxt(MetaString::ADVOB_TXT, 16); cb->showInfoDialog(&iw); - cb->startBattleI(h, this, false, boost::bind(&CGPandoraBox::endBattle, this, h, _1)); //grants things after battle + cb->startBattleI(h, this, boost::bind(&CGPandoraBox::endBattle, this, h, _1)); //grants things after battle } else if (message.size() == 0 && resources.size() == 0 && primskills.size() == 0 && abilities.size() == 0 @@ -3415,7 +3417,7 @@ void CGEvent::activated( const CGHeroInstance * h ) const else iw.text.addTxt(MetaString::ADVOB_TXT, 16); cb->showInfoDialog(&iw); - cb->startBattleI(h, this, false, boost::bind(&CGEvent::endBattle,this,h,_1)); + cb->startBattleI(h, this, boost::bind(&CGEvent::endBattle,this,h,_1)); } else { @@ -3623,7 +3625,7 @@ void CGGarrison::onHeroVisit (const CGHeroInstance *h) const { if (h->tempOwner != tempOwner && army) { //TODO: Find a way to apply magic garrison effects in battle. - cb->startBattleI(h, this, false, boost::bind(&CGGarrison::fightOver, this, h, _1)); + cb->startBattleI(h, this, boost::bind(&CGGarrison::fightOver, this, h, _1)); return; } @@ -4026,7 +4028,7 @@ void CBank::fightGuards (const CGHeroInstance * h, ui32 accept) const if (accept) { cb->setObjProperty (id, 17, ran()); //get army - cb->startBattleI (h, this, true, boost::bind (&CBank::endBattle, this, h, _1)); + cb->startBattleI (h, this, boost::bind (&CBank::endBattle, this, h, _1), true); } } void CBank::endBattle (const CGHeroInstance *h, const BattleResult *result) const diff --git a/lib/CGameState.cpp b/lib/CGameState.cpp index dc5246284..3697c4d16 100644 --- a/lib/CGameState.cpp +++ b/lib/CGameState.cpp @@ -1485,16 +1485,22 @@ void CGameState::init(StartInfo * si, Mapa * map, int Seed) //init visiting and garrisoned heroes for(unsigned int l=0; lsecond.heroes.size();l++) { + CGHeroInstance *h = k->second.heroes[l]; for(unsigned int m=0; msecond.towns.size();m++) { - int3 vistile = k->second.towns[m]->pos; vistile.x--; //tile next to the entrance - if(vistile == k->second.heroes[l]->pos || k->second.heroes[l]->pos==k->second.towns[m]->pos) + CGTownInstance *t = k->second.towns[m]; + int3 vistile = t->pos; vistile.x--; //tile next to the entrance + if(vistile == h->pos || h->pos==t->pos) { - k->second.towns[m]->visitingHero = k->second.heroes[l]; - k->second.heroes[l]->visitedTown = k->second.towns[m]; - k->second.heroes[l]->inTownGarrison = false; - if(k->second.heroes[l]->pos==k->second.towns[m]->pos) - k->second.heroes[l]->pos.x -= 1; + t->visitingHero = h; + h->visitedTown = t; + h->inTownGarrison = false; + if(h->pos == t->pos) //visiting hero placed in the editor has same pos as the town - we need to correct it + { + map->removeBlockVisTiles(h); + h->pos.x -= 1; + map->addBlockVisTiles(h); + } break; } } diff --git a/lib/IGameCallback.h b/lib/IGameCallback.h index 0e227f780..698f24424 100644 --- a/lib/IGameCallback.h +++ b/lib/IGameCallback.h @@ -80,9 +80,9 @@ public: virtual void heroVisitCastle(int obj, int heroID)=0; virtual void stopHeroVisitCastle(int obj, int heroID)=0; virtual void giveHeroArtifact(int artid, int hid, int position)=0; //pos==-1 - first free slot in backpack=0; pos==-2 - default if available or backpack - virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank, boost::function cb = 0, const CGTownInstance *town = NULL)=0; //use hero=NULL for no hero - virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, bool creatureBank, boost::function cb = 0)=0; //if any of armies is hero, hero will be used - virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, bool creatureBank, boost::function cb = 0)=0; //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle + virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, boost::function cb = 0, const CGTownInstance *town = NULL)=0; //use hero=NULL for no hero + virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, boost::function cb = 0, bool creatureBank = false)=0; //if any of armies is hero, hero will be used + virtual void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, boost::function cb = 0, bool creatureBank = false)=0; //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle //virtual void startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function cb)=0; //for hero<=>neutral army virtual void setAmount(int objid, ui32 val)=0; virtual bool moveHero(si32 hid, int3 dst, ui8 instant, ui8 asker = 255)=0; diff --git a/lib/RegisterTypes.cpp b/lib/RegisterTypes.cpp index b9a14dfeb..9f96f76a8 100644 --- a/lib/RegisterTypes.cpp +++ b/lib/RegisterTypes.cpp @@ -25,6 +25,7 @@ void registerTypes1(Serializer &s) s.template registerType(); s.template registerType(); s.template registerType(); + s.template registerType(); s.template registerType(); s.template registerType(); s.template registerType(); diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 26aa7be6d..d971fe0d5 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -1501,7 +1501,7 @@ bool CGameHandler::moveHero( si32 hid, int3 dst, ui8 instant, ui8 asker /*= 255* return true; } //TODO: check for ally - startBattleI(h, dh, false); + startBattleI(h, dh); return true; } } @@ -1670,7 +1670,7 @@ void CGameHandler::startBattleI(const CArmedInstance *army1, const CArmedInstanc boost::thread(boost::bind(&CGameHandler::startBattle, this, army1, army2, tile, hero1, hero2, creatureBank, cb, town)); } -void CGameHandler::startBattleI( const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, bool creatureBank, boost::function cb ) +void CGameHandler::startBattleI( const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, boost::function cb, bool creatureBank ) { startBattleI(army1, army2, tile, army1->ID == HEROI_TYPE ? static_cast(army1) : NULL, @@ -1678,9 +1678,9 @@ void CGameHandler::startBattleI( const CArmedInstance *army1, const CArmedInstan creatureBank, cb); } -void CGameHandler::startBattleI( const CArmedInstance *army1, const CArmedInstance *army2, bool creatureBank, boost::function cb) +void CGameHandler::startBattleI( const CArmedInstance *army1, const CArmedInstance *army2, boost::function cb, bool creatureBank) { - startBattleI(army1, army2, army2->pos - army2->getVisitableOffset(), creatureBank, cb); + startBattleI(army1, army2, army2->pos - army2->getVisitableOffset(), cb, creatureBank); } //void CGameHandler::startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function cb) //for hero<=>neutral army diff --git a/server/CGameHandler.h b/server/CGameHandler.h index f81dd7610..9c99eac11 100644 --- a/server/CGameHandler.h +++ b/server/CGameHandler.h @@ -122,10 +122,9 @@ public: void giveHeroArtifact(int artid, int hid, int position); //pos==-1 - first free slot in backpack; pos==-2 - default if available or backpack void moveArtifact(int hid, int oldPosition, int destPos); void removeArtifact(int hid, int pos); - void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank, boost::function cb, const CGTownInstance *town = NULL); //use hero=NULL for no hero - void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, bool creatureBank, boost::function cb); - void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, bool creatureBank, boost::function cb = 0); //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle - //void startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function cb); //for hero<=>neutral army + void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool creatureBank = false, boost::function cb = 0, const CGTownInstance *town = NULL); //use hero=NULL for no hero + void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, int3 tile, boost::function cb = 0, bool creatureBank = false); //if any of armies is hero, hero will be used + void startBattleI(const CArmedInstance *army1, const CArmedInstance *army2, boost::function cb = 0, bool creatureBank = false); //if any of armies is hero, hero will be used, visitable tile of second obj is place of battle//void startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function cb); //for hero<=>neutral army void setAmount(int objid, ui32 val); bool moveHero(si32 hid, int3 dst, ui8 instant, ui8 asker = 255); void giveHeroBonus(GiveBonus * bonus);