mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Merge pull request #4766 from SoundSSGood/fused-artifacts
Fused artifacts
This commit is contained in:
		| @@ -358,6 +358,7 @@ | ||||
| 	"vcmi.heroWindow.sortBackpackBySlot.help"  : "Sort artifacts in backpack by equipped slot.", | ||||
| 	"vcmi.heroWindow.sortBackpackByClass.hover"  : "Sort by class", | ||||
| 	"vcmi.heroWindow.sortBackpackByClass.help"  : "Sort artifacts in backpack by artifact class. Treasure, Minor, Major, Relic", | ||||
| 	"vcmi.heroWindow.fusingArtifact.fusing" : "You possess all of the components needed for the fusion of the %s. Do you wish to perform the fusion? {All components will be consumed upon fusion.}", | ||||
|  | ||||
| 	"vcmi.tavernWindow.inviteHero"  : "Invite hero", | ||||
|  | ||||
|   | ||||
| @@ -74,7 +74,10 @@ bool ArtifactsUIController::askToAssemble(const CGHeroInstance * hero, const Art | ||||
| 					MetaString message = MetaString::createFromTextID(art->artType->getDescriptionTextID()); | ||||
| 					message.appendEOL(); | ||||
| 					message.appendEOL(); | ||||
| 					message.appendRawString(CGI->generaltexth->allTexts[732]); // You possess all of the components needed to assemble the | ||||
| 					if(combinedArt->isFused()) | ||||
| 						message.appendRawString(CGI->generaltexth->translate("vcmi.heroWindow.fusingArtifact.fusing")); | ||||
| 					else | ||||
| 						message.appendRawString(CGI->generaltexth->allTexts[732]); // You possess all of the components needed to assemble the | ||||
| 					message.replaceName(ArtifactID(combinedArt->getId())); | ||||
| 					LOCPLINT->showYesNoDialog(message.toString(), [&assembleConfirmed, hero, slot, combinedArt]() | ||||
| 						{ | ||||
| @@ -102,7 +105,7 @@ bool ArtifactsUIController::askToDisassemble(const CGHeroInstance * hero, const | ||||
| 	if(hero->tempOwner != LOCPLINT->playerID) | ||||
| 		return false; | ||||
|  | ||||
| 	if(art->isCombined()) | ||||
| 	if(art->hasParts()) | ||||
| 	{ | ||||
| 		if(ArtifactUtils::isSlotBackpack(slot) && !ArtifactUtils::isBackpackFreeSlots(hero, art->artType->getConstituents().size() - 1)) | ||||
| 			return false; | ||||
|   | ||||
| @@ -217,9 +217,9 @@ void CArtPlace::setGestureCallback(const ClickFunctor & callback) | ||||
|  | ||||
| void CArtPlace::addCombinedArtInfo(const std::map<const ArtifactID, std::vector<ArtifactID>> & arts) | ||||
| { | ||||
| 	for(const auto & availableArts : arts) | ||||
| 	for(auto [combinedId, availableArts] : arts) | ||||
| 	{ | ||||
| 		const auto combinedArt = availableArts.first.toArtifact(); | ||||
| 		const auto combinedArt = combinedId.toArtifact(); | ||||
| 		MetaString info; | ||||
| 		info.appendEOL(); | ||||
| 		info.appendEOL(); | ||||
| @@ -227,14 +227,20 @@ void CArtPlace::addCombinedArtInfo(const std::map<const ArtifactID, std::vector< | ||||
| 		info.appendName(combinedArt->getId()); | ||||
| 		info.appendRawString("}"); | ||||
| 		info.appendRawString(" (%d/%d)"); | ||||
| 		info.replaceNumber(availableArts.second.size()); | ||||
| 		info.replaceNumber(availableArts.size()); | ||||
| 		info.replaceNumber(combinedArt->getConstituents().size()); | ||||
| 		for(const auto part : combinedArt->getConstituents()) | ||||
| 		{ | ||||
| 			const auto found = std::find_if(availableArts.begin(), availableArts.end(), [part](const auto & availablePart) -> bool | ||||
| 				{ | ||||
| 					return availablePart == part->getId() ? true : false; | ||||
| 				}); | ||||
|  | ||||
| 			info.appendEOL(); | ||||
| 			if(vstd::contains(availableArts.second, part->getId())) | ||||
| 			if(found < availableArts.end()) | ||||
| 			{ | ||||
| 				info.appendName(part->getId()); | ||||
| 				availableArts.erase(found); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
|   | ||||
| @@ -268,11 +268,17 @@ void CArtifactsOfHeroBase::setSlotData(ArtPlacePtr artPlace, const ArtifactPosit | ||||
| 		std::map<const ArtifactID, std::vector<ArtifactID>> arts; | ||||
| 		for(const auto combinedArt : slotInfo->artifact->artType->getPartOf()) | ||||
| 		{ | ||||
| 			arts.try_emplace(combinedArt->getId(), std::vector<ArtifactID>{}); | ||||
| 			assert(combinedArt->isCombined()); | ||||
| 			arts.try_emplace(combinedArt->getId()); | ||||
| 			CArtifactFittingSet fittingSet(*curHero); | ||||
| 			for(const auto part : combinedArt->getConstituents()) | ||||
| 			{ | ||||
| 				if(curHero->hasArt(part->getId(), false, false)) | ||||
| 				const auto partSlot = fittingSet.getArtPos(part->getId(), false, false); | ||||
| 				if(partSlot != ArtifactPosition::PRE_FIRST) | ||||
| 				{ | ||||
| 					arts.at(combinedArt->getId()).emplace_back(part->getId()); | ||||
| 					fittingSet.lockSlot(partSlot); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		artPlace->addCombinedArtInfo(arts); | ||||
|   | ||||
| @@ -61,6 +61,10 @@ | ||||
| 			"description" : "Optional, list of components for combinational artifacts", | ||||
| 			"items" : { "type" : "string" } | ||||
| 		}, | ||||
| 		"fusedComponents" : { | ||||
| 			"type" : "boolean", | ||||
| 			"description" : "Used together with components fild. Marks the artifact as fused. Cannot be disassembled." | ||||
| 		}, | ||||
| 		"bonuses" : { | ||||
| 			"type" : "array", | ||||
| 			"description" : "Bonuses provided by this artifact using bonus system", | ||||
|   | ||||
| @@ -67,6 +67,9 @@ In order to make functional artifact you also need: | ||||
| 		"artifact2", | ||||
| 		"artifact3" | ||||
| 	], | ||||
| 	 | ||||
| 	// Optional, by default is false. Set to true if components are supposed to be fused.  | ||||
| 	"fusedComponents" : true, | ||||
|  | ||||
| 	// Creature id to use on battle field. If set, this artifact is war machine | ||||
| 	"warMachine" : "some.creature"  | ||||
|   | ||||
| @@ -202,21 +202,23 @@ DLL_LINKAGE std::vector<const CArtifact*> ArtifactUtils::assemblyPossibilities( | ||||
| 	if(art->isCombined()) | ||||
| 		return arts; | ||||
|  | ||||
| 	for(const auto artifact : art->getPartOf()) | ||||
| 	for(const auto combinedArt : art->getPartOf()) | ||||
| 	{ | ||||
| 		assert(artifact->isCombined()); | ||||
| 		assert(combinedArt->isCombined()); | ||||
| 		bool possible = true; | ||||
|  | ||||
| 		for(const auto constituent : artifact->getConstituents()) //check if all constituents are available | ||||
| 		CArtifactFittingSet fittingSet(*artSet); | ||||
| 		for(const auto part : combinedArt->getConstituents()) // check if all constituents are available | ||||
| 		{ | ||||
| 			if(!artSet->hasArt(constituent->getId(), onlyEquiped, false)) | ||||
| 			const auto slot = fittingSet.getArtPos(part->getId(), onlyEquiped, false); | ||||
| 			if(slot == ArtifactPosition::PRE_FIRST) | ||||
| 			{ | ||||
| 				possible = false; | ||||
| 				break; | ||||
| 			} | ||||
| 			fittingSet.lockSlot(slot); | ||||
| 		} | ||||
| 		if(possible) | ||||
| 			arts.push_back(artifact); | ||||
| 			arts.push_back(combinedArt); | ||||
| 	} | ||||
| 	return arts; | ||||
| } | ||||
|   | ||||
| @@ -56,11 +56,26 @@ const std::vector<const CArtifact*> & CCombinedArtifact::getConstituents() const | ||||
| 	return constituents; | ||||
| } | ||||
|  | ||||
| const std::vector<const CArtifact*> & CCombinedArtifact::getPartOf() const | ||||
| const std::set<const CArtifact*> & CCombinedArtifact::getPartOf() const | ||||
| { | ||||
| 	return partOf; | ||||
| } | ||||
|  | ||||
| void CCombinedArtifact::setFused(bool isFused) | ||||
| { | ||||
| 	fused = isFused; | ||||
| } | ||||
|  | ||||
| bool CCombinedArtifact::isFused() const | ||||
| { | ||||
| 	return fused; | ||||
| } | ||||
|  | ||||
| bool CCombinedArtifact::hasParts() const | ||||
| { | ||||
| 	return isCombined() && !isFused(); | ||||
| } | ||||
|  | ||||
| bool CScrollArtifact::isScroll() const | ||||
| { | ||||
| 	return static_cast<const CArtifact*>(this)->getId() == ArtifactID::SPELL_SCROLL; | ||||
| @@ -203,7 +218,7 @@ bool CArtifact::canBePutAt(const CArtifactSet * artSet, ArtifactPosition slot, b | ||||
|  | ||||
| 	auto artCanBePutAt = [this, simpleArtCanBePutAt](const CArtifactSet * artSet, ArtifactPosition slot, bool assumeDestRemoved) -> bool | ||||
| 	{ | ||||
| 		if(isCombined()) | ||||
| 		if(hasParts()) | ||||
| 		{ | ||||
| 			if(!simpleArtCanBePutAt(artSet, slot, assumeDestRemoved)) | ||||
| 				return false; | ||||
| @@ -606,19 +621,21 @@ void CArtHandler::loadType(CArtifact * art, const JsonNode & node) const | ||||
|  | ||||
| void CArtHandler::loadComponents(CArtifact * art, const JsonNode & node) | ||||
| { | ||||
| 	if (!node["components"].isNull()) | ||||
| 	if(!node["components"].isNull()) | ||||
| 	{ | ||||
| 		for(const auto & component : node["components"].Vector()) | ||||
| 		{ | ||||
| 			VLC->identifiers()->requestIdentifier("artifact", component, [=](si32 id) | ||||
| 			VLC->identifiers()->requestIdentifier("artifact", component, [this, art](int32_t id) | ||||
| 			{ | ||||
| 				// when this code is called both combinational art as well as component are loaded | ||||
| 				// so it is safe to access any of them | ||||
| 				art->constituents.push_back(ArtifactID(id).toArtifact()); | ||||
| 				objects[id]->partOf.push_back(art); | ||||
| 				objects[id]->partOf.insert(art); | ||||
| 			}); | ||||
| 		} | ||||
| 	} | ||||
| 	if(!node["fusedComponents"].isNull()) | ||||
| 		art->setFused(node["fusedComponents"].Bool()); | ||||
| } | ||||
|  | ||||
| void CArtHandler::makeItCreatureArt(CArtifact * a, bool onlyCreature) | ||||
| @@ -767,8 +784,27 @@ bool CArtifactSet::hasArt(const ArtifactID & aid, bool onlyWorn, bool searchComb | ||||
| CArtifactSet::ArtPlacementMap CArtifactSet::putArtifact(const ArtifactPosition & slot, CArtifactInstance * art) | ||||
| { | ||||
| 	ArtPlacementMap resArtPlacement; | ||||
| 	const auto putToSlot = [this](const ArtifactPosition & targetSlot, CArtifactInstance * targetArt, bool locked) | ||||
| 	{ | ||||
| 		ArtSlotInfo * slotInfo; | ||||
| 		if(targetSlot == ArtifactPosition::TRANSITION_POS) | ||||
| 		{ | ||||
| 			slotInfo = &artifactsTransitionPos; | ||||
| 		} | ||||
| 		else if(ArtifactUtils::isSlotEquipment(targetSlot)) | ||||
| 		{ | ||||
| 			slotInfo = &artifactsWorn[targetSlot]; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			auto position = artifactsInBackpack.begin() + targetSlot - ArtifactPosition::BACKPACK_START; | ||||
| 			slotInfo = &(*artifactsInBackpack.emplace(position)); | ||||
| 		} | ||||
| 		slotInfo->artifact = targetArt; | ||||
| 		slotInfo->locked = locked; | ||||
| 	}; | ||||
|  | ||||
| 	setNewArtSlot(slot, art, false); | ||||
| 	putToSlot(slot, art, false); | ||||
| 	if(art->artType->isCombined() && ArtifactUtils::isSlotEquipment(slot)) | ||||
| 	{ | ||||
| 		const CArtifactInstance * mainPart = nullptr; | ||||
| @@ -789,7 +825,7 @@ CArtifactSet::ArtPlacementMap CArtifactSet::putArtifact(const ArtifactPosition & | ||||
| 					partSlot = ArtifactUtils::getArtAnyPosition(this, part.art->getTypeId()); | ||||
|  | ||||
| 				assert(ArtifactUtils::isSlotEquipment(partSlot)); | ||||
| 				setNewArtSlot(partSlot, part.art, true); | ||||
| 				putToSlot(partSlot, part.art, true); | ||||
| 				resArtPlacement.emplace(part.art, partSlot); | ||||
| 			} | ||||
| 			else | ||||
| @@ -877,7 +913,15 @@ const ArtSlotInfo * CArtifactSet::getSlot(const ArtifactPosition & pos) const | ||||
|  | ||||
| void CArtifactSet::lockSlot(const ArtifactPosition & pos) | ||||
| { | ||||
| 	setNewArtSlot(pos, nullptr, true); | ||||
| 	if(pos == ArtifactPosition::TRANSITION_POS) | ||||
| 		artifactsTransitionPos.locked = true; | ||||
| 	else if(ArtifactUtils::isSlotEquipment(pos)) | ||||
| 		artifactsWorn[pos].locked = true; | ||||
| 	else | ||||
| 	{ | ||||
| 		assert(artifactsInBackpack.size() > pos - ArtifactPosition::BACKPACK_START); | ||||
| 		(artifactsInBackpack.begin() + pos - ArtifactPosition::BACKPACK_START)->locked = true; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| bool CArtifactSet::isPositionFree(const ArtifactPosition & pos, bool onlyLockCheck) const | ||||
| @@ -891,28 +935,6 @@ bool CArtifactSet::isPositionFree(const ArtifactPosition & pos, bool onlyLockChe | ||||
| 	return true; //no slot means not used | ||||
| } | ||||
|  | ||||
| void CArtifactSet::setNewArtSlot(const ArtifactPosition & slot, CArtifactInstance * art, bool locked) | ||||
| { | ||||
| 	assert(!vstd::contains(artifactsWorn, slot)); | ||||
|  | ||||
| 	ArtSlotInfo * slotInfo; | ||||
| 	if(slot == ArtifactPosition::TRANSITION_POS) | ||||
| 	{ | ||||
| 		slotInfo = &artifactsTransitionPos; | ||||
| 	} | ||||
| 	else if(ArtifactUtils::isSlotEquipment(slot)) | ||||
| 	{ | ||||
| 		slotInfo =  &artifactsWorn[slot]; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		auto position = artifactsInBackpack.begin() + slot - ArtifactPosition::BACKPACK_START; | ||||
| 		slotInfo = &(*artifactsInBackpack.emplace(position)); | ||||
| 	} | ||||
| 	slotInfo->artifact = art; | ||||
| 	slotInfo->locked = locked; | ||||
| } | ||||
|  | ||||
| void CArtifactSet::artDeserializationFix(CBonusSystemNode *node) | ||||
| { | ||||
| 	for(auto & elem : artifactsWorn) | ||||
|   | ||||
| @@ -46,14 +46,19 @@ namespace ArtBearer | ||||
| class DLL_LINKAGE CCombinedArtifact | ||||
| { | ||||
| protected: | ||||
| 	CCombinedArtifact() = default; | ||||
| 	CCombinedArtifact() : fused(false) {}; | ||||
|  | ||||
| 	std::vector<const CArtifact*> constituents; // Artifacts IDs a combined artifact consists of, or nullptr. | ||||
| 	std::vector<const CArtifact*> partOf; // Reverse map of constituents - combined arts that include this art | ||||
| 	std::set<const CArtifact*> partOf; // Reverse map of constituents - combined arts that include this art | ||||
| 	bool fused; | ||||
|  | ||||
| public: | ||||
| 	bool isCombined() const; | ||||
| 	const std::vector<const CArtifact*> & getConstituents() const; | ||||
| 	const std::vector<const CArtifact*> & getPartOf() const; | ||||
| 	const std::set<const CArtifact*> & getPartOf() const; | ||||
| 	void setFused(bool isFused); | ||||
| 	bool isFused() const; | ||||
| 	bool hasParts() const; | ||||
| }; | ||||
|  | ||||
| class DLL_LINKAGE CScrollArtifact | ||||
| @@ -224,8 +229,6 @@ public: | ||||
| 	const CArtifactInstance * getCombinedArtWithPart(const ArtifactID & partId) const; | ||||
|  | ||||
| private: | ||||
| 	void setNewArtSlot(const ArtifactPosition & slot, CArtifactInstance * art, bool locked); | ||||
|  | ||||
| 	void serializeJsonHero(JsonSerializeFormat & handler); | ||||
| 	void serializeJsonCreature(JsonSerializeFormat & handler); | ||||
| 	void serializeJsonCommander(JsonSerializeFormat & handler); | ||||
|   | ||||
| @@ -44,6 +44,11 @@ bool CCombinedArtifactInstance::isPart(const CArtifactInstance * supposedPart) c | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| bool CCombinedArtifactInstance::hasParts() const | ||||
| { | ||||
| 	return !partsInfo.empty(); | ||||
| } | ||||
|  | ||||
| const std::vector<CCombinedArtifactInstance::PartInfo> & CCombinedArtifactInstance::getPartsInfo() const | ||||
| { | ||||
| 	return partsInfo; | ||||
|   | ||||
| @@ -38,6 +38,7 @@ public: | ||||
| 	void addPart(CArtifactInstance * art, const ArtifactPosition & slot); | ||||
| 	// Checks if supposed part inst is part of this combined art inst | ||||
| 	bool isPart(const CArtifactInstance * supposedPart) const; | ||||
| 	bool hasParts() const; | ||||
| 	const std::vector<PartInfo> & getPartsInfo() const; | ||||
| 	void addPlacementMap(const CArtifactSet::ArtPlacementMap & placementMap); | ||||
|  | ||||
|   | ||||
| @@ -1805,6 +1805,7 @@ void AssembledArtifact::applyGs(CGameState *gs) | ||||
| 	assert(hero); | ||||
| 	const auto transformedArt = hero->getArt(al.slot); | ||||
| 	assert(transformedArt); | ||||
| 	const auto builtArt = artId.toArtifact(); | ||||
| 	assert(vstd::contains_if(ArtifactUtils::assemblyPossibilities(hero, transformedArt->getTypeId()), [=](const CArtifact * art)->bool | ||||
| 		{ | ||||
| 			return art->getId() == builtArt->getId(); | ||||
| @@ -1816,14 +1817,11 @@ void AssembledArtifact::applyGs(CGameState *gs) | ||||
|  | ||||
| 	// Find slots for all involved artifacts | ||||
| 	std::vector<ArtifactPosition> slotsInvolved; | ||||
| 	CArtifactFittingSet artSet(*hero); | ||||
| 	for(const auto constituent : builtArt->getConstituents()) | ||||
| 	{ | ||||
| 		ArtifactPosition slot; | ||||
| 		if(transformedArt->getTypeId() == constituent->getId()) | ||||
| 			slot = transformedArtSlot; | ||||
| 		else | ||||
| 			slot = hero->getArtPos(constituent->getId(), false, false); | ||||
|  | ||||
| 		const auto slot = artSet.getArtPos(constituent->getId(), false, false); | ||||
| 		artSet.lockSlot(slot); | ||||
| 		assert(slot != ArtifactPosition::PRE_FIRST); | ||||
| 		slotsInvolved.emplace_back(slot); | ||||
| 	} | ||||
| @@ -1831,7 +1829,7 @@ void AssembledArtifact::applyGs(CGameState *gs) | ||||
|  | ||||
| 	// Find a slot for combined artifact | ||||
| 	al.slot = transformedArtSlot; | ||||
| 	for(const auto slot : slotsInvolved) | ||||
| 	for(const auto & slot : slotsInvolved) | ||||
| 	{ | ||||
| 		if(ArtifactUtils::isSlotEquipment(transformedArtSlot)) | ||||
| 		{ | ||||
| @@ -1854,15 +1852,18 @@ void AssembledArtifact::applyGs(CGameState *gs) | ||||
| 	} | ||||
|  | ||||
| 	// Delete parts from hero | ||||
| 	for(const auto slot : slotsInvolved) | ||||
| 	for(const auto & slot : slotsInvolved) | ||||
| 	{ | ||||
| 		const auto constituentInstance = hero->getArt(slot); | ||||
| 		gs->map->removeArtifactInstance(*hero, slot); | ||||
|  | ||||
| 		if(ArtifactUtils::isSlotEquipment(al.slot) && slot != al.slot) | ||||
| 			combinedArt->addPart(constituentInstance, slot); | ||||
| 		else | ||||
| 			combinedArt->addPart(constituentInstance, ArtifactPosition::PRE_FIRST); | ||||
| 		if(!combinedArt->artType->isFused()) | ||||
| 		{ | ||||
| 			if(ArtifactUtils::isSlotEquipment(al.slot) && slot != al.slot) | ||||
| 				combinedArt->addPart(constituentInstance, slot); | ||||
| 			else | ||||
| 				combinedArt->addPart(constituentInstance, ArtifactPosition::PRE_FIRST); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Put new combined artifacts | ||||
| @@ -2482,10 +2483,7 @@ void SetBankConfiguration::applyGs(CGameState *gs) | ||||
| const CArtifactInstance * ArtSlotInfo::getArt() const | ||||
| { | ||||
| 	if(locked) | ||||
| 	{ | ||||
| 		logNetwork->warn("ArtifactLocation::getArt: This location is locked!"); | ||||
| 		return nullptr; | ||||
| 	} | ||||
| 	return artifact; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1108,8 +1108,8 @@ struct DLL_LINKAGE BulkMoveArtifacts : CArtifactOperationPack | ||||
|  | ||||
| struct DLL_LINKAGE AssembledArtifact : CArtifactOperationPack | ||||
| { | ||||
| 	ArtifactLocation al; //where assembly will be put | ||||
| 	const CArtifact * builtArt; | ||||
| 	ArtifactLocation al; | ||||
| 	ArtifactID artId; | ||||
|  | ||||
| 	void applyGs(CGameState * gs) override; | ||||
|  | ||||
| @@ -1118,7 +1118,7 @@ struct DLL_LINKAGE AssembledArtifact : CArtifactOperationPack | ||||
| 	template <typename Handler> void serialize(Handler & h) | ||||
| 	{ | ||||
| 		h & al; | ||||
| 		h & builtArt; | ||||
| 		h & artId; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -2913,7 +2913,7 @@ bool CGameHandler::assembleArtifacts(ObjectInstanceID heroID, ArtifactPosition a | ||||
|  | ||||
| 		AssembledArtifact aa; | ||||
| 		aa.al = dstLoc; | ||||
| 		aa.builtArt = combinedArt; | ||||
| 		aa.artId = assembleTo; | ||||
| 		sendAndApply(aa); | ||||
| 	} | ||||
| 	else | ||||
| @@ -2921,6 +2921,9 @@ bool CGameHandler::assembleArtifacts(ObjectInstanceID heroID, ArtifactPosition a | ||||
| 		if(!destArtifact->isCombined()) | ||||
| 			COMPLAIN_RET("assembleArtifacts: Artifact being attempted to disassemble is not a combined artifact!"); | ||||
|  | ||||
| 		if(!destArtifact->hasParts()) | ||||
| 			COMPLAIN_RET("assembleArtifacts: Artifact being attempted to disassemble is fused combined artifact!"); | ||||
|  | ||||
| 		if(ArtifactUtils::isSlotBackpack(artifactSlot) | ||||
| 			&& !ArtifactUtils::isBackpackFreeSlots(hero, destArtifact->artType->getConstituents().size() - 1)) | ||||
| 			COMPLAIN_RET("assembleArtifacts: Artifact being attempted to disassemble but backpack is full!"); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user