2023-04-23 14:10:35 +02:00
|
|
|
/*
|
|
|
|
* CWindowWithArtifacts.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
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
#include "StdInc.h"
|
|
|
|
#include "CWindowWithArtifacts.h"
|
|
|
|
|
2024-05-19 12:53:56 +02:00
|
|
|
#include "CHeroWindow.h"
|
|
|
|
#include "CSpellWindow.h"
|
|
|
|
#include "CExchangeWindow.h"
|
|
|
|
#include "CHeroBackpackWindow.h"
|
|
|
|
|
2023-04-23 14:10:35 +02:00
|
|
|
#include "../gui/CGuiHandler.h"
|
|
|
|
#include "../gui/CursorHandler.h"
|
2023-05-16 14:10:26 +02:00
|
|
|
#include "../gui/WindowHandler.h"
|
2023-04-23 14:10:35 +02:00
|
|
|
|
2023-09-25 22:58:59 +02:00
|
|
|
#include "../render/IRenderHandler.h"
|
|
|
|
#include "../render/CAnimation.h"
|
|
|
|
#include "../render/IImage.h"
|
|
|
|
|
2024-04-23 15:21:45 +02:00
|
|
|
#include "../widgets/CComponent.h"
|
2023-04-23 14:10:35 +02:00
|
|
|
|
|
|
|
#include "../CPlayerInterface.h"
|
|
|
|
#include "../CGameInfo.h"
|
|
|
|
|
2023-05-17 15:52:16 +02:00
|
|
|
#include "../../lib/ArtifactUtils.h"
|
2024-07-20 14:55:17 +02:00
|
|
|
#include "../../lib/texts/CGeneralTextHandler.h"
|
2024-05-08 13:16:16 +02:00
|
|
|
#include "../../lib/mapObjects/CGHeroInstance.h"
|
2023-10-23 15:38:05 +02:00
|
|
|
#include "../../lib/networkPacks/ArtifactLocation.h"
|
2023-09-25 23:02:16 +02:00
|
|
|
#include "../../lib/CConfigHandler.h"
|
2023-04-23 14:10:35 +02:00
|
|
|
|
2024-01-27 23:48:11 +02:00
|
|
|
#include "../../CCallback.h"
|
|
|
|
|
2024-05-20 11:47:25 +02:00
|
|
|
CWindowWithArtifacts::CWindowWithArtifacts(const std::vector<CArtifactsOfHeroPtr> * artSets)
|
2024-04-16 16:45:31 +02:00
|
|
|
{
|
|
|
|
if(artSets)
|
|
|
|
this->artSets.insert(this->artSets.end(), artSets->begin(), artSets->end());
|
|
|
|
}
|
|
|
|
|
2024-05-20 11:47:25 +02:00
|
|
|
void CWindowWithArtifacts::addSet(const std::shared_ptr<CArtifactsOfHeroBase> & newArtSet)
|
2023-09-18 21:58:08 +02:00
|
|
|
{
|
2024-04-23 19:26:21 +02:00
|
|
|
artSets.emplace_back(newArtSet);
|
2023-09-18 21:58:08 +02:00
|
|
|
}
|
|
|
|
|
2024-05-20 14:31:07 +02:00
|
|
|
const CGHeroInstance * CWindowWithArtifacts::getHeroPickedArtifact() const
|
2023-04-23 14:10:35 +02:00
|
|
|
{
|
2024-04-30 11:39:20 +02:00
|
|
|
const CGHeroInstance * hero = nullptr;
|
|
|
|
|
2024-05-20 14:31:07 +02:00
|
|
|
for(const auto & artSet : artSets)
|
2024-05-20 11:47:25 +02:00
|
|
|
if(const auto pickedArt = artSet->getHero()->getArt(ArtifactPosition::TRANSITION_POS))
|
|
|
|
{
|
|
|
|
hero = artSet->getHero();
|
|
|
|
break;
|
|
|
|
}
|
2024-04-30 11:39:20 +02:00
|
|
|
return hero;
|
2023-04-23 14:10:35 +02:00
|
|
|
}
|
|
|
|
|
2024-05-20 14:31:07 +02:00
|
|
|
const CArtifactInstance * CWindowWithArtifacts::getPickedArtifact() const
|
2023-04-23 14:10:35 +02:00
|
|
|
{
|
2024-05-20 14:31:07 +02:00
|
|
|
for(const auto & artSet : artSets)
|
2024-05-20 11:47:25 +02:00
|
|
|
if(const auto pickedArt = artSet->getHero()->getArt(ArtifactPosition::TRANSITION_POS))
|
|
|
|
{
|
2024-09-06 16:59:40 +02:00
|
|
|
return pickedArt;
|
2024-05-20 11:47:25 +02:00
|
|
|
}
|
2024-09-06 16:59:40 +02:00
|
|
|
return nullptr;
|
2023-04-23 14:10:35 +02:00
|
|
|
}
|
|
|
|
|
2024-05-20 11:47:25 +02:00
|
|
|
void CWindowWithArtifacts::clickPressedOnArtPlace(const CGHeroInstance * hero, const ArtifactPosition & slot,
|
2024-11-04 13:45:44 +02:00
|
|
|
bool allowExchange, bool altarTrading, bool closeWindow, const Point & cursorPosition)
|
2023-04-23 14:10:35 +02:00
|
|
|
{
|
2024-05-01 20:18:36 +02:00
|
|
|
if(!LOCPLINT->makingTurn)
|
2024-04-28 14:58:54 +02:00
|
|
|
return;
|
2024-05-20 11:47:25 +02:00
|
|
|
if(hero == nullptr)
|
|
|
|
return;
|
2024-04-28 14:58:54 +02:00
|
|
|
|
2024-05-02 00:49:17 +02:00
|
|
|
if(const auto heroArtOwner = getHeroPickedArtifact())
|
|
|
|
{
|
2024-05-20 11:47:25 +02:00
|
|
|
if(allowExchange || hero->id == heroArtOwner->id)
|
|
|
|
putPickedArtifact(*hero, slot);
|
2024-05-02 00:49:17 +02:00
|
|
|
}
|
2024-09-24 15:35:28 +02:00
|
|
|
else if(GH.isKeyboardShiftDown())
|
|
|
|
{
|
2024-11-04 13:45:44 +02:00
|
|
|
showQuickBackpackWindow(hero, slot, cursorPosition);
|
2024-09-24 15:35:28 +02:00
|
|
|
}
|
2024-05-20 11:47:25 +02:00
|
|
|
else if(auto art = hero->getArt(slot))
|
2024-05-02 00:49:17 +02:00
|
|
|
{
|
2024-05-20 11:47:25 +02:00
|
|
|
if(hero->getOwner() == LOCPLINT->playerID)
|
2023-04-23 14:10:35 +02:00
|
|
|
{
|
2024-05-20 11:47:25 +02:00
|
|
|
if(checkSpecialArts(*art, *hero, altarTrading))
|
|
|
|
onClickPressedCommonArtifact(*hero, slot, closeWindow);
|
2024-05-02 00:49:17 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for(const auto & artSlot : ArtifactUtils::unmovableSlots())
|
|
|
|
if(slot == artSlot)
|
2023-04-23 14:10:35 +02:00
|
|
|
{
|
2024-05-02 00:49:17 +02:00
|
|
|
LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[21]);
|
|
|
|
break;
|
2023-04-23 14:10:35 +02:00
|
|
|
}
|
2024-05-02 00:49:17 +02:00
|
|
|
}
|
|
|
|
}
|
2023-04-23 14:10:35 +02:00
|
|
|
}
|
|
|
|
|
2024-05-08 13:16:16 +02:00
|
|
|
void CWindowWithArtifacts::swapArtifactAndClose(const CArtifactsOfHeroBase & artsInst, const ArtifactPosition & slot,
|
2024-05-20 14:31:07 +02:00
|
|
|
const ArtifactLocation & dstLoc)
|
2023-04-23 14:10:35 +02:00
|
|
|
{
|
2024-05-08 13:16:16 +02:00
|
|
|
LOCPLINT->cb->swapArtifacts(ArtifactLocation(artsInst.getHero()->id, slot), dstLoc);
|
2024-05-20 14:31:07 +02:00
|
|
|
close();
|
2024-05-02 00:49:17 +02:00
|
|
|
}
|
2023-04-23 14:10:35 +02:00
|
|
|
|
2024-05-08 13:16:16 +02:00
|
|
|
void CWindowWithArtifacts::showArtifactAssembling(const CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace,
|
|
|
|
const Point & cursorPosition) const
|
2024-05-02 00:49:17 +02:00
|
|
|
{
|
2024-05-08 13:16:16 +02:00
|
|
|
if(artsInst.getArt(artPlace.slot))
|
2024-05-02 00:49:17 +02:00
|
|
|
{
|
2024-07-15 23:03:06 +02:00
|
|
|
if(LOCPLINT->artifactController->askToDisassemble(artsInst.getHero(), artPlace.slot))
|
2024-05-02 00:49:17 +02:00
|
|
|
return;
|
2024-07-15 23:03:06 +02:00
|
|
|
if(LOCPLINT->artifactController->askToAssemble(artsInst.getHero(), artPlace.slot))
|
2024-05-02 00:49:17 +02:00
|
|
|
return;
|
|
|
|
if(artPlace.text.size())
|
|
|
|
artPlace.LRClickableAreaWTextComp::showPopupWindow(cursorPosition);
|
|
|
|
}
|
|
|
|
}
|
2023-04-23 14:10:35 +02:00
|
|
|
|
2024-05-20 11:47:25 +02:00
|
|
|
void CWindowWithArtifacts::showQuickBackpackWindow(const CGHeroInstance * hero, const ArtifactPosition & slot,
|
2024-05-08 13:16:16 +02:00
|
|
|
const Point & cursorPosition) const
|
2023-12-17 16:30:19 +02:00
|
|
|
{
|
2024-05-02 00:49:17 +02:00
|
|
|
if(!settings["general"]["enableUiEnhancements"].Bool())
|
2023-12-17 16:30:19 +02:00
|
|
|
return;
|
|
|
|
|
2024-11-04 13:45:44 +02:00
|
|
|
if(!ArtifactUtils::isSlotEquipment(slot))
|
|
|
|
return;
|
|
|
|
|
2024-05-20 11:47:25 +02:00
|
|
|
GH.windows().createAndPushWindow<CHeroQuickBackpackWindow>(hero, slot);
|
2024-05-02 00:49:17 +02:00
|
|
|
auto backpackWindow = GH.windows().topWindow<CHeroQuickBackpackWindow>();
|
|
|
|
backpackWindow->moveTo(cursorPosition - Point(1, 1));
|
|
|
|
backpackWindow->fitToScreen(15);
|
2023-12-17 16:30:19 +02:00
|
|
|
}
|
|
|
|
|
2024-04-23 15:21:45 +02:00
|
|
|
void CWindowWithArtifacts::activate()
|
|
|
|
{
|
|
|
|
if(const auto art = getPickedArtifact())
|
2024-05-08 13:16:16 +02:00
|
|
|
{
|
|
|
|
markPossibleSlots();
|
2024-04-23 15:21:45 +02:00
|
|
|
setCursorAnimation(*art);
|
2024-05-08 13:16:16 +02:00
|
|
|
}
|
2024-04-23 15:21:45 +02:00
|
|
|
CWindowObject::activate();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWindowWithArtifacts::deactivate()
|
|
|
|
{
|
|
|
|
CCS->curh->dragAndDropCursor(nullptr);
|
|
|
|
CWindowObject::deactivate();
|
|
|
|
}
|
|
|
|
|
2024-05-20 11:47:25 +02:00
|
|
|
void CWindowWithArtifacts::enableKeyboardShortcuts() const
|
2024-04-19 16:14:41 +02:00
|
|
|
{
|
2024-05-01 20:18:36 +02:00
|
|
|
for(auto & artSet : artSets)
|
2024-05-20 11:47:25 +02:00
|
|
|
artSet->enableKeyboardShortcuts();
|
2024-04-19 16:14:41 +02:00
|
|
|
}
|
|
|
|
|
2024-06-22 18:29:39 +02:00
|
|
|
void CWindowWithArtifacts::update()
|
2023-04-23 14:10:35 +02:00
|
|
|
{
|
2024-05-20 14:31:07 +02:00
|
|
|
for(const auto & artSet : artSets)
|
2024-06-22 18:29:39 +02:00
|
|
|
{
|
|
|
|
artSet->updateWornSlots();
|
|
|
|
artSet->updateBackpackSlots();
|
|
|
|
|
2024-05-20 11:47:25 +02:00
|
|
|
if(const auto pickedArtInst = getPickedArtifact())
|
|
|
|
{
|
|
|
|
markPossibleSlots();
|
|
|
|
setCursorAnimation(*pickedArtInst);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
artSet->unmarkSlots();
|
|
|
|
CCS->curh->dragAndDropCursor(nullptr);
|
|
|
|
}
|
2023-04-23 14:10:35 +02:00
|
|
|
|
2024-05-20 11:47:25 +02:00
|
|
|
// Make sure the status bar is updated so it does not display old text
|
|
|
|
if(auto artPlace = artSet->getArtPlace(GH.getCursorPosition()))
|
|
|
|
artPlace->hover(true);
|
|
|
|
}
|
2024-06-23 22:48:19 +02:00
|
|
|
redraw();
|
2023-04-23 14:10:35 +02:00
|
|
|
}
|
|
|
|
|
2024-05-20 14:31:07 +02:00
|
|
|
void CWindowWithArtifacts::markPossibleSlots() const
|
2023-09-03 20:41:00 +02:00
|
|
|
{
|
|
|
|
if(const auto pickedArtInst = getPickedArtifact())
|
|
|
|
{
|
2024-05-20 14:31:07 +02:00
|
|
|
for(const auto & artSet : artSets)
|
2023-09-03 20:41:00 +02:00
|
|
|
{
|
2024-05-20 14:31:07 +02:00
|
|
|
const auto hero = artSet->getHero();
|
|
|
|
if(hero == nullptr || !artSet->isActive())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if(getHeroPickedArtifact() == hero || !std::dynamic_pointer_cast<CArtifactsOfHeroKingdom>(artSet))
|
2024-10-12 10:41:59 +02:00
|
|
|
artSet->markPossibleSlots(pickedArtInst->getType(), hero->tempOwner == LOCPLINT->playerID);
|
2024-05-20 14:31:07 +02:00
|
|
|
}
|
2023-09-03 20:41:00 +02:00
|
|
|
}
|
|
|
|
}
|
2024-01-27 23:48:11 +02:00
|
|
|
|
2024-05-02 00:49:17 +02:00
|
|
|
bool CWindowWithArtifacts::checkSpecialArts(const CArtifactInstance & artInst, const CGHeroInstance & hero, bool isTrade) const
|
2024-01-27 23:48:11 +02:00
|
|
|
{
|
|
|
|
const auto artId = artInst.getTypeId();
|
|
|
|
|
|
|
|
if(artId == ArtifactID::SPELLBOOK)
|
|
|
|
{
|
2024-05-02 00:49:17 +02:00
|
|
|
GH.windows().createAndPushWindow<CSpellWindow>(&hero, LOCPLINT, LOCPLINT->battleInt.get());
|
2024-01-27 23:48:11 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if(artId == ArtifactID::CATAPULT)
|
|
|
|
{
|
|
|
|
// The Catapult must be equipped
|
|
|
|
LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[312],
|
|
|
|
std::vector<std::shared_ptr<CComponent>>(1, std::make_shared<CComponent>(ComponentType::ARTIFACT, ArtifactID(ArtifactID::CATAPULT))));
|
|
|
|
return false;
|
|
|
|
}
|
2024-10-12 10:41:59 +02:00
|
|
|
if(isTrade && !artInst.getType()->isTradable())
|
2024-01-27 23:48:11 +02:00
|
|
|
{
|
2024-04-23 19:26:21 +02:00
|
|
|
LOCPLINT->showInfoDialog(CGI->generaltexth->allTexts[21],
|
|
|
|
std::vector<std::shared_ptr<CComponent>>(1, std::make_shared<CComponent>(ComponentType::ARTIFACT, artId)));
|
|
|
|
return false;
|
2024-01-27 23:48:11 +02:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2024-04-16 16:45:31 +02:00
|
|
|
|
2024-05-20 14:31:07 +02:00
|
|
|
void CWindowWithArtifacts::setCursorAnimation(const CArtifactInstance & artInst) const
|
2024-04-16 16:45:31 +02:00
|
|
|
{
|
|
|
|
if(artInst.isScroll() && settings["general"]["enableUiEnhancements"].Bool())
|
|
|
|
{
|
|
|
|
assert(artInst.getScrollSpellID().num >= 0);
|
2024-06-08 09:35:13 +02:00
|
|
|
auto image = GH.renderHandler().loadImage(AnimationPath::builtin("spellscr"), artInst.getScrollSpellID().num, 0, EImageBlitMode::COLORKEY);
|
2024-07-25 20:22:27 +02:00
|
|
|
image->scaleTo(Point(44,34));
|
2024-06-04 13:46:45 +02:00
|
|
|
|
|
|
|
CCS->curh->dragAndDropCursor(image);
|
2024-04-16 16:45:31 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-10-12 10:41:59 +02:00
|
|
|
CCS->curh->dragAndDropCursor(AnimationPath::builtin("artifact"), artInst.getType()->getIconIndex());
|
2024-04-16 16:45:31 +02:00
|
|
|
}
|
|
|
|
}
|
2024-05-02 00:49:17 +02:00
|
|
|
|
2024-05-20 14:31:07 +02:00
|
|
|
void CWindowWithArtifacts::putPickedArtifact(const CGHeroInstance & curHero, const ArtifactPosition & targetSlot) const
|
2024-05-02 00:49:17 +02:00
|
|
|
{
|
|
|
|
const auto heroArtOwner = getHeroPickedArtifact();
|
|
|
|
const auto pickedArt = getPickedArtifact();
|
|
|
|
auto srcLoc = ArtifactLocation(heroArtOwner->id, ArtifactPosition::TRANSITION_POS);
|
|
|
|
auto dstLoc = ArtifactLocation(curHero.id, targetSlot);
|
|
|
|
|
|
|
|
if(ArtifactUtils::isSlotBackpack(dstLoc.slot))
|
|
|
|
{
|
2024-10-12 10:41:59 +02:00
|
|
|
if(pickedArt->getType()->isBig())
|
2024-05-02 00:49:17 +02:00
|
|
|
{
|
|
|
|
// War machines cannot go to backpack
|
2024-10-12 10:41:59 +02:00
|
|
|
LOCPLINT->showInfoDialog(boost::str(boost::format(CGI->generaltexth->allTexts[153]) % pickedArt->getType()->getNameTranslated()));
|
2024-05-02 00:49:17 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(ArtifactUtils::isBackpackFreeSlots(heroArtOwner))
|
|
|
|
LOCPLINT->cb->swapArtifacts(srcLoc, dstLoc);
|
|
|
|
else
|
|
|
|
LOCPLINT->showInfoDialog(CGI->generaltexth->translate("core.genrltxt.152"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Check if artifact transfer is possible
|
|
|
|
else if(pickedArt->canBePutAt(&curHero, dstLoc.slot, true) && (!curHero.getArt(targetSlot) || curHero.tempOwner == LOCPLINT->playerID))
|
|
|
|
{
|
|
|
|
LOCPLINT->cb->swapArtifacts(srcLoc, dstLoc);
|
|
|
|
}
|
|
|
|
}
|
2024-05-08 13:16:16 +02:00
|
|
|
|
|
|
|
void CWindowWithArtifacts::onClickPressedCommonArtifact(const CGHeroInstance & curHero, const ArtifactPosition & slot, bool closeWindow)
|
|
|
|
{
|
|
|
|
assert(curHero.getArt(slot));
|
|
|
|
auto srcLoc = ArtifactLocation(curHero.id, slot);
|
|
|
|
auto dstLoc = ArtifactLocation(curHero.id, ArtifactPosition::TRANSITION_POS);
|
|
|
|
|
|
|
|
if(GH.isKeyboardCmdDown())
|
|
|
|
{
|
2024-05-20 14:31:07 +02:00
|
|
|
for(const auto & anotherSet : artSets)
|
2024-05-08 13:16:16 +02:00
|
|
|
{
|
2024-05-20 14:31:07 +02:00
|
|
|
if(std::dynamic_pointer_cast<CArtifactsOfHeroMain>(anotherSet) && curHero.id != anotherSet->getHero()->id)
|
2024-05-08 13:16:16 +02:00
|
|
|
{
|
2024-05-20 14:31:07 +02:00
|
|
|
dstLoc.slot = ArtifactPosition::FIRST_AVAILABLE;
|
|
|
|
dstLoc.artHolder = anotherSet->getHero()->id;
|
|
|
|
break;
|
2024-05-08 13:16:16 +02:00
|
|
|
}
|
2024-05-20 11:47:25 +02:00
|
|
|
if(const auto heroSetAltar = std::dynamic_pointer_cast<CArtifactsOfHeroAltar>(anotherSet))
|
2024-05-08 13:16:16 +02:00
|
|
|
{
|
|
|
|
dstLoc.slot = ArtifactPosition::FIRST_AVAILABLE;
|
2024-05-20 11:47:25 +02:00
|
|
|
dstLoc.artHolder = heroSetAltar->altarId;
|
2024-05-08 13:16:16 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(GH.isKeyboardAltDown())
|
|
|
|
{
|
|
|
|
const auto artId = curHero.getArt(slot)->getTypeId();
|
|
|
|
if(ArtifactUtils::isSlotEquipment(slot))
|
|
|
|
dstLoc.slot = ArtifactUtils::getArtBackpackPosition(&curHero, artId);
|
|
|
|
else if(ArtifactUtils::isSlotBackpack(slot))
|
|
|
|
dstLoc.slot = ArtifactUtils::getArtEquippedPosition(&curHero, artId);
|
|
|
|
}
|
2024-05-20 14:31:07 +02:00
|
|
|
else if(closeWindow)
|
2024-05-08 13:16:16 +02:00
|
|
|
{
|
2024-05-20 14:31:07 +02:00
|
|
|
close();
|
2024-05-08 13:16:16 +02:00
|
|
|
}
|
|
|
|
if(dstLoc.slot != ArtifactPosition::PRE_FIRST)
|
|
|
|
LOCPLINT->cb->swapArtifacts(srcLoc, dstLoc);
|
|
|
|
}
|