|
@@ -0,0 +1,1507 @@
|
|
|
+#include "StdInc.h"
|
|
|
+#include "CTradeWindow.h"
|
|
|
+
|
|
|
+#include "CGuiHandler.h"
|
|
|
+#include "CAnimation.h"
|
|
|
+#include "CCursorHandler.h"
|
|
|
+
|
|
|
+#include "../CAdvmapInterface.h"
|
|
|
+#include "../CGameInfo.h"
|
|
|
+#include "../CPlayerInterface.h"
|
|
|
+
|
|
|
+#include "../../CCallback.h"
|
|
|
+
|
|
|
+#include "../../lib/VCMI_Lib.h"
|
|
|
+#include "../../lib/CArtHandler.h"
|
|
|
+#include "../../lib/CCreatureHandler.h"
|
|
|
+#include "../../lib/CGeneralTextHandler.h"
|
|
|
+#include "../../lib/CHeroHandler.h"
|
|
|
+#include "../../lib/mapObjects/CGHeroInstance.h"
|
|
|
+
|
|
|
+
|
|
|
+/*
|
|
|
+ * CTradeWindow.cpp, part of VCMI engine
|
|
|
+ *
|
|
|
+ * Authors: listed in file AUTHORS in main folder
|
|
|
+ *
|
|
|
+ * License: GNU General Public License v2.0 or later
|
|
|
+ * Full text of license available in license.txt file, in main folder
|
|
|
+ *
|
|
|
+ */
|
|
|
+
|
|
|
+CTradeWindow::CTradeableItem::CTradeableItem(Point pos, EType Type, int ID, bool Left, int Serial):
|
|
|
+ CIntObject(LCLICK | HOVER | RCLICK, pos),
|
|
|
+ type(EType(-1)),// set to invalid, will be corrected in setType
|
|
|
+ id(ID),
|
|
|
+ serial(Serial),
|
|
|
+ left(Left)
|
|
|
+{
|
|
|
+ downSelection = false;
|
|
|
+ hlp = nullptr;
|
|
|
+ image = nullptr;
|
|
|
+ setType(Type);
|
|
|
+}
|
|
|
+
|
|
|
+void CTradeWindow::CTradeableItem::setType(EType newType)
|
|
|
+{
|
|
|
+ if (type != newType)
|
|
|
+ {
|
|
|
+ OBJ_CONSTRUCTION_CAPTURING_ALL;
|
|
|
+ type = newType;
|
|
|
+ delete image;
|
|
|
+
|
|
|
+ if (getIndex() < 0)
|
|
|
+ {
|
|
|
+ image = new CAnimImage(getFilename(), 0);
|
|
|
+ image->disable();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ image = new CAnimImage(getFilename(), getIndex());
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void CTradeWindow::CTradeableItem::setID(int newID)
|
|
|
+{
|
|
|
+ if (id != newID)
|
|
|
+ {
|
|
|
+ id = newID;
|
|
|
+ if (image)
|
|
|
+ {
|
|
|
+ int index = getIndex();
|
|
|
+ if (index < 0)
|
|
|
+ image->disable();
|
|
|
+ else
|
|
|
+ {
|
|
|
+ image->enable();
|
|
|
+ image->setFrame(index);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+std::string CTradeWindow::CTradeableItem::getFilename()
|
|
|
+{
|
|
|
+ switch(type)
|
|
|
+ {
|
|
|
+ case RESOURCE:
|
|
|
+ return "RESOURCE";
|
|
|
+ case PLAYER:
|
|
|
+ return "CREST58";
|
|
|
+ case ARTIFACT_TYPE:
|
|
|
+ case ARTIFACT_PLACEHOLDER:
|
|
|
+ case ARTIFACT_INSTANCE:
|
|
|
+ return "artifact";
|
|
|
+ case CREATURE:
|
|
|
+ return "TWCRPORT";
|
|
|
+ default:
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+int CTradeWindow::CTradeableItem::getIndex()
|
|
|
+{
|
|
|
+ if (id < 0)
|
|
|
+ return -1;
|
|
|
+
|
|
|
+ switch(type)
|
|
|
+ {
|
|
|
+ case RESOURCE:
|
|
|
+ case PLAYER:
|
|
|
+ return id;
|
|
|
+ case ARTIFACT_TYPE:
|
|
|
+ case ARTIFACT_INSTANCE:
|
|
|
+ case ARTIFACT_PLACEHOLDER:
|
|
|
+ return VLC->arth->artifacts[id]->iconIndex;
|
|
|
+ case CREATURE:
|
|
|
+ return VLC->creh->creatures[id]->iconIndex;
|
|
|
+ default:
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void CTradeWindow::CTradeableItem::showAll(SDL_Surface * to)
|
|
|
+{
|
|
|
+ Point posToBitmap;
|
|
|
+ Point posToSubCenter;
|
|
|
+
|
|
|
+ switch(type)
|
|
|
+ {
|
|
|
+ case RESOURCE:
|
|
|
+ posToBitmap = Point(19,9);
|
|
|
+ posToSubCenter = Point(36, 59);
|
|
|
+ break;
|
|
|
+ case CREATURE_PLACEHOLDER:
|
|
|
+ case CREATURE:
|
|
|
+ posToSubCenter = Point(29, 76);
|
|
|
+ if(downSelection)
|
|
|
+ posToSubCenter.y += 5;
|
|
|
+ break;
|
|
|
+ case PLAYER:
|
|
|
+ posToSubCenter = Point(31, 76);
|
|
|
+ break;
|
|
|
+ case ARTIFACT_PLACEHOLDER:
|
|
|
+ case ARTIFACT_INSTANCE:
|
|
|
+ posToSubCenter = Point(19, 55);
|
|
|
+ if(downSelection)
|
|
|
+ posToSubCenter.y += 8;
|
|
|
+ break;
|
|
|
+ case ARTIFACT_TYPE:
|
|
|
+ posToSubCenter = Point(19, 58);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (image)
|
|
|
+ {
|
|
|
+ image->moveTo(pos.topLeft() + posToBitmap);
|
|
|
+ CIntObject::showAll(to);
|
|
|
+ }
|
|
|
+
|
|
|
+ printAtMiddleLoc(subtitle, posToSubCenter, FONT_SMALL, Colors::WHITE, to);
|
|
|
+}
|
|
|
+
|
|
|
+void CTradeWindow::CTradeableItem::clickLeft(tribool down, bool previousState)
|
|
|
+{
|
|
|
+ CTradeWindow *mw = dynamic_cast<CTradeWindow *>(parent);
|
|
|
+ assert(mw);
|
|
|
+ if(down)
|
|
|
+ {
|
|
|
+
|
|
|
+ if(type == ARTIFACT_PLACEHOLDER)
|
|
|
+ {
|
|
|
+ CAltarWindow *aw = static_cast<CAltarWindow *>(mw);
|
|
|
+ if(const CArtifactInstance *movedArt = aw->arts->commonInfo->src.art)
|
|
|
+ {
|
|
|
+ aw->moveFromSlotToAltar(aw->arts->commonInfo->src.slotID, this, movedArt);
|
|
|
+ }
|
|
|
+ else if(const CArtifactInstance *art = getArtInstance())
|
|
|
+ {
|
|
|
+ aw->arts->commonInfo->src.AOH = aw->arts;
|
|
|
+ aw->arts->commonInfo->src.art = art;
|
|
|
+ aw->arts->commonInfo->src.slotID = aw->hero->getArtPos(art);
|
|
|
+ aw->arts->markPossibleSlots(art);
|
|
|
+
|
|
|
+ //aw->arts->commonInfo->dst.AOH = aw->arts;
|
|
|
+ CCS->curh->dragAndDropCursor(new CAnimImage("artifact", art->artType->iconIndex));
|
|
|
+
|
|
|
+ aw->arts->artifactsOnAltar.erase(art);
|
|
|
+ setID(-1);
|
|
|
+ subtitle = "";
|
|
|
+ aw->deal->block(!aw->arts->artifactsOnAltar.size());
|
|
|
+ }
|
|
|
+
|
|
|
+ aw->calcTotalExp();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if(left)
|
|
|
+ {
|
|
|
+ if(mw->hLeft != this)
|
|
|
+ mw->hLeft = this;
|
|
|
+ else
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if(mw->hRight != this)
|
|
|
+ mw->hRight = this;
|
|
|
+ else
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ mw->selectionChanged(left);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void CTradeWindow::CTradeableItem::showAllAt(const Point &dstPos, const std::string &customSub, SDL_Surface * to)
|
|
|
+{
|
|
|
+ Rect oldPos = pos;
|
|
|
+ std::string oldSub = subtitle;
|
|
|
+ downSelection = true;
|
|
|
+
|
|
|
+ moveTo(dstPos);
|
|
|
+ subtitle = customSub;
|
|
|
+ showAll(to);
|
|
|
+
|
|
|
+ downSelection = false;
|
|
|
+ moveTo(oldPos.topLeft());
|
|
|
+ subtitle = oldSub;
|
|
|
+}
|
|
|
+
|
|
|
+void CTradeWindow::CTradeableItem::hover(bool on)
|
|
|
+{
|
|
|
+ if(!on)
|
|
|
+ {
|
|
|
+ GH.statusbar->clear();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ switch(type)
|
|
|
+ {
|
|
|
+ case CREATURE:
|
|
|
+ case CREATURE_PLACEHOLDER:
|
|
|
+ GH.statusbar->setText(boost::str(boost::format(CGI->generaltexth->allTexts[481]) % CGI->creh->creatures[id]->namePl));
|
|
|
+ break;
|
|
|
+ case ARTIFACT_PLACEHOLDER:
|
|
|
+ if(id < 0)
|
|
|
+ GH.statusbar->setText(CGI->generaltexth->zelp[582].first);
|
|
|
+ else
|
|
|
+ GH.statusbar->setText(CGI->arth->artifacts[id]->Name());
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void CTradeWindow::CTradeableItem::clickRight(tribool down, bool previousState)
|
|
|
+{
|
|
|
+ if(down)
|
|
|
+ {
|
|
|
+ switch(type)
|
|
|
+ {
|
|
|
+ case CREATURE:
|
|
|
+ case CREATURE_PLACEHOLDER:
|
|
|
+ //GH.statusbar->print(boost::str(boost::format(CGI->generaltexth->allTexts[481]) % CGI->creh->creatures[id]->namePl));
|
|
|
+ break;
|
|
|
+ case ARTIFACT_TYPE:
|
|
|
+ case ARTIFACT_PLACEHOLDER:
|
|
|
+ if(id >= 0)
|
|
|
+ adventureInt->handleRightClick(CGI->arth->artifacts[id]->Description(), down);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+std::string CTradeWindow::CTradeableItem::getName(int number /*= -1*/) const
|
|
|
+{
|
|
|
+ switch(type)
|
|
|
+ {
|
|
|
+ case PLAYER:
|
|
|
+ return CGI->generaltexth->capColors[id];
|
|
|
+ case RESOURCE:
|
|
|
+ return CGI->generaltexth->restypes[id];
|
|
|
+ case CREATURE:
|
|
|
+ if(number == 1)
|
|
|
+ return CGI->creh->creatures[id]->nameSing;
|
|
|
+ else
|
|
|
+ return CGI->creh->creatures[id]->namePl;
|
|
|
+ case ARTIFACT_TYPE:
|
|
|
+ case ARTIFACT_INSTANCE:
|
|
|
+ return CGI->arth->artifacts[id]->Name();
|
|
|
+ }
|
|
|
+ assert(0);
|
|
|
+ return "";
|
|
|
+}
|
|
|
+
|
|
|
+const CArtifactInstance * CTradeWindow::CTradeableItem::getArtInstance() const
|
|
|
+{
|
|
|
+ switch(type)
|
|
|
+ {
|
|
|
+ case ARTIFACT_PLACEHOLDER:
|
|
|
+ case ARTIFACT_INSTANCE:
|
|
|
+ return (const CArtifactInstance *)hlp;
|
|
|
+ default:
|
|
|
+ return nullptr;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void CTradeWindow::CTradeableItem::setArtInstance(const CArtifactInstance *art)
|
|
|
+{
|
|
|
+ assert(type == ARTIFACT_PLACEHOLDER || type == ARTIFACT_INSTANCE);
|
|
|
+ hlp = art;
|
|
|
+ if(art)
|
|
|
+ setID(art->artType->id);
|
|
|
+ else
|
|
|
+ setID(-1);
|
|
|
+}
|
|
|
+
|
|
|
+CTradeWindow::CTradeWindow(std::string bgName, const IMarket *Market, const CGHeroInstance *Hero, EMarketMode::EMarketMode Mode):
|
|
|
+ CWindowObject(PLAYER_COLORED, bgName),
|
|
|
+ market(Market),
|
|
|
+ hero(Hero),
|
|
|
+ arts(nullptr),
|
|
|
+ hLeft(nullptr),
|
|
|
+ hRight(nullptr),
|
|
|
+ readyToTrade(false)
|
|
|
+{
|
|
|
+ type |= BLOCK_ADV_HOTKEYS;
|
|
|
+ mode = Mode;
|
|
|
+ initTypes();
|
|
|
+}
|
|
|
+
|
|
|
+void CTradeWindow::initTypes()
|
|
|
+{
|
|
|
+ switch(mode)
|
|
|
+ {
|
|
|
+ case EMarketMode::RESOURCE_RESOURCE:
|
|
|
+ itemsType[1] = RESOURCE;
|
|
|
+ itemsType[0] = RESOURCE;
|
|
|
+ break;
|
|
|
+ case EMarketMode::RESOURCE_PLAYER:
|
|
|
+ itemsType[1] = RESOURCE;
|
|
|
+ itemsType[0] = PLAYER;
|
|
|
+ break;
|
|
|
+ case EMarketMode::CREATURE_RESOURCE:
|
|
|
+ itemsType[1] = CREATURE;
|
|
|
+ itemsType[0] = RESOURCE;
|
|
|
+ break;
|
|
|
+ case EMarketMode::RESOURCE_ARTIFACT:
|
|
|
+ itemsType[1] = RESOURCE;
|
|
|
+ itemsType[0] = ARTIFACT_TYPE;
|
|
|
+ break;
|
|
|
+ case EMarketMode::ARTIFACT_RESOURCE:
|
|
|
+ itemsType[1] = ARTIFACT_INSTANCE;
|
|
|
+ itemsType[0] = RESOURCE;
|
|
|
+ break;
|
|
|
+ case EMarketMode::CREATURE_EXP:
|
|
|
+ itemsType[1] = CREATURE;
|
|
|
+ itemsType[0] = CREATURE_PLACEHOLDER;
|
|
|
+ break;
|
|
|
+ case EMarketMode::ARTIFACT_EXP:
|
|
|
+ itemsType[1] = ARTIFACT_TYPE;
|
|
|
+ itemsType[0] = ARTIFACT_PLACEHOLDER;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void CTradeWindow::initItems(bool Left)
|
|
|
+{
|
|
|
+ if(Left && (itemsType[1] == ARTIFACT_TYPE || itemsType[1] == ARTIFACT_INSTANCE))
|
|
|
+ {
|
|
|
+ int xOffset = 0, yOffset = 0;
|
|
|
+ if(mode == EMarketMode::ARTIFACT_RESOURCE)
|
|
|
+ {
|
|
|
+ xOffset = -361;
|
|
|
+ yOffset = +46;
|
|
|
+
|
|
|
+ auto hlp = new CTradeableItem(Point(137, 469), itemsType[Left], -1, 1, 0);
|
|
|
+ hlp->recActions &= ~(UPDATE | SHOWALL);
|
|
|
+ items[Left].push_back(hlp);
|
|
|
+ }
|
|
|
+ else //ARTIFACT_EXP
|
|
|
+ {
|
|
|
+ xOffset = -363;
|
|
|
+ yOffset = -12;
|
|
|
+ }
|
|
|
+
|
|
|
+ BLOCK_CAPTURING;
|
|
|
+ arts = new CArtifactsOfHero(Point(pos.x+xOffset, pos.y+yOffset));
|
|
|
+ arts->commonInfo = new CArtifactsOfHero::SCommonPart;
|
|
|
+ arts->commonInfo->participants.insert(arts);
|
|
|
+ arts->recActions = 255;
|
|
|
+ arts->setHero(hero);
|
|
|
+ arts->allowedAssembling = false;
|
|
|
+ addChild(arts);
|
|
|
+ artSets.push_back(arts);
|
|
|
+
|
|
|
+ if(mode == EMarketMode::ARTIFACT_RESOURCE)
|
|
|
+ arts->highlightModeCallback = boost::bind(&CTradeWindow::artifactSelected, this, _1);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ std::vector<int> *ids = getItemsIds(Left);
|
|
|
+ std::vector<Rect> pos;
|
|
|
+ int amount = -1;
|
|
|
+
|
|
|
+ getPositionsFor(pos, Left, itemsType[Left]);
|
|
|
+
|
|
|
+ if(Left || !ids)
|
|
|
+ amount = 7;
|
|
|
+ else
|
|
|
+ amount = ids->size();
|
|
|
+
|
|
|
+ if(ids)
|
|
|
+ vstd::amin(amount, ids->size());
|
|
|
+
|
|
|
+ for(int j=0; j<amount; j++)
|
|
|
+ {
|
|
|
+ int id = (ids && ids->size()>j) ? (*ids)[j] : j;
|
|
|
+ if(id < 0 && mode != EMarketMode::ARTIFACT_EXP) //when sacrificing artifacts we need to prepare empty slots
|
|
|
+ continue;
|
|
|
+
|
|
|
+ auto hlp = new CTradeableItem(pos[j].topLeft(), itemsType[Left], id, Left, j);
|
|
|
+ hlp->pos = pos[j] + this->pos.topLeft();
|
|
|
+ items[Left].push_back(hlp);
|
|
|
+ }
|
|
|
+
|
|
|
+ initSubs(Left);
|
|
|
+}
|
|
|
+
|
|
|
+std::vector<int> *CTradeWindow::getItemsIds(bool Left)
|
|
|
+{
|
|
|
+ std::vector<int> *ids = nullptr;
|
|
|
+
|
|
|
+ if(mode == EMarketMode::ARTIFACT_EXP)
|
|
|
+ return new std::vector<int>(22, -1);
|
|
|
+
|
|
|
+ if(Left)
|
|
|
+ {
|
|
|
+ switch(itemsType[1])
|
|
|
+ {
|
|
|
+ case CREATURE:
|
|
|
+ ids = new std::vector<int>;
|
|
|
+ for(int i = 0; i < 7; i++)
|
|
|
+ {
|
|
|
+ if(const CCreature *c = hero->getCreature(SlotID(i)))
|
|
|
+ ids->push_back(c->idNumber);
|
|
|
+ else
|
|
|
+ ids->push_back(-1);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ switch(itemsType[0])
|
|
|
+ {
|
|
|
+ case PLAYER:
|
|
|
+ ids = new std::vector<int>;
|
|
|
+ for(int i = 0; i < PlayerColor::PLAYER_LIMIT_I; i++)
|
|
|
+ if(PlayerColor(i) != LOCPLINT->playerID && LOCPLINT->cb->getPlayerStatus(PlayerColor(i)) == EPlayerStatus::INGAME)
|
|
|
+ ids->push_back(i);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case ARTIFACT_TYPE:
|
|
|
+ ids = new std::vector<int>(market->availableItemsIds(mode));
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return ids;
|
|
|
+}
|
|
|
+
|
|
|
+void CTradeWindow::getPositionsFor(std::vector<Rect> &poss, bool Left, EType type) const
|
|
|
+{
|
|
|
+ using namespace boost::assign;
|
|
|
+
|
|
|
+ if(mode == EMarketMode::ARTIFACT_EXP && !Left)
|
|
|
+ {
|
|
|
+ //22 boxes, 5 in row, last row: two boxes centered
|
|
|
+ int h, w, x, y, dx, dy;
|
|
|
+ h = w = 44;
|
|
|
+ x = 317;
|
|
|
+ y = 53;
|
|
|
+ dx = 54;
|
|
|
+ dy = 70;
|
|
|
+ for (int i = 0; i < 4 ; i++)
|
|
|
+ for (int j = 0; j < 5 ; j++)
|
|
|
+ poss += Rect(x + dx*j, y + dy*i, w, h);
|
|
|
+
|
|
|
+ poss += Rect(x + dx*1.5, y + dy*4, w, h);
|
|
|
+ poss += Rect(x + dx*2.5, y + dy*4, w, h);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ //seven boxes:
|
|
|
+ // X X X
|
|
|
+ // X X X
|
|
|
+ // X
|
|
|
+ int h, w, x, y, dx, dy;
|
|
|
+ int leftToRightOffset;
|
|
|
+ getBaseForPositions(type, dx, dy, x, y, h, w, !Left, leftToRightOffset);
|
|
|
+
|
|
|
+ poss += genRect(h, w, x, y), genRect(h, w, x + dx, y), genRect(h, w, x + 2*dx, y),
|
|
|
+ genRect(h, w, x, y + dy), genRect(h, w, x + dx, y + dy), genRect(h, w, x + 2*dx, y + dy),
|
|
|
+ genRect(h, w, x + dx, y + 2*dy);
|
|
|
+
|
|
|
+ if(!Left)
|
|
|
+ {
|
|
|
+ for(Rect &r : poss)
|
|
|
+ r.x += leftToRightOffset;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void CTradeWindow::initSubs(bool Left)
|
|
|
+{
|
|
|
+ for(CTradeableItem *t : items[Left])
|
|
|
+ {
|
|
|
+ if(Left)
|
|
|
+ {
|
|
|
+ switch(itemsType[1])
|
|
|
+ {
|
|
|
+ case CREATURE:
|
|
|
+ t->subtitle = boost::lexical_cast<std::string>(hero->getStackCount(SlotID(t->serial)));
|
|
|
+ break;
|
|
|
+ case RESOURCE:
|
|
|
+ t->subtitle = boost::lexical_cast<std::string>(LOCPLINT->cb->getResourceAmount(static_cast<Res::ERes>(t->serial)));
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else //right side
|
|
|
+ {
|
|
|
+ if(itemsType[0] == PLAYER)
|
|
|
+ {
|
|
|
+ t->subtitle = CGI->generaltexth->capColors[t->id];
|
|
|
+ }
|
|
|
+ else if(hLeft)//artifact, creature
|
|
|
+ {
|
|
|
+ int h1, h2; //hlp variables for getting offer
|
|
|
+ market->getOffer(hLeft->id, t->id, h1, h2, mode);
|
|
|
+ if(t->id != hLeft->id || mode != EMarketMode::RESOURCE_RESOURCE) //don't allow exchanging same resources
|
|
|
+ {
|
|
|
+ std::ostringstream oss;
|
|
|
+ oss << h2;
|
|
|
+ if(h1!=1)
|
|
|
+ oss << "/" << h1;
|
|
|
+ t->subtitle = oss.str();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ t->subtitle = CGI->generaltexth->allTexts[164]; // n/a
|
|
|
+ }
|
|
|
+ else
|
|
|
+ t->subtitle = "";
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void CTradeWindow::showAll(SDL_Surface * to)
|
|
|
+{
|
|
|
+ CWindowObject::showAll(to);
|
|
|
+
|
|
|
+ if(hRight)
|
|
|
+ CSDL_Ext::drawBorder(to,hRight->pos.x-1,hRight->pos.y-1,hRight->pos.w+2,hRight->pos.h+2,int3(255,231,148));
|
|
|
+ if(hLeft && hLeft->type != ARTIFACT_INSTANCE)
|
|
|
+ CSDL_Ext::drawBorder(to,hLeft->pos.x-1,hLeft->pos.y-1,hLeft->pos.w+2,hLeft->pos.h+2,int3(255,231,148));
|
|
|
+
|
|
|
+ if(readyToTrade)
|
|
|
+ {
|
|
|
+ hLeft->showAllAt(pos.topLeft() + selectionOffset(true), selectionSubtitle(true), to);
|
|
|
+ hRight->showAllAt(pos.topLeft() + selectionOffset(false), selectionSubtitle(false), to);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void CTradeWindow::removeItems(const std::set<CTradeableItem *> &toRemove)
|
|
|
+{
|
|
|
+ for(CTradeableItem *t : toRemove)
|
|
|
+ removeItem(t);
|
|
|
+}
|
|
|
+
|
|
|
+void CTradeWindow::removeItem(CTradeableItem * t)
|
|
|
+{
|
|
|
+ items[t->left] -= t;
|
|
|
+ delete t;
|
|
|
+
|
|
|
+ if(hRight == t)
|
|
|
+ {
|
|
|
+ hRight = nullptr;
|
|
|
+ selectionChanged(false);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void CTradeWindow::getEmptySlots(std::set<CTradeableItem *> &toRemove)
|
|
|
+{
|
|
|
+ for(CTradeableItem *t : items[1])
|
|
|
+ if(!hero->getStackCount(SlotID(t->serial)))
|
|
|
+ toRemove.insert(t);
|
|
|
+}
|
|
|
+
|
|
|
+void CTradeWindow::setMode(EMarketMode::EMarketMode Mode)
|
|
|
+{
|
|
|
+ const IMarket *m = market;
|
|
|
+ const CGHeroInstance *h = hero;
|
|
|
+ CTradeWindow *nwindow = nullptr;
|
|
|
+
|
|
|
+ GH.popIntTotally(this);
|
|
|
+
|
|
|
+ switch(Mode)
|
|
|
+ {
|
|
|
+ case EMarketMode::CREATURE_EXP:
|
|
|
+ case EMarketMode::ARTIFACT_EXP:
|
|
|
+ nwindow = new CAltarWindow(m, h, Mode);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ nwindow = new CMarketplaceWindow(m, h, Mode);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ GH.pushInt(nwindow);
|
|
|
+}
|
|
|
+
|
|
|
+void CTradeWindow::artifactSelected(CArtPlace *slot)
|
|
|
+{
|
|
|
+ assert(mode == EMarketMode::ARTIFACT_RESOURCE);
|
|
|
+ items[1][0]->setArtInstance(slot->ourArt);
|
|
|
+ if(slot->ourArt)
|
|
|
+ hLeft = items[1][0];
|
|
|
+ else
|
|
|
+ hLeft = nullptr;
|
|
|
+
|
|
|
+ selectionChanged(true);
|
|
|
+}
|
|
|
+
|
|
|
+std::string CMarketplaceWindow::getBackgroundForMode(EMarketMode::EMarketMode mode)
|
|
|
+{
|
|
|
+ switch(mode)
|
|
|
+ {
|
|
|
+ case EMarketMode::RESOURCE_RESOURCE:
|
|
|
+ return "TPMRKRES.bmp";
|
|
|
+ case EMarketMode::RESOURCE_PLAYER:
|
|
|
+ return "TPMRKPTS.bmp";
|
|
|
+ case EMarketMode::CREATURE_RESOURCE:
|
|
|
+ return "TPMRKCRS.bmp";
|
|
|
+ case EMarketMode::RESOURCE_ARTIFACT:
|
|
|
+ return "TPMRKABS.bmp";
|
|
|
+ case EMarketMode::ARTIFACT_RESOURCE:
|
|
|
+ return "TPMRKASS.bmp";
|
|
|
+ }
|
|
|
+ assert(0);
|
|
|
+ return "";
|
|
|
+}
|
|
|
+
|
|
|
+CMarketplaceWindow::CMarketplaceWindow(const IMarket *Market, const CGHeroInstance *Hero, EMarketMode::EMarketMode Mode)
|
|
|
+ : CTradeWindow(getBackgroundForMode(Mode), Market, Hero, Mode)
|
|
|
+{
|
|
|
+ OBJ_CONSTRUCTION_CAPTURING_ALL;
|
|
|
+
|
|
|
+ madeTransaction = false;
|
|
|
+ bool sliderNeeded = true;
|
|
|
+
|
|
|
+ new CGStatusBar(new CPicture(*background, Rect(8, pos.h - 26, pos.w - 16, 19), 8, pos.h - 26));
|
|
|
+
|
|
|
+ std::string title;
|
|
|
+
|
|
|
+ if (market->o->ID == Obj::TOWN)
|
|
|
+ {
|
|
|
+ switch (mode)
|
|
|
+ {
|
|
|
+ break; case EMarketMode::CREATURE_RESOURCE:
|
|
|
+ title = CGI->townh->factions[ETownType::STRONGHOLD]->town->buildings[BuildingID::FREELANCERS_GUILD]->Name();
|
|
|
+
|
|
|
+ break; case EMarketMode::RESOURCE_ARTIFACT:
|
|
|
+ title = CGI->townh->factions[market->o->subID]->town->buildings[BuildingID::ARTIFACT_MERCHANT]->Name();
|
|
|
+ sliderNeeded = false;
|
|
|
+
|
|
|
+ break; case EMarketMode::ARTIFACT_RESOURCE:
|
|
|
+ title = CGI->townh->factions[market->o->subID]->town->buildings[BuildingID::ARTIFACT_MERCHANT]->Name();
|
|
|
+ sliderNeeded = false;
|
|
|
+
|
|
|
+ break; default:
|
|
|
+ title = CGI->generaltexth->allTexts[158];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ switch (market->o->ID)
|
|
|
+ {
|
|
|
+ break; case Obj::BLACK_MARKET: title = CGI->generaltexth->allTexts[349];
|
|
|
+ break; case Obj::TRADING_POST: title = CGI->generaltexth->allTexts[159];
|
|
|
+ break; case Obj::TRADING_POST_SNOW: title = CGI->generaltexth->allTexts[159];
|
|
|
+ break; default: title = market->o->getObjectName();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ new CLabel(300, 27, FONT_BIG, CENTER, Colors::YELLOW, title);
|
|
|
+
|
|
|
+ initItems(false);
|
|
|
+ initItems(true);
|
|
|
+
|
|
|
+ ok = new CAdventureMapButton(CGI->generaltexth->zelp[600],boost::bind(&CGuiHandler::popIntTotally,&GH,this),516,520,"IOK6432.DEF",SDLK_RETURN);
|
|
|
+ ok->assignedKeys.insert(SDLK_ESCAPE);
|
|
|
+ deal = new CAdventureMapButton(CGI->generaltexth->zelp[595],boost::bind(&CMarketplaceWindow::makeDeal,this),307,520,"TPMRKB.DEF");
|
|
|
+ deal->block(true);
|
|
|
+
|
|
|
+ if(sliderNeeded)
|
|
|
+ {
|
|
|
+ slider = new CSlider(231,490,137,nullptr,0,0);
|
|
|
+ slider->moved = boost::bind(&CMarketplaceWindow::sliderMoved,this,_1);
|
|
|
+ max = new CAdventureMapButton(CGI->generaltexth->zelp[596],boost::bind(&CMarketplaceWindow::setMax,this),229,520,"IRCBTNS.DEF");
|
|
|
+ max->block(true);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ slider = nullptr;
|
|
|
+ max = nullptr;
|
|
|
+ deal->moveBy(Point(-30, 0));
|
|
|
+ }
|
|
|
+
|
|
|
+ Rect traderTextRect;
|
|
|
+
|
|
|
+ //left side
|
|
|
+ switch(Mode)
|
|
|
+ {
|
|
|
+ case EMarketMode::RESOURCE_RESOURCE:
|
|
|
+ case EMarketMode::RESOURCE_PLAYER:
|
|
|
+ case EMarketMode::RESOURCE_ARTIFACT:
|
|
|
+ new CLabel(154, 148, FONT_SMALL, CENTER, Colors::WHITE, CGI->generaltexth->allTexts[270]);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case EMarketMode::CREATURE_RESOURCE:
|
|
|
+ //%s's Creatures
|
|
|
+ new CLabel(152, 102, FONT_SMALL, CENTER, Colors::WHITE,
|
|
|
+ boost::str(boost::format(CGI->generaltexth->allTexts[272]) % hero->name));
|
|
|
+ break;
|
|
|
+ case EMarketMode::ARTIFACT_RESOURCE:
|
|
|
+ //%s's Artifacts
|
|
|
+ new CLabel(152, 102, FONT_SMALL, CENTER, Colors::WHITE,
|
|
|
+ boost::str(boost::format(CGI->generaltexth->allTexts[272]) % hero->name));
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ //right side
|
|
|
+ switch(Mode)
|
|
|
+ {
|
|
|
+ case EMarketMode::RESOURCE_RESOURCE:
|
|
|
+ case EMarketMode::CREATURE_RESOURCE:
|
|
|
+ case EMarketMode::RESOURCE_ARTIFACT:
|
|
|
+ case EMarketMode::ARTIFACT_RESOURCE:
|
|
|
+ new CLabel(445, 148, FONT_SMALL, CENTER, Colors::WHITE, CGI->generaltexth->allTexts[168]);
|
|
|
+ traderTextRect = Rect(316, 48, 260, 75);
|
|
|
+ break;
|
|
|
+ case EMarketMode::RESOURCE_PLAYER:
|
|
|
+ new CLabel(445, 55, FONT_SMALL, CENTER, Colors::WHITE, CGI->generaltexth->allTexts[169]);
|
|
|
+ traderTextRect = Rect(28, 48, 260, 75);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ traderText = new CTextBox("", traderTextRect, 0, FONT_SMALL, CENTER);
|
|
|
+ int specialOffset = mode == EMarketMode::ARTIFACT_RESOURCE ? 35 : 0; //in selling artifacts mode we need to move res-res and art-res buttons down
|
|
|
+
|
|
|
+ if(printButtonFor(EMarketMode::RESOURCE_PLAYER))
|
|
|
+ new CAdventureMapButton(CGI->generaltexth->zelp[612],boost::bind(&CMarketplaceWindow::setMode,this, EMarketMode::RESOURCE_PLAYER), 18, 520,"TPMRKBU1.DEF");
|
|
|
+ if(printButtonFor(EMarketMode::RESOURCE_RESOURCE))
|
|
|
+ new CAdventureMapButton(CGI->generaltexth->zelp[605],boost::bind(&CMarketplaceWindow::setMode,this, EMarketMode::RESOURCE_RESOURCE), 516, 450 + specialOffset,"TPMRKBU5.DEF");
|
|
|
+ if(printButtonFor(EMarketMode::CREATURE_RESOURCE))
|
|
|
+ new CAdventureMapButton(CGI->generaltexth->zelp[599],boost::bind(&CMarketplaceWindow::setMode,this, EMarketMode::CREATURE_RESOURCE), 516, 485,"TPMRKBU4.DEF"); //was y=450, changed to not overlap res-res in some conditions
|
|
|
+ if(printButtonFor(EMarketMode::RESOURCE_ARTIFACT))
|
|
|
+ new CAdventureMapButton(CGI->generaltexth->zelp[598],boost::bind(&CMarketplaceWindow::setMode,this, EMarketMode::RESOURCE_ARTIFACT), 18, 450 + specialOffset,"TPMRKBU2.DEF");
|
|
|
+ if(printButtonFor(EMarketMode::ARTIFACT_RESOURCE))
|
|
|
+ new CAdventureMapButton(CGI->generaltexth->zelp[613],boost::bind(&CMarketplaceWindow::setMode,this, EMarketMode::ARTIFACT_RESOURCE), 18, 485,"TPMRKBU3.DEF"); //was y=450, changed to not overlap res-art in some conditions
|
|
|
+
|
|
|
+ updateTraderText();
|
|
|
+}
|
|
|
+
|
|
|
+CMarketplaceWindow::~CMarketplaceWindow()
|
|
|
+{
|
|
|
+ hLeft = hRight = nullptr;
|
|
|
+ for(auto & elem : items[1])
|
|
|
+ delete elem;
|
|
|
+ for(auto & elem : items[0])
|
|
|
+ delete elem;
|
|
|
+
|
|
|
+ items[1].clear();
|
|
|
+ items[0].clear();
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+void CMarketplaceWindow::setMax()
|
|
|
+{
|
|
|
+ slider->moveToMax();
|
|
|
+}
|
|
|
+
|
|
|
+void CMarketplaceWindow::makeDeal()
|
|
|
+{
|
|
|
+ int sliderValue = 0;
|
|
|
+ if(slider)
|
|
|
+ sliderValue = slider->value;
|
|
|
+ else
|
|
|
+ sliderValue = !deal->isBlocked(); //should always be 1
|
|
|
+
|
|
|
+ if(!sliderValue)
|
|
|
+ return;
|
|
|
+
|
|
|
+ int leftIdToSend = -1;
|
|
|
+ switch (mode)
|
|
|
+ {
|
|
|
+ case EMarketMode::CREATURE_RESOURCE:
|
|
|
+ leftIdToSend = hLeft->serial;
|
|
|
+ break;
|
|
|
+ case EMarketMode::ARTIFACT_RESOURCE:
|
|
|
+ leftIdToSend = hLeft->getArtInstance()->id.getNum();
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ leftIdToSend = hLeft->id;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(slider)
|
|
|
+ {
|
|
|
+ LOCPLINT->cb->trade(market->o, mode, leftIdToSend, hRight->id, slider->value*r1, hero);
|
|
|
+ slider->moveTo(0);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ LOCPLINT->cb->trade(market->o, mode, leftIdToSend, hRight->id, r2, hero);
|
|
|
+ }
|
|
|
+ madeTransaction = true;
|
|
|
+
|
|
|
+ hLeft = nullptr;
|
|
|
+ hRight = nullptr;
|
|
|
+ selectionChanged(true);
|
|
|
+}
|
|
|
+
|
|
|
+void CMarketplaceWindow::sliderMoved( int to )
|
|
|
+{
|
|
|
+ redraw();
|
|
|
+}
|
|
|
+
|
|
|
+void CMarketplaceWindow::selectionChanged(bool side)
|
|
|
+{
|
|
|
+ readyToTrade = hLeft && hRight;
|
|
|
+ if(mode == EMarketMode::RESOURCE_RESOURCE)
|
|
|
+ readyToTrade = readyToTrade && (hLeft->id != hRight->id); //for resource trade, two DIFFERENT resources must be selected
|
|
|
+
|
|
|
+ if(mode == EMarketMode::ARTIFACT_RESOURCE && !hLeft)
|
|
|
+ arts->unmarkSlots(false);
|
|
|
+
|
|
|
+ if(readyToTrade)
|
|
|
+ {
|
|
|
+ int soldItemId = hLeft->id;
|
|
|
+ market->getOffer(soldItemId, hRight->id, r1, r2, mode);
|
|
|
+
|
|
|
+ if(slider)
|
|
|
+ {
|
|
|
+ int newAmount = -1;
|
|
|
+ if(itemsType[1] == RESOURCE)
|
|
|
+ newAmount = LOCPLINT->cb->getResourceAmount(static_cast<Res::ERes>(soldItemId));
|
|
|
+ else if(itemsType[1] == CREATURE)
|
|
|
+ newAmount = hero->getStackCount(SlotID(hLeft->serial)) - (hero->Slots().size() == 1 && hero->needsLastStack());
|
|
|
+ else
|
|
|
+ assert(0);
|
|
|
+
|
|
|
+ slider->setAmount(newAmount / r1);
|
|
|
+ slider->moveTo(0);
|
|
|
+ max->block(false);
|
|
|
+ deal->block(false);
|
|
|
+ }
|
|
|
+ else if(itemsType[1] == RESOURCE) //buying -> check if we can afford transaction
|
|
|
+ {
|
|
|
+ deal->block(LOCPLINT->cb->getResourceAmount(static_cast<Res::ERes>(soldItemId)) < r1);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ deal->block(false);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if(slider)
|
|
|
+ {
|
|
|
+ max->block(true);
|
|
|
+ slider->setAmount(0);
|
|
|
+ slider->moveTo(0);
|
|
|
+ }
|
|
|
+ deal->block(true);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(side && itemsType[0] != PLAYER) //items[1] selection changed, recalculate offers
|
|
|
+ initSubs(false);
|
|
|
+
|
|
|
+ updateTraderText();
|
|
|
+ redraw();
|
|
|
+}
|
|
|
+
|
|
|
+bool CMarketplaceWindow::printButtonFor(EMarketMode::EMarketMode M) const
|
|
|
+{
|
|
|
+ return market->allowsTrade(M) && M != mode && (hero || ( M != EMarketMode::CREATURE_RESOURCE && M != EMarketMode::RESOURCE_ARTIFACT && M != EMarketMode::ARTIFACT_RESOURCE ));
|
|
|
+}
|
|
|
+
|
|
|
+void CMarketplaceWindow::garrisonChanged()
|
|
|
+{
|
|
|
+ if(mode != EMarketMode::CREATURE_RESOURCE)
|
|
|
+ return;
|
|
|
+
|
|
|
+ std::set<CTradeableItem *> toRemove;
|
|
|
+ getEmptySlots(toRemove);
|
|
|
+
|
|
|
+
|
|
|
+ removeItems(toRemove);
|
|
|
+ initSubs(true);
|
|
|
+}
|
|
|
+
|
|
|
+void CMarketplaceWindow::artifactsChanged(bool Left)
|
|
|
+{
|
|
|
+ assert(!Left);
|
|
|
+ if(mode != EMarketMode::RESOURCE_ARTIFACT)
|
|
|
+ return;
|
|
|
+
|
|
|
+ std::vector<int> available = market->availableItemsIds(mode);
|
|
|
+ std::set<CTradeableItem *> toRemove;
|
|
|
+ for(CTradeableItem *t : items[0])
|
|
|
+ if(!vstd::contains(available, t->id))
|
|
|
+ toRemove.insert(t);
|
|
|
+
|
|
|
+ removeItems(toRemove);
|
|
|
+ redraw();
|
|
|
+}
|
|
|
+
|
|
|
+std::string CMarketplaceWindow::selectionSubtitle(bool Left) const
|
|
|
+{
|
|
|
+ if(Left)
|
|
|
+ {
|
|
|
+ switch(itemsType[1])
|
|
|
+ {
|
|
|
+ case RESOURCE:
|
|
|
+ case CREATURE:
|
|
|
+ {
|
|
|
+ int val = slider
|
|
|
+ ? slider->value * r1
|
|
|
+ : (((deal->isBlocked())) ? 0 : r1);
|
|
|
+
|
|
|
+ return boost::lexical_cast<std::string>(val);
|
|
|
+ }
|
|
|
+ case ARTIFACT_INSTANCE:
|
|
|
+ return ((deal->isBlocked()) ? "0" : "1");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ switch(itemsType[0])
|
|
|
+ {
|
|
|
+ case RESOURCE:
|
|
|
+ if(slider)
|
|
|
+ return boost::lexical_cast<std::string>( slider->value * r2 );
|
|
|
+ else
|
|
|
+ return boost::lexical_cast<std::string>(r2);
|
|
|
+ case ARTIFACT_TYPE:
|
|
|
+ return ((deal->isBlocked()) ? "0" : "1");
|
|
|
+ case PLAYER:
|
|
|
+ return (hRight ? CGI->generaltexth->capColors[hRight->id] : "");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return "???";
|
|
|
+}
|
|
|
+
|
|
|
+Point CMarketplaceWindow::selectionOffset(bool Left) const
|
|
|
+{
|
|
|
+ if(Left)
|
|
|
+ {
|
|
|
+ switch(itemsType[1])
|
|
|
+ {
|
|
|
+ case RESOURCE:
|
|
|
+ return Point(122, 446);
|
|
|
+ case CREATURE:
|
|
|
+ return Point(128, 450);
|
|
|
+ case ARTIFACT_INSTANCE:
|
|
|
+ return Point(134, 466);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ switch(itemsType[0])
|
|
|
+ {
|
|
|
+ case RESOURCE:
|
|
|
+ if(mode == EMarketMode::ARTIFACT_RESOURCE)
|
|
|
+ return Point(410, 469);
|
|
|
+ else
|
|
|
+ return Point(410, 446);
|
|
|
+ case ARTIFACT_TYPE:
|
|
|
+ return Point(425, 447);
|
|
|
+ case PLAYER:
|
|
|
+ return Point(417, 451);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ assert(0);
|
|
|
+ return Point(0,0);
|
|
|
+}
|
|
|
+
|
|
|
+void CMarketplaceWindow::resourceChanged(int type, int val)
|
|
|
+{
|
|
|
+ initSubs(true);
|
|
|
+}
|
|
|
+
|
|
|
+void CMarketplaceWindow::getBaseForPositions(EType type, int &dx, int &dy, int &x, int &y, int &h, int &w, bool Right, int &leftToRightOffset) const
|
|
|
+{
|
|
|
+ switch(type)
|
|
|
+ {
|
|
|
+ case RESOURCE:
|
|
|
+ dx = 82;
|
|
|
+ dy = 79;
|
|
|
+ x = 39;
|
|
|
+ y = 180;
|
|
|
+ h = 66;
|
|
|
+ w = 74;
|
|
|
+ break;
|
|
|
+ case PLAYER:
|
|
|
+ dx = 83;
|
|
|
+ dy = 118;
|
|
|
+ h = 64;
|
|
|
+ w = 58;
|
|
|
+ x = 44;
|
|
|
+ y = 83;
|
|
|
+ assert(Right);
|
|
|
+ break;
|
|
|
+ case CREATURE://45,123
|
|
|
+ x = 45;
|
|
|
+ y = 123;
|
|
|
+ w = 58;
|
|
|
+ h = 64;
|
|
|
+ dx = 83;
|
|
|
+ dy = 98;
|
|
|
+ assert(!Right);
|
|
|
+ break;
|
|
|
+ case ARTIFACT_TYPE://45,123
|
|
|
+ x = 340-289;
|
|
|
+ y = 180;
|
|
|
+ w = 44;
|
|
|
+ h = 44;
|
|
|
+ dx = 83;
|
|
|
+ dy = 79;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ leftToRightOffset = 289;
|
|
|
+}
|
|
|
+
|
|
|
+void CMarketplaceWindow::updateTraderText()
|
|
|
+{
|
|
|
+ if(readyToTrade)
|
|
|
+ {
|
|
|
+ if(mode == EMarketMode::RESOURCE_PLAYER)
|
|
|
+ {
|
|
|
+ //I can give %s to the %s player.
|
|
|
+ traderText->setText(boost::str(boost::format(CGI->generaltexth->allTexts[165]) % hLeft->getName() % hRight->getName()));
|
|
|
+ }
|
|
|
+ else if(mode == EMarketMode::RESOURCE_ARTIFACT)
|
|
|
+ {
|
|
|
+ //I can offer you the %s for %d %s of %s.
|
|
|
+ traderText->setText(boost::str(boost::format(CGI->generaltexth->allTexts[267]) % hRight->getName() % r1 % CGI->generaltexth->allTexts[160 + (r1==1)] % hLeft->getName()));
|
|
|
+ }
|
|
|
+ else if(mode == EMarketMode::RESOURCE_RESOURCE)
|
|
|
+ {
|
|
|
+ //I can offer you %d %s of %s for %d %s of %s.
|
|
|
+ traderText->setText(boost::str(boost::format(CGI->generaltexth->allTexts[157]) % r2 % CGI->generaltexth->allTexts[160 + (r2==1)] % hRight->getName() % r1 % CGI->generaltexth->allTexts[160 + (r1==1)] % hLeft->getName()));
|
|
|
+ }
|
|
|
+ else if(mode == EMarketMode::CREATURE_RESOURCE)
|
|
|
+ {
|
|
|
+ //I can offer you %d %s of %s for %d %s.
|
|
|
+ traderText->setText(boost::str(boost::format(CGI->generaltexth->allTexts[269]) % r2 % CGI->generaltexth->allTexts[160 + (r2==1)] % hRight->getName() % r1 % hLeft->getName(r1)));
|
|
|
+ }
|
|
|
+ else if(mode == EMarketMode::ARTIFACT_RESOURCE)
|
|
|
+ {
|
|
|
+ //I can offer you %d %s of %s for your %s.
|
|
|
+ traderText->setText(boost::str(boost::format(CGI->generaltexth->allTexts[268]) % r2 % CGI->generaltexth->allTexts[160 + (r2==1)] % hRight->getName() % hLeft->getName(r1)));
|
|
|
+ }
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ int gnrtxtnr = -1;
|
|
|
+ if(madeTransaction)
|
|
|
+ {
|
|
|
+ if(mode == EMarketMode::RESOURCE_PLAYER)
|
|
|
+ gnrtxtnr = 166; //Are there any other resources you'd like to give away?
|
|
|
+ else
|
|
|
+ gnrtxtnr = 162; //You have received quite a bargain. I expect to make no profit on the deal. Can I interest you in any of my other wares?
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if(mode == EMarketMode::RESOURCE_PLAYER)
|
|
|
+ gnrtxtnr = 167; //If you'd like to give any of your resources to another player, click on the item you wish to give and to whom.
|
|
|
+ else
|
|
|
+ gnrtxtnr = 163; //Please inspect our fine wares. If you feel like offering a trade, click on the items you wish to trade with and for.
|
|
|
+ }
|
|
|
+ traderText->setText(CGI->generaltexth->allTexts[gnrtxtnr]);
|
|
|
+}
|
|
|
+
|
|
|
+CAltarWindow::CAltarWindow(const IMarket *Market, const CGHeroInstance *Hero /*= nullptr*/, EMarketMode::EMarketMode Mode)
|
|
|
+ :CTradeWindow((Mode == EMarketMode::CREATURE_EXP ? "ALTARMON.bmp" : "ALTRART2.bmp"), Market, Hero, Mode)
|
|
|
+{
|
|
|
+ OBJ_CONSTRUCTION_CAPTURING_ALL;
|
|
|
+ if(Mode == EMarketMode::CREATURE_EXP)
|
|
|
+ {
|
|
|
+ //%s's Creatures
|
|
|
+ new CLabel(155, 30, FONT_SMALL, CENTER, Colors::YELLOW,
|
|
|
+ boost::str(boost::format(CGI->generaltexth->allTexts[272]) % hero->name));
|
|
|
+
|
|
|
+ //Altar of Sacrifice
|
|
|
+ new CLabel(450, 30, FONT_SMALL, CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[479]);
|
|
|
+
|
|
|
+ //To sacrifice creatures, move them from your army on to the Altar and click Sacrifice
|
|
|
+ new CTextBox(CGI->generaltexth->allTexts[480], Rect(320, 56, 256, 40), 0, FONT_SMALL, CENTER, Colors::YELLOW);
|
|
|
+
|
|
|
+ slider = new CSlider(231,481,137,nullptr,0,0);
|
|
|
+ slider->moved = boost::bind(&CAltarWindow::sliderMoved,this,_1);
|
|
|
+ max = new CAdventureMapButton(CGI->generaltexth->zelp[578],boost::bind(&CSlider::moveToMax, slider),147,520,"IRCBTNS.DEF");
|
|
|
+
|
|
|
+ sacrificedUnits.resize(GameConstants::ARMY_SIZE, 0);
|
|
|
+ sacrificeAll = new CAdventureMapButton(CGI->generaltexth->zelp[579],boost::bind(&CAltarWindow::SacrificeAll,this),393,520,"ALTARMY.DEF");
|
|
|
+ sacrificeBackpack = nullptr;
|
|
|
+
|
|
|
+ initItems(true);
|
|
|
+ mimicCres();
|
|
|
+ artIcon = nullptr;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ //Sacrifice artifacts for experience
|
|
|
+ new CLabel(450, 34, FONT_SMALL, CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[477]);
|
|
|
+ //%s's Creatures
|
|
|
+ new CLabel(302, 423, FONT_SMALL, CENTER, Colors::YELLOW, CGI->generaltexth->allTexts[478]);
|
|
|
+
|
|
|
+ sacrificeAll = new CAdventureMapButton(CGI->generaltexth->zelp[571], boost::bind(&CAltarWindow::SacrificeAll,this),393,520,"ALTFILL.DEF");
|
|
|
+ sacrificeAll->block(hero->artifactsInBackpack.empty() && hero->artifactsWorn.empty());
|
|
|
+ sacrificeBackpack = new CAdventureMapButton(CGI->generaltexth->zelp[570],boost::bind(&CAltarWindow::SacrificeBackpack,this),147,520,"ALTEMBK.DEF");
|
|
|
+ sacrificeBackpack->block(hero->artifactsInBackpack.empty());
|
|
|
+
|
|
|
+ slider = nullptr;
|
|
|
+ max = nullptr;
|
|
|
+
|
|
|
+ initItems(true);
|
|
|
+ initItems(false);
|
|
|
+ artIcon = new CAnimImage("ARTIFACT", 0, 0, 281, 442);
|
|
|
+ artIcon->disable();
|
|
|
+ }
|
|
|
+
|
|
|
+ //Experience needed to reach next level
|
|
|
+ new CTextBox(CGI->generaltexth->allTexts[475], Rect(15, 415, 125, 50), 0, FONT_SMALL, CENTER, Colors::YELLOW);
|
|
|
+ //Total experience on the Altar
|
|
|
+ new CTextBox(CGI->generaltexth->allTexts[476], Rect(15, 495, 125, 40), 0, FONT_SMALL, CENTER, Colors::YELLOW);
|
|
|
+
|
|
|
+ new CGStatusBar(new CPicture(*background, Rect(8, pos.h - 26, pos.w - 16, 19), 8, pos.h - 26));
|
|
|
+
|
|
|
+ ok = new CAdventureMapButton(CGI->generaltexth->zelp[568],boost::bind(&CGuiHandler::popIntTotally,&GH,this),516,520,"IOK6432.DEF",SDLK_RETURN);
|
|
|
+ ok->assignedKeys.insert(SDLK_ESCAPE);
|
|
|
+
|
|
|
+ deal = new CAdventureMapButton(CGI->generaltexth->zelp[585],boost::bind(&CAltarWindow::makeDeal,this),269,520,"ALTSACR.DEF");
|
|
|
+
|
|
|
+ if(Hero->getAlignment() != ::EAlignment::EVIL && Mode == EMarketMode::CREATURE_EXP)
|
|
|
+ new CAdventureMapButton(CGI->generaltexth->zelp[580], boost::bind(&CTradeWindow::setMode,this, EMarketMode::ARTIFACT_EXP), 516, 421, "ALTART.DEF");
|
|
|
+ if(Hero->getAlignment() != ::EAlignment::GOOD && Mode == EMarketMode::ARTIFACT_EXP)
|
|
|
+ new CAdventureMapButton(CGI->generaltexth->zelp[572], boost::bind(&CTradeWindow::setMode,this, EMarketMode::CREATURE_EXP), 516, 421, "ALTSACC.DEF");
|
|
|
+
|
|
|
+ expPerUnit.resize(GameConstants::ARMY_SIZE, 0);
|
|
|
+ getExpValues();
|
|
|
+
|
|
|
+ expToLevel = new CLabel(73, 475, FONT_SMALL, CENTER);
|
|
|
+ expOnAltar = new CLabel(73, 543, FONT_SMALL, CENTER);
|
|
|
+
|
|
|
+ setExpToLevel();
|
|
|
+ calcTotalExp();
|
|
|
+ blockTrade();
|
|
|
+}
|
|
|
+
|
|
|
+CAltarWindow::~CAltarWindow()
|
|
|
+{
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+void CAltarWindow::getBaseForPositions(EType type, int &dx, int &dy, int &x, int &y, int &h, int &w, bool Right, int &leftToRightOffset) const
|
|
|
+{
|
|
|
+ leftToRightOffset = 289;
|
|
|
+ x = 45;
|
|
|
+ y = 110;
|
|
|
+ w = 58;
|
|
|
+ h = 64;
|
|
|
+ dx = 83;
|
|
|
+ dy = 98;
|
|
|
+}
|
|
|
+
|
|
|
+void CAltarWindow::sliderMoved(int to)
|
|
|
+{
|
|
|
+ sacrificedUnits[hLeft->serial] = to;
|
|
|
+ updateRight(hRight);
|
|
|
+ deal->block(!to);
|
|
|
+ calcTotalExp();
|
|
|
+ redraw();
|
|
|
+}
|
|
|
+
|
|
|
+void CAltarWindow::makeDeal()
|
|
|
+{
|
|
|
+ if(mode == EMarketMode::CREATURE_EXP)
|
|
|
+ {
|
|
|
+ blockTrade();
|
|
|
+ slider->value = 0;
|
|
|
+
|
|
|
+ std::vector<int> toSacrifice = sacrificedUnits;
|
|
|
+ for (int i = 0; i < toSacrifice.size(); i++)
|
|
|
+ {
|
|
|
+ if(toSacrifice[i])
|
|
|
+ LOCPLINT->cb->trade(market->o, mode, i, 0, toSacrifice[i], hero);
|
|
|
+ }
|
|
|
+
|
|
|
+ for(int& val : sacrificedUnits)
|
|
|
+ val = 0;
|
|
|
+
|
|
|
+ for(CTradeableItem *t : items[0])
|
|
|
+ {
|
|
|
+ t->setType(CREATURE_PLACEHOLDER);
|
|
|
+ t->subtitle = "";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ for(const CArtifactInstance *art : arts->artifactsOnAltar) //sacrifice each artifact on the list
|
|
|
+ {
|
|
|
+ LOCPLINT->cb->trade(market->o, mode, hero->getArtPos(art), -1, 1, hero);
|
|
|
+ }
|
|
|
+ arts->artifactsOnAltar.clear();
|
|
|
+
|
|
|
+ for(CTradeableItem *t : items[0])
|
|
|
+ {
|
|
|
+ t->setID(-1);
|
|
|
+ t->subtitle = "";
|
|
|
+ }
|
|
|
+
|
|
|
+ arts->commonInfo->reset();
|
|
|
+ //arts->scrollBackpack(0);
|
|
|
+ deal->block(true);
|
|
|
+ }
|
|
|
+
|
|
|
+ calcTotalExp();
|
|
|
+}
|
|
|
+
|
|
|
+void CAltarWindow::SacrificeAll()
|
|
|
+{
|
|
|
+ if(mode == EMarketMode::CREATURE_EXP)
|
|
|
+ {
|
|
|
+ bool movedAnything = false;
|
|
|
+ for(CTradeableItem *t : items[1])
|
|
|
+ sacrificedUnits[t->serial] = hero->getStackCount(SlotID(t->serial));
|
|
|
+
|
|
|
+ sacrificedUnits[items[1].front()->serial]--;
|
|
|
+
|
|
|
+ for(CTradeableItem *t : items[0])
|
|
|
+ {
|
|
|
+ updateRight(t);
|
|
|
+ if(t->type == CREATURE)
|
|
|
+ movedAnything = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ deal->block(!movedAnything);
|
|
|
+ calcTotalExp();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ for(auto i = hero->artifactsWorn.cbegin(); i != hero->artifactsWorn.cend(); i++)
|
|
|
+ {
|
|
|
+ if(i->second.artifact->artType->id != ArtifactID::ART_LOCK) //ignore locks from assembled artifacts
|
|
|
+ moveFromSlotToAltar(i->first, nullptr, i->second.artifact);
|
|
|
+ }
|
|
|
+
|
|
|
+ SacrificeBackpack();
|
|
|
+ }
|
|
|
+ redraw();
|
|
|
+}
|
|
|
+
|
|
|
+void CAltarWindow::selectionChanged(bool side)
|
|
|
+{
|
|
|
+ if(mode != EMarketMode::CREATURE_EXP)
|
|
|
+ return;
|
|
|
+
|
|
|
+ CTradeableItem *&selected = side ? hLeft : hRight;
|
|
|
+ CTradeableItem *&theOther = side ? hRight : hLeft;
|
|
|
+
|
|
|
+ theOther = *std::find_if(items[!side].begin(), items[!side].end(), [&](const CTradeableItem * item)
|
|
|
+ {
|
|
|
+ return item->serial == selected->serial;
|
|
|
+ });
|
|
|
+
|
|
|
+ int stackCount = 0;
|
|
|
+ for (int i = 0; i < GameConstants::ARMY_SIZE; i++)
|
|
|
+ if(hero->getStackCount(SlotID(i)) > sacrificedUnits[i])
|
|
|
+ stackCount++;
|
|
|
+
|
|
|
+ slider->setAmount(hero->getStackCount(SlotID(hLeft->serial)) - (stackCount == 1));
|
|
|
+ slider->block(!slider->amount);
|
|
|
+ slider->value = sacrificedUnits[hLeft->serial];
|
|
|
+ max->block(!slider->amount);
|
|
|
+ readyToTrade = true;
|
|
|
+ redraw();
|
|
|
+}
|
|
|
+
|
|
|
+void CAltarWindow::mimicCres()
|
|
|
+{
|
|
|
+ std::vector<Rect> positions;
|
|
|
+ getPositionsFor(positions, false, CREATURE);
|
|
|
+
|
|
|
+ for(CTradeableItem *t : items[1])
|
|
|
+ {
|
|
|
+ auto hlp = new CTradeableItem(positions[t->serial].topLeft(), CREATURE_PLACEHOLDER, t->id, false, t->serial);
|
|
|
+ hlp->pos = positions[t->serial] + this->pos.topLeft();
|
|
|
+ items[0].push_back(hlp);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+Point CAltarWindow::selectionOffset(bool Left) const
|
|
|
+{
|
|
|
+ if(Left)
|
|
|
+ return Point(150, 421);
|
|
|
+ else
|
|
|
+ return Point(396, 421);
|
|
|
+}
|
|
|
+
|
|
|
+std::string CAltarWindow::selectionSubtitle(bool Left) const
|
|
|
+{
|
|
|
+ if(Left && slider && hLeft)
|
|
|
+ return boost::lexical_cast<std::string>(slider->value);
|
|
|
+ else if(!Left && hRight)
|
|
|
+ return hRight->subtitle;
|
|
|
+ else
|
|
|
+ return "";
|
|
|
+}
|
|
|
+
|
|
|
+void CAltarWindow::artifactsChanged(bool left)
|
|
|
+{
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+void CAltarWindow::garrisonChanged()
|
|
|
+{
|
|
|
+ if(mode != EMarketMode::CREATURE_EXP)
|
|
|
+ return;
|
|
|
+
|
|
|
+ std::set<CTradeableItem *> empty;
|
|
|
+ getEmptySlots(empty);
|
|
|
+
|
|
|
+ for(CTradeableItem *t : empty)
|
|
|
+ {
|
|
|
+ removeItem(*std::find_if(items[0].begin(), items[0].end(), [&](const CTradeableItem * item)
|
|
|
+ {
|
|
|
+ return item->serial == t->serial;
|
|
|
+ }));
|
|
|
+ }
|
|
|
+
|
|
|
+ initSubs(true);
|
|
|
+ getExpValues();
|
|
|
+}
|
|
|
+
|
|
|
+void CAltarWindow::getExpValues()
|
|
|
+{
|
|
|
+ int dump;
|
|
|
+ for(CTradeableItem *t : items[1])
|
|
|
+ if(t->id >= 0)
|
|
|
+ market->getOffer(t->id, 0, dump, expPerUnit[t->serial], EMarketMode::CREATURE_EXP);
|
|
|
+}
|
|
|
+
|
|
|
+void CAltarWindow::calcTotalExp()
|
|
|
+{
|
|
|
+ int val = 0;
|
|
|
+ if(mode == EMarketMode::CREATURE_EXP)
|
|
|
+ {
|
|
|
+ for (int i = 0; i < sacrificedUnits.size(); i++)
|
|
|
+ {
|
|
|
+ val += expPerUnit[i] * sacrificedUnits[i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ for(const CArtifactInstance *art : arts->artifactsOnAltar)
|
|
|
+ {
|
|
|
+ int dmp, valOfArt;
|
|
|
+ market->getOffer(art->artType->id, 0, dmp, valOfArt, mode);
|
|
|
+ val += valOfArt; //WAS val += valOfArt * arts->artifactsOnAltar.count(*i);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ val = hero->calculateXp(val);
|
|
|
+ expOnAltar->setText(boost::lexical_cast<std::string>(val));
|
|
|
+}
|
|
|
+
|
|
|
+void CAltarWindow::setExpToLevel()
|
|
|
+{
|
|
|
+ expToLevel->setText(boost::lexical_cast<std::string>(CGI->heroh->reqExp(CGI->heroh->level(hero->exp)+1) - hero->exp));
|
|
|
+}
|
|
|
+
|
|
|
+void CAltarWindow::blockTrade()
|
|
|
+{
|
|
|
+ hLeft = hRight = nullptr;
|
|
|
+ readyToTrade = false;
|
|
|
+ if(slider)
|
|
|
+ {
|
|
|
+ slider->block(true);
|
|
|
+ max->block(true);
|
|
|
+ }
|
|
|
+ deal->block(true);
|
|
|
+}
|
|
|
+
|
|
|
+void CAltarWindow::updateRight(CTradeableItem *toUpdate)
|
|
|
+{
|
|
|
+ int val = sacrificedUnits[toUpdate->serial];
|
|
|
+ toUpdate->setType(val ? CREATURE : CREATURE_PLACEHOLDER);
|
|
|
+ toUpdate->subtitle = val ? boost::str(boost::format(CGI->generaltexth->allTexts[122]) % boost::lexical_cast<std::string>(val * expPerUnit[toUpdate->serial])) : ""; //%s exp
|
|
|
+}
|
|
|
+
|
|
|
+int CAltarWindow::firstFreeSlot()
|
|
|
+{
|
|
|
+ int ret = -1;
|
|
|
+ while(items[0][++ret]->id >= 0 && ret + 1 < items[0].size());
|
|
|
+ return ret < items[0].size() ? ret : -1;
|
|
|
+}
|
|
|
+
|
|
|
+void CAltarWindow::SacrificeBackpack()
|
|
|
+{
|
|
|
+ std::multiset<const CArtifactInstance *> toOmmit = arts->artifactsOnAltar;
|
|
|
+
|
|
|
+ for (auto & elem : hero->artifactsInBackpack)
|
|
|
+ {
|
|
|
+
|
|
|
+ if(vstd::contains(toOmmit, elem.artifact))
|
|
|
+ {
|
|
|
+ toOmmit -= elem.artifact;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ putOnAltar(nullptr, elem.artifact);
|
|
|
+ }
|
|
|
+
|
|
|
+ arts->scrollBackpack(0);
|
|
|
+ calcTotalExp();
|
|
|
+}
|
|
|
+
|
|
|
+void CAltarWindow::artifactPicked()
|
|
|
+{
|
|
|
+ redraw();
|
|
|
+}
|
|
|
+
|
|
|
+void CAltarWindow::showAll(SDL_Surface * to)
|
|
|
+{
|
|
|
+ CTradeWindow::showAll(to);
|
|
|
+ if(mode == EMarketMode::ARTIFACT_EXP && arts && arts->commonInfo->src.art)
|
|
|
+ {
|
|
|
+ artIcon->setFrame(arts->commonInfo->src.art->artType->iconIndex);
|
|
|
+ artIcon->showAll(to);
|
|
|
+
|
|
|
+ int dmp, val;
|
|
|
+ market->getOffer(arts->commonInfo->src.art->artType->id, 0, dmp, val, EMarketMode::ARTIFACT_EXP);
|
|
|
+ printAtMiddleLoc(boost::lexical_cast<std::string>(val), 304, 498, FONT_SMALL, Colors::WHITE, to);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+bool CAltarWindow::putOnAltar(CTradeableItem* altarSlot, const CArtifactInstance *art)
|
|
|
+{
|
|
|
+ int artID = art->artType->id;
|
|
|
+ if(artID != 1 && artID < 7) //special art
|
|
|
+ {
|
|
|
+ logGlobal->warnStream() << "Cannot put special artifact on altar!";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!altarSlot)
|
|
|
+ {
|
|
|
+ int slotIndex = firstFreeSlot();
|
|
|
+ if(slotIndex < 0)
|
|
|
+ {
|
|
|
+ logGlobal->warnStream() << "No free slots on altar!";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ altarSlot = items[0][slotIndex];
|
|
|
+ }
|
|
|
+
|
|
|
+ int dmp, val;
|
|
|
+ market->getOffer(artID, 0, dmp, val, EMarketMode::ARTIFACT_EXP);
|
|
|
+
|
|
|
+ arts->artifactsOnAltar.insert(art);
|
|
|
+ altarSlot->setArtInstance(art);
|
|
|
+ altarSlot->subtitle = boost::lexical_cast<std::string>(val);
|
|
|
+
|
|
|
+ deal->block(false);
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+void CAltarWindow::moveFromSlotToAltar(ArtifactPosition slotID, CTradeableItem* altarSlot, const CArtifactInstance *art)
|
|
|
+{
|
|
|
+ auto freeBackpackSlot = ArtifactPosition(hero->artifactsInBackpack.size() + GameConstants::BACKPACK_START);
|
|
|
+ if(arts->commonInfo->src.art)
|
|
|
+ {
|
|
|
+ arts->commonInfo->dst.slotID = freeBackpackSlot;
|
|
|
+ arts->commonInfo->dst.AOH = arts;
|
|
|
+ }
|
|
|
+
|
|
|
+ if(putOnAltar(altarSlot, art))
|
|
|
+ {
|
|
|
+ if(slotID < GameConstants::BACKPACK_START)
|
|
|
+ LOCPLINT->cb->swapArtifacts(ArtifactLocation(hero, slotID), ArtifactLocation(hero, freeBackpackSlot));
|
|
|
+ else
|
|
|
+ {
|
|
|
+ arts->commonInfo->src.clear();
|
|
|
+ arts->commonInfo->dst.clear();
|
|
|
+ CCS->curh->dragAndDropCursor(nullptr);
|
|
|
+ arts->unmarkSlots(false);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|