From 2ce73fd4e1405c069dd0efb23ffa3ffcd96ce987 Mon Sep 17 00:00:00 2001 From: Andrii Danylchenko Date: Thu, 11 Feb 2021 21:06:47 +0200 Subject: [PATCH] Army exchange implementation --- client/windows/GUIClasses.cpp | 139 ++++++++++++++++++++++++++-------- client/windows/GUIClasses.h | 15 ++++ lib/CGeneralTextHandler.cpp | 6 +- lib/CGeneralTextHandler.h | 2 +- 4 files changed, 127 insertions(+), 35 deletions(-) diff --git a/client/windows/GUIClasses.cpp b/client/windows/GUIClasses.cpp index b7896924a..f0ecd63d6 100644 --- a/client/windows/GUIClasses.cpp +++ b/client/windows/GUIClasses.cpp @@ -787,17 +787,94 @@ void CTavernWindow::HeroPortrait::hover(bool on) GH.statusbar->clear(); } -static const char *NEW_EXCHANGE_BG = "TRADE2X"; +static const std::string HD_MOD_PREFIX = "HDMOD"; +static const std::string HD_EXCHANGE_BG = HD_MOD_PREFIX + "/TRADEHD"; -static bool isNewExchangeLayout() +static bool isHdLayoutAvailable() { - return CResourceHandler::get()->existsResource(ResourceID(std::string("DATA/") + NEW_EXCHANGE_BG, EResType::IMAGE)); + return CResourceHandler::get()->existsResource(ResourceID(std::string("SPRITES/") + HD_EXCHANGE_BG, EResType::IMAGE)); +} + +CExchangeController::CExchangeController(ObjectInstanceID hero1, ObjectInstanceID hero2) + :left(LOCPLINT->cb->getHero(hero1)), right(LOCPLINT->cb->getHero(hero2)) +{ +} + +std::function CExchangeController::onMoveArmyToLeft() +{ + return [&]() { hdModQuickExchangeArmy(false); }; +} + +std::function CExchangeController::onMoveArmyToRight() +{ + return [&]() { hdModQuickExchangeArmy(true); }; +} + +std::function CExchangeController::onSwapArmy() +{ + return [&]() { + auto cb = LOCPLINT->cb; + + for(SlotID i = SlotID(0); i.validSlot(); i.advance(1)) + { + if(left->hasStackAtSlot(i) || right->hasStackAtSlot(i)) + cb->swapCreatures(left, right, SlotID(i), SlotID(i)); + } + }; +} + +void CExchangeController::hdModQuickExchangeArmy(bool leftToRight) +{ + auto source = leftToRight ? left : right; + auto target = leftToRight ? right : left; + auto cb = LOCPLINT->cb; + + boost::thread([=] + { + auto slots = source->Slots(); + std::vector> stacks(slots.begin(), slots.end()); + + std::sort(stacks.begin(), stacks.end(), [](const std::pair & a, const std::pair & b) + { + return a.second->type->level > b.second->type->level; + }); + + cb->waitTillRealize = true; + + for(auto pair : stacks) + { + SlotID i = pair.first; + + auto creature = source->getCreature(i); + SlotID targetSlot = target->getSlotFor(creature); + + if(targetSlot.validSlot()) + { + if(source->stacksCount() == 1 && source->needsLastStack()) + { + cb->splitStack( + source, + target, + i, + targetSlot, + target->getStackCount(targetSlot) + source->getStackCount(i) - 1); + } + else + { + cb->mergeOrSwapStacks(source, target, i, targetSlot); + } + } + } + + cb->waitTillRealize = false; + }); } CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2, QueryID queryID) - : CStatusbarWindow(PLAYER_COLORED | BORDERED, isNewExchangeLayout() ? NEW_EXCHANGE_BG : "TRADE2") + : CStatusbarWindow(PLAYER_COLORED | BORDERED, isHdLayoutAvailable() ? HD_EXCHANGE_BG : "TRADE2"), + controller(hero1, hero2) { - const bool newLayout = isNewExchangeLayout(); + const bool hdLayout = isHdLayoutAvailable(); OBJECT_CONSTRUCTION_CAPTURING(255-DISPOSE); @@ -821,7 +898,7 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2, for(int g = 0; g < 4; ++g) { - if (newLayout) + if (hdLayout) primSkillImages.push_back(std::make_shared(PSKIL32, g, Rect(389, 12 + 26 * g, 22, 22))); else primSkillImages.push_back(std::make_shared(PSKIL32, g, 0, 385, 19 + 36 * g)); @@ -834,19 +911,19 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2, herosWArt[leftRight] = std::make_shared(this, hero); for(int m=0; m(352 + (newLayout ? 96 : 93) * leftRight, (newLayout ? 22 : 35) + (newLayout ? 26 : 36) * m, FONT_SMALL, CENTER, Colors::WHITE)); + primSkillValues[leftRight].push_back(std::make_shared(352 + (hdLayout ? 96 : 93) * leftRight, (hdLayout ? 22 : 35) + (hdLayout ? 26 : 36) * m, FONT_SMALL, CENTER, Colors::WHITE)); for(int m=0; m < hero->secSkills.size(); ++m) - secSkillIcons[leftRight].push_back(std::make_shared(SECSK32, 0, 0, 32 + 36 * m + 454 * leftRight, newLayout ? 83 : 88)); + secSkillIcons[leftRight].push_back(std::make_shared(SECSK32, 0, 0, 32 + 36 * m + 454 * leftRight, hdLayout ? 83 : 88)); - specImages[leftRight] = std::make_shared("UN32", hero->type->imageIndex, 0, 67 + 490 * leftRight, newLayout ? 41 : 45); + specImages[leftRight] = std::make_shared("UN32", hero->type->imageIndex, 0, 67 + 490 * leftRight, hdLayout ? 41 : 45); - expImages[leftRight] = std::make_shared(PSKIL32, 4, 0, 103 + 490 * leftRight, newLayout ? 41 : 45); - expValues[leftRight] = std::make_shared(119 + 490 * leftRight, newLayout ? 66 : 71, FONT_SMALL, CENTER, Colors::WHITE); + expImages[leftRight] = std::make_shared(PSKIL32, 4, 0, 103 + 490 * leftRight, hdLayout ? 41 : 45); + expValues[leftRight] = std::make_shared(119 + 490 * leftRight, hdLayout ? 66 : 71, FONT_SMALL, CENTER, Colors::WHITE); - manaImages[leftRight] = std::make_shared(PSKIL32, 5, 0, 139 + 490 * leftRight, newLayout ? 41 : 45); - manaValues[leftRight] = std::make_shared(155 + 490 * leftRight, newLayout ? 66 : 71, FONT_SMALL, CENTER, Colors::WHITE); + manaImages[leftRight] = std::make_shared(PSKIL32, 5, 0, 139 + 490 * leftRight, hdLayout ? 41 : 45); + manaValues[leftRight] = std::make_shared(155 + 490 * leftRight, hdLayout ? 66 : 71, FONT_SMALL, CENTER, Colors::WHITE); } portraits[0] = std::make_shared("PortraitsLarge", heroInst[0]->portrait, 0, 257, 13); @@ -867,7 +944,7 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2, for(int g=0; g<4; ++g) { primSkillAreas.push_back(std::make_shared()); - if (newLayout) + if (hdLayout) primSkillAreas[g]->pos = genRect(22, 152, pos.x + 324, pos.y + 12 + 26 * g); else primSkillAreas[g]->pos = genRect(32, 140, pos.x + 329, pos.y + 19 + 36 * g); @@ -890,7 +967,7 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2, int skill = hero->secSkills[g].first, level = hero->secSkills[g].second; // <1, 3> secSkillAreas[b].push_back(std::make_shared()); - secSkillAreas[b][g]->pos = genRect(32, 32, pos.x + 32 + g*36 + b*454 , pos.y + newLayout ? 83 : 88); + secSkillAreas[b][g]->pos = genRect(32, 32, pos.x + 32 + g*36 + b*454 , pos.y + hdLayout ? 83 : 88); secSkillAreas[b][g]->baseType = 1; secSkillAreas[b][g]->type = skill; @@ -905,12 +982,12 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2, heroAreas[b] = std::make_shared(257 + 228*b, 13, hero); specialtyAreas[b] = std::make_shared(); - specialtyAreas[b]->pos = genRect(32, 32, pos.x + 69 + 490*b, pos.y + newLayout ? 41 : 45); + specialtyAreas[b]->pos = genRect(32, 32, pos.x + 69 + 490*b, pos.y + hdLayout ? 41 : 45); specialtyAreas[b]->hoverText = CGI->generaltexth->heroscrn[27]; specialtyAreas[b]->text = hero->type->specDescr; experienceAreas[b] = std::make_shared(); - experienceAreas[b]->pos = genRect(32, 32, pos.x + 105 + 490*b, pos.y + newLayout ? 41 : 45); + experienceAreas[b]->pos = genRect(32, 32, pos.x + 105 + 490*b, pos.y + hdLayout ? 41 : 45); experienceAreas[b]->hoverText = CGI->generaltexth->heroscrn[9]; experienceAreas[b]->text = CGI->generaltexth->allTexts[2]; boost::algorithm::replace_first(experienceAreas[b]->text, "%d", boost::lexical_cast(hero->level)); @@ -918,7 +995,7 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2, boost::algorithm::replace_first(experienceAreas[b]->text, "%d", boost::lexical_cast(hero->exp)); spellPointsAreas[b] = std::make_shared(); - spellPointsAreas[b]->pos = genRect(32, 32, pos.x + 141 + 490*b, pos.y + newLayout ? 41 : 45); + spellPointsAreas[b]->pos = genRect(32, 32, pos.x + 141 + 490*b, pos.y + hdLayout ? 41 : 45); spellPointsAreas[b]->hoverText = CGI->generaltexth->heroscrn[22]; spellPointsAreas[b]->text = CGI->generaltexth->allTexts[205]; boost::algorithm::replace_first(spellPointsAreas[b]->text, "%s", hero->name); @@ -933,28 +1010,28 @@ CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2, if(queryID.getNum() > 0) quit->addCallback([=](){ LOCPLINT->cb->selectionMade(0, queryID); }); - questlogButton[0] = std::make_shared(Point( 10, newLayout ? 39 : 44), "hsbtns4.def", CButton::tooltip(CGI->generaltexth->heroscrn[0]), std::bind(&CExchangeWindow::questlog, this, 0)); - questlogButton[1] = std::make_shared(Point(740, newLayout ? 39 : 44), "hsbtns4.def", CButton::tooltip(CGI->generaltexth->heroscrn[0]), std::bind(&CExchangeWindow::questlog, this, 1)); + questlogButton[0] = std::make_shared(Point( 10, hdLayout ? 39 : 44), "hsbtns4.def", CButton::tooltip(CGI->generaltexth->heroscrn[0]), std::bind(&CExchangeWindow::questlog, this, 0)); + questlogButton[1] = std::make_shared(Point(740, hdLayout ? 39 : 44), "hsbtns4.def", CButton::tooltip(CGI->generaltexth->heroscrn[0]), std::bind(&CExchangeWindow::questlog, this, 1)); Rect barRect(5, 578, 725, 18); statusbar = CGStatusBar::create(std::make_shared(*background, barRect, 5, 578, false)); //garrison interface - garr = std::make_shared(69, newLayout ? 122 : 131, 4, Point(418,0), heroInst[0], heroInst[1], true, true); + garr = std::make_shared(69, hdLayout ? 122 : 131, 4, Point(418,0), heroInst[0], heroInst[1], true, true); auto splitButtonCallback = [&](){ garr->splitClick(); }; - garr->addSplitBtn(std::make_shared( Point( 10, newLayout ? 122 : 132), "TSBTNS.DEF", CButton::tooltip(CGI->generaltexth->tcommands[3]), splitButtonCallback)); - garr->addSplitBtn(std::make_shared( Point(740, newLayout ? 122 : 132), "TSBTNS.DEF", CButton::tooltip(CGI->generaltexth->tcommands[3]), splitButtonCallback)); + garr->addSplitBtn(std::make_shared( Point( 10, hdLayout ? 122 : 132), "TSBTNS.DEF", CButton::tooltip(CGI->generaltexth->tcommands[3]), splitButtonCallback)); + garr->addSplitBtn(std::make_shared( Point(744, hdLayout ? 122 : 132), "TSBTNS.DEF", CButton::tooltip(CGI->generaltexth->tcommands[3]), splitButtonCallback)); - if (newLayout && (CGI->generaltexth->newCommands.size() >= 5)) + if (hdLayout && (CGI->generaltexth->hdModCommands.size() >= 5)) { - auto nothing = [](){}; - moveAllGarrButtonLeft = std::make_shared(Point(325, 121), "SWCMR.DEF", CButton::tooltip(CGI->generaltexth->newCommands[1]), nothing); - echangeGarrButton = std::make_shared(Point(377, 121), "SWXCH.DEF", CButton::tooltip(CGI->generaltexth->newCommands[2]), nothing); - moveAllGarrButtonRight = std::make_shared(Point(425, 121), "SWCML.DEF", CButton::tooltip(CGI->generaltexth->newCommands[1]), nothing); - moveArtifactsButtonLeft = std::make_shared(Point(325, 180), "SWAMR.DEF", CButton::tooltip(CGI->generaltexth->newCommands[3]), nothing); - echangeArtifactsButton = std::make_shared(Point(377, 180), "SWXCH.DEF", CButton::tooltip(CGI->generaltexth->newCommands[4]), nothing); - moveArtifactsButtonRight = std::make_shared(Point(425, 180), "SWAML.DEF", CButton::tooltip(CGI->generaltexth->newCommands[3]), nothing); + auto nothing = []() { logAi->error("test def"); }; + moveAllGarrButtonLeft = std::make_shared(Point(325, 118), HD_MOD_PREFIX + "/SWCMR.DEF", CButton::tooltip(CGI->generaltexth->hdModCommands[1]), controller.onMoveArmyToRight()); + echangeGarrButton = std::make_shared(Point(377, 118), HD_MOD_PREFIX + "/SWXCH.DEF", CButton::tooltip(CGI->generaltexth->hdModCommands[2]), controller.onSwapArmy()); + moveAllGarrButtonRight = std::make_shared(Point(425, 118), HD_MOD_PREFIX + "/SWCML.DEF", CButton::tooltip(CGI->generaltexth->hdModCommands[1]), controller.onMoveArmyToLeft()); + moveArtifactsButtonLeft = std::make_shared(Point(325, 154), HD_MOD_PREFIX + "/SWAMR.DEF", CButton::tooltip(CGI->generaltexth->hdModCommands[3]), nothing); + echangeArtifactsButton = std::make_shared(Point(377, 154), HD_MOD_PREFIX + "/SWXCH.DEF", CButton::tooltip(CGI->generaltexth->hdModCommands[4]), nothing); + moveArtifactsButtonRight = std::make_shared(Point(425, 154), HD_MOD_PREFIX + "/SWAML.DEF", CButton::tooltip(CGI->generaltexth->hdModCommands[3]), nothing); } updateWidgets(); diff --git a/client/windows/GUIClasses.h b/client/windows/GUIClasses.h index 1406b756a..bb724a961 100644 --- a/client/windows/GUIClasses.h +++ b/client/windows/GUIClasses.h @@ -280,6 +280,20 @@ public: void show(SDL_Surface * to) override; }; +class CExchangeController +{ +private: + const CGHeroInstance * left; + const CGHeroInstance * right; + +public: + CExchangeController(ObjectInstanceID hero1, ObjectInstanceID hero2); + void hdModQuickExchangeArmy(bool leftToRight); + std::function onMoveArmyToRight(); + std::function onSwapArmy(); + std::function onMoveArmyToLeft(); +}; + class CExchangeWindow : public CStatusbarWindow, public CGarrisonHolder, public CWindowWithArtifacts { std::array, 2> herosWArt; @@ -316,6 +330,7 @@ class CExchangeWindow : public CStatusbarWindow, public CGarrisonHolder, public std::shared_ptr moveArtifactsButtonLeft; std::shared_ptr echangeArtifactsButton; std::shared_ptr moveArtifactsButtonRight; + CExchangeController controller; public: std::array heroInst; diff --git a/lib/CGeneralTextHandler.cpp b/lib/CGeneralTextHandler.cpp index 6ae67f772..b0ced6b10 100644 --- a/lib/CGeneralTextHandler.cpp +++ b/lib/CGeneralTextHandler.cpp @@ -332,9 +332,9 @@ CGeneralTextHandler::CGeneralTextHandler() readToVector("DATA/TENTCOLR.TXT", tentColors); readToVector("DATA/SKILLLEV.TXT", levels); - static const char *NEW_COMMANDS = "DATA/XCOMMAND.TXT"; - if (CResourceHandler::get()->existsResource(ResourceID(NEW_COMMANDS, EResType::TEXT))) - readToVector(NEW_COMMANDS, newCommands); + static const char * HD_MOD_COMMANDS = "DATA/HDCOMMANDS.TXT"; + if (CResourceHandler::get()->existsResource(ResourceID(HD_MOD_COMMANDS, EResType::TEXT))) + readToVector(HD_MOD_COMMANDS, hdModCommands); localizedTexts = JsonNode(ResourceID("config/translate.json", EResType::TEXT)); diff --git a/lib/CGeneralTextHandler.h b/lib/CGeneralTextHandler.h index a5ca53c2e..39ca88e5c 100644 --- a/lib/CGeneralTextHandler.h +++ b/lib/CGeneralTextHandler.h @@ -110,7 +110,7 @@ public: std::vector tavernInfo; std::vector tavernRumors; - std::vector newCommands; // extra commands for HD mod + std::vector hdModCommands; std::vector> zelp; std::vector lossCondtions;