From 9f5d1ba6234ee7291a27c2d15906dd9b6c5b834b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20W=2E=20Urba=C5=84czyk?= Date: Mon, 27 May 2013 21:46:04 +0000 Subject: [PATCH] Fixed #1271. --- lib/CObjectHandler.cpp | 71 ++++++++++++++++++++++++++++------------- lib/CObjectHandler.h | 8 +++-- lib/IGameCallback.cpp | 7 ++++ lib/IGameCallback.h | 3 ++ server/CGameHandler.cpp | 9 ++++++ server/CGameHandler.h | 4 +++ server/CQuery.cpp | 10 ++++++ server/CQuery.h | 2 ++ 8 files changed, 89 insertions(+), 25 deletions(-) diff --git a/lib/CObjectHandler.cpp b/lib/CObjectHandler.cpp index 40078961e..1909a6ab9 100644 --- a/lib/CObjectHandler.cpp +++ b/lib/CObjectHandler.cpp @@ -140,6 +140,11 @@ void IObjectInterface::garrisonDialogClosed(const CGHeroInstance *hero) const } +void IObjectInterface::heroLevelUpDone(const CGHeroInstance *hero) const +{ + +} + void CPlayersVisited::setPropertyDer( ui8 what, ui32 val ) { if(what == 10) @@ -5307,6 +5312,7 @@ const std::string & CGMagicWell::getHoverText() const void CGPandoraBox::initObj() { blockVisit = (ID==Obj::PANDORAS_BOX); //block only if it's really pandora's box (events also derive from that class) + hasGuardians = stacks.size(); } void CGPandoraBox::onHeroVisit(const CGHeroInstance * h) const @@ -5318,11 +5324,12 @@ void CGPandoraBox::onHeroVisit(const CGHeroInstance * h) const cb->showBlockingDialog (&bd); } -void CGPandoraBox::giveContents( const CGHeroInstance *h, bool afterBattle ) const +void CGPandoraBox::giveContentsUpToExp(const CGHeroInstance *h) const { + cb->removeAfterVisit(this); + InfoWindow iw; iw.player = h->getOwner(); - std::string msg = message; //in case box is removed in the meantime bool changesPrimSkill = false; for (int i = 0; i < primskills.size(); i++) @@ -5352,14 +5359,6 @@ void CGPandoraBox::giveContents( const CGHeroInstance *h, bool afterBattle ) con cb->showInfoDialog(&iw); - //give exp - if(expVal) - cb->changePrimSkill(h, PrimarySkill::EXPERIENCE, expVal, false); - //give prim skills - for(int i=0; ichangePrimSkill(h,static_cast(i),primskills[i],false); - //give sec skills for(int i=0; ichangePrimSkill(h,static_cast(i),primskills[i],false); + + assert(!cb->isVisitCoveredByAnotherQuery(this, h)); + + //give exp + if(expVal) + cb->changePrimSkill(h, PrimarySkill::EXPERIENCE, expVal, false); } + if(!cb->isVisitCoveredByAnotherQuery(this, h)) + giveContentsAfterExp(h); + //Otherwise continuation occurs via post-level-up callback. +} + +void CGPandoraBox::giveContentsAfterExp(const CGHeroInstance *h) const +{ + bool hadGuardians = hasGuardians; //copy, because flag will be emptied after issuing first post-battle message + + std::string msg = message; //in case box is removed in the meantime + InfoWindow iw; + iw.player = h->getOwner(); + if(spells.size()) { std::set spellsToGive; @@ -5404,7 +5426,7 @@ void CGPandoraBox::giveContents( const CGHeroInstance *h, bool afterBattle ) con if(manaDiff) { - getText(iw,afterBattle,manaDiff,176,177,h); + getText(iw,hadGuardians,manaDiff,176,177,h); iw.components.push_back(Component(Component::PRIM_SKILL,5,manaDiff,0)); cb->showInfoDialog(&iw); cb->setManaPoints(h->id, h->mana + manaDiff); @@ -5412,7 +5434,7 @@ void CGPandoraBox::giveContents( const CGHeroInstance *h, bool afterBattle ) con if(moraleDiff) { - getText(iw,afterBattle,moraleDiff,178,179,h); + getText(iw,hadGuardians,moraleDiff,178,179,h); iw.components.push_back(Component(Component::MORALE,0,moraleDiff,0)); cb->showInfoDialog(&iw); GiveBonus gb; @@ -5423,7 +5445,7 @@ void CGPandoraBox::giveContents( const CGHeroInstance *h, bool afterBattle ) con if(luckDiff) { - getText(iw,afterBattle,luckDiff,180,181,h); + getText(iw,hadGuardians,luckDiff,180,181,h); iw.components.push_back(Component(Component::LUCK,0,luckDiff,0)); cb->showInfoDialog(&iw); GiveBonus gb; @@ -5441,7 +5463,7 @@ void CGPandoraBox::giveContents( const CGHeroInstance *h, bool afterBattle ) con } if(iw.components.size()) { - getText(iw,afterBattle,182,h); + getText(iw,hadGuardians,182,h); cb->showInfoDialog(&iw); } @@ -5454,12 +5476,12 @@ void CGPandoraBox::giveContents( const CGHeroInstance *h, bool afterBattle ) con } if(iw.components.size()) { - getText(iw,afterBattle,183,h); + getText(iw,hadGuardians,183,h); cb->showInfoDialog(&iw); } - iw.components.clear(); -// getText(iw,afterBattle,183,h); + iw.components.clear(); + // getText(iw,afterBattle,183,h); iw.text.addTxt(MetaString::ADVOB_TXT, 183); //% has found treasure iw.text.addReplacement(h->name); for(int i=0; ishowInfoDialog(&iw); cb->giveCreatures(this, h, creatures, true); } - if(!afterBattle && msg.size()) + if(!hasGuardians && msg.size()) { iw.text << msg; cb->showInfoDialog(&iw); } - if (!creatures.Slots().size()) - cb->removeObject(this); //only when we don't need to display garrison window } void CGPandoraBox::getText( InfoWindow &iw, bool &afterBattle, int text, const CGHeroInstance * h ) const @@ -5553,7 +5573,7 @@ void CGPandoraBox::battleFinished(const CGHeroInstance *hero, const BattleResult if(result.winner) return; - giveContents(hero, true); + giveContentsUpToExp(hero); } void CGPandoraBox::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const @@ -5576,11 +5596,16 @@ void CGPandoraBox::blockingDialogAnswered(const CGHeroInstance *hero, ui32 answe } else //if it gives something without battle { - giveContents(hero, false); + giveContentsUpToExp(hero); } } } +void CGPandoraBox::heroLevelUpDone(const CGHeroInstance *hero) const +{ + giveContentsAfterExp(hero); +} + void CGEvent::onHeroVisit( const CGHeroInstance * h ) const { if(!(availableFor & (1 << h->tempOwner.getNum()))) @@ -5609,7 +5634,7 @@ void CGEvent::activated( const CGHeroInstance * h ) const } else { - giveContents(h,false); + giveContentsUpToExp(h); } } diff --git a/lib/CObjectHandler.h b/lib/CObjectHandler.h index 982671c1b..64212632a 100644 --- a/lib/CObjectHandler.h +++ b/lib/CObjectHandler.h @@ -119,6 +119,7 @@ public: virtual void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const; virtual void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const; virtual void garrisonDialogClosed(const CGHeroInstance *hero) const; + virtual void heroLevelUpDone(const CGHeroInstance *hero) const; //unified interface, AI helpers virtual bool wasVisited (PlayerColor player) const; @@ -679,6 +680,7 @@ class DLL_LINKAGE CGPandoraBox : public CArmedInstance { public: std::string message; + bool hasGuardians; //helper - after battle even though we have no stacks, allows us to know that there was battle //gained things: ui32 gainedExp; @@ -697,15 +699,17 @@ public: void onHeroVisit(const CGHeroInstance * h) const override; void battleFinished(const CGHeroInstance *hero, const BattleResult &result) const OVERRIDE; void blockingDialogAnswered(const CGHeroInstance *hero, ui32 answer) const OVERRIDE; + void heroLevelUpDone(const CGHeroInstance *hero) const OVERRIDE; template void serialize(Handler &h, const int version) { h & static_cast(*this); - h & message & gainedExp & manaDiff & moraleDiff & luckDiff & resources & primskills + h & message & hasGuardians & gainedExp & manaDiff & moraleDiff & luckDiff & resources & primskills & abilities & abilityLevels & artifacts & spells & creatures; } protected: - void giveContents(const CGHeroInstance *h, bool afterBattle) const; + void giveContentsUpToExp(const CGHeroInstance *h) const; + void giveContentsAfterExp(const CGHeroInstance *h) const; private: void getText( InfoWindow &iw, bool &afterBattle, int val, int negative, int positive, const CGHeroInstance * h ) const; void getText( InfoWindow &iw, bool &afterBattle, int text, const CGHeroInstance * h ) const; diff --git a/lib/IGameCallback.cpp b/lib/IGameCallback.cpp index 25363d26f..e0a8c3c19 100644 --- a/lib/IGameCallback.cpp +++ b/lib/IGameCallback.cpp @@ -1012,3 +1012,10 @@ const CGCreature * IGameCallback::putNewMonster(CreatureID creID, int count, int setObjProperty(m->id, ObjProperty::MONSTER_POWER, (si64)1000*count); return dynamic_cast(m); } + +bool IGameCallback::isVisitCoveredByAnotherQuery(const CGObjectInstance *obj, const CGHeroInstance *hero) +{ + //only server knows + assert(0); + return false; +} diff --git a/lib/IGameCallback.h b/lib/IGameCallback.h index 6c537dd39..74bbc9c00 100644 --- a/lib/IGameCallback.h +++ b/lib/IGameCallback.h @@ -274,6 +274,9 @@ public: const CGObjectInstance *putNewObject(Obj ID, int subID, int3 pos); const CGCreature *putNewMonster(CreatureID creID, int count, int3 pos); + //get info + virtual bool isVisitCoveredByAnotherQuery(const CGObjectInstance *obj, const CGHeroInstance *hero); + friend struct CPack; friend struct CPackForClient; friend struct CPackForServer; diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 4f3dee308..493c28b77 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -6154,6 +6154,15 @@ void CGameHandler::removeAfterVisit(const CGObjectInstance *object) assert("This function needs to be called during the object visit!"); } +bool CGameHandler::isVisitCoveredByAnotherQuery(const CGObjectInstance *obj, const CGHeroInstance *hero) +{ + if(auto topQuery = queries.topQuery(hero->getOwner())) + if(auto visit = std::dynamic_pointer_cast(topQuery)) + return !(visit->visitedObject == obj && visit->visitingHero == hero); + + return true; +} + CasualtiesAfterBattle::CasualtiesAfterBattle(const CArmedInstance *army, BattleInfo *bat) { heroWithDeadCommander = ObjectInstanceID(); diff --git a/server/CGameHandler.h b/server/CGameHandler.h index ffb1843e2..dbc063a8a 100644 --- a/server/CGameHandler.h +++ b/server/CGameHandler.h @@ -178,6 +178,10 @@ public: void giveHero(ObjectInstanceID id, PlayerColor player) OVERRIDE; void changeObjPos(ObjectInstanceID objid, int3 newPos, ui8 flags) OVERRIDE; void heroExchange(ObjectInstanceID hero1, ObjectInstanceID hero2) OVERRIDE; + + + bool isVisitCoveredByAnotherQuery(const CGObjectInstance *obj, const CGHeroInstance *hero) OVERRIDE; + ////////////////////////////////////////////////////////////////////////// void useScholarSkill(ObjectInstanceID hero1, ObjectInstanceID hero2); void setPortalDwelling(const CGTownInstance * town, bool forced, bool clear); diff --git a/server/CQuery.cpp b/server/CQuery.cpp index 3a5f752cf..4afdb00af 100644 --- a/server/CQuery.cpp +++ b/server/CQuery.cpp @@ -295,6 +295,11 @@ void CHeroLevelUpDialogQuery::onRemoval(CGameHandler *gh, PlayerColor color) gh->levelUpHero(hlu.hero, hlu.skills[*answer]); } +void CHeroLevelUpDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const +{ + objectVisit.visitedObject->heroLevelUpDone(objectVisit.visitingHero); +} + CCommanderLevelUpDialogQuery::CCommanderLevelUpDialogQuery(const CommanderLevelUp &Clu) { clu = Clu; @@ -308,6 +313,11 @@ void CCommanderLevelUpDialogQuery::onRemoval(CGameHandler *gh, PlayerColor color gh->levelUpCommander(clu.hero->commander, clu.skills[*answer]); } +void CCommanderLevelUpDialogQuery::notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const +{ + objectVisit.visitedObject->heroLevelUpDone(objectVisit.visitingHero); +} + bool CDialogQuery::endsByPlayerAnswer() const { return true; diff --git a/server/CQuery.h b/server/CQuery.h index 345bd4407..2ab7f6089 100644 --- a/server/CQuery.h +++ b/server/CQuery.h @@ -135,6 +135,7 @@ public: CHeroLevelUpDialogQuery(const HeroLevelUp &Hlu); virtual void onRemoval(CGameHandler *gh, PlayerColor color) OVERRIDE; + virtual void notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const OVERRIDE; HeroLevelUp hlu; }; @@ -146,6 +147,7 @@ public: CCommanderLevelUpDialogQuery(const CommanderLevelUp &Clu); virtual void onRemoval(CGameHandler *gh, PlayerColor color) OVERRIDE; + virtual void notifyObjectAboutRemoval(const CObjectVisitQuery &objectVisit) const OVERRIDE; CommanderLevelUp clu; };