浏览代码

Merge pull request #1148 from SoundSSGood/ask-assemble

Feature to assemble/disassemble arts in backpack
Andrii Danylchenko 2 年之前
父节点
当前提交
dfee2eda68
共有 6 个文件被更改,包括 123 次插入63 次删除
  1. 37 32
      client/widgets/CArtifactHolder.cpp
  2. 3 3
      client/widgets/CArtifactHolder.h
  3. 54 15
      lib/CArtHandler.cpp
  4. 5 1
      lib/CArtHandler.h
  5. 19 9
      lib/NetPacksLib.cpp
  6. 5 3
      server/CGameHandler.cpp

+ 37 - 32
client/widgets/CArtifactHolder.cpp

@@ -206,12 +206,13 @@ void CHeroArtPlace::clickLeft(tribool down, bool previousState)
 bool CHeroArtPlace::askToAssemble(const CArtifactInstance *art, ArtifactPosition slot,
                               const CGHeroInstance *hero)
 {
-	assert(art != nullptr);
-	assert(hero != nullptr);
-	std::vector<const CArtifact *> assemblyPossibilities = art->assemblyPossibilities(hero);
+	assert(art);
+	assert(hero);
+	bool assembleEqipped = !ArtifactUtils::isSlotBackpack(slot);
+	auto assemblyPossibilities = art->assemblyPossibilities(hero, assembleEqipped);
 
 	// If the artifact can be assembled, display dialog.
-	for(const CArtifact *combination : assemblyPossibilities)
+	for(const auto * combination : assemblyPossibilities)
 	{
 		LOCPLINT->showArtifactAssemblyDialog(
 			art->artType,
@@ -229,27 +230,22 @@ void CHeroArtPlace::clickRight(tribool down, bool previousState)
 {
 	if(ourArt && down && !locked && text.size() && !picked)  //if there is no description or it's a lock, do nothing ;]
 	{
-		if(slotID < GameConstants::BACKPACK_START)
+		if(ourOwner->allowedAssembling)
 		{
-			if(ourOwner->allowedAssembling)
+			// If the artifact can be assembled, display dialog.
+			if(askToAssemble(ourArt, slotID, ourOwner->curHero))
 			{
-				std::vector<const CArtifact *> assemblyPossibilities = ourArt->assemblyPossibilities(ourOwner->curHero);
-
-				// If the artifact can be assembled, display dialog.
-				if(askToAssemble(ourArt, slotID, ourOwner->curHero))
-				{
-					return;
-				}
+				return;
+			}
 
-				// Otherwise if the artifact can be diasassembled, display dialog.
-				if(ourArt->canBeDisassembled())
-				{
-					LOCPLINT->showArtifactAssemblyDialog(
-						ourArt->artType,
-						nullptr,
-						std::bind(&CCallback::assembleArtifacts, LOCPLINT->cb.get(), ourOwner->curHero, slotID, false, ArtifactID()));
-					return;
-				}
+			// Otherwise if the artifact can be diasassembled, display dialog.
+			if(ourArt->canBeDisassembled())
+			{
+				LOCPLINT->showArtifactAssemblyDialog(
+					ourArt->artType,
+					nullptr,
+					std::bind(&CCallback::assembleArtifacts, LOCPLINT->cb.get(), ourOwner->curHero, slotID, false, ArtifactID()));
+				return;
 			}
 		}
 
@@ -819,16 +815,15 @@ CArtifactsOfHero::ArtPlacePtr CArtifactsOfHero::getArtPlace(int slot)
 	}
 }
 
-void CArtifactsOfHero::artifactAssembled(const ArtifactLocation &al)
+void CArtifactsOfHero::artifactUpdateSlots(const ArtifactLocation & al)
 {
 	if(al.isHolder(curHero))
-		updateWornSlots();
-}
-
-void CArtifactsOfHero::artifactDisassembled(const ArtifactLocation &al)
-{
-	if(al.isHolder(curHero))
-		updateWornSlots();
+	{
+		if(ArtifactUtils::isSlotBackpack(al.slot))
+			updateBackpackSlots();
+		else
+			updateWornSlots();
+	}
 }
 
 void CArtifactsOfHero::updateWornSlots(bool redrawParent)
@@ -840,6 +835,16 @@ void CArtifactsOfHero::updateWornSlots(bool redrawParent)
 		updateParentWindow();
 }
 
+void CArtifactsOfHero::updateBackpackSlots(bool redrawParent)
+{
+	for(auto artPlace : backpack)
+		updateSlot(artPlace->slotID);
+	scrollBackpack(0);
+
+	if(redrawParent)
+		updateParentWindow();
+}
+
 const CGHeroInstance * CArtifactsOfHero::getHero() const
 {
 	return curHero;
@@ -910,7 +915,7 @@ void CWindowWithArtifacts::artifactDisassembled(const ArtifactLocation &artLoc)
 	{
 		std::shared_ptr<CArtifactsOfHero> realPtr = artSetWeak.lock();
 		if(realPtr)
-			realPtr->artifactDisassembled(artLoc);
+			realPtr->artifactUpdateSlots(artLoc);
 	}
 }
 
@@ -920,7 +925,7 @@ void CWindowWithArtifacts::artifactAssembled(const ArtifactLocation &artLoc)
 	{
 		std::shared_ptr<CArtifactsOfHero> realPtr = artSetWeak.lock();
 		if(realPtr)
-			realPtr->artifactAssembled(artLoc);
+			realPtr->artifactUpdateSlots(artLoc);
 	}
 }
 

+ 3 - 3
client/widgets/CArtifactHolder.h

@@ -140,8 +140,7 @@ public:
 	void realizeCurrentTransaction(); //calls callback with parameters stored in commonInfo
 	void artifactMoved(const ArtifactLocation &src, const ArtifactLocation &dst);
 	void artifactRemoved(const ArtifactLocation &al);
-	void artifactAssembled(const ArtifactLocation &al);
-	void artifactDisassembled(const ArtifactLocation &al);
+	void artifactUpdateSlots(const ArtifactLocation &al);
 	ArtPlacePtr getArtPlace(int slot);//may return null
 
 	void setHero(const CGHeroInstance * hero);
@@ -153,7 +152,8 @@ public:
 	void markPossibleSlots(const CArtifactInstance* art);
 	void unmarkSlots(bool withRedraw = true); //unmarks slots in all visible AOHs
 	void unmarkLocalSlots(bool withRedraw = true); //unmarks slots in that particular AOH
-	void updateWornSlots (bool redrawParent = true);
+	void updateWornSlots(bool redrawParent = true);
+	void updateBackpackSlots(bool redrawParent = true);
 
 	void updateSlot(ArtifactPosition i);
 

+ 54 - 15
lib/CArtHandler.cpp

@@ -870,26 +870,36 @@ bool CArtifactInstance::canBeDisassembled() const
 	return bool(artType->constituents);
 }
 
-std::vector<const CArtifact *> CArtifactInstance::assemblyPossibilities(const CArtifactSet *h) const
+std::vector<const CArtifact *> CArtifactInstance::assemblyPossibilities(const CArtifactSet * h, bool equipped) const
 {
 	std::vector<const CArtifact *> ret;
 	if(artType->constituents) //combined artifact already: no combining of combined artifacts... for now.
 		return ret;
 
-	for(const CArtifact * artifact : artType->constituentOf)
+	for(const auto * artifact : artType->constituentOf)
 	{
 		assert(artifact->constituents);
 		bool possible = true;
 
-		for(const CArtifact * constituent : *artifact->constituents) //check if all constituents are available
+		for(const auto * constituent : *artifact->constituents) //check if all constituents are available
 		{
-			const bool noBackpack = false;
-			const bool notAlreadyAssembled = false;
-
-			if(!h->hasArt(constituent->id, true, noBackpack, notAlreadyAssembled)) //constituent must be equipped
+			if(equipped)
 			{
-				possible = false;
-				break;
+				// Search for equipped arts
+				if (!h->hasArt(constituent->id, true, false, false))
+				{
+					possible = false;
+					break;
+				}
+			}
+			else
+			{
+				// Search in backpack
+				if(!h->hasArtBackpack(constituent->id))
+				{
+					possible = false;
+					break;
+				}
 			}
 		}
 
@@ -1195,22 +1205,41 @@ ArtifactPosition CArtifactSet::getArtPos(int aid, bool onlyWorn, bool allowLocke
 	return result.empty() ? ArtifactPosition{ArtifactPosition::PRE_FIRST} : result[0];
 }
 
+ArtifactPosition CArtifactSet::getArtBackpackPos(int aid) const
+{
+	const auto result = getBackpackArtPositions(aid);
+	return result.empty() ? ArtifactPosition{ArtifactPosition::PRE_FIRST} : result[0];
+}
+
 std::vector<ArtifactPosition> CArtifactSet::getAllArtPositions(int aid, bool onlyWorn, bool allowLocked, bool getAll) const
 {
 	std::vector<ArtifactPosition> result;
-	for(auto i = artifactsWorn.cbegin(); i != artifactsWorn.cend(); i++)
-		if(i->second.artifact->artType->id == aid && (allowLocked || !i->second.locked))
-			result.push_back(i->first);
+	for(auto & slotInfo : artifactsWorn)
+		if(slotInfo.second.artifact->artType->id == aid && (allowLocked || !slotInfo.second.locked))
+			result.push_back(slotInfo.first);
 
 	if(onlyWorn)
 		return result;
 	if(!getAll && !result.empty())
 		return result;
 
-	for(int i = 0; i < artifactsInBackpack.size(); i++)
-		if(artifactsInBackpack[i].artifact->artType->id == aid)
-			result.push_back(ArtifactPosition(GameConstants::BACKPACK_START + i));
+	auto backpackPositions = getBackpackArtPositions(aid);
+	result.insert(result.end(), backpackPositions.begin(), backpackPositions.end());
+	return result;
+}
 
+std::vector<ArtifactPosition> CArtifactSet::getBackpackArtPositions(int aid) const
+{
+	std::vector<ArtifactPosition> result;
+
+	si32 backpackPosition = GameConstants::BACKPACK_START;
+	for(auto & artInfo : artifactsInBackpack)
+	{
+		auto * art = artInfo.getArt();
+		if(art && art->artType->id == aid)
+			result.emplace_back(backpackPosition);
+		backpackPosition++;
+	}
 	return result;
 }
 
@@ -1249,6 +1278,11 @@ bool CArtifactSet::hasArt(
 	return getArtPosCount(aid, onlyWorn, searchBackpackAssemblies, allowLocked) > 0;
 }
 
+bool CArtifactSet::hasArtBackpack(ui32 aid) const
+{
+	return getBackpackArtPositions(aid).size() > 0;
+}
+
 unsigned CArtifactSet::getArtPosCount(int aid, bool onlyWorn, bool searchBackpackAssemblies, bool allowLocked) const
 {
 	const auto allPositions = getAllArtPositions(aid, onlyWorn, allowLocked, true);
@@ -1536,4 +1570,9 @@ DLL_LINKAGE bool ArtifactUtils::checkSpellbookIsNeeded(const CGHeroInstance * he
 	return false;
 }
 
+DLL_LINKAGE bool ArtifactUtils::isSlotBackpack(ArtifactPosition slot)
+{
+	return slot >= GameConstants::BACKPACK_START;
+}
+
 VCMI_LIB_NAMESPACE_END

+ 5 - 1
lib/CArtHandler.h

@@ -163,7 +163,7 @@ public:
 	/// of itself, additionally truth is returned for constituents of combined arts
 	virtual bool isPart(const CArtifactInstance *supposedPart) const;
 
-	std::vector<const CArtifact *> assemblyPossibilities(const CArtifactSet *h) const;
+	std::vector<const CArtifact *> assemblyPossibilities(const CArtifactSet * h, bool equipped) const;
 	void move(ArtifactLocation src, ArtifactLocation dst);
 
 	template <typename Handler> void serialize(Handler &h, const int version)
@@ -329,13 +329,16 @@ public:
 	/// (if more than one such artifact lower ID is returned)
 	ArtifactPosition getArtPos(int aid, bool onlyWorn = true, bool allowLocked = true) const;
 	ArtifactPosition getArtPos(const CArtifactInstance *art) const;
+	ArtifactPosition getArtBackpackPos(int aid) const;
 	std::vector<ArtifactPosition> getAllArtPositions(int aid, bool onlyWorn, bool allowLocked, bool getAll) const;
+	std::vector<ArtifactPosition> getBackpackArtPositions(int aid) const;
 	const CArtifactInstance *getArtByInstanceId(ArtifactInstanceID artInstId) const;
 	/// Search for constituents of assemblies in backpack which do not have an ArtifactPosition
 	const CArtifactInstance *getHiddenArt(int aid) const;
 	const CCombinedArtifactInstance *getAssemblyByConstituent(int aid) const;
 	/// Checks if hero possess artifact of given id (either in backack or worn)
 	bool hasArt(ui32 aid, bool onlyWorn = false, bool searchBackpackAssemblies = false, bool allowLocked = true) const;
+	bool hasArtBackpack(ui32 aid) const;
 	bool isPositionFree(ArtifactPosition pos, bool onlyLockCheck = false) const;
 	unsigned getArtPosCount(int aid, bool onlyWorn = true, bool searchBackpackAssemblies = true, bool allowLocked = true) const;
 
@@ -386,6 +389,7 @@ namespace ArtifactUtils
 	DLL_LINKAGE std::vector<ArtifactPosition> unmovablePositions(); // TODO: Make this constexpr when the toolset is upgraded
 	DLL_LINKAGE bool isArtRemovable(const std::pair<ArtifactPosition, ArtSlotInfo> & slot);
 	DLL_LINKAGE bool checkSpellbookIsNeeded(const CGHeroInstance * heroPtr, ArtifactID artID, ArtifactPosition slot);
+	DLL_LINKAGE bool isSlotBackpack(ArtifactPosition slot);
 }
 
 VCMI_LIB_NAMESPACE_END

+ 19 - 9
lib/NetPacksLib.cpp

@@ -1089,7 +1089,7 @@ DLL_LINKAGE void EraseArtifact::applyGs(CGameState *gs)
 DLL_LINKAGE void MoveArtifact::applyGs(CGameState * gs)
 {
 	CArtifactInstance * art = src.getArt();
-	if(dst.slot < GameConstants::BACKPACK_START)
+	if(!ArtifactUtils::isSlotBackpack(dst.slot))
 		assert(!dst.getArt());
 
 	art->move(src, dst);
@@ -1114,7 +1114,7 @@ DLL_LINKAGE void BulkMoveArtifacts::applyGs(CGameState * gs)
 			// so all the following indices will be affected. Thus, we need to update
 			// the subsequent artifact slots to account for that
 			auto srcPos = slot.srcPos;
-			if((srcPos >= GameConstants::BACKPACK_START) && (operation != EBulkArtsOp::BULK_PUT))
+			if(ArtifactUtils::isSlotBackpack(srcPos) && (operation != EBulkArtsOp::BULK_PUT))
 			{
 				srcPos = ArtifactPosition(srcPos.num - numBackpackArtifactsMoved);
 			}
@@ -1167,26 +1167,36 @@ DLL_LINKAGE void BulkMoveArtifacts::applyGs(CGameState * gs)
 
 DLL_LINKAGE void AssembledArtifact::applyGs(CGameState *gs)
 {
-	CArtifactSet *artSet = al.getHolderArtSet();
+	CArtifactSet * artSet = al.getHolderArtSet();
 	const CArtifactInstance *transformedArt = al.getArt();
 	assert(transformedArt);
-	assert(vstd::contains(transformedArt->assemblyPossibilities(artSet), builtArt));
+	bool combineEquipped = !ArtifactUtils::isSlotBackpack(al.slot);
+	assert(vstd::contains(transformedArt->assemblyPossibilities(artSet, combineEquipped), builtArt));
 	UNUSED(transformedArt);
 
 	auto combinedArt = new CCombinedArtifactInstance(builtArt);
 	gs->map->addNewArtifactInstance(combinedArt);
-	//retrieve all constituents
+	// Retrieve all constituents
 	for(const CArtifact * constituent : *builtArt->constituents)
 	{
-		ArtifactPosition pos = artSet->getArtPos(constituent->id);
+		ArtifactPosition pos = combineEquipped ? artSet->getArtPos(constituent->id, true, false) :
+			artSet->getArtBackpackPos(constituent->id);
 		assert(pos >= 0);
-		CArtifactInstance *constituentInstance = artSet->getArt(pos);
+		CArtifactInstance * constituentInstance = artSet->getArt(pos);
 
 		//move constituent from hero to be part of new, combined artifact
 		constituentInstance->removeFrom(ArtifactLocation(al.artHolder, pos));
 		combinedArt->addAsConstituent(constituentInstance, pos);
-		if(!vstd::contains(combinedArt->artType->possibleSlots[artSet->bearerType()], al.slot) && vstd::contains(combinedArt->artType->possibleSlots[artSet->bearerType()], pos))
-			al.slot = pos;
+		if(combineEquipped)
+		{
+			if(!vstd::contains(combinedArt->artType->possibleSlots[artSet->bearerType()], al.slot)
+				&& vstd::contains(combinedArt->artType->possibleSlots[artSet->bearerType()], pos))
+				al.slot = pos;
+		}
+		else
+		{
+			al.slot = std::min(al.slot, pos);
+		}
 	}
 
 	//put new combined artifacts

+ 5 - 3
server/CGameHandler.cpp

@@ -4031,13 +4031,15 @@ bool CGameHandler::assembleArtifacts (ObjectInstanceID heroID, ArtifactPosition
 	if (!destArtifact)
 		COMPLAIN_RET("assembleArtifacts: there is no such artifact instance!");
 
-	if (assemble)
+	if(assemble)
 	{
 		CArtifact *combinedArt = VLC->arth->objects[assembleTo];
-		if (!combinedArt->constituents)
+		if(!combinedArt->constituents)
 			COMPLAIN_RET("assembleArtifacts: Artifact being attempted to assemble is not a combined artifacts!");
-		if (!vstd::contains(destArtifact->assemblyPossibilities(hero), combinedArt))
+		bool combineEquipped = !ArtifactUtils::isSlotBackpack(artifactSlot);
+		if(!vstd::contains(destArtifact->assemblyPossibilities(hero, combineEquipped), combinedArt))
 			COMPLAIN_RET("assembleArtifacts: It's impossible to assemble requested artifact!");
+
 		
 		if(ArtifactUtils::checkSpellbookIsNeeded(hero, assembleTo, artifactSlot))
 			giveHeroNewArtifact(hero, VLC->arth->objects[ArtifactID::SPELLBOOK], ArtifactPosition::SPELLBOOK);