diff --git a/CGameInterface.h b/CGameInterface.h index d3d4649a6..79b3bb3fd 100644 --- a/CGameInterface.h +++ b/CGameInterface.h @@ -52,6 +52,7 @@ class CSaveFile; typedef si32 TQuantity; template class CISer; template class COSer; +struct ArtifactLocation; class CBattleGameInterface { @@ -100,7 +101,9 @@ public: //virtual void garrisonChanged(const CGObjectInstance * obj){}; //artifacts operations - virtual void heroArtifactSetChanged(const CGHeroInstance*hero){}; + virtual void artifactPut(const ArtifactLocation &al){}; + virtual void artifactRemoved(const ArtifactLocation &al){}; + virtual void artifactMoved(const ArtifactLocation &src, const ArtifactLocation &dst){}; virtual void heroCreated(const CGHeroInstance*){}; virtual void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector &skills, boost::function &callback)=0; //pskill is gained primary skill, interface has to choose one of given skills and call callback with selection id diff --git a/client/CAdvmapInterface.cpp b/client/CAdvmapInterface.cpp index ef771c237..3709ea728 100644 --- a/client/CAdvmapInterface.cpp +++ b/client/CAdvmapInterface.cpp @@ -1189,7 +1189,6 @@ townList(ADVOPT.tlistSize,ADVOPT.tlistX,ADVOPT.tlistY,ADVOPT.tlistAU,ADVOPT.tlis //townList.init(); //townList.genList(); - heroWindow = NULL; for (int g=0; gdeactivate(); const CGHeroInstance * buf = LOCPLINT->getWHero(id); - getOwner()->setHero(buf); - getOwner()->activate(); + GH.popIntTotally(getOwner()); + GH.pushInt(new CHeroWindow(buf)); } } @@ -61,7 +60,7 @@ CHeroWindow * CHeroSwitcher::getOwner() CHeroSwitcher::CHeroSwitcher(int serial) { - pos = Rect(677, 95 + serial * 54, 48, 32) + pos; + pos = Rect(612, 87 + serial * 54, 48, 32) + pos; id = serial; used = LCLICK; } @@ -69,9 +68,8 @@ CHeroSwitcher::CHeroSwitcher(int serial) CHeroWindow::CHeroWindow(const CGHeroInstance *hero) { OBJ_CONSTRUCTION_CAPTURING_ALL; - artifs = NULL; garr = NULL; - curHero = NULL; + curHero = hero; player = hero->tempOwner; background = new CPicture("HeroScr4.BMP"); @@ -118,12 +116,11 @@ CHeroWindow::CHeroWindow(const CGHeroInstance *hero) specArea = new LRClickableAreaWText(Rect(18, 180, 136, 42), CGI->generaltexth->heroscrn[27]); expArea = new LRClickableAreaWText(Rect(18, 228, 136, 42), CGI->generaltexth->heroscrn[9]); - morale = new MoraleLuckBox(true, Rect(175,179,53,45)); luck = new MoraleLuckBox(false, Rect(233,179,53,45)); spellPointsArea = new LRClickableAreaWText(Rect(162,228, 136, 42), CGI->generaltexth->heroscrn[22]); - for(int i=0; isecSkills.size(), 8u); ++i) { Rect r = Rect(i%2 == 0 ? 18 : 162, 276 + 48 * (i/2), 136, 42); secSkillAreas.push_back(new LRClickableAreaWTextComp(r, SComponent::secskill)); @@ -141,7 +138,7 @@ CHeroWindow::CHeroWindow(const CGHeroInstance *hero) new CPicture(graphics->pskillsm->ourImages[4].bitmap, 20, 230, false); new CPicture(graphics->pskillsm->ourImages[3].bitmap, 162, 230, false); - setHero(hero); + update(hero); } CHeroWindow::~CHeroWindow() @@ -154,21 +151,16 @@ CHeroWindow::~CHeroWindow() //artifs->dispose(); } -void CHeroWindow::setHero(const CGHeroInstance *hero) +void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded /*= false*/) { if(!hero) //something strange... no hero? it shouldn't happen { tlog1 << "Set NULL hero? no way...\n"; return; } - if(hero == curHero) - { - tlog3 << "Spurious call to CHeroWindow::setHero\n"; - return; - } + assert(hero == curHero); assert(hero->tempOwner == LOCPLINT->playerID); //for now we won't show hero windows for non-our heroes - curHero = hero; specArea->text = CGI->generaltexth->hTxts[hero->subID].longBonus; @@ -179,21 +171,29 @@ void CHeroWindow::setHero(const CGHeroInstance *hero) portraitArea->hoverText = boost::str(boost::format(CGI->generaltexth->allTexts[15]) % curHero->name % curHero->type->heroClass->name); portraitArea->text = hero->getBiography(); + { - delete garr; + AdventureMapButton * split = NULL; + { + BLOCK_CAPTURING; + split = new AdventureMapButton(CGI->generaltexth->allTexts[256], CGI->generaltexth->heroscrn[32], boost::bind(&CGarrisonInt::splitClick,garr), 604, 527, "hsbtns9.def", false, NULL, false); //deleted by garrison destructor + boost::algorithm::replace_first(split->hoverTexts[0],"%s",CGI->generaltexth->allTexts[43]); + } + //delete garr; OBJ_CONSTRUCTION_CAPTURING_ALL; - garr = new CGarrisonInt(15, 485, 8, Point(), background->bg, Point(15,485), curHero); - artifs = new CArtifactsOfHero(Point(-65, -8), true); - artifs->setHero(hero); + if(!garr) + { + garr = new CGarrisonInt(15, 485, 8, Point(), background->bg, Point(15,485), curHero); + garr->addSplitBtn(split); + } + if(!artSets.size()) + { + CArtifactsOfHero *arts = new CArtifactsOfHero(Point(-65, -8), true); + arts->setHero(hero); + artSets.push_back(arts); + } } - AdventureMapButton * split = NULL; - { - BLOCK_CAPTURING; - split = new AdventureMapButton(CGI->generaltexth->allTexts[256], CGI->generaltexth->heroscrn[32], boost::bind(&CGarrisonInt::splitClick,garr), 604, 527, "hsbtns9.def", false, NULL, false); //deleted by garrison destructor - } - boost::algorithm::replace_first(split->hoverTexts[0],"%s",CGI->generaltexth->allTexts[43]); - garr->addSplitBtn(split); //primary skills support for(size_t g=0; gsecSkills.size()); ++g) + for(size_t g=0; g< secSkillAreas.size(); ++g) { int skill = hero->secSkills[g].first, level = hero->getSecSkillLevel(static_cast(hero->secSkills[g].first)); @@ -212,7 +212,6 @@ void CHeroWindow::setHero(const CGHeroInstance *hero) secSkillAreas[g]->hoverText = boost::str(boost::format(CGI->generaltexth->heroscrn[21]) % CGI->generaltexth->levels[level-1] % CGI->generaltexth->skillName[skill]); } - //printing experience - original format does not support ui64 expArea->text = CGI->generaltexth->allTexts[2]; boost::replace_first(expArea->text, "%d", boost::lexical_cast(hero->level)); @@ -252,11 +251,13 @@ void CHeroWindow::setHero(const CGHeroInstance *hero) morale->set(hero); luck->set(hero); + + if(redrawNeeded) + redraw(); } void CHeroWindow::quit() { - adventureInt->heroWindow = NULL; GH.popIntTotally(this); } @@ -322,10 +323,6 @@ void CHeroWindow::showAll(SDL_Surface * to) printAtMiddleLoc(primarySkill.str(), 53 + 70 * m, 166, FONT_SMALL, zwykly, to); } - //morale and luck printing - blitAtLoc(graphics->luck42->ourImages[curHero->LuckVal()+3].bitmap, 239, 182, to); - blitAtLoc(graphics->morale42->ourImages[curHero->MoraleVal()+3].bitmap, 181, 182, to); - blitAtLoc(flags->ourImages[player].bitmap, 606, 8, to); //hero list blitting diff --git a/client/CHeroWindow.h b/client/CHeroWindow.h index 9714a3a19..190fd078e 100644 --- a/client/CHeroWindow.h +++ b/client/CHeroWindow.h @@ -38,7 +38,7 @@ public: -class CHeroWindow: public CWindowWithGarrison +class CHeroWindow: public CWindowWithGarrison, public CWindowWithArtifacts { enum ELabel {}; std::map labels; @@ -52,8 +52,6 @@ class CHeroWindow: public CWindowWithGarrison //AdventureMapButton * gar4button; //splitting std::vector heroListMi; //new better list of heroes - CArtifactsOfHero * artifs; - //clickable areas LRClickableAreaWText * portraitArea; std::vector primSkillAreas; @@ -71,7 +69,8 @@ public: int player; CHeroWindow(const CGHeroInstance *hero); //c-tor ~CHeroWindow(); //d-tor - void setHero(const CGHeroInstance * hero); //sets main displayed hero + + void update(const CGHeroInstance * hero, bool redrawNeeded = false); //sets main displayed hero void showAll(SDL_Surface * to); //shows and activates adv. map interface // void redrawCurBack(); //redraws curBAck from scratch void quit(); //stops displaying hero window and disposes diff --git a/client/CPlayerInterface.cpp b/client/CPlayerInterface.cpp index 529389761..eec6b83a4 100644 --- a/client/CPlayerInterface.cpp +++ b/client/CPlayerInterface.cpp @@ -46,6 +46,7 @@ #include #include #include "../StartInfo.h" +#include #ifdef min #undef min @@ -508,7 +509,7 @@ void CPlayerInterface::garrisonChanged(const CGObjectInstance * obj) { if((*i)->type & IShowActivable::WITH_GARRISON) { - CGarrisonHolder *cgh = static_cast(*i); + CGarrisonHolder *cgh = dynamic_cast(*i); cgh->updateGarrisons(); } else if(CTradeWindow *cmw = dynamic_cast(*i)) @@ -954,11 +955,9 @@ void CPlayerInterface::tileHidden(const std::set &pos) void CPlayerInterface::openHeroWindow(const CGHeroInstance *hero) { boost::unique_lock un(*pim); - adventureInt->heroWindow = new CHeroWindow(hero); - adventureInt->heroWindow->setHero(hero); - GH.pushInt(adventureInt->heroWindow); + GH.pushInt(new CHeroWindow(hero)); } - +/* void CPlayerInterface::heroArtifactSetChanged(const CGHeroInstance*hero) { boost::unique_lock un(*pim); @@ -997,7 +996,7 @@ void CPlayerInterface::heroArtifactSetChanged(const CGHeroInstance*hero) } updateInfo(hero); -} +}*/ void CPlayerInterface::availableCreaturesChanged( const CGDwelling *town ) { @@ -2121,21 +2120,25 @@ void CPlayerInterface::sendCustomEvent( int code ) void CPlayerInterface::stackChagedCount(const StackLocation &location, const TQuantity &change, bool isAbsolute) { + boost::unique_lock un(*pim); garrisonChanged(location.army); } void CPlayerInterface::stackChangedType(const StackLocation &location, const CCreature &newType) { + boost::unique_lock un(*pim); garrisonChanged(location.army); } void CPlayerInterface::stacksErased(const StackLocation &location) { + boost::unique_lock un(*pim); garrisonChanged(location.army); } void CPlayerInterface::stacksSwapped(const StackLocation &loc1, const StackLocation &loc2) { + boost::unique_lock un(*pim); garrisonChanged(loc1.army); if(loc2.army != loc1.army) garrisonChanged(loc2.army); @@ -2143,16 +2146,37 @@ void CPlayerInterface::stacksSwapped(const StackLocation &loc1, const StackLocat void CPlayerInterface::newStackInserted(const StackLocation &location, const CStackInstance &stack) { + boost::unique_lock un(*pim); garrisonChanged(location.army); } void CPlayerInterface::stacksRebalanced(const StackLocation &src, const StackLocation &dst, TQuantity count) { + boost::unique_lock un(*pim); garrisonChanged(src.army); if(dst.army != src.army) garrisonChanged(dst.army); } +void CPlayerInterface::artifactPut(const ArtifactLocation &al) +{ + boost::unique_lock un(*pim); +} + +void CPlayerInterface::artifactRemoved(const ArtifactLocation &al) +{ + boost::unique_lock un(*pim); +} + +void CPlayerInterface::artifactMoved(const ArtifactLocation &src, const ArtifactLocation &dst) +{ + boost::unique_lock un(*pim); + BOOST_FOREACH(IShowActivable *isa, GH.listInt) + if(isa->type & IShowActivable::WITH_ARTIFACTS) + BOOST_FOREACH(CArtifactsOfHero *aoh, (dynamic_cast(isa))->artSets) + aoh->artifactMoved(src, dst); +} + CPlayerInterface::SpellbookLastSetting::SpellbookLastSetting() { spellbookLastPageBattle = spellbokLastPageAdvmap = 0; diff --git a/client/CPlayerInterface.h b/client/CPlayerInterface.h index 3de23483e..6f9d64e64 100644 --- a/client/CPlayerInterface.h +++ b/client/CPlayerInterface.h @@ -166,7 +166,11 @@ public: void stacksSwapped(const StackLocation &loc1, const StackLocation &loc2) OVERRIDE; void newStackInserted(const StackLocation &location, const CStackInstance &stack) OVERRIDE; //new stack inserted at given (previously empty position) void stacksRebalanced(const StackLocation &src, const StackLocation &dst, TQuantity count) OVERRIDE; //moves creatures from src stack to dst slot, may be used for merging/splittint/moving stacks - void heroArtifactSetChanged(const CGHeroInstance* hero) OVERRIDE; + + void artifactPut(const ArtifactLocation &al); + void artifactRemoved(const ArtifactLocation &al); + void artifactMoved(const ArtifactLocation &src, const ArtifactLocation &dst); + void heroCreated(const CGHeroInstance* hero) OVERRIDE; void heroGotLevel(const CGHeroInstance *hero, int pskill, std::vector &skills, boost::function &callback) OVERRIDE; void heroInGarrisonChange(const CGTownInstance *town) OVERRIDE; diff --git a/client/GUIBase.cpp b/client/GUIBase.cpp index dc6199562..9e86cc78d 100644 --- a/client/GUIBase.cpp +++ b/client/GUIBase.cpp @@ -1023,4 +1023,9 @@ Rect Rect::createCentered( int w, int h ) Rect Rect::around(const Rect &r, int width /*= 1*/) /*creates rect around another */ { return Rect(r.x - width, r.y - width, r.w + width * 2, r.h + width * 2); +} + +Rect Rect::centerIn(const Rect &r) +{ + return Rect(r.x + (r.w - w) / 2, r.y + (r.h - h) / 2, w, h); } \ No newline at end of file diff --git a/client/GUIBase.h b/client/GUIBase.h index 510b3c98a..1f0a0eb18 100644 --- a/client/GUIBase.h +++ b/client/GUIBase.h @@ -149,6 +149,7 @@ struct Rect : public SDL_Rect h = surf->h; } + Rect centerIn(const Rect &r); static Rect createCentered(int w, int h); static Rect around(const Rect &r, int width = 1); //creates rect around another @@ -300,7 +301,7 @@ public: class IShowActivable : public IShowable, public IActivable { public: - enum {WITH_GARRISON = 1, BLOCK_ADV_HOTKEYS = 2}; + enum {WITH_GARRISON = 1, BLOCK_ADV_HOTKEYS = 2, WITH_ARTIFACTS = 4}; int type; //bin flags using etype IShowActivable(); virtual ~IShowActivable(){}; //d-tor @@ -435,7 +436,7 @@ public: virtual void keyPressed(const SDL_KeyboardEvent & key); //call-in }; -class CGarrisonHolder : public CIntObject// to unify updating garrisons via PlayerInterface +class CGarrisonHolder : public virtual CIntObject// to unify updating garrisons via PlayerInterface { public: CGarrisonHolder(); diff --git a/client/GUIClasses.cpp b/client/GUIClasses.cpp index 4649c87d3..bdf825200 100644 --- a/client/GUIClasses.cpp +++ b/client/GUIClasses.cpp @@ -326,7 +326,7 @@ CGarrisonSlot::~CGarrisonSlot() if(active) deactivate(); } -void CGarrisonSlot::show(SDL_Surface * to) +void CGarrisonSlot::showAll(SDL_Surface * to) { std::map &imgs = (owner->smallIcons ? graphics->smallImgs : graphics->bigImgs); if(creature) @@ -2200,10 +2200,10 @@ void CCreInfoWindow::init(const CCreature *cre, const CBonusSystemNode *stackNod printLine(6, CGI->generaltexth->zelp[441].first, cre->valOfBonuses(Bonus::STACKS_SPEED), stackNode->valOfBonuses(Bonus::STACKS_SPEED)); //setting morale - morale = new MoraleLuckBox(true, genRect(42, 42, pos.x + 24, pos.y + 189)); + morale = new MoraleLuckBox(true, genRect(42, 42, 24, 189)); morale->set(stackNode); //setting luck - luck = new MoraleLuckBox(false, genRect(42, 42, pos.x + 77, pos.y + 189)); + luck = new MoraleLuckBox(false, genRect(42, 42, 77, 189)); luck->set(stackNode); //luck and morale @@ -2628,20 +2628,20 @@ void CTradeWindow::CTradeableItem::clickLeft(tribool down, bool previousState) if(type == ARTIFACT_PLACEHOLDER) { CAltarWindow *aw = static_cast(mw); - const CArtifactInstance *movedArt = aw->arts->commonInfo->srcArtifact; + const CArtifactInstance *movedArt = aw->arts->commonInfo->src.art; if(movedArt) { - aw->moveFromSlotToAltar(aw->arts->commonInfo->srcSlotID, this, movedArt->id); + aw->moveFromSlotToAltar(aw->arts->commonInfo->src.slotID, this, movedArt->id); } else if(const CArtifactInstance *art = getArtInstance()) { movedArt = art; - aw->arts->commonInfo->srcAOH = aw->arts; - aw->arts->commonInfo->srcArtifact = movedArt; - aw->arts->commonInfo->srcSlotID = aw->hero->CArtifactSet::getArtPos(art);// vstd::findPos(aw->hero->artifacts, const_cast(movedArt)); + aw->arts->commonInfo->src.AOH = aw->arts; + aw->arts->commonInfo->src.art = movedArt; + aw->arts->commonInfo->src.slotID = aw->hero->CArtifactSet::getArtPos(art);// vstd::findPos(aw->hero->artifacts, const_cast(movedArt)); - aw->arts->commonInfo->destAOH = aw->arts; - CCS->curh->dragAndDropCursor(graphics->artDefs->ourImages[movedArt->id].bitmap); + aw->arts->commonInfo->dst.AOH = aw->arts; + CCS->curh->dragAndDropCursor(graphics->artDefs->ourImages[movedArt->artType->id].bitmap); id = -1; subtitle = ""; @@ -3825,12 +3825,12 @@ void CAltarWindow::artifactPicked() void CAltarWindow::showAll(SDL_Surface * to) { CTradeWindow::showAll(to); - if(mode == ARTIFACT_EXP && arts && arts->commonInfo->srcArtifact) + if(mode == ARTIFACT_EXP && arts && arts->commonInfo->src.art) { - blitAtLoc(graphics->artDefs->ourImages[arts->commonInfo->srcArtifact->id].bitmap, 281, 442, to); + blitAtLoc(graphics->artDefs->ourImages[arts->commonInfo->src.art->artType->id].bitmap, 281, 442, to); int dmp, val; - market->getOffer(arts->commonInfo->srcArtifact->id, 0, dmp, val, ARTIFACT_EXP); + market->getOffer(arts->commonInfo->src.art->artType->id, 0, dmp, val, ARTIFACT_EXP); printAtMiddleLoc(boost::lexical_cast(val), 304, 498, FONT_SMALL, zwykly, to); } } @@ -3864,10 +3864,10 @@ bool CAltarWindow::putOnAltar(CTradeableItem* altarSlot, int artID) void CAltarWindow::moveFromSlotToAltar(int slotID, CTradeableItem* altarSlot, int artID) { - if(arts->commonInfo->srcArtifact) + if(arts->commonInfo->src.art) { - arts->commonInfo->destSlotID = 65500; - arts->commonInfo->destAOH = arts; + arts->commonInfo->dst.slotID = 65500; + arts->commonInfo->dst.AOH = arts; } if(putOnAltar(altarSlot, artID)) @@ -4159,8 +4159,7 @@ void CTavernWindow::HeroPortrait::clickRight(tribool down, bool previousState) { if(down && h) { - adventureInt->heroWindow->setHero(h); - GH.pushInt(new CRClickPopupInt(adventureInt->heroWindow,false)); + GH.pushInt(new CRClickPopupInt(new CHeroWindow(h), true)); } } @@ -4539,7 +4538,7 @@ void CArtPlace::clickLeft(tribool down, bool previousState) //LRClickableAreaWTextComp::clickLeft(down); // If clicked on spellbook, open it only if no artifact is held at the moment. - if(ourArt && !down && previousState && !ourOwner->commonInfo->srcAOH) + if(ourArt && !down && previousState && !ourOwner->commonInfo->src.AOH) { if(ourArt->artType->id == 0) { @@ -4553,7 +4552,7 @@ void CArtPlace::clickLeft(tribool down, bool previousState) if(ourArt && ourArt->id == 0) //spellbook return; //this is handled separately - if(!ourOwner->commonInfo->srcAOH) //nothing has been clicked + if(!ourOwner->commonInfo->src.AOH) //nothing has been clicked { if(ourArt //to prevent selecting empty slots (bugfix to what GrayFace reported) && ourOwner->curHero->tempOwner == LOCPLINT->playerID)//can't take art from another player @@ -4567,11 +4566,15 @@ void CArtPlace::clickLeft(tribool down, bool previousState) select(); } } + else if(ourArt == ourOwner->commonInfo->src.art) //restore previously picked artifact + { + deselect(); + } else //perform artifact substitution { if (slotID >= 19) // Backpack destination. { - const CArtifact * const cur = ourOwner->commonInfo->srcArtifact->artType; + const CArtifact * const cur = ourOwner->commonInfo->src.art->artType; switch(cur->id) { @@ -4584,6 +4587,7 @@ void CArtPlace::clickLeft(tribool down, bool previousState) break; default: setMeAsDest(); + amin(ourOwner->commonInfo->dst.slotID, ourOwner->curHero->artifactsInBackpack.size() + Arts::BACKPACK_START); // // // Correction for backpack position when src lies before dest. // int correction = (ourOwner->commonInfo->srcAOH == ourOwner @@ -4597,21 +4601,21 @@ void CArtPlace::clickLeft(tribool down, bool previousState) } } //check if swap is possible - else if (this->fitsHere(ourOwner->commonInfo->srcArtifact) && + else if (fitsHere(ourOwner->commonInfo->src.art) && (!ourArt || ourOwner->curHero->tempOwner == LOCPLINT->playerID)) { setMeAsDest(); - - // Special case when the dest artifact can't be fit into the src slot. - //CGI->arth->unequipArtifact(ourOwner->curHero->artifWorn, slotID); - const CArtifactsOfHero* srcAOH = ourOwner->commonInfo->srcAOH; - ui16 srcSlotID = ourOwner->commonInfo->srcSlotID; - if (ourArt && srcSlotID < 19 && !ourArt->canBePutAt(ArtifactLocation(srcAOH->curHero, srcSlotID))) - { - // Put dest artifact into owner's backpack. - ourOwner->commonInfo->srcAOH = ourOwner; - ourOwner->commonInfo->srcSlotID = ourOwner->curHero->artifacts.size() + 19; - } +// +// // Special case when the dest artifact can't be fit into the src slot. +// //CGI->arth->unequipArtifact(ourOwner->curHero->artifWorn, slotID); +// const CArtifactsOfHero* srcAOH = ourOwner->commonInfo->src.AOH; +// ui16 srcSlotID = ourOwner->commonInfo->src.slotID; +// if (ourArt && srcSlotID < 19 && !ourArt->canBePutAt(ArtifactLocation(srcAOH->curHero, srcSlotID))) +// { +// // Put dest artifact into owner's backpack. +// ourOwner->commonInfo->src.AOH = ourOwner; +// ourOwner->commonInfo->src.slotID = ourOwner->curHero->artifacts.size() + 19; +// } ourOwner->realizeCurrentTransaction(); } @@ -4674,24 +4678,16 @@ void CArtPlace::select () int backpackCorrection = -(slotID - 19 < ourOwner->backpackPos); - CCS->curh->dragAndDropCursor(graphics->artDefs->ourImages[ourArt->id].bitmap); + CCS->curh->dragAndDropCursor(graphics->artDefs->ourImages[ourArt->artType->id].bitmap); - ourOwner->commonInfo->srcArtifact = ourArt; - ourOwner->commonInfo->srcSlotID = slotID; - ourOwner->commonInfo->srcAOH = ourOwner; + ourOwner->commonInfo->src.setTo(this, false); // Temporarily remove artifact from hero. -// if (slotID < 19) -// CGI->arth->unequipArtifact(ourOwner->curHero->artifWorn, slotID); -// else -// ourOwner->curHero->artifacts.erase(ourOwner->curHero->artifacts.begin() + (slotID - 19)); ourOwner->markPossibleSlots(ourArt); - //ourOwner->curHero->recreateArtBonuses(); - - - if (slotID >= 19) - ourOwner->scrollBackpack(backpackCorrection); - else +// +// if (slotID >= 19) +// ourOwner->scrollBackpack(backpackCorrection); +// else ourOwner->eraseSlotData(this, slotID); // Update the hero bonuses. @@ -4706,6 +4702,11 @@ void CArtPlace::deselect () { CCS->curh->dragAndDropCursor(NULL); ourOwner->unmarkSlots(); + + ourOwner->commonInfo->src.clear(); + + ourOwner->updateParentWindow(); + ourOwner->safeRedraw(); } void CArtPlace::deactivate() @@ -4749,7 +4750,7 @@ bool CArtPlace::fitsHere(const CArtifactInstance * art) const if (slotID >= 19) return !CGI->arth->isBigArtifact(art->id); - return art->canBePutAt(ArtifactLocation(ourOwner->curHero, slotID)); + return art->canBePutAt(ArtifactLocation(ourOwner->curHero, slotID), true); } CArtPlace::~CArtPlace() @@ -4764,13 +4765,7 @@ bool CArtPlace::locked() const void CArtPlace::setMeAsDest(bool backpackAsVoid /*= true*/) { - ourOwner->commonInfo->destAOH = ourOwner; - ourOwner->commonInfo->destSlotID = slotID; - if(slotID >= 19) - ourOwner->commonInfo->destArtifact = NULL; - else - ourOwner->commonInfo->destArtifact = ourArt; - + ourOwner->commonInfo->dst.setTo(this, backpackAsVoid); } void HoverableArea::hover (bool on) @@ -4897,74 +4892,72 @@ LRClickableAreaOpenTown::LRClickableAreaOpenTown() void CArtifactsOfHero::SCommonPart::reset() { - destAOH = srcAOH = NULL; - destArtifact = srcArtifact = NULL; - destSlotID = srcSlotID = -1; + src.clear(); + dst.clear(); CCS->curh->dragAndDropCursor(NULL); } void CArtifactsOfHero::setHero(const CGHeroInstance * hero) { - // An update is made, rather than initialization. - if (curHero && curHero->id == hero->id) - { - if(curHero != hero) - { - //delete curHero; - curHero = hero; //was: creating a copy - } - - // Compensate backpack pos if an artifact was insertad before it. - if (commonInfo->destSlotID >= 19 && commonInfo->destAOH == this - && commonInfo->destSlotID - 19 < backpackPos) - { - backpackPos++; - } - - if (updateState && commonInfo->srcAOH == this) - { - // A swap was made, make the replaced artifact the current selected. - if (commonInfo->destSlotID < 19 && commonInfo->destArtifact) - { -// // Temporarily remove artifact from hero. -// if (commonInfo->srcSlotID < 19) -// CGI->arth->unequipArtifact(curHero->artifWorn, commonInfo->srcSlotID); -// else -// curHero->artifacts.erase(curHero->artifacts.begin() + (commonInfo->srcSlotID - 19)); - - updateParentWindow(); //TODO: evil! but does the thing - - // Source <- Dest - commonInfo->srcArtifact = commonInfo->destArtifact; - - // Reset destination parameters. - commonInfo->destAOH = NULL; - commonInfo->destArtifact = NULL; - commonInfo->destSlotID = -1; - - CCS->curh->dragAndDropCursor(graphics->artDefs->ourImages[commonInfo->srcArtifact->id].bitmap); - markPossibleSlots(commonInfo->srcArtifact); - } - else if (commonInfo->destAOH != NULL) - { - // Reset all parameters. - commonInfo->reset(); - unmarkSlots(); - } - } - } - else - { - commonInfo->reset(); - } - - if(hero != curHero) - { -// delete curHero; - // curHero = new CGHeroInstance(*hero); - curHero = hero; //was: creating a copy - } +// // An update is made, rather than initialization. +// if (curHero && curHero->id == hero->id) +// { +// if(curHero != hero) +// { +// //delete curHero; +// curHero = hero; //was: creating a copy +// } +// +// // Compensate backpack pos if an artifact was insertad before it. +// if (commonInfo->dst.slotID >= 19 && commonInfo->destAOH == this +// && commonInfo->dst.slotID - 19 < backpackPos) +// { +// backpackPos++; +// } +// +// if (updateState && commonInfo->srcAOH == this) +// { +// // A swap was made, make the replaced artifact the current selected. +// if (commonInfo->dst.slotID < 19 && commonInfo->destArtifact) +// { +// // // Temporarily remove artifact from hero. +// // if (commonInfo->srcSlotID < 19) +// // CGI->arth->unequipArtifact(curHero->artifWorn, commonInfo->srcSlotID); +// // else +// // curHero->artifacts.erase(curHero->artifacts.begin() + (commonInfo->srcSlotID - 19)); +// +// updateParentWindow(); //TODO: evil! but does the thing +// +// // Source <- Dest +// commonInfo->srcArtifact = commonInfo->destArtifact; +// +// // Reset destination parameters. +// commonInfo->dst.clear(); +// +// CCS->curh->dragAndDropCursor(graphics->artDefs->ourImages[commonInfo->srcArtifact->id].bitmap); +// markPossibleSlots(commonInfo->srcArtifact); +// } +// else if (commonInfo->destAOH != NULL) +// { +// // Reset all parameters. +// commonInfo->reset(); +// unmarkSlots(); +// } +// } +// } +// else +// { +// commonInfo->reset(); +// } +// +// if(hero != curHero) +// { +// // delete curHero; +// // curHero = new CGHeroInstance(*hero); +// curHero = hero; //was: creating a copy +// } + curHero = hero; if (curHero->artifacts.size() > 0) backpackPos %= curHero->artifacts.size(); else @@ -5045,19 +5038,10 @@ void CArtifactsOfHero::scrollBackpack(int dir) */ void CArtifactsOfHero::markPossibleSlots(const CArtifactInstance* art) { - for (std::set::iterator it = commonInfo->participants.begin(); - it != commonInfo->participants.end(); - ++it) - { - for (int i = 0; i < (*it)->artWorn.size(); i++) - { - if ((*it)->artWorn[i]->fitsHere(art)) - (*it)->artWorn[i]->marked = true; - else - (*it)->artWorn[i]->marked = false; - } - } - + BOOST_FOREACH(CArtifactsOfHero *aoh, commonInfo->participants) + BOOST_FOREACH(CArtPlace *place, aoh->artWorn) + place->marked = art->canBePutAt(ArtifactLocation(aoh->curHero, place->slotID), true); + safeRedraw(); } @@ -5066,16 +5050,9 @@ void CArtifactsOfHero::markPossibleSlots(const CArtifactInstance* art) */ void CArtifactsOfHero::unmarkSlots(bool withRedraw /*= true*/) { - if(!commonInfo) return; - for (std::set::iterator it = commonInfo->participants.begin(); - it != commonInfo->participants.end(); - ++it) - { - for (int i = 0; i < (*it)->artWorn.size(); i++) - { - (*it)->artWorn[i]->marked = false; - } - } + BOOST_FOREACH(CArtifactsOfHero *aoh, commonInfo->participants) + BOOST_FOREACH(CArtPlace *place, aoh->artWorn) + place->marked = false; if(withRedraw) safeRedraw(); @@ -5084,7 +5061,7 @@ void CArtifactsOfHero::unmarkSlots(bool withRedraw /*= true*/) /** * Assigns an artifacts to an artifact place depending on it's new slot ID. */ -void CArtifactsOfHero::setSlotData (CArtPlace* artPlace, int slotID) +void CArtifactsOfHero::setSlotData(CArtPlace* artPlace, int slotID) { artPlace->slotID = slotID; artPlace->ourArt = curHero->CArtifactSet::getArt(slotID); @@ -5175,11 +5152,7 @@ void CArtifactsOfHero::updateParentWindow() if(updateState) chw->curHero = curHero; else - { - chw->deactivate(); - chw->setHero(curHero); - chw->activate(); - } + chw->update(curHero, true); } else if(CExchangeWindow* cew = dynamic_cast(GH.topInt())) { @@ -5218,10 +5191,78 @@ void CArtifactsOfHero::safeRedraw() void CArtifactsOfHero::realizeCurrentTransaction() { - assert(commonInfo->srcAOH); - assert(commonInfo->destAOH); - LOCPLINT->cb->swapArtifacts(commonInfo->srcAOH->curHero, commonInfo->srcSlotID, - commonInfo->destAOH->curHero, commonInfo->destSlotID); + assert(commonInfo->src.AOH); + assert(commonInfo->dst.AOH); + LOCPLINT->cb->swapArtifacts(commonInfo->src.AOH->curHero, commonInfo->src.slotID, + commonInfo->dst.AOH->curHero, commonInfo->dst.slotID); +} + +void CArtifactsOfHero::artifactMoved(const ArtifactLocation &src, const ArtifactLocation &dst) +{ + BOOST_FOREACH(CArtifactsOfHero *aoh, commonInfo->participants) //update affected slots + { + if(src.hero == aoh->curHero) + setSlotData(aoh->getArtPlace(src.slot), src.slot); + if(dst.hero == aoh->curHero) + setSlotData(aoh->getArtPlace(dst.slot), dst.slot); + } + updateParentWindow(); + + if(commonInfo->src == src) //artifact was taken from us + { + assert(commonInfo->dst == dst || dst.slot == dst.hero->artifactsInBackpack.size() + Arts::BACKPACK_START); + commonInfo->reset(); + unmarkSlots(); + } + else if(commonInfo->dst == src) //the dest artifact was moved -> we are picking it + { + assert(dst.slot >= Arts::BACKPACK_START); + commonInfo->reset(); + + CArtPlace *ap = NULL; + BOOST_FOREACH(CArtifactsOfHero *aoh, commonInfo->participants) + { + if(aoh->curHero == dst.hero) + { + commonInfo->src.AOH = aoh; + if(ap = aoh->getArtPlace(dst.slot)) + break; + } + } + + if(ap) + { + ap->select(); + } + else + { + commonInfo->src.art = src.getArt(); + commonInfo->src.slotID = src.slot; + assert(commonInfo->src.AOH); + CCS->curh->dragAndDropCursor(graphics->artDefs->ourImages[src.getArt()->artType->id].bitmap); + markPossibleSlots(dst.getArt()); + } + } + else + { + tlog1 << "Unexpected artifact movement...\n"; + } +} + +CArtPlace * CArtifactsOfHero::getArtPlace(int slot) +{ + if(slot < Arts::BACKPACK_START) + { + return artWorn[slot]; + } + else + { + BOOST_FOREACH(CArtPlace *ap, backpack) + if(ap->slotID == slot) + return ap; + } + + return NULL; } void CExchangeWindow::close() @@ -6461,7 +6502,9 @@ void MoraleLuckBox::set(const CBonusSystemNode *node) void MoraleLuckBox::showAll(SDL_Surface * to) { CDefEssential *def = morale ? graphics->morale42 : graphics->luck42; - blitAt(def->ourImages[bonusValue].bitmap, pos, to); + SDL_Surface *img = def->ourImages[bonusValue + 3].bitmap; + + blitAt(img, Rect(img).centerIn(pos), to); //put img in the center of our pos } MoraleLuckBox::MoraleLuckBox(bool Morale, const Rect &r) @@ -6811,3 +6854,45 @@ void CFocusable::moveFocus() } } } + +CWindowWithArtifacts::CWindowWithArtifacts() +{ + type |= WITH_ARTIFACTS; +} + +CWindowWithArtifacts::~CWindowWithArtifacts() +{ +} + +void CArtifactsOfHero::SCommonPart::Artpos::clear() +{ + slotID = -1; + AOH = NULL; + art = NULL; +} + +CArtifactsOfHero::SCommonPart::Artpos::Artpos() +{ + clear(); +} + +void CArtifactsOfHero::SCommonPart::Artpos::setTo(const CArtPlace *place, bool dontTakeBackpack) +{ + slotID = place->slotID; + AOH = place->ourOwner; + + if(slotID >= 19 && dontTakeBackpack) + art = NULL; + else + art = place->ourArt; +} + +bool CArtifactsOfHero::SCommonPart::Artpos::operator==(const ArtifactLocation &al) const +{ + if(!AOH) + return false; + bool ret = al.hero == AOH->curHero && al.slot == slotID; + + //assert(al.getArt() == art); + return ret; +} \ No newline at end of file diff --git a/client/GUIClasses.h b/client/GUIClasses.h index f9df75601..0f75d2480 100644 --- a/client/GUIClasses.h +++ b/client/GUIClasses.h @@ -25,6 +25,7 @@ * */ +struct ArtifactLocation; class CStackBasicDescriptor; class CBonusSystemNode; class CArtifact; @@ -214,7 +215,7 @@ public: void clickLeft(tribool down, bool previousState); void activate(); void deactivate(); - void show(SDL_Surface * to); + void showAll(SDL_Surface * to); CGarrisonSlot(CGarrisonInt *Owner, int x, int y, int IID, int Upg=0, const CStackInstance * Creature=NULL); ~CGarrisonSlot(); //d-tor }; @@ -907,6 +908,15 @@ public: void show(SDL_Surface * to); }; +class CWindowWithArtifacts : public virtual CIntObject +{ +public: + std::vector artSets; + + CWindowWithArtifacts(); + ~CWindowWithArtifacts(); +}; + class CArtPlace: public LRClickableAreaWTextComp { public: @@ -932,7 +942,6 @@ public: ~CArtPlace(); //d-tor }; - class CArtifactsOfHero : public CIntObject { const CGHeroInstance * curHero; //local copy of hero on which we operate @@ -944,13 +953,19 @@ class CArtifactsOfHero : public CIntObject public: struct SCommonPart { + struct Artpos + { + int slotID; + const CArtifactsOfHero * AOH; + const CArtifactInstance *art; + + Artpos(); + void clear(); + void setTo(const CArtPlace *place, bool dontTakeBackpack); + bool operator==(const ArtifactLocation &al) const; + } src, dst; + std::set participants; // Needed to mark slots. - const CArtifactInstance * srcArtifact; // Held artifact. - const CArtifactsOfHero * srcAOH; // Following two needed to uniquely identify the source. - int srcSlotID; // - const CArtifactsOfHero * destAOH; // For swapping. (i.e. changing what is held) - int destSlotID; // Needed to determine what kind of action was last taken in setHero - const CArtifactInstance * destArtifact; // For swapping. void reset(); } * commonInfo; //when we have more than one CArtifactsOfHero in one window with exchange possibility, we use this (eg. in exchange window); to be provided externally @@ -962,6 +977,8 @@ public: std::multiset artifactsOnAltar; //artifacts id that are technically present in backpack but in GUI are moved to the altar - they'll be ommited in backpack slots void realizeCurrentTransaction(); //calls callback with parameters stored in commonInfo + void artifactMoved(const ArtifactLocation &src, const ArtifactLocation &dst); + CArtPlace *getArtPlace(int slot); void setHero(const CGHeroInstance * hero); void dispose(); //free resources not needed after closing windows and reset state diff --git a/client/NetPacksClient.cpp b/client/NetPacksClient.cpp index d9360951c..9140588ef 100644 --- a/client/NetPacksClient.cpp +++ b/client/NetPacksClient.cpp @@ -169,15 +169,19 @@ void RebalanceStacks::applyCl( CClient *cl ) void PutArtifact::applyCl( CClient *cl ) { - + INTERFACE_CALL_IF_PRESENT(al.hero->tempOwner, artifactPut, al); } void EraseArtifact::applyCl( CClient *cl ) { + INTERFACE_CALL_IF_PRESENT(al.hero->tempOwner, artifactRemoved, al); } void MoveArtifact::applyCl( CClient *cl ) { + INTERFACE_CALL_IF_PRESENT(src.hero->tempOwner, artifactMoved, src, dst); + if(src.hero->tempOwner != dst.hero->tempOwner) + INTERFACE_CALL_IF_PRESENT(src.hero->tempOwner, artifactMoved, src, dst); } void GiveBonus::applyCl( CClient *cl ) @@ -394,13 +398,15 @@ void SetHeroesInTown::applyCl( CClient *cl ) void SetHeroArtifacts::applyCl( CClient *cl ) { - CGHeroInstance *h = GS(cl)->getHero(hid); - CGameInterface *player = (vstd::contains(cl->playerint,h->tempOwner) ? cl->playerint[h->tempOwner] : NULL); - if(!player) - return; + tlog1 << "SetHeroArtifacts :(\n"; +// +// CGHeroInstance *h = GS(cl)->getHero(hid); +// CGameInterface *player = (vstd::contains(cl->playerint,h->tempOwner) ? cl->playerint[h->tempOwner] : NULL); +// if(!player) +// return; //h->recreateArtBonuses(); - player->heroArtifactSetChanged(h); + //player->heroArtifactSetChanged(h); // BOOST_FOREACH(Bonus bonus, gained) // { diff --git a/lib/CArtHandler.cpp b/lib/CArtHandler.cpp index 9ee6d249a..4cfc8e36b 100644 --- a/lib/CArtHandler.cpp +++ b/lib/CArtHandler.cpp @@ -958,7 +958,8 @@ void CArtifactInstance::putAt(CGHeroInstance *h, ui16 slot) asi.artifact = this; asi.locked = false; - h->attachTo(this); + if(slot < Arts::BACKPACK_START) + h->attachTo(this); } void CArtifactInstance::removeFrom(CGHeroInstance *h, ui16 slot) diff --git a/lib/CObjectHandler.cpp b/lib/CObjectHandler.cpp index e26102a29..459ba16e5 100644 --- a/lib/CObjectHandler.cpp +++ b/lib/CObjectHandler.cpp @@ -1190,6 +1190,21 @@ void CGHeroInstance::UpdateSpeciality() } void CGHeroInstance::updateSkill(int which, int val) { + if(which == LEADERSHIP || which == LUCK) + { + bool luck = which == LUCK; + Bonus::BonusType type[] = {Bonus::MORALE, Bonus::LUCK}; + + Bonus *b = getBonus(Selector::type(type[luck]) && Selector::sourceType(Bonus::SECONDARY_SKILL)); + if(!b) + { + b = new Bonus(Bonus::PERMANENT, type[luck], Bonus::SECONDARY_SKILL, +val, which, which, Bonus::BASE_NUMBER); + addNewBonus(b); + } + else + b->val = +val; + } + int skillVal = 0; switch (which) { diff --git a/lib/NetPacksLib.cpp b/lib/NetPacksLib.cpp index 7e55b51fc..3fa8a3bab 100644 --- a/lib/NetPacksLib.cpp +++ b/lib/NetPacksLib.cpp @@ -712,7 +712,10 @@ DLL_EXPORT void EraseArtifact::applyGs( CGameState *gs ) DLL_EXPORT void MoveArtifact::applyGs( CGameState *gs ) { - + assert(!dst.getArt()); + CArtifactInstance *a = src.getArt(); + a->removeFrom(src.hero, src.slot); + a->putAt(dst.hero, dst.slot); } DLL_EXPORT void SetAvailableArtifacts::applyGs( CGameState *gs ) diff --git a/server/CGameHandler.cpp b/server/CGameHandler.cpp index 997464ee5..957354d8d 100644 --- a/server/CGameHandler.cpp +++ b/server/CGameHandler.cpp @@ -2486,8 +2486,8 @@ bool CGameHandler::moveArtifact(si32 srcHeroID, si32 destHeroID, ui16 srcSlot, u // Check if src/dest slots are appropriate for the artifacts exchanged. // Moving to the backpack is always allowed. if ((!srcArtifact || destSlot < Arts::BACKPACK_START) - && srcArtifact && !srcArtifact->canBePutAt(dst)) - COMPLAIN_RET("Cannot swap artifacts!"); + && srcArtifact && !srcArtifact->canBePutAt(dst, true)) + COMPLAIN_RET("Cannot move artifact!"); if ((srcArtifact && srcArtifact->artType->id == Arts::ID_LOCK) || (destArtifact && destArtifact->artType->id == Arts::ID_LOCK)) COMPLAIN_RET("Cannot move artifact locks."); @@ -2497,6 +2497,16 @@ bool CGameHandler::moveArtifact(si32 srcHeroID, si32 destHeroID, ui16 srcSlot, u if (srcSlot == Arts::MACH4 || destSlot == Arts::MACH4) COMPLAIN_RET("Cannot move catapult!"); + if(dst.slot >= Arts::BACKPACK_START) + amin(dst.slot, Arts::BACKPACK_START + dst.hero->artifactsInBackpack.size()); + + // Correction for destination from removing source artifact in backpack. + if (src.slot >= 19 && dst.slot >= 19 && src.slot < dst.slot) + dst.slot--; + + if (src.slot == dst.slot) + COMPLAIN_RET("Won't move artifact: Dest same as source!"); + //moving art to backpack is always allowed (we've ruled out exceptions) if(destSlot >= Arts::BACKPACK_START) { @@ -2506,7 +2516,7 @@ bool CGameHandler::moveArtifact(si32 srcHeroID, si32 destHeroID, ui16 srcSlot, u { if(destArtifact) //old artifact must be removed first { - moveArtifact(dst, ArtifactLocation(destHero, destHero->artifactsInBackpack.size()-1)); + moveArtifact(dst, ArtifactLocation(destHero, destHero->artifactsInBackpack.size() + Arts::BACKPACK_START)); } moveArtifact(src, dst); } @@ -2526,9 +2536,6 @@ bool CGameHandler::moveArtifact(si32 srcHeroID, si32 destHeroID, ui16 srcSlot, u // // Internal hero artifact arrangement. // if(srcHero == destHero) // { -// // Correction for destination from removing source artifact in backpack. -// if (srcSlot >= 19 && destSlot >= 19 && srcSlot < destSlot) -// destSlot--; // // sha.setArtAtPos(destSlot, srcHero->getArtAtPos(srcSlot)); // }