mirror of
				https://github.com/vcmi/vcmi.git
				synced 2025-10-31 00:07:39 +02:00 
			
		
		
		
	Switching costume
This commit is contained in:
		| @@ -195,8 +195,6 @@ void CCallback::scrollBackpackArtifacts(ObjectInstanceID hero, bool left) | |||||||
|  |  | ||||||
| void CCallback::manageHeroCostume(ObjectInstanceID hero, size_t costumeIndex, bool saveCostume) | void CCallback::manageHeroCostume(ObjectInstanceID hero, size_t costumeIndex, bool saveCostume) | ||||||
| { | { | ||||||
| 	assert(costumeIndex < GameConstants::HERO_COSTUMES_ARTIFACTS); |  | ||||||
|  |  | ||||||
| 	ManageEquippedArtifacts mea(hero, costumeIndex, saveCostume); | 	ManageEquippedArtifacts mea(hero, costumeIndex, saveCostume); | ||||||
| 	sendRequest(&mea); | 	sendRequest(&mea); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -314,12 +314,20 @@ CKeyShortcut::CKeyShortcut(EShortcut key) | |||||||
| { | { | ||||||
| } | } | ||||||
|  |  | ||||||
|  | CKeyShortcut::CKeyShortcut(const EShortcut & key, const KeyPressedFunctor & keyPressedCallback) | ||||||
|  | 	: CKeyShortcut(key) | ||||||
|  | { | ||||||
|  | 	this->keyPressedCallback = keyPressedCallback; | ||||||
|  | } | ||||||
|  |  | ||||||
| void CKeyShortcut::keyPressed(EShortcut key) | void CKeyShortcut::keyPressed(EShortcut key) | ||||||
| { | { | ||||||
| 	if( assignedKey == key && assignedKey != EShortcut::NONE && !shortcutPressed) | 	if( assignedKey == key && assignedKey != EShortcut::NONE && !shortcutPressed) | ||||||
| 	{ | 	{ | ||||||
| 		shortcutPressed = true; | 		shortcutPressed = true; | ||||||
| 		clickPressed(GH.getCursorPosition()); | 		clickPressed(GH.getCursorPosition()); | ||||||
|  | 		if(keyPressedCallback) | ||||||
|  | 			keyPressedCallback(); | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -133,14 +133,19 @@ public: | |||||||
| /// Classes wanting use it should have it as one of their base classes | /// Classes wanting use it should have it as one of their base classes | ||||||
| class CKeyShortcut : public virtual CIntObject | class CKeyShortcut : public virtual CIntObject | ||||||
| { | { | ||||||
| 	bool shortcutPressed; |  | ||||||
| public: | public: | ||||||
|  | 	using KeyPressedFunctor = std::function<void()>; | ||||||
|  |  | ||||||
| 	EShortcut assignedKey; | 	EShortcut assignedKey; | ||||||
| 	CKeyShortcut(); | 	CKeyShortcut(); | ||||||
| 	CKeyShortcut(EShortcut key); | 	CKeyShortcut(EShortcut key); | ||||||
|  | 	CKeyShortcut(const EShortcut & key, const KeyPressedFunctor & keyPressedCallback); | ||||||
| 	void keyPressed(EShortcut key) override; | 	void keyPressed(EShortcut key) override; | ||||||
| 	void keyReleased(EShortcut key) override; | 	void keyReleased(EShortcut key) override; | ||||||
|  |  | ||||||
|  | private: | ||||||
|  | 	bool shortcutPressed; | ||||||
|  | 	KeyPressedFunctor keyPressedCallback; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| class WindowBase : public CIntObject | class WindowBase : public CIntObject | ||||||
|   | |||||||
| @@ -18,7 +18,7 @@ | |||||||
| #include "../../CCallback.h" | #include "../../CCallback.h" | ||||||
| #include "../../lib/networkPacks/ArtifactLocation.h" | #include "../../lib/networkPacks/ArtifactLocation.h" | ||||||
|  |  | ||||||
| CArtifactsOfHeroMain::CArtifactsOfHeroMain(const Point & position, bool costumesEnabled) | CArtifactsOfHeroMain::CArtifactsOfHeroMain(const Point & position) | ||||||
| { | { | ||||||
| 	init( | 	init( | ||||||
| 		std::bind(&CArtifactsOfHeroBase::clickPrassedArtPlace, this, _1, _2), | 		std::bind(&CArtifactsOfHeroBase::clickPrassedArtPlace, this, _1, _2), | ||||||
| @@ -26,21 +26,6 @@ CArtifactsOfHeroMain::CArtifactsOfHeroMain(const Point & position, bool costumes | |||||||
| 		position, | 		position, | ||||||
| 		std::bind(&CArtifactsOfHeroBase::scrollBackpack, this, _1)); | 		std::bind(&CArtifactsOfHeroBase::scrollBackpack, this, _1)); | ||||||
| 	addGestureCallback(std::bind(&CArtifactsOfHeroBase::gestureArtPlace, this, _1, _2)); | 	addGestureCallback(std::bind(&CArtifactsOfHeroBase::gestureArtPlace, this, _1, _2)); | ||||||
|  |  | ||||||
| 	if(costumesEnabled) |  | ||||||
| 	{ |  | ||||||
| 		size_t costumeIndex = 0; |  | ||||||
| 		for(const auto & hotkey : hotkeys) |  | ||||||
| 		{ |  | ||||||
| 			auto keyProc = costumesSwitchers.emplace_back(std::make_shared<CKeyShortcutWrapper>(hotkey, |  | ||||||
| 				[this, hotkey, costumeIndex]() |  | ||||||
| 				{ |  | ||||||
| 					CArtifactsOfHeroMain::onCostumeSelect(costumeIndex); |  | ||||||
| 				})); |  | ||||||
| 			keyProc->addUsedEvents(AEventsReceiver::KEYBOARD); |  | ||||||
| 			costumeIndex++; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
|  |  | ||||||
| CArtifactsOfHeroMain::~CArtifactsOfHeroMain() | CArtifactsOfHeroMain::~CArtifactsOfHeroMain() | ||||||
| @@ -48,19 +33,17 @@ CArtifactsOfHeroMain::~CArtifactsOfHeroMain() | |||||||
| 	CArtifactsOfHeroBase::putBackPickedArtifact(); | 	CArtifactsOfHeroBase::putBackPickedArtifact(); | ||||||
| } | } | ||||||
|  |  | ||||||
| void CArtifactsOfHeroMain::onCostumeSelect(const size_t costumeIndex) | void CArtifactsOfHeroMain::enableArtifactsCostumeSwitcher() | ||||||
| { | { | ||||||
| 	LOCPLINT->cb->manageHeroCostume(getHero()->id, costumeIndex, GH.isKeyboardCtrlDown()); | 	size_t costumeIdx = 0; | ||||||
| } | 	for(const auto & hotkey : costumesSwitcherHotkeys) | ||||||
|  | 	{ | ||||||
| CArtifactsOfHeroMain::CKeyShortcutWrapper::CKeyShortcutWrapper(const EShortcut & key, const KeyPressedFunctor & onCostumeSelect) | 		auto keyProc = costumesSwitcherProcessors.emplace_back(std::make_shared<CKeyShortcut>(hotkey, | ||||||
| 	: CKeyShortcut(key) | 			[this, costumeIdx]() | ||||||
| 	, onCostumeSelect(onCostumeSelect) | 			{ | ||||||
| { | 				LOCPLINT->cb->manageHeroCostume(getHero()->id, costumeIdx, GH.isKeyboardCtrlDown()); | ||||||
| } | 			})); | ||||||
|  | 		keyProc->addUsedEvents(AEventsReceiver::KEYBOARD); | ||||||
| void CArtifactsOfHeroMain::CKeyShortcutWrapper::clickPressed(const Point & cursorPosition) | 		costumeIdx++; | ||||||
| { | 	} | ||||||
| 	if(onCostumeSelect) |  | ||||||
| 		onCostumeSelect(); |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -16,24 +16,12 @@ | |||||||
| class CArtifactsOfHeroMain : public CArtifactsOfHeroBase | class CArtifactsOfHeroMain : public CArtifactsOfHeroBase | ||||||
| { | { | ||||||
| public: | public: | ||||||
| 	CArtifactsOfHeroMain(const Point & position, bool costumesEnabled = false); | 	CArtifactsOfHeroMain(const Point & position); | ||||||
| 	~CArtifactsOfHeroMain() override; | 	~CArtifactsOfHeroMain() override; | ||||||
|  | 	void enableArtifactsCostumeSwitcher(); | ||||||
|  |  | ||||||
| private: | private: | ||||||
| 	// TODO may be removed if CKeyShortcut supports callbacks | 	const std::vector<EShortcut> costumesSwitcherHotkeys = | ||||||
| 	class CKeyShortcutWrapper : public CKeyShortcut |  | ||||||
| 	{ |  | ||||||
| 	public: |  | ||||||
| 		using KeyPressedFunctor = std::function<void()>; |  | ||||||
|  |  | ||||||
| 		CKeyShortcutWrapper(const EShortcut & key, const KeyPressedFunctor & onCostumeSelect); |  | ||||||
| 		void clickPressed(const Point & cursorPosition) override; |  | ||||||
|  |  | ||||||
| 	private: |  | ||||||
| 		KeyPressedFunctor onCostumeSelect; |  | ||||||
| 	}; |  | ||||||
|  |  | ||||||
| 	const std::array<EShortcut, GameConstants::HERO_COSTUMES_ARTIFACTS> hotkeys = |  | ||||||
| 	{ | 	{ | ||||||
| 		EShortcut::HERO_COSTUME_0, | 		EShortcut::HERO_COSTUME_0, | ||||||
| 		EShortcut::HERO_COSTUME_1, | 		EShortcut::HERO_COSTUME_1, | ||||||
| @@ -46,7 +34,5 @@ private: | |||||||
| 		EShortcut::HERO_COSTUME_8, | 		EShortcut::HERO_COSTUME_8, | ||||||
| 		EShortcut::HERO_COSTUME_9 | 		EShortcut::HERO_COSTUME_9 | ||||||
| 	}; | 	}; | ||||||
| 	std::vector<std::shared_ptr<CKeyShortcutWrapper>> costumesSwitchers; | 	std::vector<std::shared_ptr<CKeyShortcut>> costumesSwitcherProcessors; | ||||||
|  |  | ||||||
| 	void onCostumeSelect(const size_t costumeIndex); |  | ||||||
| }; | }; | ||||||
|   | |||||||
| @@ -218,9 +218,10 @@ void CHeroWindow::update(const CGHeroInstance * hero, bool redrawNeeded) | |||||||
| 		} | 		} | ||||||
| 		if(!arts) | 		if(!arts) | ||||||
| 		{ | 		{ | ||||||
| 			arts = std::make_shared<CArtifactsOfHeroMain>(Point(-65, -8), true); | 			arts = std::make_shared<CArtifactsOfHeroMain>(Point(-65, -8)); | ||||||
| 			arts->setHero(curHero); | 			arts->setHero(curHero); | ||||||
| 			addSetAndCallbacks(arts); | 			addSetAndCallbacks(arts); | ||||||
|  | 			enableArtifactsCostumeSwitcher(); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		int serial = LOCPLINT->cb->getHeroSerial(curHero, false); | 		int serial = LOCPLINT->cb->getHeroSerial(curHero, false); | ||||||
|   | |||||||
| @@ -343,6 +343,20 @@ void CWindowWithArtifacts::deactivate() | |||||||
| 	CWindowObject::deactivate(); | 	CWindowObject::deactivate(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void CWindowWithArtifacts::enableArtifactsCostumeSwitcher() | ||||||
|  | { | ||||||
|  | 	for(auto artSet : artSets) | ||||||
|  | 		std::visit( | ||||||
|  | 			[](auto artSetWeak) | ||||||
|  | 			{ | ||||||
|  | 				if constexpr(std::is_same_v<decltype(artSetWeak), std::weak_ptr<CArtifactsOfHeroMain>>) | ||||||
|  | 				{ | ||||||
|  | 					const auto artSetPtr = artSetWeak.lock(); | ||||||
|  | 					artSetPtr->enableArtifactsCostumeSwitcher(); | ||||||
|  | 				} | ||||||
|  | 			}, artSet); | ||||||
|  | } | ||||||
|  |  | ||||||
| void CWindowWithArtifacts::artifactRemoved(const ArtifactLocation & artLoc) | void CWindowWithArtifacts::artifactRemoved(const ArtifactLocation & artLoc) | ||||||
| { | { | ||||||
| 	update(); | 	update(); | ||||||
|   | |||||||
| @@ -42,6 +42,7 @@ public: | |||||||
| 	void gestureArtPlaceHero(const CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition); | 	void gestureArtPlaceHero(const CArtifactsOfHeroBase & artsInst, CArtPlace & artPlace, const Point & cursorPosition); | ||||||
| 	void activate() override; | 	void activate() override; | ||||||
| 	void deactivate() override; | 	void deactivate() override; | ||||||
|  | 	void enableArtifactsCostumeSwitcher(); | ||||||
|  |  | ||||||
| 	virtual void artifactRemoved(const ArtifactLocation & artLoc); | 	virtual void artifactRemoved(const ArtifactLocation & artLoc); | ||||||
| 	virtual void artifactMoved(const ArtifactLocation & srcLoc, const ArtifactLocation & destLoc, bool withRedraw); | 	virtual void artifactMoved(const ArtifactLocation & srcLoc, const ArtifactLocation & destLoc, bool withRedraw); | ||||||
|   | |||||||
| @@ -52,7 +52,7 @@ DLL_LINKAGE const std::vector<ArtifactPosition> & ArtifactUtils::unmovableSlots( | |||||||
| 	return positions; | 	return positions; | ||||||
| } | } | ||||||
|  |  | ||||||
| DLL_LINKAGE const std::vector<ArtifactPosition> & ArtifactUtils::constituentWornSlots() | DLL_LINKAGE const std::vector<ArtifactPosition> & ArtifactUtils::commonWornSlots() | ||||||
| { | { | ||||||
| 	static const std::vector<ArtifactPosition> positions = | 	static const std::vector<ArtifactPosition> positions = | ||||||
| 	{ | 	{ | ||||||
|   | |||||||
| @@ -30,7 +30,7 @@ namespace ArtifactUtils | |||||||
| 	DLL_LINKAGE ArtifactPosition getArtBackpackPosition(const CArtifactSet * target, const ArtifactID & aid); | 	DLL_LINKAGE ArtifactPosition getArtBackpackPosition(const CArtifactSet * target, const ArtifactID & aid); | ||||||
| 	// TODO: Make this constexpr when the toolset is upgraded | 	// TODO: Make this constexpr when the toolset is upgraded | ||||||
| 	DLL_LINKAGE const std::vector<ArtifactPosition> & unmovableSlots(); | 	DLL_LINKAGE const std::vector<ArtifactPosition> & unmovableSlots(); | ||||||
| 	DLL_LINKAGE const std::vector<ArtifactPosition> & constituentWornSlots(); | 	DLL_LINKAGE const std::vector<ArtifactPosition> & commonWornSlots(); | ||||||
| 	DLL_LINKAGE const std::vector<ArtifactPosition> & allWornSlots(); | 	DLL_LINKAGE const std::vector<ArtifactPosition> & allWornSlots(); | ||||||
| 	DLL_LINKAGE const std::vector<ArtifactPosition> & commanderSlots(); | 	DLL_LINKAGE const std::vector<ArtifactPosition> & commanderSlots(); | ||||||
| 	DLL_LINKAGE bool isArtRemovable(const std::pair<ArtifactPosition, ArtSlotInfo> & slot); | 	DLL_LINKAGE bool isArtRemovable(const std::pair<ArtifactPosition, ArtSlotInfo> & slot); | ||||||
|   | |||||||
| @@ -1086,6 +1086,14 @@ CArtifactFittingSet::CArtifactFittingSet(ArtBearer::ArtBearer Bearer): | |||||||
| { | { | ||||||
| } | } | ||||||
|  |  | ||||||
|  | CArtifactFittingSet::CArtifactFittingSet(const CArtifactSet & artSet) | ||||||
|  | 	: CArtifactFittingSet(artSet.bearerType()) | ||||||
|  | { | ||||||
|  | 	artifactsWorn = artSet.artifactsWorn; | ||||||
|  | 	artifactsInBackpack = artSet.artifactsInBackpack; | ||||||
|  | 	artifactsTransitionPos = artSet.artifactsTransitionPos; | ||||||
|  | } | ||||||
|  |  | ||||||
| ArtBearer::ArtBearer CArtifactFittingSet::bearerType() const | ArtBearer::ArtBearer CArtifactFittingSet::bearerType() const | ||||||
| { | { | ||||||
| 	return this->Bearer; | 	return this->Bearer; | ||||||
|   | |||||||
| @@ -249,6 +249,7 @@ class DLL_LINKAGE CArtifactFittingSet : public CArtifactSet | |||||||
| { | { | ||||||
| public: | public: | ||||||
| 	CArtifactFittingSet(ArtBearer::ArtBearer Bearer); | 	CArtifactFittingSet(ArtBearer::ArtBearer Bearer); | ||||||
|  | 	CArtifactFittingSet(const CArtifactSet & artSet); | ||||||
| 	ArtBearer::ArtBearer bearerType() const override; | 	ArtBearer::ArtBearer bearerType() const override; | ||||||
|  |  | ||||||
| protected: | protected: | ||||||
|   | |||||||
| @@ -1075,7 +1075,7 @@ void ChangeObjectVisitors::applyGs(CGameState * gs) const | |||||||
| void ChangeArtifactsCostume::applyGs(CGameState * gs) const | void ChangeArtifactsCostume::applyGs(CGameState * gs) const | ||||||
| { | { | ||||||
| 	auto & allCostumes = gs->getPlayerState(player)->costumesArtifacts; | 	auto & allCostumes = gs->getPlayerState(player)->costumesArtifacts; | ||||||
| 	if(auto & costume = allCostumes.find(costumeIdx); costume != allCostumes.end()) | 	if(const auto & costume = allCostumes.find(costumeIdx); costume != allCostumes.end()) | ||||||
| 		costume->second = costumeSet; | 		costume->second = costumeSet; | ||||||
| 	else | 	else | ||||||
| 		allCostumes.emplace(costumeIdx, costumeSet); | 		allCostumes.emplace(costumeIdx, costumeSet); | ||||||
| @@ -1802,69 +1802,47 @@ void MoveArtifact::applyGs(CGameState * gs) | |||||||
|  |  | ||||||
| void BulkMoveArtifacts::applyGs(CGameState * gs) | void BulkMoveArtifacts::applyGs(CGameState * gs) | ||||||
| { | { | ||||||
| 	enum class EBulkArtsOp | 	const auto bulkArtsRemove = [](std::vector<LinkedSlots> & artsPack, CArtifactSet & artSet) | ||||||
| 	{ | 	{ | ||||||
| 		BULK_MOVE, | 		std::vector<ArtifactPosition> packToRemove; | ||||||
| 		BULK_REMOVE, | 		for(const auto & slotsPair : artsPack) | ||||||
| 		BULK_PUT | 			packToRemove.push_back(slotsPair.srcPos); | ||||||
|  | 		std::sort(packToRemove.begin(), packToRemove.end(), [](const ArtifactPosition & slot0, const ArtifactPosition & slot1) -> bool | ||||||
|  | 			{ | ||||||
|  | 				return slot0.num > slot1.num; | ||||||
|  | 			}); | ||||||
|  |  | ||||||
|  | 		for(const auto & slot : packToRemove) | ||||||
|  | 		{ | ||||||
|  | 			auto * art = artSet.getArt(slot); | ||||||
|  | 			assert(art); | ||||||
|  | 			art->removeFrom(artSet, slot); | ||||||
|  | 		} | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
| 	auto bulkArtsOperation = [this, gs](std::vector<LinkedSlots> & artsPack,  | 	const auto bulkArtsPut = [](std::vector<LinkedSlots> & artsPack, CArtifactSet & initArtSet, CArtifactSet & dstArtSet) | ||||||
| 		CArtifactSet & artSet, EBulkArtsOp operation) -> void |  | ||||||
| 	{ | 	{ | ||||||
| 		int numBackpackArtifactsMoved = 0; | 		for(const auto & slotsPair : artsPack) | ||||||
| 		for(auto & slot : artsPack) |  | ||||||
| 		{ | 		{ | ||||||
| 			// When an object gets removed from the backpack, the backpack shrinks | 			auto * art = initArtSet.getArt(slotsPair.srcPos); | ||||||
| 			// 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(ArtifactUtils::isSlotBackpack(srcPos) && (operation != EBulkArtsOp::BULK_PUT)) |  | ||||||
| 			{ |  | ||||||
| 				srcPos = ArtifactPosition(srcPos.num - numBackpackArtifactsMoved); |  | ||||||
| 			} |  | ||||||
| 			auto * art = artSet.getArt(srcPos); |  | ||||||
| 			assert(art); | 			assert(art); | ||||||
| 			switch(operation) | 			art->putAt(dstArtSet, slotsPair.dstPos); | ||||||
| 			{ |  | ||||||
| 			case EBulkArtsOp::BULK_MOVE: |  | ||||||
| 				art->move(artSet, srcPos, *gs->getArtSet(ArtifactLocation(dstArtHolder, dstCreature)), slot.dstPos); |  | ||||||
| 				break; |  | ||||||
| 			case EBulkArtsOp::BULK_REMOVE: |  | ||||||
| 				art->removeFrom(artSet, srcPos); |  | ||||||
| 				break; |  | ||||||
| 			case EBulkArtsOp::BULK_PUT: |  | ||||||
| 				art->putAt(*gs->getArtSet(ArtifactLocation(srcArtHolder, srcCreature)), slot.dstPos); |  | ||||||
| 				break; |  | ||||||
| 			default: |  | ||||||
| 				break; |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 			if(srcPos >= ArtifactPosition::BACKPACK_START) |  | ||||||
| 			{ |  | ||||||
| 				numBackpackArtifactsMoved++; |  | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
| 	}; | 	}; | ||||||
| 	 | 	 | ||||||
| 	auto * leftSet = gs->getArtSet(ArtifactLocation(srcArtHolder, srcCreature)); | 	auto * leftSet = gs->getArtSet(ArtifactLocation(srcArtHolder, srcCreature)); | ||||||
| 	if(swap) | 	assert(leftSet); | ||||||
|  | 	auto * rightSet = gs->getArtSet(ArtifactLocation(dstArtHolder, dstCreature)); | ||||||
|  | 	assert(rightSet); | ||||||
|  | 	CArtifactFittingSet artInitialSetLeft(*leftSet); | ||||||
|  | 	bulkArtsRemove(artsPack0, *leftSet); | ||||||
|  | 	if(!artsPack1.empty()) | ||||||
| 	{ | 	{ | ||||||
| 		// Swap | 		CArtifactFittingSet artInitialSetRight(*rightSet); | ||||||
| 		auto * rightSet = gs->getArtSet(ArtifactLocation(dstArtHolder, dstCreature)); | 		bulkArtsRemove(artsPack1, *rightSet); | ||||||
| 		CArtifactFittingSet artFittingSet(leftSet->bearerType()); | 		bulkArtsPut(artsPack1, artInitialSetRight, *leftSet); | ||||||
|  |  | ||||||
| 		artFittingSet.artifactsWorn = rightSet->artifactsWorn; |  | ||||||
| 		artFittingSet.artifactsInBackpack = rightSet->artifactsInBackpack; |  | ||||||
|  |  | ||||||
| 		bulkArtsOperation(artsPack1, *rightSet, EBulkArtsOp::BULK_REMOVE); |  | ||||||
| 		bulkArtsOperation(artsPack0, *leftSet, EBulkArtsOp::BULK_MOVE); |  | ||||||
| 		bulkArtsOperation(artsPack1, artFittingSet, EBulkArtsOp::BULK_PUT); |  | ||||||
| 	} |  | ||||||
| 	else |  | ||||||
| 	{ |  | ||||||
| 		bulkArtsOperation(artsPack0, *leftSet, EBulkArtsOp::BULK_MOVE); |  | ||||||
| 	} | 	} | ||||||
|  | 	bulkArtsPut(artsPack0, artInitialSetLeft, *rightSet); | ||||||
| } | } | ||||||
|  |  | ||||||
| void AssembledArtifact::applyGs(CGameState *gs) | void AssembledArtifact::applyGs(CGameState *gs) | ||||||
|   | |||||||
| @@ -1291,8 +1291,8 @@ struct DLL_LINKAGE ChangeObjectVisitors : public CPackForClient | |||||||
| struct DLL_LINKAGE ChangeArtifactsCostume : public CPackForClient | struct DLL_LINKAGE ChangeArtifactsCostume : public CPackForClient | ||||||
| { | { | ||||||
| 	std::map<ArtifactPosition, ArtifactID> costumeSet; | 	std::map<ArtifactPosition, ArtifactID> costumeSet; | ||||||
| 	size_t costumeIdx; | 	size_t costumeIdx = 0; | ||||||
| 	const PlayerColor player; | 	const PlayerColor player = PlayerColor::NEUTRAL; | ||||||
|  |  | ||||||
| 	void applyGs(CGameState * gs) const; | 	void applyGs(CGameState * gs) const; | ||||||
| 	void visitTyped(ICPackVisitor & visitor) override; | 	void visitTyped(ICPackVisitor & visitor) override; | ||||||
|   | |||||||
| @@ -2896,20 +2896,74 @@ bool CGameHandler::saveArtifactsCostume(const PlayerColor & player, const Object | |||||||
| { | { | ||||||
| 	auto artSet = getArtSet(heroID); | 	auto artSet = getArtSet(heroID); | ||||||
| 	COMPLAIN_RET_FALSE_IF(artSet == nullptr, "saveArtifactsCostume: wrong hero's ID"); | 	COMPLAIN_RET_FALSE_IF(artSet == nullptr, "saveArtifactsCostume: wrong hero's ID"); | ||||||
| 	COMPLAIN_RET_FALSE_IF(costumeIdx >= GameConstants::HERO_COSTUMES_ARTIFACTS, "saveArtifactsCostume: wrong costume index"); |  | ||||||
|  |  | ||||||
| 	ChangeArtifactsCostume costume(player, costumeIdx); | 	ChangeArtifactsCostume costume(player, costumeIdx); | ||||||
| 	for(const auto & slot : ArtifactUtils::constituentWornSlots()) | 	for(const auto & slot : ArtifactUtils::commonWornSlots()) | ||||||
| 	{ | 	{ | ||||||
| 		if(const auto & slotInfo = artSet->getSlot(slot)) | 		if(const auto slotInfo = artSet->getSlot(slot); slotInfo != nullptr && !slotInfo->locked) | ||||||
| 			if(!slotInfo->locked) | 			costume.costumeSet.emplace(slot, slotInfo->getArt()->getTypeId()); | ||||||
| 				costume.costumeSet.emplace(slot, slotInfo->getArt()->getTypeId()); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	sendAndApply(&costume); | 	sendAndApply(&costume); | ||||||
| 	return true; | 	return true; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | bool CGameHandler::switchArtifactsCostume(const PlayerColor & player, const ObjectInstanceID heroID, size_t costumeIdx) | ||||||
|  | { | ||||||
|  | 	const auto artSet = getArtSet(heroID); | ||||||
|  | 	COMPLAIN_RET_FALSE_IF(artSet == nullptr, "switchArtifactsCostume: wrong hero's ID"); | ||||||
|  | 	const auto playerState = getPlayerState(player); | ||||||
|  | 	COMPLAIN_RET_FALSE_IF(playerState == nullptr, "switchArtifactsCostume: wrong player"); | ||||||
|  |  | ||||||
|  | 	if(auto costume = playerState->costumesArtifacts.find(costumeIdx); costume != playerState->costumesArtifacts.end()) | ||||||
|  | 	{ | ||||||
|  | 		CArtifactFittingSet artFittingSet(*artSet); | ||||||
|  | 		BulkMoveArtifacts bma(player, heroID, heroID, false); | ||||||
|  | 		auto costumeArtMap = costume->second; | ||||||
|  | 		auto estimateBackpackSize = artSet->artifactsInBackpack.size(); | ||||||
|  |  | ||||||
|  | 		// First, find those artifacts that are already in place | ||||||
|  | 		for(const auto & slot : ArtifactUtils::commonWornSlots()) | ||||||
|  | 		{ | ||||||
|  | 			if(const auto * slotInfo = artFittingSet.getSlot(slot); slotInfo != nullptr && !slotInfo->locked) | ||||||
|  | 				if(const auto artPos = costumeArtMap.find(slot); artPos != costumeArtMap.end() && artPos->second == slotInfo->getArt()->getTypeId()) | ||||||
|  | 				{ | ||||||
|  | 					costumeArtMap.erase(artPos); | ||||||
|  | 					artFittingSet.removeArtifact(slot); | ||||||
|  | 				} | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		// Second, find the necessary artifacts for the costume | ||||||
|  | 		for(const auto & artPos : costumeArtMap) | ||||||
|  | 		{ | ||||||
|  | 			if(const auto availableArts = artFittingSet.getAllArtPositions(artPos.second, false, false, false); !availableArts.empty()) | ||||||
|  | 			{ | ||||||
|  | 				bma.artsPack0.emplace_back(BulkMoveArtifacts::LinkedSlots | ||||||
|  | 					{ | ||||||
|  | 						artSet->getSlotByInstance(artFittingSet.getArt(availableArts.front())), | ||||||
|  | 						artPos.first | ||||||
|  | 					}); | ||||||
|  | 				artFittingSet.removeArtifact(availableArts.front()); | ||||||
|  | 				if(ArtifactUtils::isSlotBackpack(availableArts.front())) | ||||||
|  | 					estimateBackpackSize--; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Third, put unnecessary artifacts into backpack | ||||||
|  | 		for(const auto & slot : ArtifactUtils::commonWornSlots()) | ||||||
|  | 			if(artFittingSet.getArt(slot)) | ||||||
|  | 			{ | ||||||
|  | 				bma.artsPack0.emplace_back(BulkMoveArtifacts::LinkedSlots{slot, ArtifactPosition::BACKPACK_START}); | ||||||
|  | 				estimateBackpackSize++; | ||||||
|  | 			} | ||||||
|  | 		 | ||||||
|  | 		const auto backpackCap = VLC->settings()->getInteger(EGameSettings::HEROES_BACKPACK_CAP); | ||||||
|  | 		if((backpackCap < 0 || estimateBackpackSize <= backpackCap) && !bma.artsPack0.empty()) | ||||||
|  | 			sendAndApply(&bma); | ||||||
|  | 	} | ||||||
|  | 	return true; | ||||||
|  | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Assembles or disassembles a combination artifact. |  * Assembles or disassembles a combination artifact. | ||||||
|  * @param heroID ID of hero holding the artifact(s). |  * @param heroID ID of hero holding the artifact(s). | ||||||
|   | |||||||
| @@ -131,6 +131,7 @@ public: | |||||||
| 	bool bulkMoveArtifacts(const PlayerColor & player, ObjectInstanceID srcId, ObjectInstanceID dstId, bool swap, bool equipped, bool backpack); | 	bool bulkMoveArtifacts(const PlayerColor & player, ObjectInstanceID srcId, ObjectInstanceID dstId, bool swap, bool equipped, bool backpack); | ||||||
| 	bool scrollBackpackArtifacts(const PlayerColor & player, const ObjectInstanceID heroID, bool left); | 	bool scrollBackpackArtifacts(const PlayerColor & player, const ObjectInstanceID heroID, bool left); | ||||||
| 	bool saveArtifactsCostume(const PlayerColor & player, const ObjectInstanceID heroID, size_t costumeIdx); | 	bool saveArtifactsCostume(const PlayerColor & player, const ObjectInstanceID heroID, size_t costumeIdx); | ||||||
|  | 	bool switchArtifactsCostume(const PlayerColor & player, const ObjectInstanceID heroID, size_t costumeIdx); | ||||||
| 	bool eraseArtifactByClient(const ArtifactLocation & al); | 	bool eraseArtifactByClient(const ArtifactLocation & al); | ||||||
| 	void synchronizeArtifactHandlerLists(); | 	void synchronizeArtifactHandlerLists(); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -183,8 +183,9 @@ void ApplyGhNetPackVisitor::visitManageEquippedArtifacts(ManageEquippedArtifacts | |||||||
| { | { | ||||||
| 	gh.throwIfWrongOwner(&pack, pack.artHolder); | 	gh.throwIfWrongOwner(&pack, pack.artHolder); | ||||||
| 	if(pack.saveCostume) | 	if(pack.saveCostume) | ||||||
| 		gh.saveArtifactsCostume(pack.player, pack.artHolder, pack.costumeIdx); | 		result = gh.saveArtifactsCostume(pack.player, pack.artHolder, pack.costumeIdx); | ||||||
| 	result = true; | 	else | ||||||
|  | 		result = gh.switchArtifactsCostume(pack.player, pack.artHolder, pack.costumeIdx); | ||||||
| } | } | ||||||
|  |  | ||||||
| void ApplyGhNetPackVisitor::visitAssembleArtifacts(AssembleArtifacts & pack) | void ApplyGhNetPackVisitor::visitAssembleArtifacts(AssembleArtifacts & pack) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user