mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-13 19:54:17 +02:00
Merge pull request #1112 from SoundSSGood/bulk-move-swap-artifacts-rev2
Bulk move and swap artifacts rev2
This commit is contained in:
@@ -181,6 +181,12 @@ bool CCallback::assembleArtifacts (const CGHeroInstance * hero, ArtifactPosition
|
||||
return true;
|
||||
}
|
||||
|
||||
void CCallback::bulkMoveArtifacts(ObjectInstanceID srcHero, ObjectInstanceID dstHero, bool swap)
|
||||
{
|
||||
BulkExchangeArtifacts bma(srcHero, dstHero, swap);
|
||||
sendRequest(&bma);
|
||||
}
|
||||
|
||||
bool CCallback::buildBuilding(const CGTownInstance *town, BuildingID buildingID)
|
||||
{
|
||||
if(town->tempOwner!=player)
|
||||
|
@@ -94,6 +94,10 @@ public:
|
||||
virtual int bulkSplitStack(ObjectInstanceID armyId, SlotID srcSlot, int howMany = 1) = 0;
|
||||
virtual int bulkSmartSplitStack(ObjectInstanceID armyId, SlotID srcSlot) = 0;
|
||||
virtual int bulkMergeStacks(ObjectInstanceID armyId, SlotID srcSlot) = 0;
|
||||
|
||||
|
||||
// Moves all artifacts from one hero to another
|
||||
virtual void bulkMoveArtifacts(ObjectInstanceID srcHero, ObjectInstanceID dstHero, bool swap) = 0;
|
||||
};
|
||||
|
||||
class CBattleCallback : public IBattleCallback, public CPlayerBattleCallback
|
||||
@@ -151,6 +155,7 @@ public:
|
||||
bool dismissHero(const CGHeroInstance * hero) override;
|
||||
bool swapArtifacts(const ArtifactLocation &l1, const ArtifactLocation &l2) override;
|
||||
bool assembleArtifacts(const CGHeroInstance * hero, ArtifactPosition artifactSlot, bool assemble, ArtifactID assembleTo) override;
|
||||
void bulkMoveArtifacts(ObjectInstanceID srcHero, ObjectInstanceID dstHero, bool swap) override;
|
||||
bool buildBuilding(const CGTownInstance *town, BuildingID buildingID) override;
|
||||
void recruitCreatures(const CGDwelling * obj, const CArmedInstance * dst, CreatureID ID, ui32 amount, si32 level=-1) override;
|
||||
bool dismissCreature(const CArmedInstance *obj, SlotID stackPos) override;
|
||||
|
@@ -2591,6 +2591,12 @@ void CPlayerInterface::artifactMoved(const ArtifactLocation &src, const Artifact
|
||||
if (artWin)
|
||||
artWin->artifactMoved(src, dst);
|
||||
}
|
||||
if(!GH.objsToBlit.empty())
|
||||
GH.objsToBlit.back()->redraw();
|
||||
}
|
||||
|
||||
void CPlayerInterface::artifactPossibleAssembling(const ArtifactLocation & dst)
|
||||
{
|
||||
askToAssembleArtifact(dst);
|
||||
}
|
||||
|
||||
|
@@ -133,6 +133,7 @@ public:
|
||||
void artifactRemoved(const ArtifactLocation &al) override;
|
||||
void artifactMoved(const ArtifactLocation &src, const ArtifactLocation &dst) override;
|
||||
void artifactAssembled(const ArtifactLocation &al) override;
|
||||
void artifactPossibleAssembling(const ArtifactLocation & dst) override;
|
||||
void artifactDisassembled(const ArtifactLocation &al) override;
|
||||
|
||||
void heroVisit(const CGHeroInstance * visitor, const CGObjectInstance * visitedObj, bool start) override;
|
||||
|
@@ -275,8 +275,31 @@ void EraseArtifact::applyCl(CClient *cl)
|
||||
void MoveArtifact::applyCl(CClient *cl)
|
||||
{
|
||||
callInterfaceIfPresent(cl, src.owningPlayer(), &IGameEventsReceiver::artifactMoved, src, dst);
|
||||
callInterfaceIfPresent(cl, src.owningPlayer(), &IGameEventsReceiver::artifactPossibleAssembling, dst);
|
||||
if(src.owningPlayer() != dst.owningPlayer())
|
||||
{
|
||||
callInterfaceIfPresent(cl, dst.owningPlayer(), &IGameEventsReceiver::artifactMoved, src, dst);
|
||||
callInterfaceIfPresent(cl, dst.owningPlayer(), &IGameEventsReceiver::artifactPossibleAssembling, dst);
|
||||
}
|
||||
}
|
||||
|
||||
void BulkMoveArtifacts::applyCl(CClient * cl)
|
||||
{
|
||||
auto applyMove = [this, cl](std::vector<LinkedSlots> & artsPack) -> void
|
||||
{
|
||||
for(auto & slotToMove : artsPack)
|
||||
{
|
||||
auto srcLoc = ArtifactLocation(srcArtHolder, slotToMove.srcPos);
|
||||
auto dstLoc = ArtifactLocation(dstArtHolder, slotToMove.dstPos);
|
||||
callInterfaceIfPresent(cl, srcLoc.owningPlayer(), &IGameEventsReceiver::artifactMoved, srcLoc, dstLoc);
|
||||
if(srcLoc.owningPlayer() != dstLoc.owningPlayer())
|
||||
callInterfaceIfPresent(cl, dstLoc.owningPlayer(), &IGameEventsReceiver::artifactMoved, srcLoc, dstLoc);
|
||||
}
|
||||
};
|
||||
|
||||
applyMove(artsPack0);
|
||||
if(swap)
|
||||
applyMove(artsPack1);
|
||||
}
|
||||
|
||||
void AssembledArtifact::applyCl(CClient *cl)
|
||||
|
@@ -872,41 +872,6 @@ std::function<void()> CExchangeController::onMoveArmyToRight()
|
||||
return [&]() { moveArmy(true); };
|
||||
}
|
||||
|
||||
void CExchangeController::swapArtifacts(ArtifactPosition slot)
|
||||
{
|
||||
bool leftHasArt = !left->isPositionFree(slot);
|
||||
bool rightHasArt = !right->isPositionFree(slot);
|
||||
|
||||
if(!leftHasArt && !rightHasArt)
|
||||
return;
|
||||
|
||||
ArtifactLocation leftLocation = ArtifactLocation(left, slot);
|
||||
ArtifactLocation rightLocation = ArtifactLocation(right, slot);
|
||||
|
||||
if(leftHasArt && !left->artifactsWorn.at(slot).artifact->canBePutAt(rightLocation, true))
|
||||
return;
|
||||
|
||||
if(rightHasArt && !right->artifactsWorn.at(slot).artifact->canBePutAt(leftLocation, true))
|
||||
return;
|
||||
|
||||
if(leftHasArt)
|
||||
{
|
||||
if(rightHasArt)
|
||||
{
|
||||
auto art = right->getArt(slot);
|
||||
|
||||
cb->swapArtifacts(leftLocation, rightLocation);
|
||||
cb->swapArtifacts(ArtifactLocation(right, right->getArtPos(art)), leftLocation);
|
||||
}
|
||||
else
|
||||
cb->swapArtifacts(leftLocation, rightLocation);
|
||||
}
|
||||
else
|
||||
{
|
||||
cb->swapArtifacts(rightLocation, leftLocation);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<CArtifactInstance *> getBackpackArts(const CGHeroInstance * hero)
|
||||
{
|
||||
std::vector<CArtifactInstance *> result;
|
||||
@@ -919,92 +884,13 @@ std::vector<CArtifactInstance *> getBackpackArts(const CGHeroInstance * hero)
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::vector<ArtifactPosition> unmovablePositions = {ArtifactPosition::SPELLBOOK, ArtifactPosition::MACH4};
|
||||
|
||||
bool isArtRemovable(const std::pair<ArtifactPosition, ArtSlotInfo> & slot)
|
||||
{
|
||||
return slot.second.artifact
|
||||
&& !slot.second.locked
|
||||
&& !vstd::contains(unmovablePositions, slot.first);
|
||||
}
|
||||
|
||||
// Puts all composite arts to backpack and returns their previous location
|
||||
std::vector<HeroArtifact> CExchangeController::moveCompositeArtsToBackpack()
|
||||
{
|
||||
std::vector<const CGHeroInstance *> sides = {left, right};
|
||||
std::vector<HeroArtifact> artPositions;
|
||||
|
||||
for(auto hero : sides)
|
||||
{
|
||||
for(int i = ArtifactPosition::HEAD; i < ArtifactPosition::AFTER_LAST; i++)
|
||||
{
|
||||
auto artPosition = ArtifactPosition(i);
|
||||
auto art = hero->getArt(artPosition);
|
||||
|
||||
if(art && art->canBeDisassembled())
|
||||
{
|
||||
cb->swapArtifacts(
|
||||
ArtifactLocation(hero, artPosition),
|
||||
ArtifactLocation(hero, ArtifactPosition(GameConstants::BACKPACK_START)));
|
||||
|
||||
artPositions.push_back(HeroArtifact(hero, art, artPosition));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return artPositions;
|
||||
}
|
||||
|
||||
void CExchangeController::swapArtifacts()
|
||||
{
|
||||
for(int i = ArtifactPosition::HEAD; i < ArtifactPosition::AFTER_LAST; i++)
|
||||
{
|
||||
if(vstd::contains(unmovablePositions, i))
|
||||
continue;
|
||||
|
||||
swapArtifacts(ArtifactPosition(i));
|
||||
}
|
||||
|
||||
auto leftHeroBackpack = getBackpackArts(left);
|
||||
auto rightHeroBackpack = getBackpackArts(right);
|
||||
|
||||
for(auto leftArt : leftHeroBackpack)
|
||||
{
|
||||
cb->swapArtifacts(
|
||||
ArtifactLocation(left, left->getArtPos(leftArt)),
|
||||
ArtifactLocation(right, ArtifactPosition(GameConstants::BACKPACK_START)));
|
||||
}
|
||||
|
||||
for(auto rightArt : rightHeroBackpack)
|
||||
{
|
||||
cb->swapArtifacts(
|
||||
ArtifactLocation(right, right->getArtPos(rightArt)),
|
||||
ArtifactLocation(left, ArtifactPosition(GameConstants::BACKPACK_START)));
|
||||
}
|
||||
}
|
||||
|
||||
std::function<void()> CExchangeController::onSwapArtifacts()
|
||||
{
|
||||
return [&]()
|
||||
{
|
||||
GsThread::run([=]
|
||||
{
|
||||
// it is not possible directly exchange composite artifacts like Angelic Alliance and Armor of Damned
|
||||
auto compositeArtLocations = moveCompositeArtsToBackpack();
|
||||
|
||||
swapArtifacts();
|
||||
|
||||
for(HeroArtifact artLocation : compositeArtLocations)
|
||||
{
|
||||
auto target = artLocation.hero == left ? right : left;
|
||||
auto currentPos = target->getArtPos(artLocation.artifact);
|
||||
|
||||
cb->swapArtifacts(
|
||||
ArtifactLocation(target, currentPos),
|
||||
ArtifactLocation(target, artLocation.artPosition));
|
||||
}
|
||||
|
||||
view->redraw();
|
||||
cb->bulkMoveArtifacts(left->id, right->id, true);
|
||||
});
|
||||
};
|
||||
}
|
||||
@@ -1160,20 +1046,8 @@ void CExchangeController::moveArtifacts(bool leftToRight)
|
||||
}
|
||||
|
||||
GsThread::run([=]
|
||||
{
|
||||
while(vstd::contains_if(source->artifactsWorn, isArtRemovable))
|
||||
{
|
||||
auto art = std::find_if(source->artifactsWorn.begin(), source->artifactsWorn.end(), isArtRemovable);
|
||||
|
||||
moveArtifact(source, target, art->first);
|
||||
}
|
||||
|
||||
while(!source->artifactsInBackpack.empty())
|
||||
{
|
||||
moveArtifact(source, target, source->getArtPos(source->artifactsInBackpack.begin()->artifact));
|
||||
}
|
||||
|
||||
view->redraw();
|
||||
{
|
||||
cb->bulkMoveArtifacts(source->id, target->id, false);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1182,26 +1056,11 @@ void CExchangeController::moveArtifact(
|
||||
const CGHeroInstance * target,
|
||||
ArtifactPosition srcPosition)
|
||||
{
|
||||
auto artifact = source->getArt(srcPosition);
|
||||
auto srcLocation = ArtifactLocation(source, srcPosition);
|
||||
auto dstLocation = ArtifactLocation(target,
|
||||
ArtifactUtils::getArtifactDstPosition(source->getArt(srcPosition), target, target->bearerType()));
|
||||
|
||||
for(auto slot : artifact->artType->possibleSlots.at(target->bearerType()))
|
||||
{
|
||||
auto existingArtifact = target->getArt(slot);
|
||||
auto existingArtInfo = target->getSlot(slot);
|
||||
ArtifactLocation destLocation(target, slot);
|
||||
|
||||
if(!existingArtifact
|
||||
&& (!existingArtInfo || !existingArtInfo->locked)
|
||||
&& artifact->canBePutAt(destLocation))
|
||||
{
|
||||
cb->swapArtifacts(srcLocation, ArtifactLocation(target, slot));
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
cb->swapArtifacts(srcLocation, ArtifactLocation(target, ArtifactPosition(GameConstants::BACKPACK_START)));
|
||||
cb->swapArtifacts(srcLocation, dstLocation);
|
||||
}
|
||||
|
||||
CExchangeWindow::CExchangeWindow(ObjectInstanceID hero1, ObjectInstanceID hero2, QueryID queryID)
|
||||
|
@@ -324,9 +324,6 @@ private:
|
||||
void moveArtifacts(bool leftToRight);
|
||||
void moveArtifact(const CGHeroInstance * source, const CGHeroInstance * target, ArtifactPosition srcPosition);
|
||||
void moveStack(const CGHeroInstance * source, const CGHeroInstance * target, SlotID sourceSlot);
|
||||
void swapArtifacts(ArtifactPosition artPosition);
|
||||
std::vector<HeroArtifact> moveCompositeArtsToBackpack();
|
||||
void swapArtifacts();
|
||||
};
|
||||
|
||||
class CExchangeWindow : public CStatusbarWindow, public CGarrisonHolder, public CWindowWithArtifacts
|
||||
|
@@ -1457,4 +1457,83 @@ void CArtifactSet::serializeJsonSlot(JsonSerializeFormat & handler, const Artifa
|
||||
}
|
||||
}
|
||||
|
||||
CArtifactFittingSet::CArtifactFittingSet(ArtBearer::ArtBearer Bearer)
|
||||
{
|
||||
this->Bearer = Bearer;
|
||||
}
|
||||
|
||||
void CArtifactFittingSet::setNewArtSlot(ArtifactPosition slot, CArtifactInstance * art, bool locked)
|
||||
{
|
||||
ArtSlotInfo & asi = retrieveNewArtSlot(slot);
|
||||
asi.artifact = art;
|
||||
asi.locked = locked;
|
||||
}
|
||||
|
||||
void CArtifactFittingSet::putArtifact(ArtifactPosition pos, CArtifactInstance * art)
|
||||
{
|
||||
if(art && art->canBeDisassembled() && (pos < ArtifactPosition::AFTER_LAST))
|
||||
{
|
||||
for(auto & part : dynamic_cast<CCombinedArtifactInstance*>(art)->constituentsInfo)
|
||||
{
|
||||
// For the ArtFittingSet is no needed to do figureMainConstituent, just lock slots
|
||||
this->setNewArtSlot(part.art->firstAvailableSlot(this), part.art, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this->setNewArtSlot(pos, art, false);
|
||||
}
|
||||
}
|
||||
|
||||
ArtBearer::ArtBearer CArtifactFittingSet::bearerType() const
|
||||
{
|
||||
return this->Bearer;
|
||||
}
|
||||
|
||||
DLL_LINKAGE ArtifactPosition ArtifactUtils::getArtifactDstPosition( const CArtifactInstance * artifact,
|
||||
const CArtifactSet * target,
|
||||
ArtBearer::ArtBearer bearer)
|
||||
{
|
||||
for(auto slot : artifact->artType->possibleSlots.at(bearer))
|
||||
{
|
||||
auto existingArtifact = target->getArt(slot);
|
||||
auto existingArtInfo = target->getSlot(slot);
|
||||
|
||||
if(!existingArtifact
|
||||
&& (!existingArtInfo || !existingArtInfo->locked)
|
||||
&& artifact->canBePutAt(target, slot))
|
||||
{
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
return ArtifactPosition(GameConstants::BACKPACK_START);
|
||||
}
|
||||
|
||||
DLL_LINKAGE std::vector<ArtifactPosition> ArtifactUtils::unmovablePositions()
|
||||
{
|
||||
return { ArtifactPosition::SPELLBOOK, ArtifactPosition::MACH4 };
|
||||
}
|
||||
|
||||
DLL_LINKAGE bool ArtifactUtils::isArtRemovable(const std::pair<ArtifactPosition, ArtSlotInfo> & slot)
|
||||
{
|
||||
return slot.second.artifact
|
||||
&& !slot.second.locked
|
||||
&& !vstd::contains(unmovablePositions(), slot.first);
|
||||
}
|
||||
|
||||
DLL_LINKAGE bool ArtifactUtils::checkSpellbookIsNeeded(const CGHeroInstance * heroPtr, ArtifactID artID, ArtifactPosition slot)
|
||||
{
|
||||
// TODO what'll happen if Titan's thunder is equipped by pickin git up or the start of game?
|
||||
// Titan's Thunder creates new spellbook on equip
|
||||
if(artID == ArtifactID::TITANS_THUNDER && slot == ArtifactPosition::RIGHT_HAND)
|
||||
{
|
||||
if(heroPtr)
|
||||
{
|
||||
if(heroPtr && !heroPtr->hasSpellbook())
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -303,8 +303,9 @@ struct DLL_LINKAGE ArtSlotInfo
|
||||
ui8 locked; //if locked, then artifact points to the combined artifact
|
||||
|
||||
ArtSlotInfo() : locked(false) {}
|
||||
const CArtifactInstance * getArt() const;
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
template <typename Handler> void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & artifact;
|
||||
h & locked;
|
||||
@@ -363,4 +364,28 @@ private:
|
||||
void serializeJsonSlot(JsonSerializeFormat & handler, const ArtifactPosition & slot, CMap * map);//normal slots
|
||||
};
|
||||
|
||||
// Used to try on artifacts before the claimed changes have been applied
|
||||
class DLL_LINKAGE CArtifactFittingSet : public CArtifactSet
|
||||
{
|
||||
public:
|
||||
CArtifactFittingSet(ArtBearer::ArtBearer Bearer);
|
||||
void setNewArtSlot(ArtifactPosition slot, CArtifactInstance * art, bool locked);
|
||||
void putArtifact(ArtifactPosition pos, CArtifactInstance * art) override;
|
||||
ArtBearer::ArtBearer bearerType() const override;
|
||||
|
||||
protected:
|
||||
ArtBearer::ArtBearer Bearer;
|
||||
};
|
||||
|
||||
namespace ArtifactUtils
|
||||
{
|
||||
// Calculates where an artifact gets placed when it gets transferred from one hero to another.
|
||||
DLL_LINKAGE ArtifactPosition getArtifactDstPosition( const CArtifactInstance * artifact,
|
||||
const CArtifactSet * target,
|
||||
ArtBearer::ArtBearer bearer);
|
||||
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);
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -91,6 +91,7 @@ public:
|
||||
virtual void artifactAssembled(const ArtifactLocation &al){};
|
||||
virtual void artifactDisassembled(const ArtifactLocation &al){};
|
||||
virtual void artifactMoved(const ArtifactLocation &src, const ArtifactLocation &dst){};
|
||||
virtual void artifactPossibleAssembling(const ArtifactLocation & dst) {};
|
||||
|
||||
virtual void heroVisit(const CGHeroInstance *visitor, const CGObjectInstance *visitedObj, bool start){};
|
||||
virtual void heroCreated(const CGHeroInstance*){};
|
||||
|
@@ -994,18 +994,64 @@ struct EraseArtifact : CArtifactOperationPack
|
||||
|
||||
struct MoveArtifact : CArtifactOperationPack
|
||||
{
|
||||
MoveArtifact() {}
|
||||
MoveArtifact(ArtifactLocation * src, ArtifactLocation * dst)
|
||||
: src(*src), dst(*dst) {}
|
||||
ArtifactLocation src, dst;
|
||||
|
||||
void applyCl(CClient *cl);
|
||||
DLL_LINKAGE void applyGs(CGameState *gs);
|
||||
|
||||
template <typename Handler> void serialize(Handler &h, const int version)
|
||||
template <typename Handler> void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & src;
|
||||
h & dst;
|
||||
}
|
||||
};
|
||||
|
||||
struct BulkMoveArtifacts : CArtifactOperationPack
|
||||
{
|
||||
struct LinkedSlots
|
||||
{
|
||||
ArtifactPosition srcPos;
|
||||
ArtifactPosition dstPos;
|
||||
|
||||
LinkedSlots() {}
|
||||
LinkedSlots(ArtifactPosition srcPos, ArtifactPosition dstPos)
|
||||
: srcPos(srcPos), dstPos(dstPos) {}
|
||||
template <typename Handler> void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & srcPos;
|
||||
h & dstPos;
|
||||
}
|
||||
};
|
||||
|
||||
TArtHolder srcArtHolder;
|
||||
TArtHolder dstArtHolder;
|
||||
|
||||
BulkMoveArtifacts()
|
||||
: swap(false) {}
|
||||
BulkMoveArtifacts(TArtHolder srcArtHolder, TArtHolder dstArtHolder, bool swap)
|
||||
: srcArtHolder(srcArtHolder), dstArtHolder(dstArtHolder), swap(swap) {}
|
||||
|
||||
void applyCl(CClient * cl);
|
||||
DLL_LINKAGE void applyGs(CGameState * gs);
|
||||
|
||||
std::vector<LinkedSlots> artsPack0;
|
||||
std::vector<LinkedSlots> artsPack1;
|
||||
bool swap;
|
||||
CArtifactSet * getSrcHolderArtSet();
|
||||
CArtifactSet * getDstHolderArtSet();
|
||||
template <typename Handler> void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & artsPack0;
|
||||
h & artsPack1;
|
||||
h & srcArtHolder;
|
||||
h & dstArtHolder;
|
||||
h & swap;
|
||||
}
|
||||
};
|
||||
|
||||
struct AssembledArtifact : CArtifactOperationPack
|
||||
{
|
||||
ArtifactLocation al; //where assembly will be put
|
||||
@@ -2197,6 +2243,27 @@ struct ExchangeArtifacts : public CPackForServer
|
||||
}
|
||||
};
|
||||
|
||||
struct BulkExchangeArtifacts : public CPackForServer
|
||||
{
|
||||
ObjectInstanceID srcHero;
|
||||
ObjectInstanceID dstHero;
|
||||
bool swap;
|
||||
|
||||
BulkExchangeArtifacts()
|
||||
: swap(false) {}
|
||||
BulkExchangeArtifacts(ObjectInstanceID srcHero, ObjectInstanceID dstHero, bool swap)
|
||||
: srcHero(srcHero), dstHero(dstHero), swap(swap) {}
|
||||
|
||||
bool applyGh(CGameHandler * gh);
|
||||
template <typename Handler> void serialize(Handler & h, const int version)
|
||||
{
|
||||
h & static_cast<CPackForServer&>(*this);
|
||||
h & srcHero;
|
||||
h & dstHero;
|
||||
h & swap;
|
||||
}
|
||||
};
|
||||
|
||||
struct AssembleArtifacts : public CPackForServer
|
||||
{
|
||||
AssembleArtifacts():assemble(false){};
|
||||
|
@@ -845,18 +845,11 @@ DLL_LINKAGE CBonusSystemNode *ArtifactLocation::getHolderNode()
|
||||
|
||||
DLL_LINKAGE const CArtifactInstance *ArtifactLocation::getArt() const
|
||||
{
|
||||
const ArtSlotInfo *s = getSlot();
|
||||
if(s && s->artifact)
|
||||
{
|
||||
if(!s->locked)
|
||||
return s->artifact;
|
||||
else
|
||||
{
|
||||
logNetwork->warn("ArtifactLocation::getArt: This location is locked!");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
auto s = getSlot();
|
||||
if(s)
|
||||
return s->getArt();
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DLL_LINKAGE const CArtifactSet * ArtifactLocation::getHolderArtSet() const
|
||||
@@ -1093,24 +1086,82 @@ DLL_LINKAGE void EraseArtifact::applyGs(CGameState *gs)
|
||||
al.removeArtifact();
|
||||
}
|
||||
|
||||
DLL_LINKAGE void MoveArtifact::applyGs(CGameState *gs)
|
||||
DLL_LINKAGE void MoveArtifact::applyGs(CGameState * gs)
|
||||
{
|
||||
CArtifactInstance *a = src.getArt();
|
||||
CArtifactInstance * art = src.getArt();
|
||||
if(dst.slot < GameConstants::BACKPACK_START)
|
||||
assert(!dst.getArt());
|
||||
|
||||
a->move(src, dst);
|
||||
art->move(src, dst);
|
||||
}
|
||||
|
||||
//TODO what'll happen if Titan's thunder is equipped by pickin git up or the start of game?
|
||||
if (a->artType->id == ArtifactID::TITANS_THUNDER && dst.slot == ArtifactPosition::RIGHT_HAND) //Titan's Thunder creates new spellbook on equip
|
||||
DLL_LINKAGE void BulkMoveArtifacts::applyGs(CGameState * gs)
|
||||
{
|
||||
enum class EBulkArtsOp
|
||||
{
|
||||
auto hPtr = boost::get<ConstTransitivePtr<CGHeroInstance> >(&dst.artHolder);
|
||||
if(hPtr)
|
||||
BULK_MOVE,
|
||||
BULK_REMOVE,
|
||||
BULK_PUT
|
||||
};
|
||||
|
||||
auto bulkArtsOperation = [this](std::vector<LinkedSlots> & artsPack,
|
||||
CArtifactSet * artSet, EBulkArtsOp operation) -> void
|
||||
{
|
||||
int numBackpackArtifactsMoved = 0;
|
||||
for(auto & slot : artsPack)
|
||||
{
|
||||
CGHeroInstance *h = *hPtr;
|
||||
if(h && !h->hasSpellbook())
|
||||
gs->giveHeroArtifact(h, ArtifactID::SPELLBOOK);
|
||||
// When an object gets removed from the backpack, the backpack shrinks
|
||||
// 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))
|
||||
{
|
||||
srcPos = ArtifactPosition(srcPos.num - numBackpackArtifactsMoved);
|
||||
}
|
||||
auto slotInfo = artSet->getSlot(srcPos);
|
||||
assert(slotInfo);
|
||||
auto art = const_cast<CArtifactInstance*>(slotInfo->getArt());
|
||||
assert(art);
|
||||
switch(operation)
|
||||
{
|
||||
case EBulkArtsOp::BULK_MOVE:
|
||||
const_cast<CArtifactInstance*>(art)->move(
|
||||
ArtifactLocation(srcArtHolder, srcPos), ArtifactLocation(dstArtHolder, slot.dstPos));
|
||||
break;
|
||||
case EBulkArtsOp::BULK_REMOVE:
|
||||
art->removeFrom(ArtifactLocation(dstArtHolder, srcPos));
|
||||
break;
|
||||
case EBulkArtsOp::BULK_PUT:
|
||||
art->putAt(ArtifactLocation(srcArtHolder, slot.dstPos));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(srcPos >= GameConstants::BACKPACK_START)
|
||||
{
|
||||
numBackpackArtifactsMoved++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if(swap)
|
||||
{
|
||||
// Swap
|
||||
auto leftSet = getSrcHolderArtSet();
|
||||
auto rightSet = getDstHolderArtSet();
|
||||
CArtifactFittingSet artFittingSet(leftSet->bearerType());
|
||||
|
||||
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, getSrcHolderArtSet(), EBulkArtsOp::BULK_MOVE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1712,4 +1763,24 @@ DLL_LINKAGE void EntitiesChanged::applyGs(CGameState * gs)
|
||||
gs->updateEntity(change.metatype, change.entityIndex, change.data);
|
||||
}
|
||||
|
||||
const CArtifactInstance * ArtSlotInfo::getArt() const
|
||||
{
|
||||
if(locked)
|
||||
{
|
||||
logNetwork->warn("ArtifactLocation::getArt: This location is locked!");
|
||||
return nullptr;
|
||||
}
|
||||
return artifact;
|
||||
}
|
||||
|
||||
CArtifactSet * BulkMoveArtifacts::getSrcHolderArtSet()
|
||||
{
|
||||
return boost::apply_visitor(GetBase<CArtifactSet>(), srcArtHolder);
|
||||
}
|
||||
|
||||
CArtifactSet * BulkMoveArtifacts::getDstHolderArtSet()
|
||||
{
|
||||
return boost::apply_visitor(GetBase<CArtifactSet>(), dstArtHolder);
|
||||
}
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -319,6 +319,7 @@ void registerTypesClientPacks2(Serializer &s)
|
||||
s.template registerType<CArtifactOperationPack, MoveArtifact>();
|
||||
s.template registerType<CArtifactOperationPack, AssembledArtifact>();
|
||||
s.template registerType<CArtifactOperationPack, DisassembledArtifact>();
|
||||
s.template registerType<CArtifactOperationPack, BulkMoveArtifacts>();
|
||||
|
||||
s.template registerType<CPackForClient, SaveGameClient>();
|
||||
s.template registerType<CPackForClient, PlayerMessageClient>();
|
||||
@@ -358,6 +359,7 @@ void registerTypesServerPacks(Serializer &s)
|
||||
s.template registerType<CPackForServer, BulkMergeStacks>();
|
||||
s.template registerType<CPackForServer, BulkSmartSplitStack>();
|
||||
s.template registerType<CPackForServer, BulkMoveArmy>();
|
||||
s.template registerType<CPackForServer, BulkExchangeArtifacts>();
|
||||
}
|
||||
|
||||
template<typename Serializer>
|
||||
|
@@ -3916,10 +3916,101 @@ bool CGameHandler::moveArtifact(const ArtifactLocation &al1, const ArtifactLocat
|
||||
moveArtifact(dst, ArtifactLocation(dst.artHolder, ArtifactPosition(
|
||||
(si32)dst.getHolderArtSet()->artifactsInBackpack.size() + GameConstants::BACKPACK_START)));
|
||||
}
|
||||
auto hero = boost::get<ConstTransitivePtr<CGHeroInstance>>(dst.artHolder);
|
||||
if(ArtifactUtils::checkSpellbookIsNeeded(hero, srcArtifact->artType->id, dst.slot))
|
||||
giveHeroNewArtifact(hero, VLC->arth->objects[ArtifactID::SPELLBOOK], ArtifactPosition::SPELLBOOK);
|
||||
|
||||
MoveArtifact ma;
|
||||
ma.src = src;
|
||||
ma.dst = dst;
|
||||
MoveArtifact ma(&src, &dst);
|
||||
sendAndApply(&ma);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CGameHandler::bulkMoveArtifacts(ObjectInstanceID srcHero, ObjectInstanceID dstHero, bool swap)
|
||||
{
|
||||
// Make sure exchange is even possible between the two heroes.
|
||||
if(!isAllowedExchange(srcHero, dstHero))
|
||||
COMPLAIN_RET("That heroes cannot make any exchange!");
|
||||
|
||||
auto psrcHero = getHero(srcHero);
|
||||
auto pdstHero = getHero(dstHero);
|
||||
if((!psrcHero) || (!pdstHero))
|
||||
COMPLAIN_RET("bulkMoveArtifacts: wrong hero's ID");
|
||||
|
||||
BulkMoveArtifacts ma(static_cast<ConstTransitivePtr<CGHeroInstance>>(psrcHero),
|
||||
static_cast<ConstTransitivePtr<CGHeroInstance>>(pdstHero), swap);
|
||||
auto & slotsSrcDst = ma.artsPack0;
|
||||
auto & slotsDstSrc = ma.artsPack1;
|
||||
|
||||
if(swap)
|
||||
{
|
||||
auto moveArtsWorn = [this](const CGHeroInstance * srcHero, const CGHeroInstance * dstHero,
|
||||
std::vector<BulkMoveArtifacts::LinkedSlots> & slots) -> void
|
||||
{
|
||||
for(auto & artifact : srcHero->artifactsWorn)
|
||||
{
|
||||
if(artifact.second.locked)
|
||||
continue;
|
||||
if(!ArtifactUtils::isArtRemovable(artifact))
|
||||
continue;
|
||||
slots.push_back(BulkMoveArtifacts::LinkedSlots(artifact.first, artifact.first));
|
||||
|
||||
auto art = artifact.second.getArt();
|
||||
assert(art);
|
||||
if(ArtifactUtils::checkSpellbookIsNeeded(dstHero, art->artType->id, artifact.first))
|
||||
giveHeroNewArtifact(dstHero, VLC->arth->objects[ArtifactID::SPELLBOOK], ArtifactPosition::SPELLBOOK);
|
||||
}
|
||||
};
|
||||
auto moveArtsInBackpack = [](const CGHeroInstance * pHero,
|
||||
std::vector<BulkMoveArtifacts::LinkedSlots> & slots) -> void
|
||||
{
|
||||
for(auto & slotInfo : pHero->artifactsInBackpack)
|
||||
{
|
||||
auto slot = pHero->getArtPos(slotInfo.artifact);
|
||||
slots.push_back(BulkMoveArtifacts::LinkedSlots(slot, slot));
|
||||
}
|
||||
};
|
||||
// Move over artifacts that are worn srcHero -> dstHero
|
||||
moveArtsWorn(psrcHero, pdstHero, slotsSrcDst);
|
||||
// Move over artifacts that are worn dstHero -> srcHero
|
||||
moveArtsWorn(pdstHero, psrcHero, slotsDstSrc);
|
||||
// Move over artifacts that are in backpack srcHero -> dstHero
|
||||
moveArtsInBackpack(psrcHero, slotsSrcDst);
|
||||
// Move over artifacts that are in backpack dstHero -> srcHero
|
||||
moveArtsInBackpack(pdstHero, slotsDstSrc);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Temporary fitting set for artifacts. Used to select available slots before sending data.
|
||||
CArtifactFittingSet artFittingSet(pdstHero->bearerType());
|
||||
artFittingSet.artifactsInBackpack = pdstHero->artifactsInBackpack;
|
||||
artFittingSet.artifactsWorn = pdstHero->artifactsWorn;
|
||||
|
||||
auto moveArtifact = [this, &artFittingSet, &slotsSrcDst](const CArtifactInstance * artifact,
|
||||
ArtifactPosition srcSlot, const CGHeroInstance * pdstHero) -> void
|
||||
{
|
||||
assert(artifact);
|
||||
auto dstSlot = ArtifactUtils::getArtifactDstPosition(artifact, &artFittingSet, pdstHero->bearerType());
|
||||
artFittingSet.putArtifact(dstSlot, static_cast<ConstTransitivePtr<CArtifactInstance>>(artifact));
|
||||
slotsSrcDst.push_back(BulkMoveArtifacts::LinkedSlots(srcSlot, dstSlot));
|
||||
|
||||
if(ArtifactUtils::checkSpellbookIsNeeded(pdstHero, artifact->artType->id, dstSlot))
|
||||
giveHeroNewArtifact(pdstHero, VLC->arth->objects[ArtifactID::SPELLBOOK], ArtifactPosition::SPELLBOOK);
|
||||
};
|
||||
|
||||
// Move over artifacts that are worn
|
||||
for(auto & artInfo : psrcHero->artifactsWorn)
|
||||
{
|
||||
if(ArtifactUtils::isArtRemovable(artInfo))
|
||||
{
|
||||
moveArtifact(psrcHero->getArt(artInfo.first), artInfo.first, pdstHero);
|
||||
}
|
||||
}
|
||||
// Move over artifacts that are in backpack
|
||||
for(auto & slotInfo : psrcHero->artifactsInBackpack)
|
||||
{
|
||||
moveArtifact(psrcHero->getArt(psrcHero->getArtPos(slotInfo.artifact)), psrcHero->getArtPos(slotInfo.artifact), pdstHero);
|
||||
}
|
||||
}
|
||||
sendAndApply(&ma);
|
||||
return true;
|
||||
}
|
||||
@@ -3947,6 +4038,9 @@ bool CGameHandler::assembleArtifacts (ObjectInstanceID heroID, ArtifactPosition
|
||||
COMPLAIN_RET("assembleArtifacts: Artifact being attempted to assemble is not a combined artifacts!");
|
||||
if (!vstd::contains(destArtifact->assemblyPossibilities(hero), 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);
|
||||
|
||||
AssembledArtifact aa;
|
||||
aa.al = ArtifactLocation(hero, artifactSlot);
|
||||
|
@@ -180,7 +180,8 @@ public:
|
||||
void giveHeroArtifact(const CGHeroInstance *h, const CArtifactInstance *a, ArtifactPosition pos) override;
|
||||
void putArtifact(const ArtifactLocation &al, const CArtifactInstance *a) override;
|
||||
void removeArtifact(const ArtifactLocation &al) override;
|
||||
bool moveArtifact(const ArtifactLocation &al1, const ArtifactLocation &al2) override;
|
||||
bool moveArtifact(const ArtifactLocation & al1, const ArtifactLocation & al2) override;
|
||||
bool bulkMoveArtifacts(ObjectInstanceID srcHero, ObjectInstanceID dstHero, bool swap);
|
||||
void synchronizeArtifactHandlerLists();
|
||||
|
||||
void showCompInfo(ShowInInfobox * comp) override;
|
||||
|
@@ -370,6 +370,9 @@ bool CGarrisonDialogQuery::blocksPack(const CPack * pack) const
|
||||
}
|
||||
if(auto dismiss = dynamic_ptr_cast<DisbandCreature>(pack))
|
||||
return !vstd::contains(ourIds, dismiss->id);
|
||||
|
||||
if(auto arts = dynamic_ptr_cast<BulkExchangeArtifacts>(pack))
|
||||
return !vstd::contains(ourIds, arts->srcHero) || !vstd::contains(ourIds, arts->dstHero);
|
||||
|
||||
if(auto dismiss = dynamic_ptr_cast<AssembleArtifacts>(pack))
|
||||
return !vstd::contains(ourIds, dismiss->heroID);
|
||||
|
@@ -180,6 +180,13 @@ bool ExchangeArtifacts::applyGh(CGameHandler * gh)
|
||||
return gh->moveArtifact(src, dst);
|
||||
}
|
||||
|
||||
bool BulkExchangeArtifacts::applyGh(CGameHandler * gh)
|
||||
{
|
||||
const CGHeroInstance * pSrcHero = gh->getHero(srcHero);
|
||||
throwOnWrongPlayer(gh, pSrcHero->getOwner());
|
||||
return gh->bulkMoveArtifacts(srcHero, dstHero, swap);
|
||||
}
|
||||
|
||||
bool AssembleArtifacts::applyGh(CGameHandler * gh)
|
||||
{
|
||||
throwOnWrongOwner(gh, heroID);
|
||||
|
Reference in New Issue
Block a user