1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-06-19 00:17:56 +02:00
Files
vcmi/lib/entities/artifact/CArtifactSet.cpp

404 lines
11 KiB
C++
Raw Normal View History

/*
* CArtifactSet.cpp, part of VCMI engine
*
* Authors: listed in file AUTHORS in main folder
*
* License: GNU General Public License v2.0 or later
* Full text of license available in license.txt file, in main folder
*
*/
#include "StdInc.h"
#include "CArtifactSet.h"
#include "CArtifact.h"
#include "ArtifactUtils.h"
#include "../../constants/StringConstants.h"
#include "../../gameState/CGameState.h"
#include "../../mapping/CMap.h"
#include "../../serializer/JsonSerializeFormat.h"
VCMI_LIB_NAMESPACE_BEGIN
const CArtifactInstance * CArtifactSet::getArt(const ArtifactPosition & pos, bool excludeLocked) const
{
if(const ArtSlotInfo * si = getSlot(pos))
{
if(si->getArt() && (!excludeLocked || !si->locked))
return si->getArt();
}
return nullptr;
}
ArtifactInstanceID CArtifactSet::getArtID(const ArtifactPosition & pos, bool excludeLocked) const
{
if(const ArtSlotInfo * si = getSlot(pos))
{
if(si->getArt() && (!excludeLocked || !si->locked))
return si->getArt()->getId();
}
return {};
}
ArtifactPosition CArtifactSet::getArtPos(const ArtifactID & aid, bool onlyWorn, bool allowLocked) const
{
for(const auto & [slot, slotInfo] : artifactsWorn)
{
if(slotInfo.getArt()->getTypeId() == aid && (allowLocked || !slotInfo.locked))
return slot;
}
if(!onlyWorn)
{
size_t backpackPositionIdx = ArtifactPosition::BACKPACK_START;
for(const auto & artInfo : artifactsInBackpack)
{
const auto art = artInfo.getArt();
if(art && art->getType()->getId() == aid)
return ArtifactPosition(backpackPositionIdx);
backpackPositionIdx++;
}
}
return ArtifactPosition::PRE_FIRST;
}
bool CArtifactSet::hasScroll(const SpellID & spellID, bool onlyWorn) const
{
return getScrollPos(spellID, onlyWorn) != ArtifactPosition::PRE_FIRST;
}
ArtifactPosition CArtifactSet::getScrollPos(const SpellID & spellID, bool onlyWorn) const
{
for (const auto & slot : artifactsWorn)
if (slot.second.getArt() && slot.second.getArt()->isScroll() && slot.second.getArt()->getScrollSpellID() == spellID)
return slot.first;
if (!onlyWorn)
{
size_t backpackPositionIdx = ArtifactPosition::BACKPACK_START;
for (const auto & slot : artifactsInBackpack)
{
if (slot.getArt() && slot.getArt()->isScroll() && slot.getArt()->getScrollSpellID() == spellID)
return ArtifactPosition(backpackPositionIdx);
backpackPositionIdx++;
}
}
return ArtifactPosition::PRE_FIRST;
}
const CArtifactInstance * CArtifactSet::getArtByInstanceId(const ArtifactInstanceID & artInstId) const
{
for(const auto & i : artifactsWorn)
if(i.second.getArt()->getId() == artInstId)
return i.second.getArt();
for(const auto & i : artifactsInBackpack)
if(i.getArt()->getId() == artInstId)
return i.getArt();
return nullptr;
}
ArtifactPosition CArtifactSet::getArtPos(const CArtifactInstance * artInst) const
{
if(artInst)
{
for(const auto & slot : artInst->getType()->getPossibleSlots().at(bearerType()))
if(getArt(slot) == artInst)
return slot;
ArtifactPosition backpackSlot = ArtifactPosition::BACKPACK_START;
for(auto & slotInfo : artifactsInBackpack)
{
if(slotInfo.getArt() == artInst)
return backpackSlot;
backpackSlot = ArtifactPosition(backpackSlot + 1);
}
}
return ArtifactPosition::PRE_FIRST;
}
bool CArtifactSet::hasArt(const ArtifactID & aid, bool onlyWorn, bool searchCombinedParts) const
{
if(searchCombinedParts && getCombinedArtWithPart(aid))
return true;
if(getArtPos(aid, onlyWorn, searchCombinedParts) != ArtifactPosition::PRE_FIRST)
return true;
return false;
}
CArtifactSet::ArtPlacementMap CArtifactSet::putArtifact(const ArtifactPosition & slot, const CArtifactInstance * art)
{
ArtPlacementMap resArtPlacement;
const auto putToSlot = [this](const ArtifactPosition & targetSlot, const CArtifactInstance * targetArt, bool locked)
{
ArtSlotInfo newSlot(targetArt, locked);
if(targetSlot == ArtifactPosition::TRANSITION_POS)
{
artifactsTransitionPos = newSlot;
}
else if(ArtifactUtils::isSlotEquipment(targetSlot))
{
artifactsWorn.insert_or_assign(targetSlot, newSlot);
}
else
{
auto position = artifactsInBackpack.begin() + targetSlot - ArtifactPosition::BACKPACK_START;
artifactsInBackpack.insert(position, newSlot);
}
};
putToSlot(slot, art, false);
if(art->getType()->isCombined() && ArtifactUtils::isSlotEquipment(slot))
{
const CArtifactInstance * mainPart = nullptr;
for(const auto & part : art->getPartsInfo())
if(vstd::contains(part.getArtifact()->getType()->getPossibleSlots().at(bearerType()), slot)
&& (part.slot == ArtifactPosition::PRE_FIRST))
{
mainPart = part.getArtifact();
break;
}
for(const auto & part : art->getPartsInfo())
{
if(part.getArtifact() != mainPart)
{
auto partSlot = part.slot;
if(!part.getArtifact()->getType()->canBePutAt(this, partSlot))
partSlot = ArtifactUtils::getArtAnyPosition(this, part.getArtifact()->getTypeId());
assert(ArtifactUtils::isSlotEquipment(partSlot));
putToSlot(partSlot, part.getArtifact(), true);
resArtPlacement.emplace(part.getArtifact(), partSlot);
}
else
{
resArtPlacement.emplace(part.getArtifact(), part.slot);
}
}
}
return resArtPlacement;
}
CArtifactSet::CArtifactSet(CPrivilegedInfoCallback * cb)
:artifactsTransitionPos(cb)
{}
void CArtifactSet::removeArtifact(const ArtifactPosition & slot)
{
const auto eraseArtSlot = [this](const ArtifactPosition & slotForErase)
{
if(slotForErase == ArtifactPosition::TRANSITION_POS)
{
artifactsTransitionPos.artifactID = {};
}
else if(ArtifactUtils::isSlotBackpack(slotForErase))
{
auto backpackSlot = ArtifactPosition(slotForErase - ArtifactPosition::BACKPACK_START);
assert(artifactsInBackpack.begin() + backpackSlot < artifactsInBackpack.end());
artifactsInBackpack.erase(artifactsInBackpack.begin() + backpackSlot);
}
else
{
artifactsWorn.erase(slotForErase);
}
};
if(const auto art = getArt(slot, false))
{
if(art->isCombined())
{
for(const auto & part : art->getPartsInfo())
{
if(part.slot != ArtifactPosition::PRE_FIRST)
{
assert(getArt(part.slot, false));
assert(getArt(part.slot, false) == part.getArtifact());
}
eraseArtSlot(part.slot);
}
}
eraseArtSlot(slot);
}
}
const CArtifactInstance * CArtifactSet::getCombinedArtWithPart(const ArtifactID & partId) const
{
for(const auto & slot : artifactsInBackpack)
{
auto art = slot.getArt();
if(art->isCombined())
{
for(auto & ci : art->getPartsInfo())
{
if(ci.getArtifact()->getTypeId() == partId)
return art;
}
}
}
return nullptr;
}
const ArtSlotInfo * CArtifactSet::getSlot(const ArtifactPosition & pos) const
{
if(pos == ArtifactPosition::TRANSITION_POS)
return &artifactsTransitionPos;
if(vstd::contains(artifactsWorn, pos))
return &artifactsWorn.at(pos);
if(ArtifactUtils::isSlotBackpack(pos))
{
auto backpackPos = pos - ArtifactPosition::BACKPACK_START;
if(backpackPos < 0 || backpackPos >= artifactsInBackpack.size())
return nullptr;
else
return &artifactsInBackpack[backpackPos];
}
return nullptr;
}
void CArtifactSet::lockSlot(const ArtifactPosition & pos)
{
if(pos == ArtifactPosition::TRANSITION_POS)
artifactsTransitionPos.locked = true;
else if(ArtifactUtils::isSlotEquipment(pos))
artifactsWorn.at(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
{
if(bearerType() == ArtBearer::ALTAR)
return artifactsInBackpack.size() < GameConstants::ALTAR_ARTIFACTS_SLOTS;
if(const ArtSlotInfo *s = getSlot(pos))
return (onlyLockCheck || !s->getID().hasValue()) && !s->locked;
return true; //no slot means not used
}
void CArtifactSet::artDeserializationFix(CGameState & gs, CBonusSystemNode *node)
{
for(auto & elem : artifactsWorn)
if(elem.second.artifactID.hasValue() && !elem.second.locked)
node->attachToSource(*gs.getArtInstance(elem.second.artifactID));
}
void CArtifactSet::serializeJsonArtifacts(JsonSerializeFormat & handler, const std::string & fieldName, CMap * map)
{
//todo: creature and commander artifacts
if(handler.saving && artifactsInBackpack.empty() && artifactsWorn.empty())
return;
if(!handler.saving)
{
artifactsInBackpack.clear();
artifactsWorn.clear();
}
auto s = handler.enterStruct(fieldName);
switch(bearerType())
{
case ArtBearer::HERO:
serializeJsonHero(handler, map);
break;
case ArtBearer::CREATURE:
serializeJsonCreature(handler);
break;
case ArtBearer::COMMANDER:
serializeJsonCommander(handler);
break;
default:
assert(false);
break;
}
}
void CArtifactSet::serializeJsonHero(JsonSerializeFormat & handler, CMap * map)
{
for(const auto & slot : ArtifactUtils::allWornSlots())
{
serializeJsonSlot(handler, slot, map);
}
std::vector<ArtifactID> backpackTemp;
if(handler.saving)
{
backpackTemp.reserve(artifactsInBackpack.size());
for(const ArtSlotInfo & info : artifactsInBackpack)
backpackTemp.push_back(info.getArt()->getTypeId());
}
handler.serializeIdArray(NArtifactPosition::backpack, backpackTemp);
if(!handler.saving)
{
for(const ArtifactID & artifactID : backpackTemp)
{
auto * artifact = map->createArtifact(artifactID);
auto slot = ArtifactPosition::BACKPACK_START + artifactsInBackpack.size();
if(artifact->getType()->canBePutAt(this, slot))
{
auto artsMap = putArtifact(slot, artifact);
artifact->addPlacementMap(artsMap);
}
}
}
}
void CArtifactSet::serializeJsonCreature(JsonSerializeFormat & handler)
{
logGlobal->error("CArtifactSet::serializeJsonCreature not implemented");
}
void CArtifactSet::serializeJsonCommander(JsonSerializeFormat & handler)
{
logGlobal->error("CArtifactSet::serializeJsonCommander not implemented");
}
void CArtifactSet::serializeJsonSlot(JsonSerializeFormat & handler, const ArtifactPosition & slot, CMap * map)
{
ArtifactID artifactID;
if(handler.saving)
{
const ArtSlotInfo * info = getSlot(slot);
if(info != nullptr && !info->locked)
{
artifactID = info->getArt()->getTypeId();
2025-05-05 16:05:59 +03:00
handler.serializeId(NArtifactPosition::namesHero.at(slot.num), artifactID, ArtifactID::NONE);
}
}
else
{
2025-05-05 16:05:59 +03:00
handler.serializeId(NArtifactPosition::namesHero.at(slot.num), artifactID, ArtifactID::NONE);
if(artifactID != ArtifactID::NONE)
{
auto * artifact = map->createArtifact(artifactID.toEnum());
if(artifact->getType()->canBePutAt(this, slot))
{
auto artsMap = putArtifact(slot, artifact);
artifact->addPlacementMap(artsMap);
}
else
{
logGlobal->debug("Artifact can't be put at the specified location."); //TODO add more debugging information
}
}
}
}
VCMI_LIB_NAMESPACE_END