Pārlūkot izejas kodu

bulk move to altar

SoundSSGood 1 gadu atpakaļ
vecāks
revīzija
f66918ea14

+ 83 - 86
client/widgets/markets/CAltarArtifacts.cpp

@@ -12,7 +12,6 @@
 #include "CAltarArtifacts.h"
 
 #include "../../gui/CGuiHandler.h"
-#include "../../gui/CursorHandler.h"
 #include "../../widgets/Buttons.h"
 #include "../../widgets/TextControls.h"
 
@@ -51,8 +50,8 @@ CAltarArtifacts::CAltarArtifacts(const IMarket * market, const CGHeroInstance *
 		CGI->generaltexth->zelp[570], std::bind(&CAltarArtifacts::sacrificeBackpack, this));
 	sacrificeBackpackButton->block(hero->artifactsInBackpack.empty());
 
-	arts = std::make_shared<CArtifactsOfHeroAltar>(Point(-365, -11));
-	arts->setHero(hero);
+	heroArts = std::make_shared<CArtifactsOfHeroAltar>(Point(-365, -11));
+	heroArts->setHero(hero);
 
 	int slotNum = 0;
 	for(auto & altarSlotPos : posSlotsAltar)
@@ -70,32 +69,25 @@ CAltarArtifacts::CAltarArtifacts(const IMarket * market, const CGHeroInstance *
 
 TExpType CAltarArtifacts::calcExpAltarForHero()
 {
-	auto artifactsOfHero = std::dynamic_pointer_cast<CArtifactsOfHeroAltar>(arts);
 	TExpType expOnAltar(0);
-	for(const auto art : artifactsOfHero->artifactsOnAltar)
-	{
-		int dmp = 0;
-		int expOfArt = 0;
-		market->getOffer(art->getTypeId(), 0, dmp, expOfArt, EMarketMode::ARTIFACT_EXP);
-		expOnAltar += expOfArt;
-	}
-	auto resultExp = hero->calculateXp(expOnAltar);
-	expForHero->setText(std::to_string(resultExp));
-	return resultExp;
+	for(const auto & tradeSlot : tradeSlotsMap)
+		expOnAltar += calcExpCost(tradeSlot.first);
+	expForHero->setText(std::to_string(expOnAltar));
+	return expOnAltar;
 }
 
 void CAltarArtifacts::makeDeal()
 {
 	std::vector<TradeItemSell> positions;
-	for(const auto art : arts->artifactsOnAltar)
+	for(const auto art : tradeSlotsMap)
 	{
-		positions.push_back(hero->getSlotByInstance(art));
+		positions.push_back(hero->getSlotByInstance(art.first));
 	}
 	std::sort(positions.begin(), positions.end());
 	std::reverse(positions.begin(), positions.end());
 
 	LOCPLINT->cb->trade(market, EMarketMode::ARTIFACT_EXP, positions, std::vector<TradeItemBuy>(), std::vector<ui32>(), hero);
-	arts->artifactsOnAltar.clear();
+	heroArts->artifactsOnAltar.clear();
 
 	for(auto item : items[0])
 	{
@@ -108,37 +100,19 @@ void CAltarArtifacts::makeDeal()
 
 void CAltarArtifacts::sacrificeAll()
 {
-	std::vector<ConstTransitivePtr<CArtifactInstance>> artsForMove;
-	for(const auto & [slot, slotInfo] : arts->getHero()->artifactsWorn)
-	{
-		if(!slotInfo.locked && slotInfo.artifact->artType->isTradable())
-			artsForMove.emplace_back(slotInfo.artifact);
-	}
-	for(auto artInst : artsForMove)
-		moveArtToAltar(nullptr, artInst);
-	arts->updateWornSlots();
-	sacrificeBackpack();
+	LOCPLINT->cb->bulkMoveArtifacts(heroArts->getHero()->id, altarId, false, true, true);
 }
 
 void CAltarArtifacts::sacrificeBackpack()
 {
-	/*while (!arts->visibleArtSet.artifactsInBackpack.empty())
-	{
-		if(!putArtOnAltar(nullptr, arts->visibleArtSet.artifactsInBackpack[0].artifact))
-			break;
-	};*/
-	calcExpAltarForHero();
+	LOCPLINT->cb->bulkMoveArtifacts(heroArts->getHero()->id, altarId, false, false, true);
 }
 
 void CAltarArtifacts::setSelectedArtifact(const CArtifactInstance * art)
 {
 	if(art)
 	{
-		selectedArt->setArtifact(art);
-		int dmp = 0;
-		int exp = 0;
-		market->getOffer(art->getTypeId(), 0, dmp, exp, EMarketMode::ARTIFACT_EXP);
-		selectedCost->setText(std::to_string(hero->calculateXp(exp)));
+		selectedCost->setText(std::to_string(calcExpCost(art)));
 	}
 	else
 	{
@@ -147,75 +121,98 @@ void CAltarArtifacts::setSelectedArtifact(const CArtifactInstance * art)
 	}
 }
 
-void CAltarArtifacts::moveArtToAltar(std::shared_ptr<CTradeableItem> altarSlot, const CArtifactInstance * art)
+std::shared_ptr<CArtifactsOfHeroAltar> CAltarArtifacts::getAOHset() const
 {
-	if(putArtOnAltar(altarSlot, art))
-	{
-		CCS->curh->dragAndDropCursor(nullptr);
-		arts->unmarkSlots();
-	}
+	return heroArts;
 }
 
-std::shared_ptr<CArtifactsOfHeroAltar> CAltarArtifacts::getAOHset() const
+ObjectInstanceID CAltarArtifacts::getObjId() const
 {
-	return arts;
+	return altarId;
 }
 
-bool CAltarArtifacts::putArtOnAltar(std::shared_ptr<CTradeableItem> altarSlot, const CArtifactInstance * art)
+void CAltarArtifacts::updateSlots()
 {
-	if(!art->artType->isTradable())
+	assert(altarArtifacts->artifactsInBackpack.size() <= 22);
+	assert(tradeSlotsMap.size() <= 22);
+	
+	auto slotsToAdd = tradeSlotsMap;
+	for(auto & altarSlot : items[0])
 	{
-		logGlobal->warn("Cannot put special artifact on altar!");
-		return false;
+		if(altarSlot->id != -1)
+			if(tradeSlotsMap.find(altarSlot->getArtInstance()) == tradeSlotsMap.end())
+			{
+				altarSlot->setID(-1);
+				altarSlot->subtitle.clear();
+			}
+			else
+			{
+				slotsToAdd.erase(altarSlot->getArtInstance());
+			}
 	}
 
-	if(!altarSlot || altarSlot->id != -1)
+	for(auto & tradeSlot : slotsToAdd)
 	{
-		int slotIndex = -1;
-		while(items[0][++slotIndex]->id >= 0 && slotIndex + 1 < items[0].size());
-		slotIndex = items[0][slotIndex]->id == -1 ? slotIndex : -1;
-		if(slotIndex < 0)
+		assert(tradeSlot.second->id == -1);
+		assert(altarArtifacts->getSlotByInstance(tradeSlot.first) != ArtifactPosition::PRE_FIRST);
+		tradeSlot.second->setArtInstance(tradeSlot.first);
+		tradeSlot.second->subtitle = std::to_string(calcExpCost(tradeSlot.first));
+	}
+	for(auto & slotInfo : altarArtifacts->artifactsInBackpack)
+	{
+		if(tradeSlotsMap.find(slotInfo.artifact) == tradeSlotsMap.end())
 		{
-			logGlobal->warn("No free slots on altar!");
-			return false;
+			for(auto & altarSlot : items[0])
+				if(altarSlot->id == -1)
+				{
+					altarSlot->setArtInstance(slotInfo.artifact);
+					altarSlot->subtitle = std::to_string(calcExpCost(slotInfo.artifact));
+					tradeSlotsMap.emplace(slotInfo.artifact, altarSlot);
+					break;
+				}
 		}
-		altarSlot = items[0][slotIndex];
 	}
+	calcExpAltarForHero();
+	deal->block(tradeSlotsMap.empty());
+}
 
-	int dmp = 0;
-	int exp = 0;
-	market->getOffer(art->artType->getId(), 0, dmp, exp, EMarketMode::ARTIFACT_EXP);
-	exp = static_cast<int>(hero->calculateXp(exp));
-
-	arts->artifactsOnAltar.insert(art);
-	altarSlot->setArtInstance(art);
-	altarSlot->subtitle = std::to_string(exp);
-
-	deal->block(false);
-	return true;
-};
-
-void CAltarArtifacts::onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot)
+void CAltarArtifacts::onSlotClickPressed(const std::shared_ptr<CTradeableItem> & altarSlot, std::shared_ptr<CTradeableItem> & hCurSlot)
 {
-	if(const auto pickedArtInst = arts->getPickedArtifact())
+	assert(altarSlot);
+
+	if(const auto pickedArtInst = heroArts->getPickedArtifact())
 	{
 		if(pickedArtInst->canBePutAt(altarArtifacts))
-		{
-			LOCPLINT->cb->swapArtifacts(ArtifactLocation(arts->getHero()->id, ArtifactPosition::TRANSITION_POS),
-			ArtifactLocation(altarId, ArtifactPosition::ALTAR));
-			moveArtToAltar(newSlot, pickedArtInst);
-		}
+			if(pickedArtInst->artType->isTradable())
+			{
+				if(altarSlot->id == -1)
+					tradeSlotsMap.emplace(pickedArtInst, altarSlot);
+				heroArts->artifactsOnAltar.insert(pickedArtInst);
+				deal->block(false);
+
+				LOCPLINT->cb->swapArtifacts(ArtifactLocation(heroArts->getHero()->id, ArtifactPosition::TRANSITION_POS),
+					ArtifactLocation(altarId, ArtifactPosition::ALTAR));
+			}
+			else
+			{
+				logGlobal->warn("Cannot put special artifact on altar!");
+				return;
+			}
 	}
-	else if(const CArtifactInstance * art = newSlot->getArtInstance())
+	else if(const CArtifactInstance * art = altarSlot->getArtInstance())
 	{
 		const auto slot = altarArtifacts->getSlotByInstance(art);
 		assert(slot != ArtifactPosition::PRE_FIRST);
-		LOCPLINT->cb->swapArtifacts(ArtifactLocation(altarId, slot),
-			ArtifactLocation(hero->id, ArtifactPosition::TRANSITION_POS));
-		arts->artifactsOnAltar.erase(art);
-		newSlot->setID(-1);
-		newSlot->subtitle.clear();
-		deal->block(!arts->artifactsOnAltar.size());
+		LOCPLINT->cb->swapArtifacts(ArtifactLocation(altarId, slot), ArtifactLocation(hero->id, ArtifactPosition::TRANSITION_POS));
+		heroArts->artifactsOnAltar.erase(art);
+		tradeSlotsMap.erase(art);
 	}
-	calcExpAltarForHero();
+}
+
+TExpType CAltarArtifacts::calcExpCost(const CArtifactInstance* art)
+{
+	int dmp = 0;
+	int expOfArt = 0;
+	market->getOffer(art->getTypeId(), 0, dmp, expOfArt, EMarketMode::ARTIFACT_EXP);
+	return hero->calculateXp(expOfArt);
 }

+ 6 - 4
client/widgets/markets/CAltarArtifacts.h

@@ -21,8 +21,9 @@ public:
 	void sacrificeAll() override;
 	void sacrificeBackpack();
 	void setSelectedArtifact(const CArtifactInstance * art);
-	void moveArtToAltar(std::shared_ptr<CTradeableItem>, const CArtifactInstance * art);
 	std::shared_ptr<CArtifactsOfHeroAltar> getAOHset() const;
+	ObjectInstanceID getObjId() const;
+	void updateSlots();
 
 private:
 	ObjectInstanceID altarId;
@@ -30,7 +31,8 @@ private:
 	std::shared_ptr<CArtPlace> selectedArt;
 	std::shared_ptr<CLabel> selectedCost;
 	std::shared_ptr<CButton> sacrificeBackpackButton;
-	std::shared_ptr<CArtifactsOfHeroAltar> arts;
+	std::shared_ptr<CArtifactsOfHeroAltar> heroArts;
+	std::map<const CArtifactInstance*, std::shared_ptr<CTradeableItem>> tradeSlotsMap;
 
 	const std::vector<Point> posSlotsAltar =
 	{
@@ -44,6 +46,6 @@ private:
 		Point(452, 333)
 	};
 
-	bool putArtOnAltar(std::shared_ptr<CTradeableItem> altarSlot, const CArtifactInstance * art);
-	void onSlotClickPressed(const std::shared_ptr<CTradeableItem> & newSlot, std::shared_ptr<CTradeableItem> & hCurSlot) override;
+	void onSlotClickPressed(const std::shared_ptr<CTradeableItem> & altarSlot, std::shared_ptr<CTradeableItem> & hCurSlot) override;
+	TExpType calcExpCost(const CArtifactInstance * art);
 };

+ 4 - 0
client/windows/CAltarWindow.cpp

@@ -19,6 +19,7 @@
 
 #include "../CGameInfo.h"
 
+#include "../lib/networkPacks/ArtifactLocation.h"
 #include "../../lib/CGeneralTextHandler.h"
 #include "../../lib/CHeroHandler.h"
 #include "../../lib/mapObjects/CGHeroInstance.h"
@@ -115,6 +116,9 @@ void CAltarWindow::artifactMoved(const ArtifactLocation & srcLoc, const Artifact
 
 	if(auto altarArtifacts = std::static_pointer_cast<CAltarArtifacts>(altar))
 	{
+		if(srcLoc.artHolder == altarArtifacts->getObjId() || destLoc.artHolder == altarArtifacts->getObjId())
+			altarArtifacts->updateSlots();
+
 		if(const auto pickedArt = getPickedArtifact())
 			altarArtifacts->setSelectedArtifact(pickedArt);
 		else

+ 29 - 27
server/CGameHandler.cpp

@@ -2767,27 +2767,26 @@ bool CGameHandler::moveArtifact(const ArtifactLocation & src, const ArtifactLoca
 	return true;
 }
 
-bool CGameHandler::bulkMoveArtifacts(ObjectInstanceID srcHero, ObjectInstanceID dstHero, bool swap, bool equipped, bool backpack)
+bool CGameHandler::bulkMoveArtifacts(ObjectInstanceID srcId, ObjectInstanceID dstId, bool swap, bool equipped, bool backpack)
 {
 	// Make sure exchange is even possible between the two heroes.
-	if(!isAllowedExchange(srcHero, dstHero))
+	if(!isAllowedExchange(srcId, dstId))
 		COMPLAIN_RET("That heroes cannot make any exchange!");
 
-	auto psrcHero = getHero(srcHero);
-	auto pdstHero = getHero(dstHero);
-	if((!psrcHero) || (!pdstHero))
+	auto psrcSet = getArtSet(srcId);
+	auto pdstSet = getArtSet(dstId);
+	if((!psrcSet) || (!pdstSet))
 		COMPLAIN_RET("bulkMoveArtifacts: wrong hero's ID");
 
-	BulkMoveArtifacts ma(srcHero, dstHero, swap);
+	BulkMoveArtifacts ma(srcId, dstId, swap);
 	auto & slotsSrcDst = ma.artsPack0;
 	auto & slotsDstSrc = ma.artsPack1;
 
 	// Temporary fitting set for artifacts. Used to select available slots before sending data.
-	CArtifactFittingSet artFittingSet(pdstHero->bearerType());
+	CArtifactFittingSet artFittingSet(pdstSet->bearerType());
 
-	auto moveArtifact = [this, &artFittingSet](const CArtifactInstance * artifact,
-		ArtifactPosition srcSlot, const CGHeroInstance * dstHero,
-		std::vector<BulkMoveArtifacts::LinkedSlots> & slots) -> void
+	auto moveArtifact = [this, &artFittingSet, dstId](const CArtifactInstance * artifact,
+		ArtifactPosition srcSlot, std::vector<BulkMoveArtifacts::LinkedSlots> & slots) -> void
 	{
 		assert(artifact);
 		auto dstSlot = ArtifactUtils::getArtAnyPosition(&artFittingSet, artifact->getTypeId());
@@ -2796,20 +2795,23 @@ bool CGameHandler::bulkMoveArtifacts(ObjectInstanceID srcHero, ObjectInstanceID
 			artFittingSet.putArtifact(dstSlot, static_cast<ConstTransitivePtr<CArtifactInstance>>(artifact));
 			slots.push_back(BulkMoveArtifacts::LinkedSlots(srcSlot, dstSlot));
 
-			if(ArtifactUtils::checkSpellbookIsNeeded(dstHero, artifact->getTypeId(), dstSlot))
-				giveHeroNewArtifact(dstHero, ArtifactID(ArtifactID::SPELLBOOK).toArtifact(), ArtifactPosition::SPELLBOOK);
+			// TODO Shouldn't be here. Possibly in callback after equipping the artifact
+			if(auto dstHero = getHero(dstId))
+			{
+				if(ArtifactUtils::checkSpellbookIsNeeded(dstHero, artifact->getTypeId(), dstSlot))
+					giveHeroNewArtifact(dstHero, ArtifactID(ArtifactID::SPELLBOOK).toArtifact(), ArtifactPosition::SPELLBOOK);
+			}
 		}
 	};
 
 	if(swap)
 	{
-		auto moveArtsWorn = [moveArtifact](const CGHeroInstance * srcHero, const CGHeroInstance * dstHero,
-			std::vector<BulkMoveArtifacts::LinkedSlots> & slots) -> void
+		auto moveArtsWorn = [moveArtifact](const CArtifactSet * srcArtSet, std::vector<BulkMoveArtifacts::LinkedSlots> & slots)
 		{
-			for(auto & artifact : srcHero->artifactsWorn)
+			for(auto & artifact : srcArtSet->artifactsWorn)
 			{
 				if(ArtifactUtils::isArtRemovable(artifact))
-					moveArtifact(artifact.second.getArt(), artifact.first, dstHero, slots);
+					moveArtifact(artifact.second.getArt(), artifact.first, slots);
 			}
 		};
 		auto moveArtsInBackpack = [](const CArtifactSet * artSet,
@@ -2824,41 +2826,41 @@ bool CGameHandler::bulkMoveArtifacts(ObjectInstanceID srcHero, ObjectInstanceID
 		if(equipped)
 		{
 			// Move over artifacts that are worn srcHero -> dstHero
-			moveArtsWorn(psrcHero, pdstHero, slotsSrcDst);
+			moveArtsWorn(psrcSet, slotsSrcDst);
 			artFittingSet.artifactsWorn.clear();
 			// Move over artifacts that are worn dstHero -> srcHero
-			moveArtsWorn(pdstHero, psrcHero, slotsDstSrc);
+			moveArtsWorn(pdstSet, slotsDstSrc);
 		}
 		if(backpack)
 		{
 			// Move over artifacts that are in backpack srcHero -> dstHero
-			moveArtsInBackpack(psrcHero, slotsSrcDst);
+			moveArtsInBackpack(psrcSet, slotsSrcDst);
 			// Move over artifacts that are in backpack dstHero -> srcHero
-			moveArtsInBackpack(pdstHero, slotsDstSrc);
+			moveArtsInBackpack(pdstSet, slotsDstSrc);
 		}
 	}
 	else
 	{
-		artFittingSet.artifactsInBackpack = pdstHero->artifactsInBackpack;
-		artFittingSet.artifactsWorn = pdstHero->artifactsWorn;
+		artFittingSet.artifactsInBackpack = pdstSet->artifactsInBackpack;
+		artFittingSet.artifactsWorn = pdstSet->artifactsWorn;
 		if(equipped)
 		{
 			// Move over artifacts that are worn
-			for(auto & artInfo : psrcHero->artifactsWorn)
+			for(auto & artInfo : psrcSet->artifactsWorn)
 			{
 				if(ArtifactUtils::isArtRemovable(artInfo))
 				{
-					moveArtifact(psrcHero->getArt(artInfo.first), artInfo.first, pdstHero, slotsSrcDst);
+					moveArtifact(psrcSet->getArt(artInfo.first), artInfo.first, slotsSrcDst);
 				}
 			}
 		}
 		if(backpack)
 		{
 			// Move over artifacts that are in backpack
-			for(auto & slotInfo : psrcHero->artifactsInBackpack)
+			for(auto & slotInfo : psrcSet->artifactsInBackpack)
 			{
-				moveArtifact(psrcHero->getArt(psrcHero->getArtPos(slotInfo.artifact)),
-					psrcHero->getArtPos(slotInfo.artifact), pdstHero, slotsSrcDst);
+				moveArtifact(psrcSet->getArt(psrcSet->getArtPos(slotInfo.artifact)),
+					psrcSet->getArtPos(slotInfo.artifact), slotsSrcDst);
 			}
 		}
 	}

+ 1 - 1
server/CGameHandler.h

@@ -130,7 +130,7 @@ public:
 	bool putArtifact(const ArtifactLocation & al, const CArtifactInstance * art, std::optional<bool> askAssemble) override;
 	void removeArtifact(const ArtifactLocation &al) override;
 	bool moveArtifact(const ArtifactLocation & src, const ArtifactLocation & dst) override;
-	bool bulkMoveArtifacts(ObjectInstanceID srcHero, ObjectInstanceID dstHero, bool swap, bool equipped, bool backpack);
+	bool bulkMoveArtifacts(ObjectInstanceID srcId, ObjectInstanceID dstId, bool swap, bool equipped, bool backpack);
 	bool eraseArtifactByClient(const ArtifactLocation & al);
 	void synchronizeArtifactHandlerLists();
 

+ 3 - 0
server/queries/MapQueries.cpp

@@ -200,6 +200,9 @@ bool OpenWindowQuery::blocksPack(const CPack *pack) const
 		if(dynamic_ptr_cast<ExchangeArtifacts>(pack) != nullptr)
 			return false;
 
+		if(dynamic_ptr_cast<BulkExchangeArtifacts>(pack) != nullptr)
+			return false;
+
 		if(dynamic_ptr_cast<AssembleArtifacts>(pack))
 			return false;